Compare commits

...

69 Commits
v3.2.5 ... 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
181 changed files with 9692 additions and 881 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,130 @@
## 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:

204
Cargo.lock generated
View File

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.14.1"
@ -284,7 +286,7 @@ version = "0.1.0"
dependencies = [
"byteorder",
"criterion 0.3.0",
"ethbloom",
"ethbloom 0.9.2",
"parking_lot 0.11.1",
"tempdir",
"tiny-keccak 1.5.0",
@ -421,7 +423,7 @@ dependencies = [
name = "cli-signer"
version = "1.4.0"
dependencies = [
"ethereum-types",
"ethereum-types 0.9.2",
"futures",
"parity-rpc",
"parity-rpc-client",
@ -450,7 +452,7 @@ dependencies = [
name = "common-types"
version = "0.1.0"
dependencies = [
"ethereum-types",
"ethereum-types 0.9.2",
"ethkey",
"hex",
"inflate",
@ -750,7 +752,7 @@ name = "dir"
version = "0.1.2"
dependencies = [
"app_dirs",
"ethereum-types",
"ethereum-types 0.9.2",
"home 0.3.4",
"journaldb",
]
@ -785,7 +787,7 @@ name = "eip-712"
version = "0.1.0"
dependencies = [
"ethabi",
"ethereum-types",
"ethereum-types 0.9.2",
"failure",
"indexmap",
"itertools 0.7.11",
@ -871,7 +873,7 @@ dependencies = [
"num-bigint 0.2.3",
"num-traits 0.2.8",
"once_cell",
"static_assertions",
"static_assertions 1.1.0",
]
[[package]]
@ -891,7 +893,7 @@ version = "12.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052a565e3de82944527d6d10a465697e6bb92476b772ca7141080c901f6a63c6"
dependencies = [
"ethereum-types",
"ethereum-types 0.9.2",
"rustc-hex 2.1.0",
"serde",
"serde_json",
@ -925,7 +927,7 @@ dependencies = [
"criterion 0.2.11",
"crunchy 0.1.6",
"either",
"ethereum-types",
"ethereum-types 0.9.2",
"keccak-hash",
"log",
"memmap",
@ -937,6 +939,19 @@ dependencies = [
"tiny-keccak 2.0.2",
]
[[package]]
name = "ethbloom"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0584482a6433370908dee84ea13992c2cf39c569600e4dbfafe520bb3b90d1"
dependencies = [
"crunchy 0.2.2",
"fixed-hash 0.4.0",
"impl-rlp",
"impl-serde 0.2.3",
"tiny-keccak 1.5.0",
]
[[package]]
name = "ethbloom"
version = "0.9.2"
@ -944,9 +959,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71a6567e6fd35589fea0c63b94b4cf2e55573e413901bdbe60ab15cf0e25e5df"
dependencies = [
"crunchy 0.2.2",
"fixed-hash",
"fixed-hash 0.6.1",
"impl-rlp",
"impl-serde",
"impl-serde 0.3.1",
"tiny-keccak 2.0.2",
]
@ -976,7 +991,7 @@ dependencies = [
"ethcore-io",
"ethcore-miner",
"ethcore-stratum",
"ethereum-types",
"ethereum-types 0.9.2",
"ethjson",
"ethkey",
"evm",
@ -1040,7 +1055,7 @@ name = "ethcore-accounts"
version = "0.1.0"
dependencies = [
"common-types",
"ethereum-types",
"ethereum-types 0.9.2",
"ethkey",
"ethstore",
"log",
@ -1061,7 +1076,7 @@ dependencies = [
"common-types",
"env_logger",
"ethcore-db",
"ethereum-types",
"ethereum-types 0.9.2",
"ethkey",
"itertools 0.5.10",
"keccak-hash",
@ -1098,7 +1113,7 @@ dependencies = [
"byteorder",
"eip-152",
"eth_pairings",
"ethereum-types",
"ethereum-types 0.9.2",
"ethjson",
"ethkey",
"hex-literal",
@ -1117,7 +1132,7 @@ name = "ethcore-call-contract"
version = "0.1.0"
dependencies = [
"common-types",
"ethereum-types",
"ethereum-types 0.9.2",
"parity-bytes",
]
@ -1126,7 +1141,7 @@ name = "ethcore-db"
version = "0.1.0"
dependencies = [
"common-types",
"ethereum-types",
"ethereum-types 0.9.2",
"kvdb",
"kvdb-memorydb",
"kvdb-rocksdb",
@ -1182,7 +1197,7 @@ dependencies = [
"ethabi-derive",
"ethash",
"ethcore-call-contract",
"ethereum-types",
"ethereum-types 0.9.2",
"ethkey",
"fetch",
"futures",
@ -1201,7 +1216,7 @@ dependencies = [
"serde_derive",
"serde_json",
"trace-time",
"transaction-pool",
"txpool",
"url 2.1.0",
]
@ -1212,7 +1227,7 @@ dependencies = [
"assert_matches",
"error-chain",
"ethcore-io",
"ethereum-types",
"ethereum-types 0.9.2",
"ethkey",
"ipnetwork",
"lazy_static",
@ -1236,7 +1251,7 @@ dependencies = [
"error-chain",
"ethcore-io",
"ethcore-network",
"ethereum-types",
"ethereum-types 0.9.2",
"ethkey",
"igd",
"ipnetwork",
@ -1273,7 +1288,7 @@ dependencies = [
"ethcore-db",
"ethcore-io",
"ethcore-sync",
"ethereum-types",
"ethereum-types 0.9.2",
"kvdb",
"kvdb-rocksdb",
"log",
@ -1286,7 +1301,7 @@ name = "ethcore-stratum"
version = "1.12.0"
dependencies = [
"env_logger",
"ethereum-types",
"ethereum-types 0.9.2",
"jsonrpc-core",
"jsonrpc-tcp-server",
"keccak-hash",
@ -1309,7 +1324,7 @@ dependencies = [
"ethcore-network",
"ethcore-network-devp2p",
"ethereum-forkid",
"ethereum-types",
"ethereum-types 0.9.2",
"ethkey",
"ethstore",
"fastmap",
@ -1324,7 +1339,7 @@ dependencies = [
"parity-crypto",
"parity-util-mem",
"parking_lot 0.11.1",
"primitive-types",
"primitive-types 0.7.2",
"rand 0.7.3",
"rand_xorshift 0.2.0",
"rlp",
@ -1341,24 +1356,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3010d8372e3a76d4e2c44de0a080257ab62b6d108857ee7bd70fe8dfb2815f13"
dependencies = [
"crc",
"ethereum-types",
"ethereum-types 0.9.2",
"maplit",
"parity-util-mem",
"rlp",
"rlp-derive",
]
[[package]]
name = "ethereum-types"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5a7777cb75d9ee2b8d3752634b15e4e4e70d2ef81a227e9d157acfa18592b1"
dependencies = [
"ethbloom 0.7.0",
"fixed-hash 0.4.0",
"impl-rlp",
"impl-serde 0.2.3",
"primitive-types 0.5.1",
"uint",
]
[[package]]
name = "ethereum-types"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "473aecff686bd8e7b9db0165cbbb53562376b39bf35b427f0c60446a9e1634b0"
dependencies = [
"ethbloom",
"fixed-hash",
"ethbloom 0.9.2",
"fixed-hash 0.6.1",
"impl-rlp",
"impl-serde",
"primitive-types",
"impl-serde 0.3.1",
"primitive-types 0.7.2",
"uint",
]
@ -1367,7 +1396,7 @@ name = "ethjson"
version = "0.1.0"
dependencies = [
"common-types",
"ethereum-types",
"ethereum-types 0.9.2",
"macros",
"maplit",
"parity-crypto",
@ -1383,7 +1412,7 @@ version = "0.3.0"
dependencies = [
"edit-distance",
"eth-secp256k1",
"ethereum-types",
"ethereum-types 0.9.2",
"lazy_static",
"log",
"memzero",
@ -1417,7 +1446,7 @@ dependencies = [
name = "ethstore"
version = "0.2.1"
dependencies = [
"ethereum-types",
"ethereum-types 0.9.2",
"ethkey",
"itertools 0.5.10",
"lazy_static",
@ -1461,7 +1490,7 @@ dependencies = [
"bit-set",
"criterion 0.2.11",
"ethcore-builtin",
"ethereum-types",
"ethereum-types 0.9.2",
"hex-literal",
"keccak-hash",
"lazy_static",
@ -1484,7 +1513,7 @@ dependencies = [
"docopt",
"env_logger",
"ethcore",
"ethereum-types",
"ethereum-types 0.9.2",
"ethjson",
"evm",
"panic_hook",
@ -1539,7 +1568,7 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
name = "fastmap"
version = "0.1.0"
dependencies = [
"ethereum-types",
"ethereum-types 0.9.2",
"plain_hasher",
]
@ -1566,6 +1595,18 @@ dependencies = [
"url 2.1.0",
]
[[package]]
name = "fixed-hash"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "516877b7b9a1cc2d0293cbce23cd6203f0edbfd4090e6ca4489fecb5aa73050e"
dependencies = [
"byteorder",
"rand 0.5.6",
"rustc-hex 2.1.0",
"static_assertions 0.2.5",
]
[[package]]
name = "fixed-hash"
version = "0.6.1"
@ -1575,7 +1616,7 @@ dependencies = [
"byteorder",
"rand 0.7.3",
"rustc-hex 2.1.0",
"static_assertions",
"static_assertions 1.1.0",
]
[[package]]
@ -2060,6 +2101,15 @@ dependencies = [
"rlp",
]
[[package]]
name = "impl-serde"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8"
dependencies = [
"serde",
]
[[package]]
name = "impl-serde"
version = "0.3.1"
@ -2167,7 +2217,7 @@ version = "0.2.0"
dependencies = [
"env_logger",
"ethcore-db",
"ethereum-types",
"ethereum-types 0.9.2",
"fastmap",
"hash-db 0.11.0",
"keccak-hash",
@ -2298,7 +2348,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f58a51ef3df9398cf2434bea8d4eb61fb748d0feb1571f87388579a120a4c8f"
dependencies = [
"primitive-types",
"primitive-types 0.7.2",
"tiny-keccak 2.0.2",
]
@ -2306,7 +2356,7 @@ dependencies = [
name = "keccak-hasher"
version = "0.1.1"
dependencies = [
"ethereum-types",
"ethereum-types 0.9.2",
"hash-db 0.11.0",
"plain_hasher",
"tiny-keccak 1.5.0",
@ -2745,7 +2795,7 @@ dependencies = [
"ethcore-io",
"ethcore-network",
"ethcore-network-devp2p",
"ethereum-types",
"ethereum-types 0.9.2",
"kvdb-memorydb",
"log",
"lru-cache",
@ -2882,7 +2932,7 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "openethereum"
version = "3.2.5"
version = "3.3.3"
dependencies = [
"ansi_term 0.10.2",
"atty",
@ -2904,7 +2954,7 @@ dependencies = [
"ethcore-network",
"ethcore-service",
"ethcore-sync",
"ethereum-types",
"ethereum-types 0.9.2",
"ethkey",
"ethstore",
"fake-fetch",
@ -2991,7 +3041,7 @@ dependencies = [
"aes-ctr",
"block-modes",
"digest",
"ethereum-types",
"ethereum-types 0.9.2",
"hmac",
"lazy_static",
"pbkdf2",
@ -3084,7 +3134,7 @@ dependencies = [
"ethcore-miner",
"ethcore-network",
"ethcore-sync",
"ethereum-types",
"ethereum-types 0.9.2",
"ethjson",
"ethkey",
"ethstore",
@ -3119,8 +3169,8 @@ dependencies = [
"tempdir",
"tiny-keccak 1.5.0",
"tokio-timer 0.1.2",
"transaction-pool",
"transient-hashmap",
"txpool",
"vm",
]
@ -3128,7 +3178,7 @@ dependencies = [
name = "parity-rpc-client"
version = "1.4.0"
dependencies = [
"ethereum-types",
"ethereum-types 0.9.2",
"futures",
"jsonrpc-core",
"jsonrpc-ws-server",
@ -3208,13 +3258,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "297ff91fa36aec49ce183484b102f6b75b46776822bd81525bfc4cc9b0dd0f5c"
dependencies = [
"cfg-if 0.1.10",
"ethereum-types",
"ethereum-types 0.9.2",
"hashbrown 0.8.2",
"impl-trait-for-tuples",
"lru",
"parity-util-mem-derive",
"parking_lot 0.10.2",
"primitive-types",
"primitive-types 0.7.2",
"smallvec 1.6.1",
"winapi 0.3.8",
]
@ -3232,7 +3282,7 @@ dependencies = [
[[package]]
name = "parity-version"
version = "3.2.5"
version = "3.3.3"
dependencies = [
"parity-bytes",
"rlp",
@ -3385,7 +3435,7 @@ name = "patricia-trie-ethereum"
version = "0.1.0"
dependencies = [
"elastic-array",
"ethereum-types",
"ethereum-types 0.9.2",
"hash-db 0.11.0",
"journaldb",
"keccak-hash",
@ -3517,16 +3567,29 @@ dependencies = [
"smallvec 0.6.13",
]
[[package]]
name = "primitive-types"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83ef7b3b965c0eadcb6838f34f827e1dfb2939bdd5ebd43f9647e009b12b0371"
dependencies = [
"fixed-hash 0.4.0",
"impl-codec",
"impl-rlp",
"impl-serde 0.2.3",
"uint",
]
[[package]]
name = "primitive-types"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c55c21c64d0eaa4d7ed885d959ef2d62d9e488c27c0e02d9aa5ce6c877b7d5f8"
dependencies = [
"fixed-hash",
"fixed-hash 0.6.1",
"impl-codec",
"impl-rlp",
"impl-serde",
"impl-serde 0.3.1",
"uint",
]
@ -4297,7 +4360,7 @@ dependencies = [
"byteorder",
"crunchy 0.2.2",
"rustc-hex 2.1.0",
"static_assertions",
"static_assertions 1.1.0",
]
[[package]]
@ -4373,6 +4436,12 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
[[package]]
name = "static_assertions"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
[[package]]
name = "static_assertions"
version = "1.1.0"
@ -4945,17 +5014,6 @@ dependencies = [
"log",
]
[[package]]
name = "transaction-pool"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8bbee24c711a878e7d8f89460569034cacf2d8c58dde785b5ffa06ed6b59663"
dependencies = [
"log",
"smallvec 0.6.13",
"trace-time",
]
[[package]]
name = "transient-hashmap"
version = "0.4.1"
@ -4998,7 +5056,7 @@ dependencies = [
name = "triehash-ethereum"
version = "0.2.0"
dependencies = [
"ethereum-types",
"ethereum-types 0.9.2",
"keccak-hasher 0.1.1",
"triehash",
]
@ -5015,6 +5073,16 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
[[package]]
name = "txpool"
version = "1.0.0-alpha"
dependencies = [
"ethereum-types 0.7.0",
"log",
"smallvec 0.6.13",
"trace-time",
]
[[package]]
name = "typenum"
version = "1.11.2"
@ -5036,7 +5104,7 @@ dependencies = [
"byteorder",
"crunchy 0.2.2",
"rustc-hex 2.1.0",
"static_assertions",
"static_assertions 1.1.0",
]
[[package]]
@ -5188,7 +5256,7 @@ checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
name = "vm"
version = "0.1.0"
dependencies = [
"ethereum-types",
"ethereum-types 0.9.2",
"ethjson",
"keccak-hash",
"parity-bytes",
@ -5247,7 +5315,7 @@ version = "0.1.0"
dependencies = [
"byteorder",
"env_logger",
"ethereum-types",
"ethereum-types 0.9.2",
"libc",
"log",
"parity-wasm",

View File

@ -2,7 +2,7 @@
description = "OpenEthereum"
name = "openethereum"
# NOTE Make sure to update util/version/Cargo.toml as well
version = "3.2.5"
version = "3.3.3"
license = "GPL-3.0"
authors = [
"OpenEthereum developers",

View File

@ -46,6 +46,8 @@ use bytes::Bytes;
use docopt::Docopt;
use ethcore::{json_tests, spec, TrieSpec};
use ethereum_types::{Address, U256};
use ethjson::spec::ForkSpec;
use evm::EnvInfo;
use rustc_hex::FromHex;
use std::{fmt, fs, path::PathBuf, sync::Arc};
use vm::{ActionParams, CallType};
@ -192,10 +194,18 @@ fn run_state_test(args: Args) {
}
let multitransaction = test.transaction;
let env_info = test.env.into();
let env_info: EnvInfo = test.env.into();
let pre = test.pre_state.into();
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
.as_ref()
.map(|only_chain| &format!("{:?}", spec).to_lowercase() == only_chain)
@ -218,7 +228,7 @@ fn run_state_test(args: Args) {
&spec,
&pre,
post_root,
&env_info,
&test_env,
transaction,
display::json::Informant::new(config),
trie_spec,
@ -231,7 +241,7 @@ fn run_state_test(args: Args) {
&spec,
&pre,
post_root,
&env_info,
&test_env,
transaction,
display::std_json::Informant::err_only(config),
trie_spec,
@ -243,7 +253,7 @@ fn run_state_test(args: Args) {
&spec,
&pre,
post_root,
&env_info,
&test_env,
transaction,
display::std_json::Informant::out_only(config),
trie_spec,
@ -255,7 +265,7 @@ fn run_state_test(args: Args) {
&spec,
&pre,
post_root,
&env_info,
&test_env,
transaction,
display::std_json::Informant::new_default(config),
trie_spec,
@ -268,7 +278,7 @@ fn run_state_test(args: Args) {
&spec,
&pre,
post_root,
&env_info,
&test_env,
transaction,
display::simple::Informant::new(config),
trie_spec,

View File

@ -680,7 +680,7 @@ usage! {
ARG arg_min_gas_price: (Option<u64>) = None, or |c: &Config| c.mining.as_ref()?.min_gas_price.clone(),
"--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,
"--gas-price-percentile=[PCT]",

View File

@ -640,14 +640,16 @@ impl Configuration {
fn pool_verification_options(&self) -> Result<pool::verifier::Options, String> {
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,
block_gas_limit: U256::max_value(),
block_base_fee: None,
tx_gas_limit: match self.args.arg_tx_gas_limit {
Some(ref d) => to_u256(d)?,
None => U256::max_value(),
},
no_early_reject: self.args.flag_tx_queue_no_early_reject,
allow_non_eoa_sender: false,
})
}

View File

@ -254,6 +254,7 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<RunningClient
_ => sync::WarpSync::Disabled,
};
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)?;
@ -365,8 +366,18 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<RunningClient
// take handle to client
let client = service.client();
// Update miners block gas limit
miner.update_transaction_queue_limits(*client.best_block_header().gas_limit());
// Update miners block gas limit and base_fee
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| {
Arc::new(NodeFilter::new(

View File

@ -36,7 +36,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_derive = "1.0"
serde_json = "1.0"
trace-time = "0.1"
transaction-pool = "2.0.1"
txpool = { path = "../../transaction-pool" }
[dev-dependencies]
env_logger = "0.5"

View File

@ -35,7 +35,7 @@ extern crate parking_lot;
#[cfg(feature = "price-info")]
extern crate price_info;
extern crate rlp;
extern crate transaction_pool as txpool;
extern crate txpool;
#[macro_use]
extern crate ethabi_contract;

View File

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

View File

@ -71,6 +71,9 @@ pub struct PendingSettings {
pub max_len: usize,
/// Ordering of transactions.
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 {
@ -82,6 +85,7 @@ impl PendingSettings {
nonce_cap: None,
max_len: usize::max_value(),
ordering: PendingOrdering::Priority,
includable_boundary: Default::default(),
}
}
}
@ -118,7 +122,7 @@ pub trait ScoredTransaction {
fn priority(&self) -> Priority;
/// Gets transaction gas price.
fn gas_price(&self) -> &U256;
fn effective_gas_price(&self, block_base_fee: Option<U256>) -> U256;
/// Gets transaction nonce.
fn nonce(&self) -> U256;
@ -184,6 +188,10 @@ impl txpool::VerifiedTransaction for VerifiedTransaction {
fn sender(&self) -> &Address {
&self.sender
}
fn has_zero_gas_price(&self) -> bool {
self.transaction.has_zero_gas_price()
}
}
impl ScoredTransaction for VerifiedTransaction {
@ -191,9 +199,8 @@ impl ScoredTransaction for VerifiedTransaction {
self.priority
}
/// Gets transaction gas price.
fn gas_price(&self) -> &U256 {
&self.transaction.tx().gas_price
fn effective_gas_price(&self, block_base_fee: Option<U256>) -> U256 {
self.transaction.effective_gas_price(block_base_fee)
}
/// Gets transaction nonce.

View File

@ -26,6 +26,7 @@ use std::{
},
};
use self::scoring::ScoringEvent;
use ethereum_types::{Address, H256, U256};
use parking_lot::RwLock;
use txpool::{self, Verifier};
@ -245,7 +246,10 @@ impl TransactionQueue {
insertion_id: Default::default(),
pool: RwLock::new(txpool::Pool::new(
Default::default(),
scoring::NonceAndGasPrice(strategy),
scoring::NonceAndGasPrice {
strategy,
block_base_fee: verification_options.block_base_fee,
},
limits,
)),
options: RwLock::new(verification_options),
@ -257,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
///
/// Some parameters of verification may vary in time (like block gas limit or minimal gas price).
@ -307,8 +331,11 @@ impl TransactionQueue {
transaction_to_replace,
);
let mut replace =
replace::ReplaceByScoreAndReadiness::new(self.pool.read().scoring().clone(), client);
let mut replace = replace::ReplaceByScoreAndReadiness::new(
self.pool.read().scoring().clone(),
client,
self.options.read().block_base_fee,
);
let results = transactions
.into_iter()
@ -353,7 +380,10 @@ impl TransactionQueue {
/// Returns all transactions in the queue without explicit ordering.
pub fn all_transactions(&self) -> Vec<Arc<pool::VerifiedTransaction>> {
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.
@ -361,7 +391,7 @@ impl TransactionQueue {
let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready;
self.pool
.read()
.unordered_pending(ready)
.unordered_pending(ready, Default::default())
.map(|tx| tx.hash)
.collect()
}
@ -376,7 +406,7 @@ impl TransactionQueue {
let ready = ready::OptionalState::new(nonce);
self.pool
.read()
.unordered_pending(ready)
.unordered_pending(ready, Default::default())
.map(|tx| tx.hash)
.collect()
}
@ -400,6 +430,7 @@ impl TransactionQueue {
nonce_cap,
max_len,
ordering,
includable_boundary,
} = settings;
if let Some(pending) = self.cached_pending.read().pending(
block_number,
@ -425,15 +456,19 @@ impl TransactionQueue {
return self
.pool
.read()
.unordered_pending(ready)
.unordered_pending(ready, includable_boundary)
.take(max_len)
.collect();
}
let pending: Vec<_> =
self.collect_pending(client, block_number, current_timestamp, nonce_cap, |i| {
i.take(max_len).collect()
});
let pending: Vec<_> = self.collect_pending(
client,
includable_boundary,
block_number,
current_timestamp,
nonce_cap,
|i| i.take(max_len).collect(),
);
*cached_pending = CachedPending {
block_number,
@ -461,6 +496,7 @@ impl TransactionQueue {
{
self.collect_pending(
client,
settings.includable_boundary,
settings.block_number,
settings.current_timestamp,
settings.nonce_cap,
@ -479,6 +515,7 @@ impl TransactionQueue {
pub fn collect_pending<C, F, T>(
&self,
client: C,
includable_boundary: U256,
block_number: u64,
current_timestamp: u64,
nonce_cap: Option<U256>,
@ -498,7 +535,7 @@ impl TransactionQueue {
debug!(target: "txqueue", "Re-computing pending set for block: {}", block_number);
trace_time!("pool::collect_pending");
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>(
@ -563,7 +600,7 @@ impl TransactionQueue {
self.pool
.read()
.pending_from_sender(state_readiness, address)
.pending_from_sender(state_readiness, address, Default::default())
.last()
.map(|tx| tx.signed().tx().nonce.saturating_add(U256::from(1)))
}
@ -612,18 +649,37 @@ impl TransactionQueue {
pub fn penalize<'a, T: IntoIterator<Item = &'a Address>>(&self, senders: T) {
let mut pool = self.pool.write();
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.
pub fn current_worst_gas_price(&self) -> U256 {
match self.pool.read().worst_transaction() {
Some(tx) => tx.signed().tx().gas_price,
None => self.options.read().minimal_gas_price,
Some(tx) => tx
.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.
pub fn status(&self) -> Status {
let pool = self.pool.read();

View File

@ -39,12 +39,18 @@ use txpool::{
pub struct ReplaceByScoreAndReadiness<S, C> {
scoring: S,
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> {
/// Create a new `ReplaceByScoreAndReadiness`
pub fn new(scoring: S, client: C) -> Self {
ReplaceByScoreAndReadiness { scoring, client }
pub fn new(scoring: S, client: C, block_base_fee: Option<U256>) -> Self {
ReplaceByScoreAndReadiness {
scoring,
client,
block_base_fee,
}
}
}
@ -67,8 +73,9 @@ where
} else if both_local {
Choice::InsertNew
} else {
let old_score = (old.priority(), old.gas_price());
let new_score = (new.priority(), new.gas_price());
let old_score = (old.priority(), old.effective_gas_price(self.block_base_fee));
let new_score = (new.priority(), new.effective_gas_price(self.block_base_fee));
if new_score > old_score {
// Check if this is a replacement transaction.
//
@ -155,9 +162,12 @@ mod tests {
#[test]
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 replace = ReplaceByScoreAndReadiness::new(scoring, client);
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
// same sender txs
let keypair = Random.generate();
@ -249,9 +259,12 @@ mod tests {
#[test]
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 replace = ReplaceByScoreAndReadiness::new(scoring, client);
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
let tx1 = Tx {
nonce: 1,
@ -311,9 +324,12 @@ mod tests {
#[test]
fn should_replace_different_sender_by_priority_and_gas_price() {
// given
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
let scoring = NonceAndGasPrice {
strategy: PrioritizationStrategy::GasPriceOnly,
block_base_fee: None,
};
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 = Tx {
@ -406,9 +422,12 @@ mod tests {
#[test]
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 replace = ReplaceByScoreAndReadiness::new(scoring, client);
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
let tx_ready_low_score = {
let tx = Tx {
@ -436,9 +455,12 @@ mod tests {
#[test]
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 replace = ReplaceByScoreAndReadiness::new(scoring, client);
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
let old_sender = Random.generate();
let tx_old_ready_1 = {
@ -504,9 +526,12 @@ mod tests {
#[test]
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 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
let old_tx = {
@ -572,9 +597,12 @@ mod tests {
#[test]
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 replace = ReplaceByScoreAndReadiness::new(scoring, client);
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
// current transaction is ready
let old_tx = {
@ -627,9 +655,12 @@ mod tests {
#[test]
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 replace = ReplaceByScoreAndReadiness::new(scoring, client);
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
// current transaction is ready
let old_tx = {

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 {
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.
///
/// NOTE: Currently penalization does not apply to new transactions that enter the pool.
/// We might want to store penalization status in some persistent state.
#[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 {
/// Decide if the transaction should even be considered into the pool (if the pool is full).
@ -67,7 +79,7 @@ impl NonceAndGasPrice {
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,
{
type Score = U256;
type Event = ();
type Event = ScoringEvent;
fn compare(&self, old: &P, other: &P) -> cmp::Ordering {
old.nonce().cmp(&other.nonce())
@ -87,10 +99,10 @@ where
return scoring::Choice::InsertNew;
}
let old_gp = old.gas_price();
let new_gp = new.gas_price();
let old_gp = old.effective_gas_price(self.block_base_fee);
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) {
cmp::Ordering::Greater => scoring::Choice::RejectNew,
@ -102,7 +114,7 @@ where
&self,
txs: &[txpool::Transaction<P>],
scores: &mut [U256],
change: scoring::Change,
change: scoring::Change<ScoringEvent>,
) {
use self::scoring::Change;
@ -113,21 +125,46 @@ where
assert!(i < txs.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() {
super::Priority::Local => 15,
super::Priority::Retracted => 10,
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.
// So just lower the priority of all non-local transactions.
Change::Event(_) => {
for (score, tx) in scores.iter_mut().zip(txs) {
// Never penalize local transactions.
if !tx.priority().is_local() {
*score = *score >> 3;
Change::Event(event) => {
match event {
ScoringEvent::Penalize => {
for (score, tx) in scores.iter_mut().zip(txs) {
// 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]
fn should_calculate_score_correctly() {
// 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 transactions = vec![tx1, tx2, tx3]
.into_iter()
@ -200,7 +240,11 @@ mod tests {
assert_eq!(scores, vec![32768.into(), 1024.into(), 1.into()]);
// 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()]);
}
}

View File

@ -43,6 +43,7 @@ impl Default for TestClient {
account_details: AccountDetails {
nonce: 123.into(),
balance: 63_100.into(),
code_hash: None,
is_local: false,
},
gas_required: 21_000.into(),
@ -68,6 +69,11 @@ impl TestClient {
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 {
self.gas_required = gas_required.into();
self

View File

@ -15,6 +15,7 @@
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use ethereum_types::U256;
use hash::KECCAK_EMPTY;
use txpool;
use types::transaction::{self, PendingTransaction};
@ -46,6 +47,8 @@ fn new_queue() -> TransactionQueue {
block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(),
no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
},
PrioritizationStrategy::GasPriceOnly,
)
@ -64,6 +67,8 @@ fn should_return_correct_nonces_when_dropped_because_of_limit() {
block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(),
no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
},
PrioritizationStrategy::GasPriceOnly,
);
@ -124,6 +129,8 @@ fn should_never_drop_local_transactions_from_different_senders() {
block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(),
no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
},
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);
}
#[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]
fn should_import_txs_from_same_sender() {
// given
@ -541,6 +613,8 @@ fn should_prefer_current_transactions_when_hitting_the_limit() {
block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(),
no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
},
PrioritizationStrategy::GasPriceOnly,
);
@ -898,6 +972,7 @@ fn should_not_return_transactions_over_nonce_cap() {
nonce_cap: Some(123.into()),
max_len: usize::max_value(),
ordering: PendingOrdering::Priority,
includable_boundary: Default::default(),
},
);
@ -932,6 +1007,7 @@ fn should_return_cached_pending_even_if_unordered_is_requested() {
nonce_cap: None,
max_len: 3,
ordering: PendingOrdering::Unordered,
includable_boundary: Default::default(),
},
);
@ -960,6 +1036,7 @@ fn should_return_unordered_and_not_populate_the_cache() {
nonce_cap: None,
max_len: usize::max_value(),
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(),
tx_gas_limit: 1_000_000.into(),
no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
},
PrioritizationStrategy::GasPriceOnly,
);
@ -1067,6 +1146,8 @@ fn should_avoid_verifying_transaction_already_in_pool() {
block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(),
no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
},
PrioritizationStrategy::GasPriceOnly,
);
@ -1102,6 +1183,8 @@ fn should_avoid_reverifying_recently_rejected_transactions() {
block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(),
no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
},
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(),
tx_gas_limit: 1_000_000.into(),
no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
},
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(),
tx_gas_limit: 1_000_000.into(),
no_early_reject: true,
block_base_fee: None,
allow_non_eoa_sender: false,
},
PrioritizationStrategy::GasPriceOnly,
);

View File

@ -31,6 +31,7 @@ use std::{
};
use ethereum_types::{H256, U256};
use hash::KECCAK_EMPTY;
use txpool;
use types::transaction;
@ -42,14 +43,18 @@ use super::{
/// Verification options.
#[derive(Debug, Clone, PartialEq)]
pub struct Options {
/// Minimal allowed gas price.
/// Minimal allowed gas price (actually minimal block producer reward = effective_priority_fee).
pub minimal_gas_price: U256,
/// Current block gas limit.
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.
pub tx_gas_limit: U256,
/// Skip checks for early rejection, to make sure that local transactions are always imported.
pub no_early_reject: bool,
/// Accept transactions from non EOAs (see EIP-3607)
pub allow_non_eoa_sender: bool,
}
#[cfg(test)]
@ -58,8 +63,10 @@ impl Default for Options {
Options {
minimal_gas_price: 0.into(),
block_gas_limit: U256::max_value(),
block_base_fee: None,
tx_gas_limit: U256::max_value(),
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 {
match *self {
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 {
match *self {
Transaction::Unverified(ref tx) => &*tx,
@ -213,22 +247,26 @@ impl<C: Client> txpool::Verifier<Transaction>
}
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
//
// We're checking if the transaction is below configured minimal gas price
// 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!(
target: "txqueue",
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
hash,
tx.gas_price(),
effective_priority_fee,
self.options.minimal_gas_price,
);
bail!(transaction::Error::InsufficientGasPrice {
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",
"[{:?}] Rejected tx early, cause it doesn't have any chance to get to the pool: (gas price: {} < {})",
hash,
tx.gas_price(),
vtx.transaction.tx().gas_price,
tx.effective_gas_price(self.options.block_base_fee),
vtx.transaction.effective_gas_price(self.options.block_base_fee),
);
return Err(transaction::Error::TooCheapToReplace {
prev: Some(vtx.transaction.tx().gas_price),
new: Some(*tx.gas_price()),
prev: Some(
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 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);
if let TransactionType::Service = transaction_type {
debug!(target: "txqueue", "Service tx {:?} below minimal gas price accepted", hash);
@ -291,20 +349,26 @@ impl<C: Client> txpool::Verifier<Transaction>
target: "txqueue",
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
hash,
transaction.tx().gas_price,
effective_priority_fee,
self.options.minimal_gas_price,
);
bail!(transaction::Error::InsufficientGasPrice {
minimal: self.options.minimal_gas_price,
got: transaction.tx().gas_price,
got: effective_priority_fee,
});
}
}
let (full_gas_price, overflow_1) = transaction
.tx()
.gas_price
.overflowing_mul(transaction.tx().gas);
let gas_price = transaction.tx().gas_price;
if gas_price < transaction.max_priority_fee_per_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);
if overflow_1 || overflow_2 {
trace!(

View File

@ -45,7 +45,7 @@ impl ServiceTransactionChecker {
) -> Result<bool, String> {
let sender = tx.sender();
// Skip checking the contract if the transaction does not have zero gas price
if !tx.tx().gas_price.is_zero() {
if !tx.has_zero_gas_price() {
return Ok(false);
}
@ -72,7 +72,7 @@ impl ServiceTransactionChecker {
SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned(),
BlockId::Latest,
)
.ok_or_else(|| "contract is not configured")?;
.ok_or_else(|| "Certifier contract is not configured")?;
self.call_contract(client, contract_address, sender)
.and_then(|allowed| {
if let Some(mut cache) = self.certified_addresses_cache.try_write() {

View File

@ -25,12 +25,14 @@ use std::{
use super::{
error_key_already_exists, error_negatively_reference_hash, memory_db::*, LATEST_ERA_KEY,
};
use bytes::Bytes;
use ethcore_db::{DBTransaction, DBValue, KeyValueDB};
use ethereum_types::H256;
use hash_db::HashDB;
use keccak_hasher::KeccakHasher;
use rlp::{decode, encode};
use traits::JournalDB;
use DB_PREFIX_LEN;
/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay
/// and latent-removal semantics.
@ -214,12 +216,19 @@ impl JournalDB for ArchiveDB {
fn consolidate(&mut self, with: MemoryDB<KeccakHasher, DBValue>) {
self.overlay.consolidate(with);
}
fn state(&self, id: &H256) -> Option<Bytes> {
self.backing
.get_by_prefix(self.column, &id[0..DB_PREFIX_LEN])
.map(|b| b.into_vec())
}
}
#[cfg(test)]
mod tests {
use super::*;
use ethcore_db::InMemoryWithMetrics;
use hash_db::HashDB;
use keccak::keccak;
use JournalDB;
@ -497,4 +506,22 @@ mod tests {
assert!(jdb.get(&key).is_none());
}
#[test]
fn returns_state() {
let shared_db = Arc::new(InMemoryWithMetrics::create(0));
let key = {
let mut jdb = ArchiveDB::new(shared_db.clone(), None);
let key = jdb.insert(b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
key
};
{
let jdb = ArchiveDB::new(shared_db, None);
let state = jdb.state(&key);
assert!(state.is_some());
}
}
}

View File

@ -35,6 +35,7 @@ use parity_util_mem::MallocSizeOf;
use parking_lot::RwLock;
use rlp::{decode, encode};
use util::{DatabaseKey, DatabaseValueRef, DatabaseValueView};
use DB_PREFIX_LEN;
#[derive(Debug, Clone, PartialEq, Eq, MallocSizeOf)]
struct RefInfo {
@ -608,6 +609,12 @@ impl JournalDB for EarlyMergeDB {
fn consolidate(&mut self, with: MemoryDB<KeccakHasher, DBValue>) {
self.overlay.consolidate(with);
}
fn state(&self, id: &H256) -> Option<Bytes> {
self.backing
.get_by_prefix(self.column, &id[0..DB_PREFIX_LEN])
.map(|b| b.into_vec())
}
}
#[cfg(test)]

View File

@ -23,6 +23,7 @@ use std::{
};
use super::{error_negatively_reference_hash, JournalDB, DB_PREFIX_LEN, LATEST_ERA_KEY};
use bytes::Bytes;
use ethcore_db::{DBTransaction, DBValue, KeyValueDB};
use ethereum_types::H256;
use fastmap::H256FastMap;
@ -509,6 +510,26 @@ impl JournalDB for OverlayRecentDB {
fn consolidate(&mut self, with: MemoryDB<KeccakHasher, DBValue>) {
self.transaction_overlay.consolidate(with);
}
fn state(&self, key: &H256) -> Option<Bytes> {
let journal_overlay = self.journal_overlay.read();
let key = to_short_key(key);
journal_overlay
.backing_overlay
.get(&key)
.map(|v| v.into_vec())
.or_else(|| {
journal_overlay
.pending_overlay
.get(&key)
.map(|d| d.clone().into_vec())
})
.or_else(|| {
self.backing
.get_by_prefix(self.column, &key[0..DB_PREFIX_LEN])
.map(|b| b.into_vec())
})
}
}
impl HashDB<KeccakHasher, DBValue> for OverlayRecentDB {

View File

@ -23,6 +23,7 @@ use std::{
};
use super::{traits::JournalDB, LATEST_ERA_KEY};
use bytes::Bytes;
use ethcore_db::{DBTransaction, DBValue, KeyValueDB};
use ethereum_types::H256;
use hash_db::HashDB;
@ -32,6 +33,7 @@ use overlaydb::OverlayDB;
use parity_util_mem::{allocators::new_malloc_size_ops, MallocSizeOf};
use rlp::{decode, encode};
use util::{DatabaseKey, DatabaseValueRef, DatabaseValueView};
use DB_PREFIX_LEN;
/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay
/// and latent-removal semantics.
@ -245,6 +247,12 @@ impl JournalDB for RefCountedDB {
}
}
}
fn state(&self, id: &H256) -> Option<Bytes> {
self.backing
.get_by_prefix(self.column, &id[0..DB_PREFIX_LEN])
.map(|b| b.into_vec())
}
}
#[cfg(test)]

View File

@ -18,6 +18,7 @@
use std::{io, sync::Arc};
use bytes::Bytes;
use ethcore_db::{DBTransaction, DBValue, KeyValueDB};
use ethereum_types::H256;
use hash_db::{AsHashDB, HashDB};
@ -95,6 +96,9 @@ pub trait JournalDB: KeyedHashDB {
/// Consolidate all the insertions and deletions in the given memory overlay.
fn consolidate(&mut self, overlay: ::memory_db::MemoryDB<KeccakHasher, DBValue>);
/// State data query
fn state(&self, id: &H256) -> Option<Bytes>;
/// Commit all changes in a single batch
#[cfg(test)]
fn commit_batch(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> io::Result<u32> {

View File

@ -153,8 +153,9 @@ pub trait BlockProvider {
/// Get a list of uncles for a given block.
/// Returns None if block does not exist.
fn uncles(&self, hash: &H256) -> Option<Vec<Header>> {
self.block_body(hash).map(|body| body.uncles())
fn uncles(&self, hash: &H256, eip1559_transition: BlockNumber) -> Option<Vec<Header>> {
self.block_body(hash)
.map(|body| body.uncles(eip1559_transition))
}
/// Get a list of uncle hashes for a given block.
@ -272,6 +273,9 @@ pub struct BlockChain {
pending_block_hashes: RwLock<HashMap<BlockNumber, H256>>,
pending_block_details: RwLock<HashMap<H256, BlockDetails>>,
pending_transaction_addresses: RwLock<HashMap<H256, Option<TransactionAddress>>>,
/// Number of first block where EIP-1559 rules begin. New encoding/decoding block format.
pub eip1559_transition: BlockNumber,
}
impl BlockProvider for BlockChain {
@ -559,7 +563,7 @@ impl<'a> Iterator for AncestryWithMetadataIter<'a> {
} else {
let details = self.chain.block_details(&self.current);
let header = self.chain.block_header_data(&self.current).map(|h| {
h.decode()
h.decode(self.chain.eip1559_transition)
.expect("Stored block header data is valid RLP; qed")
});
@ -630,7 +634,12 @@ impl<'a> Iterator for EpochTransitionIter<'a> {
impl BlockChain {
/// Create new instance of blockchain from given Genesis.
pub fn new(config: Config, genesis: &[u8], db: Arc<dyn BlockChainDB>) -> BlockChain {
pub fn new(
config: Config,
genesis: &[u8],
db: Arc<dyn BlockChainDB>,
eip1559_transition: BlockNumber,
) -> BlockChain {
// 400 is the average size of the key
let cache_man = CacheManager::new(config.pref_cache_size, config.max_cache_size, 400);
@ -656,6 +665,7 @@ impl BlockChain {
pending_block_hashes: RwLock::new(HashMap::new()),
pending_block_details: RwLock::new(HashMap::new()),
pending_transaction_addresses: RwLock::new(HashMap::new()),
eip1559_transition,
};
// load best block
@ -715,7 +725,7 @@ impl BlockChain {
let mut best_block = bc.best_block.write();
*best_block = BestBlock {
total_difficulty: best_block_total_difficulty,
header: best_block_rlp.decode_header(),
header: best_block_rlp.decode_header(eip1559_transition),
block: best_block_rlp,
};
}
@ -1044,7 +1054,7 @@ impl BlockChain {
let mut best_block = self.best_block.write();
*best_block = BestBlock {
total_difficulty: best_block_total_difficulty,
header: best_block_rlp.decode_header(),
header: best_block_rlp.decode_header(self.eip1559_transition),
block: best_block_rlp,
};
}
@ -1463,7 +1473,7 @@ impl BlockChain {
batch.put(db::COL_EXTRA, b"best", update.info.hash.as_bytes());
*best_block = Some(BestBlock {
total_difficulty: update.info.total_difficulty,
header: update.block.decode_header(),
header: update.block.decode_header(self.eip1559_transition),
block: update.block,
});
}
@ -1991,8 +2001,12 @@ mod tests {
Arc::new(db)
}
fn new_chain(genesis: encoded::Block, db: Arc<dyn BlockChainDB>) -> BlockChain {
BlockChain::new(Config::default(), genesis.raw(), db)
fn new_chain(
genesis: encoded::Block,
db: Arc<dyn BlockChainDB>,
eip1559_transition: BlockNumber,
) -> BlockChain {
BlockChain::new(Config::default(), genesis.raw(), db, eip1559_transition)
}
fn insert_block(
@ -2058,7 +2072,11 @@ mod tests {
let first = genesis.add_block();
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
assert_eq!(bc.best_block_number(), 0);
// when
@ -2086,7 +2104,7 @@ mod tests {
let first_hash = first.hash();
let db = new_db();
let bc = new_chain(genesis.encoded(), db.clone());
let bc = new_chain(genesis.encoded(), db.clone(), BlockNumber::max_value());
assert_eq!(bc.genesis_hash(), genesis_hash);
assert_eq!(bc.best_block_hash(), genesis_hash);
@ -2118,7 +2136,11 @@ mod tests {
let generator = BlockGenerator::new(vec![first_10]);
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
let mut block_hashes = vec![genesis.last().hash()];
let mut batch = db.key_value().transaction();
@ -2165,7 +2187,11 @@ mod tests {
let generator = BlockGenerator::new(vec![b1a, b1b, b2a, b2b, b3a, b3b, b4a, b4b, b5a, b5b]);
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
for b in generator {
insert_block(&db, &bc, b.encoded(), vec![]);
@ -2204,7 +2230,11 @@ mod tests {
let b2_hash = b2.last().hash();
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
let mut batch = db.key_value().transaction();
let _ = insert_block_batch(&mut batch, &bc, b1a.last().encoded(), vec![]);
@ -2291,7 +2321,11 @@ mod tests {
let t3_hash = t3.hash();
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
let mut batch = db.key_value().transaction();
let _ = insert_block_batch(&mut batch, &bc, b1a.last().encoded(), vec![]);
@ -2364,7 +2398,11 @@ mod tests {
let best_block_hash = b3a_hash;
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
let mut batch = db.key_value().transaction();
let ir1 = insert_block_batch(&mut batch, &bc, b1.last().encoded(), vec![]);
@ -2490,7 +2528,11 @@ mod tests {
let db = new_db();
{
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
assert_eq!(bc.best_block_hash(), genesis_hash);
let mut batch = db.key_value().transaction();
insert_block_batch(&mut batch, &bc, first.last().encoded(), vec![]);
@ -2500,7 +2542,11 @@ mod tests {
}
{
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
assert_eq!(bc.best_block_hash(), first_hash);
}
@ -2515,7 +2561,11 @@ mod tests {
.unwrap();
let db = new_db();
let bc = new_chain(encoded::Block::new(genesis), db.clone());
let bc = new_chain(
encoded::Block::new(genesis),
db.clone(),
BlockNumber::max_value(),
);
let mut batch = db.key_value().transaction();
insert_block_batch(&mut batch, &bc, encoded::Block::new(b1), vec![]);
db.key_value().write(batch).unwrap();
@ -2599,7 +2649,11 @@ mod tests {
let b3_number = b3.last().number();
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
insert_block(
&db,
&bc,
@ -2783,7 +2837,11 @@ mod tests {
let b2a = b1a.add_block_with_bloom(bloom_ba);
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5);
let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5);
@ -2845,7 +2903,11 @@ mod tests {
let b1_total_difficulty = genesis.last().difficulty() + b1.last().difficulty();
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
let mut batch = db.key_value().transaction();
bc.insert_unordered_block(
&mut batch,
@ -2885,7 +2947,11 @@ mod tests {
let db = new_db();
{
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
let mut batch = db.key_value().transaction();
// create a longer fork
@ -2901,7 +2967,7 @@ mod tests {
}
// re-loading the blockchain should load the correct best block.
let bc = new_chain(genesis.last().encoded(), db);
let bc = new_chain(genesis.last().encoded(), db, BlockNumber::max_value());
assert_eq!(bc.best_block_number(), 5);
}
@ -2916,7 +2982,11 @@ mod tests {
let db = new_db();
{
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
let mut batch = db.key_value().transaction();
// create a longer fork
@ -2958,7 +3028,7 @@ mod tests {
}
// re-loading the blockchain should load the correct best block.
let bc = new_chain(genesis.last().encoded(), db);
let bc = new_chain(genesis.last().encoded(), db, BlockNumber::max_value());
assert_eq!(bc.best_block_number(), 5);
assert_eq!(
@ -2982,7 +3052,11 @@ mod tests {
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
let mut batch = db.key_value().transaction();
bc.insert_epoch_transition(
@ -3067,7 +3141,11 @@ mod tests {
let bootstrap_chain = |blocks: Vec<&BlockBuilder>| {
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
let bc = new_chain(
genesis.last().encoded(),
db.clone(),
BlockNumber::max_value(),
);
let mut batch = db.key_value().transaction();
for block in blocks {
insert_block_batch(&mut batch, &bc, block.last().encoded(), vec![]);

View File

@ -0,0 +1,195 @@
{
"name": "Aleut",
"engine": {
"clique": {
"params": {
"epoch": 30000,
"period": 15
}
}
},
"params": {
"accountStartNonce": "0x00",
"eip1014Transition": "0x0",
"eip1052Transition": "0x0",
"eip1283DisableTransition": "0x0",
"eip1283ReenableTransition": "0x0",
"eip1283Transition": "0x0",
"eip1344Transition": "0x0",
"eip140Transition": "0x0",
"eip145Transition": "0x0",
"eip150Transition": "0x0",
"eip155Transition": "0x0",
"eip160Transition": "0x0",
"eip161abcTransition": "0x0",
"eip161dTransition": "0x0",
"eip1706Transition": "0x0",
"eip1884Transition": "0x0",
"eip2028Transition": "0x0",
"eip211Transition": "0x0",
"eip214Transition": "0x0",
"eip2929Transition": "0x0",
"eip2930Transition": "0x0",
"eip658Transition": "0x0",
"eip1559Transition": "0xa",
"eip3198Transition": "0xa",
"gasLimitBoundDivisor": "0x0400",
"maxCodeSize": 24576,
"maxCodeSizeTransition": "0x0",
"maximumExtraDataSize": "0xffff",
"minGasLimit": "0x1388",
"networkID": "7822",
"chainID": "7822",
"registrar": "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"eip1559BaseFeeMaxChangeDenominator": "0x8",
"eip1559ElasticityMultiplier": "0x2",
"eip1559BaseFeeInitialValue": "0x3B9ACA00"
},
"genesis": {
"author": "0x0000000000000000000000000000000000000000",
"difficulty": "0x400",
"extraData": "0x000000000000000000000000000000000000000000000000000000000000000036267c845cc42b57ccb869d655e5d5fb620cc69a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1312D00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"seal": {
"ethereum": {
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000"
}
},
"timestamp": "0x0"
},
"nodes": [ "enode://0c72e2b7873e4342d725b5990c17adb2b159aad2ff5853de7e4910b25522a1f9e78f9cd802a8a3225b8fae4e994e522b50d6bd5a163eb3a7b49a0a73ca9a1c7e@3.12.166.199:30303", "enode://aec88fd902744bf67705c098bf532b01017ccc3a156395508e2d9c4e7c22699ecccae1e7316614f8a2d4c5698a9be3fe6151ee25b9ed4aa052f88e112c65387a@164.90.171.157:31559"
],
"accounts": {
"0000000000000000000000000000000000000001": {
"builtin": {
"name": "ecrecover",
"pricing": {
"linear": {
"base": 3000,
"word": 0
}
}
}
},
"0000000000000000000000000000000000000002": {
"builtin": {
"name": "sha256",
"pricing": {
"linear": {
"base": 60,
"word": 12
}
}
}
},
"0000000000000000000000000000000000000003": {
"builtin": {
"name": "ripemd160",
"pricing": {
"linear": {
"base": 600,
"word": 120
}
}
}
},
"0000000000000000000000000000000000000004": {
"builtin": {
"name": "identity",
"pricing": {
"linear": {
"base": 15,
"word": 3
}
}
}
},
"0000000000000000000000000000000000000005": {
"builtin": {
"activate_at": "0x00",
"name": "modexp",
"pricing": {
"0": {
"price": {
"modexp2565": {}
}
}
}
}
},
"0000000000000000000000000000000000000006": {
"builtin": {
"name": "alt_bn128_add",
"pricing": {
"0": {
"info": "EIP 1108 transition",
"price": {
"alt_bn128_const_operations": {
"price": 150
}
}
}
}
}
},
"0000000000000000000000000000000000000007": {
"builtin": {
"name": "alt_bn128_mul",
"pricing": {
"0": {
"info": "EIP 1108 transition",
"price": {
"alt_bn128_const_operations": {
"price": 6000
}
}
}
}
}
},
"0000000000000000000000000000000000000008": {
"builtin": {
"name": "alt_bn128_pairing",
"pricing": {
"0": {
"info": "EIP 1108 transition",
"price": {
"alt_bn128_pairing": {
"base": 45000,
"pair": 34000
}
}
}
}
}
},
"0000000000000000000000000000000000000009": {
"builtin": {
"activate_at": "0x00",
"name": "blake2_f",
"pricing": {
"blake2_f": {
"gas_per_round": 1
}
}
}
},
"0xfe3b557e8fb62b89f4916b721be55ceb828dbd73": {
"balance": "90000000000000000000000"
},
"0x627306090abaB3A6e1400e9345bC60c78a8BEf57": {
"balance": "90000000000000000000000"
},
"0xf17f52151EbEF6C7334FAD080c5704D77216b732": {
"balance": "90000000000000000000000"
},
"0xb8c3bfFb71F76BeE2B2f81bdBC53Ad4C43e3f58E": {
"balance": "90000000000000000000000"
},
"0x60AdC0F89a41AF237ce73554EDe170D733ec14E0": {
"balance": "90000000000000000000000"
}
}
}

View File

@ -0,0 +1,953 @@
{
"name": "Baikal",
"engine": {
"clique": {
"params": {
"epoch": 30000,
"period": 30
}
}
},
"params": {
"accountStartNonce": "0x00",
"eip1014Transition": "0x0",
"eip1052Transition": "0x0",
"eip1283DisableTransition": "0x0",
"eip1283ReenableTransition": "0x0",
"eip1283Transition": "0x0",
"eip1344Transition": "0x0",
"eip140Transition": "0x0",
"eip145Transition": "0x0",
"eip150Transition": "0x0",
"eip155Transition": "0x0",
"eip160Transition": "0x0",
"eip161abcTransition": "0x0",
"eip161dTransition": "0x0",
"eip1706Transition": "0x0",
"eip1884Transition": "0x0",
"eip2028Transition": "0x0",
"eip211Transition": "0x0",
"eip214Transition": "0x0",
"eip2929Transition": "0x0",
"eip2930Transition": "0x0",
"eip658Transition": "0x0",
"eip1559Transition": "0x1F4",
"eip3198Transition": "0x1F4",
"eip3529Transition": "0x1F4",
"gasLimitBoundDivisor": "0x0400",
"maxCodeSize": 24576,
"maxCodeSizeTransition": "0x0",
"maximumExtraDataSize": "0xffff",
"minGasLimit": "0x1388",
"networkID": "1642",
"chainID": "1642",
"registrar": "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"eip1559BaseFeeMaxChangeDenominator": "0x8",
"eip1559ElasticityMultiplier": "0x2",
"eip1559BaseFeeInitialValue": "0x3B9ACA00"
},
"genesis": {
"author": "0x0000000000000000000000000000000000000000",
"difficulty": "0x1",
"extraData": "0x00000000000000000000000000000000000000000000000000000000000000005211cea3870c7ba7c6c44b185e62eecdb864cd8c560228ce57d31efbf64c200b2c200aacec78cf17a7148e784fe95a7a750335f8b9572ee28d72e7650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x47b760",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"seal": {
"ethereum": {
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000"
}
},
"timestamp": "0x6092ca7f"
},
"nodes": [
"enode://39eb08bbfad87481553c471a63ff2a4b4885fffa4ff50f1cf46744d9ad6e2f764ede146fe4df563fa9ccda1a46b9b1a88fb08135e1bf1d71b320912499da773d@3.21.156.138:30303"
],
"accounts": {
"0000000000000000000000000000000000000000": {
"balance": "0x1"
},
"0000000000000000000000000000000000000001": {
"builtin": {
"name": "ecrecover",
"pricing": {
"linear": {
"base": 3000,
"word": 0
}
}
},
"balance": "0x1"
},
"0000000000000000000000000000000000000002": {
"builtin": {
"name": "sha256",
"pricing": {
"linear": {
"base": 60,
"word": 12
}
}
},
"balance": "0x1"
},
"0000000000000000000000000000000000000003": {
"builtin": {
"name": "ripemd160",
"pricing": {
"linear": {
"base": 600,
"word": 120
}
}
},
"balance": "0x1"
},
"0000000000000000000000000000000000000004": {
"builtin": {
"name": "identity",
"pricing": {
"linear": {
"base": 15,
"word": 3
}
}
},
"balance": "0x1"
},
"0000000000000000000000000000000000000005": {
"builtin": {
"activate_at": "0x00",
"name": "modexp",
"pricing": {
"0": {
"price": {
"modexp2565": {}
}
}
}
},
"balance": "0x1"
},
"0000000000000000000000000000000000000006": {
"builtin": {
"name": "alt_bn128_add",
"pricing": {
"0": {
"info": "EIP 1108 transition",
"price": {
"alt_bn128_const_operations": {
"price": 150
}
}
}
}
},
"balance": "0x1"
},
"0000000000000000000000000000000000000007": {
"builtin": {
"name": "alt_bn128_mul",
"pricing": {
"0": {
"info": "EIP 1108 transition",
"price": {
"alt_bn128_const_operations": {
"price": 6000
}
}
}
}
},
"balance": "0x1"
},
"0000000000000000000000000000000000000008": {
"builtin": {
"name": "alt_bn128_pairing",
"pricing": {
"0": {
"info": "EIP 1108 transition",
"price": {
"alt_bn128_pairing": {
"base": 45000,
"pair": 34000
}
}
}
}
},
"balance": "0x1"
},
"0000000000000000000000000000000000000009": {
"builtin": {
"activate_at": "0x00",
"name": "blake2_f",
"pricing": {
"blake2_f": {
"gas_per_round": 1
}
}
},
"balance": "0x1"
},
"000000000000000000000000000000000000000a": {
"balance": "0x1"
},
"000000000000000000000000000000000000000b": {
"balance": "0x1"
},
"000000000000000000000000000000000000000c": {
"balance": "0x1"
},
"000000000000000000000000000000000000000d": {
"balance": "0x1"
},
"000000000000000000000000000000000000000e": {
"balance": "0x1"
},
"000000000000000000000000000000000000000f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000010": {
"balance": "0x1"
},
"0000000000000000000000000000000000000011": {
"balance": "0x1"
},
"0000000000000000000000000000000000000012": {
"balance": "0x1"
},
"0000000000000000000000000000000000000013": {
"balance": "0x1"
},
"0000000000000000000000000000000000000014": {
"balance": "0x1"
},
"0000000000000000000000000000000000000015": {
"balance": "0x1"
},
"0000000000000000000000000000000000000016": {
"balance": "0x1"
},
"0000000000000000000000000000000000000017": {
"balance": "0x1"
},
"0000000000000000000000000000000000000018": {
"balance": "0x1"
},
"0000000000000000000000000000000000000019": {
"balance": "0x1"
},
"000000000000000000000000000000000000001a": {
"balance": "0x1"
},
"000000000000000000000000000000000000001b": {
"balance": "0x1"
},
"000000000000000000000000000000000000001c": {
"balance": "0x1"
},
"000000000000000000000000000000000000001d": {
"balance": "0x1"
},
"000000000000000000000000000000000000001e": {
"balance": "0x1"
},
"000000000000000000000000000000000000001f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000020": {
"balance": "0x1"
},
"0000000000000000000000000000000000000021": {
"balance": "0x1"
},
"0000000000000000000000000000000000000022": {
"balance": "0x1"
},
"0000000000000000000000000000000000000023": {
"balance": "0x1"
},
"0000000000000000000000000000000000000024": {
"balance": "0x1"
},
"0000000000000000000000000000000000000025": {
"balance": "0x1"
},
"0000000000000000000000000000000000000026": {
"balance": "0x1"
},
"0000000000000000000000000000000000000027": {
"balance": "0x1"
},
"0000000000000000000000000000000000000028": {
"balance": "0x1"
},
"0000000000000000000000000000000000000029": {
"balance": "0x1"
},
"000000000000000000000000000000000000002a": {
"balance": "0x1"
},
"000000000000000000000000000000000000002b": {
"balance": "0x1"
},
"000000000000000000000000000000000000002c": {
"balance": "0x1"
},
"000000000000000000000000000000000000002d": {
"balance": "0x1"
},
"000000000000000000000000000000000000002e": {
"balance": "0x1"
},
"000000000000000000000000000000000000002f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000030": {
"balance": "0x1"
},
"0000000000000000000000000000000000000031": {
"balance": "0x1"
},
"0000000000000000000000000000000000000032": {
"balance": "0x1"
},
"0000000000000000000000000000000000000033": {
"balance": "0x1"
},
"0000000000000000000000000000000000000034": {
"balance": "0x1"
},
"0000000000000000000000000000000000000035": {
"balance": "0x1"
},
"0000000000000000000000000000000000000036": {
"balance": "0x1"
},
"0000000000000000000000000000000000000037": {
"balance": "0x1"
},
"0000000000000000000000000000000000000038": {
"balance": "0x1"
},
"0000000000000000000000000000000000000039": {
"balance": "0x1"
},
"000000000000000000000000000000000000003a": {
"balance": "0x1"
},
"000000000000000000000000000000000000003b": {
"balance": "0x1"
},
"000000000000000000000000000000000000003c": {
"balance": "0x1"
},
"000000000000000000000000000000000000003d": {
"balance": "0x1"
},
"000000000000000000000000000000000000003e": {
"balance": "0x1"
},
"000000000000000000000000000000000000003f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000040": {
"balance": "0x1"
},
"0000000000000000000000000000000000000041": {
"balance": "0x1"
},
"0000000000000000000000000000000000000042": {
"balance": "0x1"
},
"0000000000000000000000000000000000000043": {
"balance": "0x1"
},
"0000000000000000000000000000000000000044": {
"balance": "0x1"
},
"0000000000000000000000000000000000000045": {
"balance": "0x1"
},
"0000000000000000000000000000000000000046": {
"balance": "0x1"
},
"0000000000000000000000000000000000000047": {
"balance": "0x1"
},
"0000000000000000000000000000000000000048": {
"balance": "0x1"
},
"0000000000000000000000000000000000000049": {
"balance": "0x1"
},
"000000000000000000000000000000000000004a": {
"balance": "0x1"
},
"000000000000000000000000000000000000004b": {
"balance": "0x1"
},
"000000000000000000000000000000000000004c": {
"balance": "0x1"
},
"000000000000000000000000000000000000004d": {
"balance": "0x1"
},
"000000000000000000000000000000000000004e": {
"balance": "0x1"
},
"000000000000000000000000000000000000004f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000050": {
"balance": "0x1"
},
"0000000000000000000000000000000000000051": {
"balance": "0x1"
},
"0000000000000000000000000000000000000052": {
"balance": "0x1"
},
"0000000000000000000000000000000000000053": {
"balance": "0x1"
},
"0000000000000000000000000000000000000054": {
"balance": "0x1"
},
"0000000000000000000000000000000000000055": {
"balance": "0x1"
},
"0000000000000000000000000000000000000056": {
"balance": "0x1"
},
"0000000000000000000000000000000000000057": {
"balance": "0x1"
},
"0000000000000000000000000000000000000058": {
"balance": "0x1"
},
"0000000000000000000000000000000000000059": {
"balance": "0x1"
},
"000000000000000000000000000000000000005a": {
"balance": "0x1"
},
"000000000000000000000000000000000000005b": {
"balance": "0x1"
},
"000000000000000000000000000000000000005c": {
"balance": "0x1"
},
"000000000000000000000000000000000000005d": {
"balance": "0x1"
},
"000000000000000000000000000000000000005e": {
"balance": "0x1"
},
"000000000000000000000000000000000000005f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000060": {
"balance": "0x1"
},
"0000000000000000000000000000000000000061": {
"balance": "0x1"
},
"0000000000000000000000000000000000000062": {
"balance": "0x1"
},
"0000000000000000000000000000000000000063": {
"balance": "0x1"
},
"0000000000000000000000000000000000000064": {
"balance": "0x1"
},
"0000000000000000000000000000000000000065": {
"balance": "0x1"
},
"0000000000000000000000000000000000000066": {
"balance": "0x1"
},
"0000000000000000000000000000000000000067": {
"balance": "0x1"
},
"0000000000000000000000000000000000000068": {
"balance": "0x1"
},
"0000000000000000000000000000000000000069": {
"balance": "0x1"
},
"000000000000000000000000000000000000006a": {
"balance": "0x1"
},
"000000000000000000000000000000000000006b": {
"balance": "0x1"
},
"000000000000000000000000000000000000006c": {
"balance": "0x1"
},
"000000000000000000000000000000000000006d": {
"balance": "0x1"
},
"000000000000000000000000000000000000006e": {
"balance": "0x1"
},
"000000000000000000000000000000000000006f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000070": {
"balance": "0x1"
},
"0000000000000000000000000000000000000071": {
"balance": "0x1"
},
"0000000000000000000000000000000000000072": {
"balance": "0x1"
},
"0000000000000000000000000000000000000073": {
"balance": "0x1"
},
"0000000000000000000000000000000000000074": {
"balance": "0x1"
},
"0000000000000000000000000000000000000075": {
"balance": "0x1"
},
"0000000000000000000000000000000000000076": {
"balance": "0x1"
},
"0000000000000000000000000000000000000077": {
"balance": "0x1"
},
"0000000000000000000000000000000000000078": {
"balance": "0x1"
},
"0000000000000000000000000000000000000079": {
"balance": "0x1"
},
"000000000000000000000000000000000000007a": {
"balance": "0x1"
},
"000000000000000000000000000000000000007b": {
"balance": "0x1"
},
"000000000000000000000000000000000000007c": {
"balance": "0x1"
},
"000000000000000000000000000000000000007d": {
"balance": "0x1"
},
"000000000000000000000000000000000000007e": {
"balance": "0x1"
},
"000000000000000000000000000000000000007f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000080": {
"balance": "0x1"
},
"0000000000000000000000000000000000000081": {
"balance": "0x1"
},
"0000000000000000000000000000000000000082": {
"balance": "0x1"
},
"0000000000000000000000000000000000000083": {
"balance": "0x1"
},
"0000000000000000000000000000000000000084": {
"balance": "0x1"
},
"0000000000000000000000000000000000000085": {
"balance": "0x1"
},
"0000000000000000000000000000000000000086": {
"balance": "0x1"
},
"0000000000000000000000000000000000000087": {
"balance": "0x1"
},
"0000000000000000000000000000000000000088": {
"balance": "0x1"
},
"0000000000000000000000000000000000000089": {
"balance": "0x1"
},
"000000000000000000000000000000000000008a": {
"balance": "0x1"
},
"000000000000000000000000000000000000008b": {
"balance": "0x1"
},
"000000000000000000000000000000000000008c": {
"balance": "0x1"
},
"000000000000000000000000000000000000008d": {
"balance": "0x1"
},
"000000000000000000000000000000000000008e": {
"balance": "0x1"
},
"000000000000000000000000000000000000008f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000090": {
"balance": "0x1"
},
"0000000000000000000000000000000000000091": {
"balance": "0x1"
},
"0000000000000000000000000000000000000092": {
"balance": "0x1"
},
"0000000000000000000000000000000000000093": {
"balance": "0x1"
},
"0000000000000000000000000000000000000094": {
"balance": "0x1"
},
"0000000000000000000000000000000000000095": {
"balance": "0x1"
},
"0000000000000000000000000000000000000096": {
"balance": "0x1"
},
"0000000000000000000000000000000000000097": {
"balance": "0x1"
},
"0000000000000000000000000000000000000098": {
"balance": "0x1"
},
"0000000000000000000000000000000000000099": {
"balance": "0x1"
},
"000000000000000000000000000000000000009a": {
"balance": "0x1"
},
"000000000000000000000000000000000000009b": {
"balance": "0x1"
},
"000000000000000000000000000000000000009c": {
"balance": "0x1"
},
"000000000000000000000000000000000000009d": {
"balance": "0x1"
},
"000000000000000000000000000000000000009e": {
"balance": "0x1"
},
"000000000000000000000000000000000000009f": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a0": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a1": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a2": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a3": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a4": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a5": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a6": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a7": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a8": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a9": {
"balance": "0x1"
},
"00000000000000000000000000000000000000aa": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ab": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ac": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ad": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ae": {
"balance": "0x1"
},
"00000000000000000000000000000000000000af": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b0": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b1": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b2": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b3": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b4": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b5": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b6": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b7": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b8": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b9": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ba": {
"balance": "0x1"
},
"00000000000000000000000000000000000000bb": {
"balance": "0x1"
},
"00000000000000000000000000000000000000bc": {
"balance": "0x1"
},
"00000000000000000000000000000000000000bd": {
"balance": "0x1"
},
"00000000000000000000000000000000000000be": {
"balance": "0x1"
},
"00000000000000000000000000000000000000bf": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c0": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c1": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c2": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c3": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c4": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c5": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c6": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c7": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c8": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c9": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ca": {
"balance": "0x1"
},
"00000000000000000000000000000000000000cb": {
"balance": "0x1"
},
"00000000000000000000000000000000000000cc": {
"balance": "0x1"
},
"00000000000000000000000000000000000000cd": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ce": {
"balance": "0x1"
},
"00000000000000000000000000000000000000cf": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d0": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d1": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d2": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d3": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d4": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d5": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d6": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d7": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d8": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d9": {
"balance": "0x1"
},
"00000000000000000000000000000000000000da": {
"balance": "0x1"
},
"00000000000000000000000000000000000000db": {
"balance": "0x1"
},
"00000000000000000000000000000000000000dc": {
"balance": "0x1"
},
"00000000000000000000000000000000000000dd": {
"balance": "0x1"
},
"00000000000000000000000000000000000000de": {
"balance": "0x1"
},
"00000000000000000000000000000000000000df": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e0": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e1": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e2": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e3": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e4": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e5": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e6": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e7": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e8": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e9": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ea": {
"balance": "0x1"
},
"00000000000000000000000000000000000000eb": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ec": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ed": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ee": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ef": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f0": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f1": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f2": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f3": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f4": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f5": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f6": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f7": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f8": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f9": {
"balance": "0x1"
},
"00000000000000000000000000000000000000fa": {
"balance": "0x1"
},
"00000000000000000000000000000000000000fb": {
"balance": "0x1"
},
"00000000000000000000000000000000000000fc": {
"balance": "0x1"
},
"00000000000000000000000000000000000000fd": {
"balance": "0x1"
},
"00000000000000000000000000000000000000fe": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ff": {
"balance": "0x1"
},
"0x0e89e2aedb1cfcdb9424d41a1f218f4132738172": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"0x60adc0f89a41af237ce73554ede170d733ec14e0": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"0x799d329e5f583419167cd722962485926e338f4a": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"0x7cf5b79bfe291a67ab02b393e456ccc4c266f753": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"0x8ba1f109551bd432803012645ac136ddd64dba72": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"0xb02a2eda1b317fbd16760128836b0ac59b560e9d": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
}
}
}

View File

@ -137,7 +137,9 @@
"difficultyBombDelays": {
"0x42ae50": "0x2dc6c0",
"0x6f1580": "0x1e8480",
"0x8c6180": "0x3d0900"
"0x8c6180": "0x3d0900",
"0xc5d488": "0xaae60",
"0xd228c8": "0xf4240"
}
}
}
@ -171,7 +173,14 @@
"eip1884Transition": "0x8a61c8",
"eip2028Transition": "0x8a61c8",
"eip2929Transition": "0xbad420",
"eip2930Transition": "0xbad420"
"eip2930Transition": "0xbad420",
"eip1559Transition": "0xc5d488",
"eip3198Transition": "0xc5d488",
"eip3541Transition": "0xc5d488",
"eip3529Transition": "0xc5d488",
"eip1559BaseFeeMaxChangeDenominator": "0x8",
"eip1559ElasticityMultiplier": "0x2",
"eip1559BaseFeeInitialValue": "0x3B9ACA00"
},
"genesis": {
"seal": {

View File

@ -33,6 +33,13 @@
"eip2028Transition": "0x17d433",
"eip2929Transition": "0x441064",
"eip2930Transition": "0x441064",
"eip1559Transition": "0x4d3fcd",
"eip3198Transition": "0x4d3fcd",
"eip3541Transition": "0x4d3fcd",
"eip3529Transition": "0x4d3fcd",
"eip1559BaseFeeMaxChangeDenominator": "0x8",
"eip1559ElasticityMultiplier": "0x2",
"eip1559BaseFeeInitialValue": "0x3B9ACA00",
"gasLimitBoundDivisor": "0x400",
"maxCodeSize": "0x6000",
"maxCodeSizeTransition": "0x0",

View File

@ -59,6 +59,7 @@
"eip214Transition": "0x4d50f8",
"eip658Transition": "0x4d50f8",
"wasmActivationTransition": "0x64b540",
"wasmDisableTransition": "0x198096c",
"eip145Transition": "0x8c6180",
"eip1014Transition": "0x8c6180",
"eip1052Transition": "0x8c6180",
@ -71,6 +72,13 @@
"eip2028Transition": "0xd751a5",
"eip2929Transition": "0x179f954",
"eip2930Transition": "0x179f954",
"eip1559Transition": "0x198096c",
"eip3198Transition": "0x198096c",
"eip3541Transition": "0x198096c",
"eip3529Transition": "0x198096c",
"eip1559BaseFeeMaxChangeDenominator": "0x8",
"eip1559ElasticityMultiplier": "0x2",
"eip1559BaseFeeInitialValue": "0x3B9ACA00",
"kip4Transition": "0x8c6180",
"kip6Transition": "0x8c6180"
},
@ -257,6 +265,7 @@
},
"nodes": [
"enode://30499bde23362f7d310a34518a2a6ff765921870bf0c3e63d21153cfa7ba9cf39cc7c8e54e9dad2f2b3c07288b3e91b220656833cc2d843a54875c229f3f959a@8.9.8.175:30303",
"enode://30499bde23362f7d310a34518a2a6ff765921870bf0c3e63d21153cfa7ba9cf39cc7c8e54e9dad2f2b3c07288b3e91b220656833cc2d843a54875c229f3f959a@45.33.77.29:30303",
"enode://16898006ba2cd4fa8bf9a3dfe32684c178fa861df144bfc21fe800dc4838a03e342056951fa9fd533dcb0be1219e306106442ff2cf1f7e9f8faa5f2fc1a3aa45@116.203.116.241:30303",
"enode://49a0e1aa38caa12cbf31222cb4e31cef1e8794cb4dd38012f84498ac867b19584e29bbf6d53201d7dfd3b5eb0998a4d908d096ed4ddb5f9102c623852cd331ec@54.87.247.5:30303"
]

View File

@ -45,7 +45,20 @@
"eip1344Transition": 12598600,
"eip1706Transition": 12598600,
"eip1884Transition": 12598600,
"eip2028Transition": 12598600
"eip2028Transition": 12598600,
"eip2929Transition": 21364900,
"eip2930Transition": 21364900,
"eip3198Transition": 24090200,
"eip3529Transition": 24090200,
"eip3541Transition": 24090200,
"eip1559Transition": 24090200,
"eip1559BaseFeeMaxChangeDenominator": "0x8",
"eip1559ElasticityMultiplier": "0x2",
"eip1559BaseFeeInitialValue": "0x3b9aca00",
"eip1559BaseFeeMinValue": "0x2540be400",
"eip1559BaseFeeMinValueTransition": 24199500,
"eip1559FeeCollector": "0x517F3AcfF3aFC2fb45e574718bca6F919b798e10",
"eip1559FeeCollectorTransition": 24090200
},
"genesis": {
"seal": {
@ -76,6 +89,12 @@
"divisor": 20
}
}
},
"21364900": {
"info": "EIP-2565: ModExp Gas Cost. Berlin hardfork (May 24, 2021, ~10:00 am UTC)",
"price": {
"modexp2565": {}
}
}
}
}

View File

@ -50,7 +50,18 @@
"eip1344Transition": 12095200,
"eip1706Transition": 12095200,
"eip1884Transition": 12095200,
"eip2028Transition": 12095200
"eip2028Transition": 12095200,
"eip2929Transition": 21050600,
"eip2930Transition": 21050600,
"eip3198Transition": 24114400,
"eip3529Transition": 24114400,
"eip3541Transition": 24114400,
"eip1559Transition": 24114400,
"eip1559BaseFeeMaxChangeDenominator": "0x8",
"eip1559ElasticityMultiplier": "0x2",
"eip1559BaseFeeInitialValue": "0x3b9aca00",
"eip1559FeeCollector": "0xE8DDc5c7A2d2F0D7a9798459c0104fDf5E987ACA",
"eip1559FeeCollectorTransition": 24114400
},
"genesis": {
"seal": {
@ -79,6 +90,12 @@
"divisor": 20
}
}
},
"21050600": {
"info": "EIP-2565: ModExp Gas Cost. Berlin hardfork (May 24, 2021, ~10:00 am UTC)",
"price": {
"modexp2565": {}
}
}
}
}

View File

@ -33,6 +33,13 @@
"eip2028Transition": "0x52efd1",
"eip2929Transition": "0x7e8270",
"eip2930Transition": "0x7e8270",
"eip1559Transition": "0x87c5c4",
"eip3198Transition": "0x87c5c4",
"eip3541Transition": "0x87c5c4",
"eip3529Transition": "0x87c5c4",
"eip1559BaseFeeMaxChangeDenominator": "0x8",
"eip1559ElasticityMultiplier": "0x2",
"eip1559BaseFeeInitialValue": "0x3B9ACA00",
"gasLimitBoundDivisor": "0x400",
"maxCodeSize": "0x6000",
"maxCodeSizeTransition": "0x0",

View File

@ -17,7 +17,8 @@
"difficultyBombDelays": {
"0x19f0a0": "0x2dc6c0",
"0x408b70": "0x1e8480",
"0x6c993d": "0x3d0900"
"0x6c993d": "0x3d0900",
"0xa03549": "0xaae60"
}
}
}
@ -53,7 +54,14 @@
"eip1884Transition": "0x62f756",
"eip2028Transition": "0x62f756",
"eip2929Transition": "0x95b8dd",
"eip2930Transition": "0x95b8dd"
"eip2930Transition": "0x95b8dd",
"eip1559Transition": "0xa03549",
"eip3198Transition": "0xa03549",
"eip3541Transition": "0xa03549",
"eip3529Transition": "0xa03549",
"eip1559BaseFeeMaxChangeDenominator": "0x8",
"eip1559ElasticityMultiplier": "0x2",
"eip1559BaseFeeInitialValue": "0x3B9ACA00"
},
"genesis": {

View File

@ -0,0 +1,212 @@
{
"name": "BerlinToLondonAt5 (test)",
"engine": {
"Ethash": {
"params": {
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x1BC16D674EC80000",
"homesteadTransition": "0x0",
"eip100bTransition": "0x0",
"difficultyBombDelays": {
"0": 5000000
}
}
}
},
"params": {
"gasLimitBoundDivisor": "0x0400",
"registrar": "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID": "0x1",
"maxCodeSize": 24576,
"maxCodeSizeTransition": "0x0",
"eip150Transition": "0x0",
"eip160Transition": "0x0",
"eip161abcTransition": "0x0",
"eip161dTransition": "0x0",
"eip140Transition": "0x0",
"eip211Transition": "0x0",
"eip214Transition": "0x0",
"eip155Transition": "0x0",
"eip658Transition": "0x0",
"eip145Transition": "0x0",
"eip1014Transition": "0x0",
"eip1052Transition": "0x0",
"eip1283Transition": "0x0",
"eip1283DisableTransition": "0x0",
"eip1283ReenableTransition": "0x0",
"eip1344Transition": "0x0",
"eip1706Transition": "0x0",
"eip1884Transition": "0x0",
"eip2028Transition": "0x0",
"eip2929Transition": "0x0",
"eip2930Transition": "0x0",
"eip1559Transition": "0x5",
"eip3198Transition": "0x5",
"eip3541Transition": "0x5",
"eip3529Transition": "0x5",
"eip1559BaseFeeMaxChangeDenominator": "0x8",
"eip1559ElasticityMultiplier": "0x2",
"eip1559BaseFeeInitialValue": "0x3B9ACA00"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388"
},
"accounts": {
"0000000000000000000000000000000000000001": {
"balance": "1",
"builtin": {
"name": "ecrecover",
"pricing": {
"linear": {
"base": 3000,
"word": 0
}
}
}
},
"0000000000000000000000000000000000000002": {
"balance": "1",
"builtin": {
"name": "sha256",
"pricing": {
"linear": {
"base": 60,
"word": 12
}
}
}
},
"0000000000000000000000000000000000000003": {
"balance": "1",
"builtin": {
"name": "ripemd160",
"pricing": {
"linear": {
"base": 600,
"word": 120
}
}
}
},
"0000000000000000000000000000000000000004": {
"balance": "1",
"builtin": {
"name": "identity",
"pricing": {
"linear": {
"base": 15,
"word": 3
}
}
}
},
"0000000000000000000000000000000000000005": {
"builtin": {
"name": "modexp",
"activate_at": "0x00",
"pricing": {
"0": {
"price": {
"modexp2565": {}
}
}
}
}
},
"0000000000000000000000000000000000000006": {
"builtin": {
"name": "alt_bn128_add",
"pricing": {
"0": {
"price": {
"alt_bn128_const_operations": {
"price": 500
}
}
},
"0": {
"info": "EIP 1108 transition",
"price": {
"alt_bn128_const_operations": {
"price": 150
}
}
}
}
}
},
"0000000000000000000000000000000000000007": {
"builtin": {
"name": "alt_bn128_mul",
"pricing": {
"0": {
"price": {
"alt_bn128_const_operations": {
"price": 40000
}
}
},
"0": {
"info": "EIP 1108 transition",
"price": {
"alt_bn128_const_operations": {
"price": 6000
}
}
}
}
}
},
"0000000000000000000000000000000000000008": {
"builtin": {
"name": "alt_bn128_pairing",
"pricing": {
"0": {
"price": {
"alt_bn128_pairing": {
"base": 100000,
"pair": 80000
}
}
},
"0": {
"info": "EIP 1108 transition",
"price": {
"alt_bn128_pairing": {
"base": 45000,
"pair": 34000
}
}
}
}
}
},
"0000000000000000000000000000000000000009": {
"builtin": {
"name": "blake2_f",
"activate_at": "0x00",
"pricing": {
"blake2_f": {
"gas_per_round": 1
}
}
}
}
}
}

View File

@ -0,0 +1,65 @@
pragma solidity ^0.4.20;
// Adapted from https://gist.github.com/VladLupashevskyi/84f18eabb1e4afadf572cf92af3e7e7f
// and: https://github.com/poanetwork/posdao-contracts/blob/master/contracts/TxPermission.sol
contract TxPermission {
/// Allowed transaction types mask
uint32 constant None = 0;
uint32 constant All = 0xffffffff;
uint32 constant Basic = 0x01;
uint32 constant Call = 0x02;
uint32 constant Create = 0x04;
uint32 constant Private = 0x08;
/// Contract name
function contractName() public constant returns (string) {
return "TX_PERMISSION_CONTRACT";
}
/// Contract name hash
function contractNameHash() public constant returns (bytes32) {
return keccak256(contractName());
}
/// Contract version
function contractVersion() public constant returns (uint256) {
return 4;
}
/// @dev Defines the allowed transaction types which may be initiated by the specified sender with
/// the specified gas price and data. Used by node's engine each time a transaction is about to be
/// included into a block. See https://openethereum.github.io/Permissioning.html#how-it-works-1
/// @param _sender Transaction sender address.
/// @param _to Transaction recipient address. If creating a contract, the `_to` address is zero.
/// @param _value Transaction amount in wei.
/// @param _maxFeePerGas The `maxFeePerGas` in Wei for EIP-1559 transaction, or gas price for a legacy transaction.
/// @param _maxInclusionFeePerGas The `maxInclusionFeePerGas` in Wei for EIP-1559 transaction.
/// Equals to gas price for a legacy transaction.
/// @param _gasLimit Gas limit for the transaction.
/// @param _data Transaction data.
/// @return `uint32 typesMask` - Set of allowed transactions for `_sender` depending on tx `_to` address,
/// `_gasPrice`, and `_data`. The result is represented as a set of flags:
/// 0x01 - basic transaction (e.g. ether transferring to user wallet);
/// 0x02 - contract call;
/// 0x04 - contract creation;
/// 0x08 - private transaction.
/// `bool cache` - If `true` is returned, the same permissions will be applied from the same
/// `_sender` without calling this contract again.
function allowedTxTypes(
address _sender,
address _to,
uint256 _value,
uint256 _maxFeePerGas, // equals to gasPrice for legacy transactions
uint256 _maxInclusionFeePerGas, // equals to gasPrice for legacy transactions
uint256 _gasLimit,
bytes memory _data
)
public
view
returns(uint32 typesMask, bool cache)
{
if (_maxFeePerGas > 0 || _data.length < 4) return (All, false);
return (None, false);
}
}

View File

@ -0,0 +1,44 @@
{
"name": "TestNodeFilterContract",
"engine": {
"authorityRound": {
"params": {
"stepDuration": 1,
"startStep": 2,
"validators": {
"contract": "0x0000000000000000000000000000000000000000"
}
}
}
},
"params": {
"accountStartNonce": "0x0",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x69",
"gasLimitBoundDivisor": "0x0400",
"transactionPermissionContract": "0xAB5b100cf7C8deFB3c8f3C48474223997A50fB13",
"transactionPermissionContractTransition": "1"
},
"genesis": {
"seal": {
"generic": "0xc180"
},
"difficulty": "0x20000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x222222"
},
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"0xAB5b100cf7C8deFB3c8f3C48474223997A50fB13": {
"balance": "1",
"constructor": "608060405234801561001057600080fd5b50610370806100206000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063469ab1e31461006757806375d0c0dc1461009a578063a0a8e4601461012a578063e4e3b5e514610155575b600080fd5b34801561007357600080fd5b5061007c610251565b60405180826000191660001916815260200191505060405180910390f35b3480156100a657600080fd5b506100af6102c2565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100ef5780820151818401526020810190506100d4565b50505050905090810190601f16801561011c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013657600080fd5b5061013f6102ff565b6040518082815260200191505060405180910390f35b34801561016157600080fd5b50610224600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610308565b604051808363ffffffff1663ffffffff168152602001821515151581526020019250505060405180910390f35b600061025b6102c2565b6040518082805190602001908083835b602083101515610290578051825260208201915060208101905060208303925061026b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905090565b60606040805190810160405280601681526020017f54585f5045524d495353494f4e5f434f4e545241435400000000000000000000815250905090565b60006004905090565b600080600086118061031b575060048351105b156103305763ffffffff600091509150610338565b600080915091505b975097955050505050505600a165627a7a72305820592b45ee74cc856b6c84f99ed8ddd4790d844a9065a07c7bbfc5dfa05cc394c50029"
}
}
}

View File

@ -0,0 +1,47 @@
{
"name": "Morden",
"engine": {
"null": {
"params": {}
}
},
"params": {
"gasLimitBoundDivisor": "0x0400",
"accountStartNonce": "0x0",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2",
"registrar" : "0x0000000000000000000000000000000000001337",
"eip140Transition": "0x0",
"eip211Transition": "0x0",
"eip214Transition": "0x0",
"eip658Transition": "0x0",
"eip3607Transition": "0x2"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x00006d6f7264656e",
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578"
}
},
"difficulty": "0x20000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2fefd8"
},
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" },
"0x71562b71999873DB5b286dF957af199Ec94617F7": {
"balance": "1000000000000000000",
"nonce": "0",
"code": "0xB0B0FACE"
}
}
}

View File

@ -0,0 +1,212 @@
{
"name": "London (test)",
"engine": {
"Ethash": {
"params": {
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x1BC16D674EC80000",
"homesteadTransition": "0x0",
"eip100bTransition": "0x0",
"difficultyBombDelays": {
"0": 5000000
}
}
}
},
"params": {
"gasLimitBoundDivisor": "0x0400",
"registrar": "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID": "0x1",
"maxCodeSize": 24576,
"maxCodeSizeTransition": "0x0",
"eip150Transition": "0x0",
"eip160Transition": "0x0",
"eip161abcTransition": "0x0",
"eip161dTransition": "0x0",
"eip140Transition": "0x0",
"eip211Transition": "0x0",
"eip214Transition": "0x0",
"eip155Transition": "0x0",
"eip658Transition": "0x0",
"eip145Transition": "0x0",
"eip1014Transition": "0x0",
"eip1052Transition": "0x0",
"eip1283Transition": "0x0",
"eip1283DisableTransition": "0x0",
"eip1283ReenableTransition": "0x0",
"eip1344Transition": "0x0",
"eip1706Transition": "0x0",
"eip1884Transition": "0x0",
"eip2028Transition": "0x0",
"eip2929Transition": "0x0",
"eip2930Transition": "0x0",
"eip1559Transition": "0x0",
"eip3198Transition": "0x0",
"eip3541Transition": "0x0",
"eip3529Transition": "0x0",
"eip1559BaseFeeMaxChangeDenominator": "0x8",
"eip1559ElasticityMultiplier": "0x2",
"eip1559BaseFeeInitialValue": "0x3B9ACA00"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388"
},
"accounts": {
"0000000000000000000000000000000000000001": {
"balance": "1",
"builtin": {
"name": "ecrecover",
"pricing": {
"linear": {
"base": 3000,
"word": 0
}
}
}
},
"0000000000000000000000000000000000000002": {
"balance": "1",
"builtin": {
"name": "sha256",
"pricing": {
"linear": {
"base": 60,
"word": 12
}
}
}
},
"0000000000000000000000000000000000000003": {
"balance": "1",
"builtin": {
"name": "ripemd160",
"pricing": {
"linear": {
"base": 600,
"word": 120
}
}
}
},
"0000000000000000000000000000000000000004": {
"balance": "1",
"builtin": {
"name": "identity",
"pricing": {
"linear": {
"base": 15,
"word": 3
}
}
}
},
"0000000000000000000000000000000000000005": {
"builtin": {
"name": "modexp",
"activate_at": "0x00",
"pricing": {
"0": {
"price": {
"modexp2565": {}
}
}
}
}
},
"0000000000000000000000000000000000000006": {
"builtin": {
"name": "alt_bn128_add",
"pricing": {
"0": {
"price": {
"alt_bn128_const_operations": {
"price": 500
}
}
},
"0": {
"info": "EIP 1108 transition",
"price": {
"alt_bn128_const_operations": {
"price": 150
}
}
}
}
}
},
"0000000000000000000000000000000000000007": {
"builtin": {
"name": "alt_bn128_mul",
"pricing": {
"0": {
"price": {
"alt_bn128_const_operations": {
"price": 40000
}
}
},
"0": {
"info": "EIP 1108 transition",
"price": {
"alt_bn128_const_operations": {
"price": 6000
}
}
}
}
}
},
"0000000000000000000000000000000000000008": {
"builtin": {
"name": "alt_bn128_pairing",
"pricing": {
"0": {
"price": {
"alt_bn128_pairing": {
"base": 100000,
"pair": 80000
}
}
},
"0": {
"info": "EIP 1108 transition",
"price": {
"alt_bn128_pairing": {
"base": 45000,
"pair": 34000
}
}
}
}
}
},
"0000000000000000000000000000000000000009": {
"builtin": {
"name": "blake2_f",
"activate_at": "0x00",
"pricing": {
"blake2_f": {
"gas_per_round": 1
}
}
}
}
}
}

View File

@ -56,6 +56,15 @@
"eip2028Transition": 7298030,
"eip2929Transition": 16101500,
"eip2930Transition": 16101500,
"eip3198Transition": 19040000,
"eip3529Transition": 19040000,
"eip3541Transition": 19040000,
"eip1559Transition": 19040000,
"eip1559BaseFeeMaxChangeDenominator": "0x8",
"eip1559ElasticityMultiplier": "0x2",
"eip1559BaseFeeInitialValue": "0x3b9aca00",
"eip1559FeeCollector": "0x6BBe78ee9e474842Dbd4AB4987b3CeFE88426A92",
"eip1559FeeCollectorTransition": 19040000,
"registrar": "0x6B53721D4f2Fb9514B85f5C49b197D857e36Cf03",
"transactionPermissionContract": "0x7Dd7032AA75A37ea0b150f57F899119C7379A78b",
"transactionPermissionContractTransition": 9186425

View File

@ -0,0 +1,91 @@
[
{
"constant": true,
"inputs": [],
"name": "contractNameHash",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "contractName",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "contractVersion",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "sender",
"type": "address"
},
{
"name": "to",
"type": "address"
},
{
"name": "value",
"type": "uint256"
},
{
"name": "maxFeePerGas",
"type": "uint256"
},
{
"name": "maxPriorityFeePerGas",
"type": "uint256"
},
{
"name": "gasLimit",
"type": "uint256"
},
{
"name": "data",
"type": "bytes"
}
],
"name": "allowedTxTypes",
"outputs": [
{
"name": "",
"type": "uint32"
},
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
]

@ -1 +1 @@
Subproject commit 644967e345bbc6642fab613e1b1737abbe131f78
Subproject commit e20d7f39aae1e33394ae6b94590d15083e224fa5

View File

@ -139,7 +139,8 @@ impl ExecutedBlock {
difficulty: self.header.difficulty().clone(),
last_hashes: self.last_hashes.clone(),
gas_used: self.receipts.last().map_or(U256::zero(), |r| r.gas_used),
gas_limit: self.header.gas_limit().clone(),
gas_limit: *self.header.gas_limit(),
base_fee: self.header.base_fee(),
}
}
@ -196,6 +197,9 @@ impl<'x> OpenBlock<'x> {
.header
.set_timestamp(engine.open_block_header_timestamp(parent.timestamp()));
r.block.header.set_extra_data(extra_data);
r.block
.header
.set_base_fee(engine.calculate_base_fee(parent));
let gas_floor_target = cmp::max(gas_range_target.0, engine.params().min_gas_limit);
let gas_ceil_target = cmp::max(gas_range_target.1, gas_floor_target);
@ -227,6 +231,11 @@ impl<'x> OpenBlock<'x> {
self.block.header.set_gas_limit(U256::max_value());
}
/// Set block gas limit.
pub fn set_gas_limit(&mut self, gas_limit: U256) {
self.block.header.set_gas_limit(gas_limit);
}
// t_nb 8.4 Add an uncle to the block, if possible.
///
/// NOTE Will check chain constraints and the uncle number but will NOT check
@ -559,11 +568,9 @@ pub(crate) fn enact(
)?;
if let Some(ref s) = trace_state {
let env = b.env_info();
let root = s.root();
let author_balance = s.balance(&env.author)?;
let author_balance = s.balance(&b.header.author())?;
trace!(target: "enact", "num={}, root={}, author={}, author_balance={}\n",
b.block.header.number(), root, env.author, author_balance);
b.block.header.number(), s.root(), b.header.author(), author_balance);
}
// t_nb 8.2 transfer all field from current header to OpenBlock header that we created
@ -632,7 +639,7 @@ mod tests {
last_hashes: Arc<LastHashes>,
factories: Factories,
) -> Result<LockedBlock, Error> {
let block = Unverified::from_rlp(block_bytes)?;
let block = Unverified::from_rlp(block_bytes, engine.params().eip1559_transition)?;
let header = block.header;
let transactions: Result<Vec<_>, Error> = block
.transactions
@ -689,7 +696,8 @@ mod tests {
last_hashes: Arc<LastHashes>,
factories: Factories,
) -> Result<SealedBlock, Error> {
let header = Unverified::from_rlp(block_bytes.clone())?.header;
let header =
Unverified::from_rlp(block_bytes.clone(), engine.params().eip1559_transition)?.header;
Ok(enact_bytes(
block_bytes,
engine,
@ -846,7 +854,7 @@ mod tests {
let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes);
let uncles = view!(BlockView, &bytes).uncles();
let uncles = view!(BlockView, &bytes).uncles(engine.params().eip1559_transition);
assert_eq!(uncles[1].extra_data(), b"uncle2");
let db = e.drain().state.drop().1;

View File

@ -21,6 +21,7 @@ use ethereum_types::H256;
use itertools::Itertools;
use memory_cache::MemoryLruCache;
use parking_lot::RwLock;
use types::BlockNumber;
use verification::queue::kind::blocks::Unverified;
/// Recently seen bad blocks.
@ -38,8 +39,8 @@ impl Default for BadBlocks {
impl BadBlocks {
/// Reports given RLP as invalid block.
pub fn report(&self, raw: Bytes, message: String) {
match Unverified::from_rlp(raw) {
pub fn report(&self, raw: Bytes, message: String, eip1559_transition: BlockNumber) {
match Unverified::from_rlp(raw, eip1559_transition) {
Ok(unverified) => {
error!(
target: "client",
@ -69,14 +70,14 @@ impl BadBlocks {
}
/// Returns a list of recently detected bad blocks with error descriptions.
pub fn bad_blocks(&self) -> Vec<(Unverified, String)> {
pub fn bad_blocks(&self, eip1559_transition: BlockNumber) -> Vec<(Unverified, String)> {
self.last_blocks
.read()
.backstore()
.iter()
.map(|(_k, (unverified, message))| {
(
Unverified::from_rlp(unverified.bytes.clone())
Unverified::from_rlp(unverified.bytes.clone(), eip1559_transition)
.expect("Bytes coming from UnverifiedBlock so decodable; qed"),
message.clone(),
)

View File

@ -355,7 +355,11 @@ impl Importer {
.accrue_block(&header, transactions_len);
}
Err(err) => {
self.bad_blocks.report(bytes, format!("{:?}", err));
self.bad_blocks.report(
bytes,
format!("{:?}", err),
self.engine.params().eip1559_transition,
);
invalid_blocks.insert(hash);
}
}
@ -484,6 +488,52 @@ impl Importer {
.epoch_transition(parent.number(), *header.parent_hash())
.is_some();
if header.number() >= engine.params().validate_service_transactions_transition {
// Check if zero gas price transactions are certified to be service transactions
// using the Certifier contract. If they are not certified, the block is treated as invalid.
let service_transaction_checker = self.miner.service_transaction_checker();
if service_transaction_checker.is_some() {
match service_transaction_checker.unwrap().refresh_cache(client) {
Ok(true) => {
trace!(target: "client", "Service transaction cache was refreshed successfully");
}
Ok(false) => {
trace!(target: "client", "Registrar or/and service transactions contract does not exist");
}
Err(e) => {
error!(target: "client", "Error occurred while refreshing service transaction cache: {}", e)
}
};
};
for t in &block.transactions {
if t.has_zero_gas_price() {
match self.miner.service_transaction_checker() {
None => {
let e = "Service transactions are not allowed. You need to enable Certifier contract.";
warn!(target: "client", "Service tx checker error: {:?}", e);
bail!(e);
}
Some(ref checker) => match checker.check(client, &t) {
Ok(true) => {}
Ok(false) => {
let e = format!(
"Service transactions are not allowed for the sender {:?}",
t.sender()
);
warn!(target: "client", "Service tx checker error: {:?}", e);
bail!(e);
}
Err(e) => {
debug!(target: "client", "Unable to verify service transaction: {:?}", e);
warn!(target: "client", "Service tx checker error: {:?}", e);
bail!(e);
}
},
}
};
}
}
// t_nb 8.0 Block enacting. Execution of transactions.
let enact_result = enact_verified(
block,
@ -629,7 +679,7 @@ impl Importer {
let header = chain
.block_header_data(&hash)
.expect("Best block is in the database; qed")
.decode()
.decode(self.engine.params().eip1559_transition)
.expect("Stored block header is valid RLP; qed");
let details = chain
.block_details(&hash)
@ -767,6 +817,7 @@ impl Importer {
last_hashes: client.build_last_hashes(header.parent_hash()),
gas_used: U256::default(),
gas_limit: u64::max_value().into(),
base_fee: header.base_fee(),
};
let call = move |addr, data| {
@ -905,7 +956,12 @@ impl Client {
}
let gb = spec.genesis_block();
let chain = Arc::new(BlockChain::new(config.blockchain.clone(), &gb, db.clone()));
let chain = Arc::new(BlockChain::new(
config.blockchain.clone(),
&gb,
db.clone(),
spec.params().eip1559_transition,
));
let tracedb = RwLock::new(TraceDB::new(
config.tracing.clone(),
db.clone(),
@ -1144,6 +1200,11 @@ impl Client {
last_hashes: self.build_last_hashes(&header.parent_hash()),
gas_used: U256::default(),
gas_limit: header.gas_limit(),
base_fee: if header.number() >= self.engine.params().eip1559_transition {
Some(header.base_fee())
} else {
None
},
})
}
@ -1646,7 +1707,9 @@ impl Client {
BlockId::Number(number) if number == self.chain.read().best_block_number() => {
Some(self.chain.read().best_block_header())
}
_ => self.block_header(id).and_then(|h| h.decode().ok()),
_ => self
.block_header(id)
.and_then(|h| h.decode(self.engine.params().eip1559_transition).ok()),
}
}
}
@ -1673,6 +1736,7 @@ impl snapshot::DatabaseRestore for Client {
self.config.blockchain.clone(),
&[],
db.clone(),
self.engine.params().eip1559_transition,
));
*tracedb = TraceDB::new(self.config.tracing.clone(), db.clone(), chain.clone());
Ok(())
@ -1884,9 +1948,11 @@ impl ImportBlock for Client {
}
// t_nb 2.5 if block is not okay print error. we only care about block errors (not import errors)
Err((Some(block), EthcoreError(EthcoreErrorKind::Block(err), _))) => {
self.importer
.bad_blocks
.report(block.bytes, err.to_string());
self.importer.bad_blocks.report(
block.bytes,
err.to_string(),
self.engine.params().eip1559_transition,
);
bail!(EthcoreErrorKind::Block(err))
}
Err((None, EthcoreError(EthcoreErrorKind::Block(err), _))) => {
@ -1934,6 +2000,12 @@ impl Call for Client {
last_hashes: self.build_last_hashes(header.parent_hash()),
gas_used: U256::default(),
gas_limit: U256::max_value(),
//if gas pricing is not defined, force base_fee to zero
base_fee: if transaction.effective_gas_price(header.base_fee()).is_zero() {
Some(0.into())
} else {
header.base_fee()
},
};
let machine = self.engine.machine();
@ -1954,12 +2026,20 @@ impl Call for Client {
last_hashes: self.build_last_hashes(header.parent_hash()),
gas_used: U256::default(),
gas_limit: U256::max_value(),
base_fee: header.base_fee(),
};
let mut results = Vec::with_capacity(transactions.len());
let machine = self.engine.machine();
for &(ref t, analytics) in transactions {
//if gas pricing is not defined, force base_fee to zero
if t.effective_gas_price(header.base_fee()).is_zero() {
env_info.base_fee = Some(0.into());
} else {
env_info.base_fee = header.base_fee()
}
let ret = Self::do_virtual_call(machine, &env_info, state, t, analytics)?;
env_info.gas_used = ret.cumulative_gas_used;
results.push(ret);
@ -1986,6 +2066,11 @@ impl Call for Client {
last_hashes: self.build_last_hashes(header.parent_hash()),
gas_used: U256::default(),
gas_limit: max,
base_fee: if t.effective_gas_price(header.base_fee()).is_zero() {
Some(0.into())
} else {
header.base_fee()
},
};
(init, max, env_info)
@ -2069,7 +2154,9 @@ impl EngineInfo for Client {
impl BadBlocks for Client {
fn bad_blocks(&self) -> Vec<(Unverified, String)> {
self.importer.bad_blocks.bad_blocks()
self.importer
.bad_blocks
.bad_blocks(self.engine.params().eip1559_transition)
}
}
@ -2367,6 +2454,7 @@ impl BlockChainClient for Client {
let chain = self.chain.read();
let number = chain.block_number(&hash)?;
let body = chain.block_body(&hash)?;
let header = chain.block_header_data(&hash)?;
let mut receipts = chain.block_receipts(&hash)?.receipts;
receipts.truncate(address.index + 1);
@ -2379,6 +2467,11 @@ impl BlockChainClient for Client {
.into_iter()
.map(|receipt| receipt.logs.len())
.sum::<usize>();
let base_fee = if number >= self.engine().params().eip1559_transition {
Some(header.base_fee())
} else {
None
};
let receipt = transaction_receipt(
self.engine().machine(),
@ -2386,6 +2479,7 @@ impl BlockChainClient for Client {
receipt,
gas_used,
no_of_logs,
base_fee,
);
Some(receipt)
}
@ -2397,7 +2491,13 @@ impl BlockChainClient for Client {
let receipts = chain.block_receipts(&hash)?;
let number = chain.block_number(&hash)?;
let body = chain.block_body(&hash)?;
let header = chain.block_header_data(&hash)?;
let engine = self.engine.clone();
let base_fee = if number >= engine.params().eip1559_transition {
Some(header.base_fee())
} else {
None
};
let mut gas_used = 0.into();
let mut no_of_logs = 0;
@ -2414,6 +2514,7 @@ impl BlockChainClient for Client {
receipt,
gas_used,
no_of_logs,
base_fee,
);
gas_used = result.cumulative_gas_used;
no_of_logs += result.logs.len();
@ -2654,8 +2755,11 @@ impl BlockChainClient for Client {
}
fn uncle_extra_info(&self, id: UncleId) -> Option<BTreeMap<String, String>> {
self.uncle(id)
.and_then(|h| h.decode().map(|dh| self.engine.extra_info(&dh)).ok())
self.uncle(id).and_then(|h| {
h.decode(self.engine.params().eip1559_transition)
.map(|dh| self.engine.extra_info(&dh))
.ok()
})
}
fn pruning_info(&self) -> PruningInfo {
@ -2718,6 +2822,10 @@ impl BlockChainClient for Client {
fn registrar_address(&self) -> Option<Address> {
self.registrar_address.clone()
}
fn state_data(&self, hash: &H256) -> Option<Bytes> {
self.state_db.read().journal_db().state(hash)
}
}
impl IoClient for Client {
@ -2837,7 +2945,9 @@ impl ReopenBlock for Client {
let uncle = chain
.block_header_data(&h)
.expect("find_uncle_hashes only returns hashes for existing headers; qed");
let uncle = uncle.decode().expect("decoding failure");
let uncle = uncle
.decode(self.engine.params().eip1559_transition)
.expect("decoding failure");
block.push_uncle(uncle).expect(
"pushing up to maximum_uncle_count;
push_uncle is not ok only if more than maximum_uncle_count is pushed;
@ -2889,7 +2999,10 @@ impl PrepareOpenBlock for Client {
.take(engine.maximum_uncle_count(open_block.header.number()))
.foreach(|h| {
open_block
.push_uncle(h.decode().expect("decoding failure"))
.push_uncle(
h.decode(engine.params().eip1559_transition)
.expect("decoding failure"),
)
.expect(
"pushing maximum_uncle_count;
open_block was just created;
@ -2925,6 +3038,7 @@ impl ImportSealedBlock for Client {
self.importer.bad_blocks.report(
block.rlp_bytes(),
format!("Detected an issue with locally sealed block: {}", e),
self.engine.params().eip1559_transition,
);
return Err(e.into());
}
@ -3155,7 +3269,8 @@ impl ImportExportBlocks for Client {
};
let do_import = |bytes: Vec<u8>| {
let block = Unverified::from_rlp(bytes).map_err(|_| "Invalid block rlp")?;
let block = Unverified::from_rlp(bytes, self.engine.params().eip1559_transition)
.map_err(|_| "Invalid block rlp")?;
let number = block.header.number();
while self.queue_info().is_full() {
std::thread::sleep(Duration::from_secs(1));
@ -3229,6 +3344,7 @@ fn transaction_receipt(
receipt: TypedReceipt,
prior_gas_used: U256,
prior_no_of_logs: usize,
base_fee: Option<U256>,
) -> LocalizedReceipt {
let sender = tx.sender();
let transaction_hash = tx.hash();
@ -3280,6 +3396,7 @@ fn transaction_receipt(
.collect(),
log_bloom: receipt.log_bloom,
outcome: receipt.outcome.clone(),
effective_gas_price: tx.effective_gas_price(base_fee),
}
}
@ -3608,7 +3725,7 @@ mod tests {
});
// when
let receipt = transaction_receipt(&machine, transaction, receipt, 5.into(), 1);
let receipt = transaction_receipt(&machine, transaction, receipt, 5.into(), 1, None);
// then
assert_eq!(
@ -3649,6 +3766,7 @@ mod tests {
],
log_bloom: Default::default(),
outcome: TransactionOutcome::StateRoot(state_root),
effective_gas_price: Default::default(),
}
);
}

View File

@ -107,6 +107,8 @@ impl<'a> EvmTestClient<'a> {
Some(ethereum::new_byzantium_to_constantinoplefixat5_test())
}
ForkSpec::Berlin => Some(ethereum::new_berlin_test()),
ForkSpec::London => Some(ethereum::new_london_test()),
ForkSpec::BerlinToLondonAt5 => Some(ethereum::new_berlin_to_london_test()),
ForkSpec::FrontierToHomesteadAt5
| ForkSpec::HomesteadToDaoAt5
| ForkSpec::HomesteadToEIP150At5
@ -248,6 +250,7 @@ impl<'a> EvmTestClient<'a> {
last_hashes: Arc::new([H256::default(); 256].to_vec()),
gas_used: 0.into(),
gas_limit: *genesis.gas_limit(),
base_fee: genesis.base_fee(),
};
self.call_envinfo(params, tracer, vm_tracer, info)
}

View File

@ -322,7 +322,7 @@ impl TestBlockChainClient {
rlp.append(&header);
rlp.append_raw(&txs, 1);
rlp.append_raw(uncles.as_raw(), 1);
let unverified = Unverified::from_rlp(rlp.out()).unwrap();
let unverified = Unverified::from_rlp(rlp.out(), BlockNumber::max_value()).unwrap();
self.import_block(unverified).unwrap();
}
@ -339,7 +339,7 @@ impl TestBlockChainClient {
let mut header: Header = self
.block_header(BlockId::Number(n))
.unwrap()
.decode()
.decode(BlockNumber::max_value())
.expect("decoding failed");
header.set_parent_hash(H256::from_low_u64_be(42));
let mut rlp = RlpStream::new_list(3);
@ -550,7 +550,7 @@ impl BlockInfo for TestBlockChainClient {
fn best_block_header(&self) -> Header {
self.block_header(BlockId::Hash(self.chain_info().best_block_hash))
.expect("Best block always has header.")
.decode()
.decode(BlockNumber::max_value())
.expect("decoding failed")
}
@ -608,7 +608,7 @@ impl ImportBlock for TestBlockChainClient {
if number > 0 {
match self.blocks.read().get(header.parent_hash()) {
Some(parent) => {
let parent = view!(BlockView, parent).header();
let parent = view!(BlockView, parent).header(BlockNumber::max_value());
if parent.number() != (header.number() - 1) {
panic!("Unexpected block parent");
}
@ -638,7 +638,7 @@ impl ImportBlock for TestBlockChainClient {
*self.numbers.write().get_mut(&n).unwrap() = parent_hash.clone();
n -= 1;
parent_hash = view!(BlockView, &self.blocks.read()[&parent_hash])
.header()
.header(BlockNumber::max_value())
.parent_hash()
.clone();
}
@ -720,7 +720,7 @@ impl StateClient for TestBlockChainClient {
impl EngineInfo for TestBlockChainClient {
fn engine(&self) -> &dyn EthEngine {
unimplemented!()
&*self.spec.engine
}
}
@ -882,7 +882,7 @@ impl BlockChainClient for TestBlockChainClient {
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> {
self.block(id)
.map(|block| block.view().header())
.map(|block| block.view().header(BlockNumber::max_value()))
.map(|header| self.spec.engine.extra_info(&header))
}
@ -1078,6 +1078,29 @@ impl BlockChainClient for TestBlockChainClient {
fn registrar_address(&self) -> Option<Address> {
None
}
fn state_data(&self, hash: &H256) -> Option<Bytes> {
let begins_with_f =
H256::from_str("f000000000000000000000000000000000000000000000000000000000000000")
.unwrap();
if *hash > begins_with_f {
let mut rlp = RlpStream::new();
rlp.append(&hash.clone());
return Some(rlp.out());
} else if *hash
== H256::from_str("000000000000000000000000000000000000000000000000000000000000000a")
.unwrap()
{
// for basic `return_node_data` tests
return Some(vec![0xaa, 0xaa]);
} else if *hash
== H256::from_str("000000000000000000000000000000000000000000000000000000000000000c")
.unwrap()
{
return Some(vec![0xcc]);
}
None
}
}
impl IoClient for TestBlockChainClient {

View File

@ -40,7 +40,7 @@ use types::{
pruning_info::PruningInfo,
receipt::LocalizedReceipt,
trace_filter::Filter as TraceFilter,
transaction::{self, Action, LocalizedTransaction, SignedTransaction},
transaction::{self, Action, LocalizedTransaction, SignedTransaction, TypedTxId},
BlockNumber,
};
use vm::LastHashes;
@ -333,6 +333,9 @@ pub trait BlockChainClient:
/// Get all possible uncle hashes for a block.
fn find_uncles(&self, hash: &H256) -> Option<Vec<H256>>;
/// Get latest state node
fn state_data(&self, hash: &H256) -> Option<Bytes>;
/// Get block receipts data by block header hash.
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts>;
@ -395,10 +398,49 @@ pub trait BlockChainClient:
if block.number() == 0 {
return corpus.into();
}
block.transaction_views().iter().foreach(|t| {
corpus.push(t.effective_gas_price({
match t.transaction_type() {
TypedTxId::Legacy => None,
TypedTxId::AccessList => None,
TypedTxId::EIP1559Transaction => Some(block.header().base_fee()),
}
}))
});
h = block.parent_hash().clone();
}
}
corpus.into()
}
/// Sorted list of transaction priority gas prices from at least last sample_size blocks.
fn priority_gas_price_corpus(
&self,
sample_size: usize,
eip1559_transition: BlockNumber,
) -> ::stats::Corpus<U256> {
let mut h = self.chain_info().best_block_hash;
let mut corpus = Vec::new();
while corpus.is_empty() {
for _ in 0..sample_size {
let block = match self.block(BlockId::Hash(h)) {
Some(block) => block,
None => return corpus.into(),
};
if block.number() == 0 || block.number() < eip1559_transition {
return corpus.into();
}
block
.transaction_views()
.iter()
.foreach(|t| corpus.push(t.gas_price()));
.filter(
|t| t.gas_price() > 0.into(), /* filter zero cost transactions */
)
.foreach(|t| {
// As block.number() >= eip_1559_transition, the base_fee should exist
corpus.push(t.effective_priority_gas_price(Some(block.header().base_fee())))
});
h = block.parent_hash().clone();
}
}

View File

@ -49,6 +49,7 @@ use self::finality::RollingFinality;
use super::{
signer::EngineSigner,
validator_set::{new_validator_set_posdao, SimpleList, ValidatorSet},
EthEngine,
};
use block::*;
use bytes::Bytes;
@ -692,6 +693,7 @@ struct EpochVerifier {
empty_steps_transition: u64,
/// First block for which a 2/3 quorum (instead of 1/2) is required.
two_thirds_majority_transition: BlockNumber,
eip1559_transition: BlockNumber,
}
impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
@ -716,7 +718,9 @@ impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
RollingFinality::blank(signers, self.two_thirds_majority_transition);
let mut finalized = Vec::new();
let headers: Vec<Header> = Rlp::new(proof).as_list().ok()?;
let proof_rlp = Rlp::new(proof);
let headers: Vec<Header> =
Header::decode_rlp_list(&proof_rlp, self.eip1559_transition).ok()?;
{
let mut push_header = |parent_header: &Header, header: Option<&Header>| {
@ -1553,6 +1557,43 @@ impl Engine<EthereumMachine> for AuthorityRound {
}
}
// Mostly is the same as `fn sealing_state(&self)` except that it does not
// check whether the node is a step proposer.
fn is_allowed_to_seal(&self) -> bool {
let our_addr = match *self.signer.read() {
Some(ref signer) => signer.address(),
None => return false,
};
let client = match self.upgrade_client_or("Not preparing block") {
Ok(client) => client,
Err(_) => return false,
};
let parent = match client.as_full_client() {
Some(full_client) => full_client.best_block_header(),
None => {
return false;
}
};
let validators = if self.immediate_transitions {
CowLike::Borrowed(&*self.validators)
} else {
let mut epoch_manager = self.epoch_manager.lock();
if !epoch_manager.zoom_to_after(
&*client,
&self.machine,
&*self.validators,
parent.hash(),
) {
return false;
}
CowLike::Owned(epoch_manager.validators().clone())
};
validators.contains(&parent.hash(), &our_addr)
}
fn sealing_state(&self) -> SealingState {
let our_addr = match *self.signer.read() {
Some(ref signer) => signer.address(),
@ -1805,7 +1846,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
let parent = client
.block_header(::client::BlockId::Hash(*block.header.parent_hash()))
.expect("hash is from parent; parent header must exist; qed")
.decode()?;
.decode(self.params().eip1559_transition)?;
let parent_step = header_step(&parent, self.empty_steps_transition)?;
let current_step = self.step.inner.load();
@ -2200,6 +2241,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
subchain_validators: list,
empty_steps_transition: self.empty_steps_transition,
two_thirds_majority_transition: self.two_thirds_majority_transition,
eip1559_transition: self.params().eip1559_transition,
});
match finalize {

View File

@ -316,7 +316,8 @@ impl Clique {
return Err(BlockError::UnknownParent(last_parent_hash))?;
}
Some(next) => {
chain.push_front(next.decode()?);
chain
.push_front(next.decode(self.machine.params().eip1559_transition)?);
}
}
}
@ -332,7 +333,7 @@ impl Clique {
None => {
return Err(EngineError::CliqueMissingCheckpoint(last_checkpoint_hash))?
}
Some(header) => header.decode()?,
Some(header) => header.decode(self.machine.params().eip1559_transition)?,
};
let last_checkpoint_state = match block_state_by_hash.get_mut(&last_checkpoint_hash)

View File

@ -470,6 +470,14 @@ pub trait Engine<M: Machine>: Sync + Send {
/// Register a component which signs consensus messages.
fn set_signer(&self, _signer: Option<Box<dyn EngineSigner>>) {}
/// Returns whether the current node is a validator and
/// actually may seal a block if AuRa engine is used.
///
/// Used by `eth_mining` rpc call.
fn is_allowed_to_seal(&self) -> bool {
true
}
/// Sign using the EngineSigner, to be used for consensus tx signing.
fn sign(&self, _hash: H256) -> Result<Signature, M::Error> {
unimplemented!()
@ -648,10 +656,26 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> {
self.machine().decode_transaction(transaction, &schedule)
}
/// Calculates base fee for the block that should be mined next.
/// This base fee is calculated based on the parent header (last block in blockchain / best block).
///
/// Introduced by EIP1559 to support new market fee mechanism.
fn calculate_base_fee(&self, parent: &Header) -> Option<U256> {
self.machine().calc_base_fee(parent)
}
/// The configured minimum gas limit. Used by AuRa Engine.
fn min_gas_limit(&self) -> U256 {
self.params().min_gas_limit
}
/// Returns whether transactions from non externally owned accounts (EOA)
/// are allowed in the given block number (see EIP-3607).
///
/// That is only possible if EIP-3607 is still not activated.
fn allow_non_eoa_sender(&self, best_block_number: BlockNumber) -> bool {
self.params().eip3607_transition > best_block_number
}
}
// convenience wrappers for existing functions.

View File

@ -287,8 +287,11 @@ mod tests {
for i in 1..4 {
sync_client
.import_block(
Unverified::from_rlp(client.block(BlockId::Number(i)).unwrap().into_inner())
.unwrap(),
Unverified::from_rlp(
client.block(BlockId::Number(i)).unwrap().into_inner(),
client.engine().params().eip1559_transition,
)
.unwrap(),
)
.unwrap();
}

View File

@ -70,8 +70,9 @@ impl ::engines::StateDependentProof<EthereumMachine> for StateProof {
}
fn check_proof(&self, machine: &EthereumMachine, proof: &[u8]) -> Result<(), String> {
let (header, state_items) = decode_first_proof(&Rlp::new(proof))
.map_err(|e| format!("proof incorrectly encoded: {}", e))?;
let (header, state_items) =
decode_first_proof(&Rlp::new(proof), machine.params().eip1559_transition)
.map_err(|e| format!("proof incorrectly encoded: {}", e))?;
if &header != &self.header {
return Err("wrong header in proof".into());
}
@ -129,6 +130,7 @@ fn check_first_proof(
Arc::new(last_hashes)
},
gas_used: 0.into(),
base_fee: old_header.base_fee(),
};
// check state proof using given machine.
@ -163,8 +165,11 @@ fn check_first_proof(
}
}
fn decode_first_proof(rlp: &Rlp) -> Result<(Header, Vec<DBValue>), ::error::Error> {
let header = rlp.val_at(0)?;
fn decode_first_proof(
rlp: &Rlp,
eip1559_transition: BlockNumber,
) -> Result<(Header, Vec<DBValue>), ::error::Error> {
let header = Header::decode_rlp(&rlp.at(0)?, eip1559_transition)?;
let state_items = rlp
.at(1)?
.iter()
@ -188,8 +193,14 @@ fn encode_proof(header: &Header, receipts: &[TypedReceipt]) -> Bytes {
stream.drain()
}
fn decode_proof(rlp: &Rlp) -> Result<(Header, Vec<TypedReceipt>), ::error::Error> {
Ok((rlp.val_at(0)?, TypedReceipt::decode_rlp_list(&rlp.at(1)?)?))
fn decode_proof(
rlp: &Rlp,
eip1559_transition: BlockNumber,
) -> Result<(Header, Vec<TypedReceipt>), ::error::Error> {
Ok((
Header::decode_rlp(&rlp.at(0)?, eip1559_transition)?,
TypedReceipt::decode_rlp_list(&rlp.at(1)?)?,
))
}
// given a provider and caller, generate proof. this will just be a state proof
@ -554,7 +565,8 @@ impl ValidatorSet for ValidatorSafeContract {
if first {
trace!(target: "engine", "Recovering initial epoch set");
let (old_header, state_items) = decode_first_proof(&rlp)?;
let (old_header, state_items) =
decode_first_proof(&rlp, machine.params().eip1559_transition)?;
let number = old_header.number();
let old_hash = old_header.hash();
let addresses =
@ -566,7 +578,7 @@ impl ValidatorSet for ValidatorSafeContract {
Ok((SimpleList::new(addresses), Some(old_hash)))
} else {
let (old_header, receipts) = decode_proof(&rlp)?;
let (old_header, receipts) = decode_proof(&rlp, machine.params().eip1559_transition)?;
// ensure receipts match header.
// TODO: optimize? these were just decoded.
@ -830,8 +842,11 @@ mod tests {
for i in 1..4 {
sync_client
.import_block(
Unverified::from_rlp(client.block(BlockId::Number(i)).unwrap().into_inner())
.unwrap(),
Unverified::from_rlp(
client.block(BlockId::Number(i)).unwrap().into_inner(),
client.engine().params().eip1559_transition,
)
.unwrap(),
)
.unwrap();
}

View File

@ -46,6 +46,10 @@ pub enum BlockError {
InvalidSealArity(Mismatch<usize>),
/// Block has too much gas used.
TooMuchGasUsed(OutOfBounds<U256>),
/// Gas target increased too much from previous block
GasTargetTooBig(OutOfBounds<U256>),
/// Gas target decreased too much from previous block
GasTargetTooSmall(OutOfBounds<U256>),
/// Uncles hash in header is invalid.
InvalidUnclesHash(Mismatch<H256>),
/// An uncle is from a generation too old.
@ -79,6 +83,8 @@ pub enum BlockError {
InvalidSeal,
/// Gas limit header field is invalid.
InvalidGasLimit(OutOfBounds<U256>),
/// Base fee is incorrect; base fee is different from the expected calculated value.
IncorrectBaseFee(Mismatch<U256>),
/// Receipts trie root header field is invalid.
InvalidReceiptsRoot(Mismatch<H256>),
/// Timestamp header field is invalid.
@ -112,6 +118,8 @@ impl fmt::Display for BlockError {
ExtraDataOutOfBounds(ref oob) => format!("Extra block data too long. {}", oob),
InvalidSealArity(ref mis) => format!("Block seal in incorrect format: {}", mis),
TooMuchGasUsed(ref oob) => format!("Block has too much gas used. {}", oob),
GasTargetTooBig(ref oob) => format!("Gas target is bigger then expected. {}", oob),
GasTargetTooSmall(ref oob) => format!("Gas target is smaller then expected. {}", oob),
InvalidUnclesHash(ref mis) => format!("Block has invalid uncles hash: {}", mis),
UncleTooOld(ref oob) => format!("Uncle block is too old. {}", oob),
UncleIsBrother(ref oob) => format!("Uncle from same generation as block. {}", oob),
@ -131,6 +139,7 @@ impl fmt::Display for BlockError {
InvalidProofOfWork(ref oob) => format!("Block has invalid PoW: {}", oob),
InvalidSeal => "Block has invalid seal.".into(),
InvalidGasLimit(ref oob) => format!("Invalid gas limit: {}", oob),
IncorrectBaseFee(ref mis) => format!("Incorrect base fee: {}", mis),
InvalidReceiptsRoot(ref mis) => {
format!("Invalid receipts trie root in header: {}", mis)
}

View File

@ -14,7 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use std::{cmp, collections::BTreeMap, path::Path, sync::Arc};
use std::{
cmp::{self},
collections::BTreeMap,
path::Path,
sync::Arc,
};
use ethereum_types::{H256, H64, U256};
use ethjson::{self, uint::Uint};

View File

@ -274,6 +274,22 @@ pub fn new_berlin_test() -> Spec {
)
}
/// Create a new Foundation London era spec.
pub fn new_london_test() -> Spec {
load(
None,
include_bytes!("../../res/chainspec/test/london_test.json"),
)
}
/// Create a new BerlinToLondonAt5 era spec.
pub fn new_berlin_to_london_test() -> Spec {
load(
None,
include_bytes!("../../res/chainspec/test/berlin_to_londonat5_test.json"),
)
}
/// Create a new Musicoin-MCIP3-era spec.
pub fn new_mcip3_test() -> Spec {
load(
@ -298,6 +314,11 @@ pub fn new_homestead_test_machine() -> EthereumMachine {
))
}
/// Create a new Foundation London era chain spec.
pub fn new_london_test_machine() -> EthereumMachine {
load_machine(include_bytes!("../../res/chainspec/test/london_test.json"))
}
/// Create a new Foundation Homestead-EIP210-era chain spec as though it never changed from Homestead/Frontier.
pub fn new_eip210_test_machine() -> EthereumMachine {
load_machine(include_bytes!("../../res/chainspec/test/eip210_test.json"))

View File

@ -91,6 +91,13 @@ pub enum ExecutionError {
/// Amount of gas in block.
gas: U256,
},
/// Transaction's max gas price is lower then block base fee.
GasPriceLowerThanBaseFee {
/// Max gas price of the transaction.
gas_price: U256,
/// Block base fee.
base_fee: U256,
},
/// Returned when transaction nonce does not match state nonce.
InvalidNonce {
/// Nonce expected.
@ -148,6 +155,13 @@ impl fmt::Display for ExecutionError {
already been used, and {} more is required",
gas_limit, gas_used, gas
),
GasPriceLowerThanBaseFee {
ref gas_price,
ref base_fee,
} => format!(
"Max gas price is lowert than block base fee. Gas price is {}, while base fee is {}",
gas_price, base_fee
),
InvalidNonce {
ref expected,
ref got,

View File

@ -444,6 +444,7 @@ impl<'a> CallCreateExecutive<'a> {
| Err(vm::Error::SubStackUnderflow { .. })
| Err(vm::Error::OutOfSubStack { .. })
| Err(vm::Error::InvalidSubEntry)
| Err(vm::Error::InvalidCode)
| Ok(FinalizationResult {
apply_state: false, ..
}) => {
@ -1133,6 +1134,13 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
));
}
}
TypedTransaction::EIP1559Transaction(_) => {
if !schedule.eip1559 {
return Err(ExecutionError::TransactionMalformed(
"1559 type of transactions not enabled".into(),
));
}
}
TypedTransaction::Legacy(_) => (), //legacy transactions are allways valid
};
@ -1150,17 +1158,15 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
access_list.insert_address(*address);
}
}
if schedule.eip2930 {
// optional access list
if let TypedTransaction::AccessList(al_tx) = t.as_unsigned() {
for item in al_tx.access_list.iter() {
access_list.insert_address(item.0);
base_gas_required += vm::schedule::EIP2930_ACCESS_LIST_ADDRESS_COST.into();
for key in item.1.iter() {
access_list.insert_storage_key(item.0, *key);
base_gas_required +=
vm::schedule::EIP2930_ACCESS_LIST_STORAGE_KEY_COST.into();
}
if let Some(al) = t.access_list() {
for item in al.iter() {
access_list.insert_address(item.0);
base_gas_required += vm::schedule::EIP2930_ACCESS_LIST_ADDRESS_COST.into();
for key in item.1.iter() {
access_list.insert_storage_key(item.0, *key);
base_gas_required +=
vm::schedule::EIP2930_ACCESS_LIST_STORAGE_KEY_COST.into();
}
}
}
@ -1200,16 +1206,35 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
});
}
// ensure that the user was willing to at least pay the base fee
if t.tx().gas_price < self.info.base_fee.unwrap_or_default() && !t.has_zero_gas_price() {
return Err(ExecutionError::GasPriceLowerThanBaseFee {
gas_price: t.tx().gas_price,
base_fee: self.info.base_fee.unwrap_or_default(),
});
}
// verify that transaction max_fee_per_gas is higher or equal to max_priority_fee_per_gas
if t.tx().gas_price < t.max_priority_fee_per_gas() {
return Err(ExecutionError::TransactionMalformed(
"maxPriorityFeePerGas higher than maxFeePerGas".into(),
));
}
// TODO: we might need bigints here, or at least check overflows.
let balance = self.state.balance(&sender)?;
let gas_cost = t.tx().gas.full_mul(t.tx().gas_price);
let total_cost = U512::from(t.tx().value) + gas_cost;
let gas_cost_effective = t
.tx()
.gas
.full_mul(t.effective_gas_price(self.info.base_fee));
let gas_cost_max = t.tx().gas.full_mul(t.tx().gas_price);
let needed_balance = U512::from(t.tx().value) + gas_cost_max;
// avoid unaffordable transactions
let balance512 = U512::from(balance);
if balance512 < total_cost {
if balance512 < needed_balance {
return Err(ExecutionError::NotEnoughCash {
required: total_cost,
required: needed_balance,
got: balance512,
});
}
@ -1222,7 +1247,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
}
self.state.sub_balance(
&sender,
&U256::try_from(gas_cost).expect("Total cost (value + gas_cost) is lower than max allowed balance (U256); gas_cost has to fit U256; qed"),
&U256::try_from(gas_cost_effective).expect("Total cost (value + gas_cost_effective) is lower than max allowed balance (U256); gas_cost has to fit U256; qed"),
&mut substate.to_cleanup_mode(&schedule),
)?;
@ -1242,7 +1267,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
sender: sender.clone(),
origin: sender.clone(),
gas: init_gas,
gas_price: t.tx().gas_price,
gas_price: t.effective_gas_price(self.info.base_fee),
value: ActionValue::Transfer(t.tx().value),
code: Some(Arc::new(t.tx().data.clone())),
data: None,
@ -1265,7 +1290,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
sender: sender.clone(),
origin: sender.clone(),
gas: init_gas,
gas_price: t.tx().gas_price,
gas_price: t.effective_gas_price(self.info.base_fee),
value: ActionValue::Transfer(t.tx().value),
code: self.state.code(address)?,
code_hash: self.state.code_hash(address)?,
@ -1463,23 +1488,49 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
U256::from(schedule.suicide_refund_gas) * U256::from(substate.suicides.len());
let refunds_bound = sstore_refunds + suicide_refunds;
// real ammount to refund
// real amount to refund
let gas_left_prerefund = match result {
Ok(FinalizationResult { gas_left, .. }) => gas_left,
_ => 0.into(),
};
let refunded = cmp::min(refunds_bound, (t.tx().gas - gas_left_prerefund) >> 1);
let refunded = if refunds_bound.is_zero() {
refunds_bound
} else {
let gas_used = t.tx().gas - gas_left_prerefund;
let max_refund = gas_used / schedule.max_refund_quotient;
cmp::min(max_refund, refunds_bound)
};
let gas_left = gas_left_prerefund + refunded;
let gas_used = t.tx().gas.saturating_sub(gas_left);
let (refund_value, overflow_1) = gas_left.overflowing_mul(t.tx().gas_price);
let (fees_value, overflow_2) = gas_used.overflowing_mul(t.tx().gas_price);
let (refund_value, overflow_1) =
gas_left.overflowing_mul(t.effective_gas_price(self.info.base_fee));
let (fees_value, overflow_2) =
gas_used.overflowing_mul(t.effective_gas_price(self.info.base_fee));
if overflow_1 || overflow_2 {
return Err(ExecutionError::TransactionMalformed(
"U256 Overflow".to_string(),
));
}
// Up until now, fees_value is calculated for each type of transaction based on their gas prices
// Now, if eip1559 is activated, burn the base fee
// miner only receives the inclusion fee; note that the base fee is not given to anyone (it is burned)
let burnt_fee = if schedule.eip1559 && !t.has_zero_gas_price() {
let (fee, overflow_3) =
gas_used.overflowing_mul(self.info.base_fee.unwrap_or_default());
if overflow_3 {
return Err(ExecutionError::TransactionMalformed(
"U256 Overflow".to_string(),
));
}
fee
} else {
U256::from(0)
};
let fees_value = fees_value.saturating_sub(burnt_fee);
trace!("exec::finalize: t.gas={}, sstore_refunds={}, suicide_refunds={}, refunds_bound={}, gas_left_prerefund={}, refunded={}, gas_left={}, gas_used={}, refund_value={}, fees_value={}\n",
t.tx().gas, sstore_refunds, suicide_refunds, refunds_bound, gas_left_prerefund, refunded, gas_left, gas_used, refund_value, fees_value);
@ -1503,6 +1554,17 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
substate.to_cleanup_mode(&schedule),
)?;
if burnt_fee > U256::from(0)
&& self.machine.params().eip1559_fee_collector.is_some()
&& self.info.number >= self.machine.params().eip1559_fee_collector_transition
{
self.state.add_balance(
&self.machine.params().eip1559_fee_collector.unwrap(),
&burnt_fee,
substate.to_cleanup_mode(&schedule),
)?;
};
// perform suicides
for address in &substate.suicides {
self.state.kill_account(address);
@ -1512,7 +1574,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
let min_balance = if schedule.kill_dust != CleanDustMode::Off {
Some(
U256::from(schedule.tx_gas)
.overflowing_mul(t.tx().gas_price)
.overflowing_mul(t.effective_gas_price(self.info.base_fee))
.0,
)
} else {
@ -1578,7 +1640,9 @@ mod tests {
trace, ExecutiveTracer, ExecutiveVMTracer, FlatTrace, MemoryDiff, NoopTracer, NoopVMTracer,
StorageDiff, Tracer, VMExecutedOperation, VMOperation, VMTrace, VMTracer,
};
use types::transaction::{Action, Transaction, TypedTransaction};
use types::transaction::{
AccessListTx, Action, EIP1559TransactionTx, Transaction, TypedTransaction,
};
use vm::{ActionParams, ActionValue, CallType, CreateContractAddress, EnvInfo};
fn make_frontier_machine(max_depth: usize) -> EthereumMachine {
@ -1593,6 +1657,12 @@ mod tests {
machine
}
fn make_london_machine(max_depth: usize) -> EthereumMachine {
let mut machine = ::ethereum::new_london_test_machine();
machine.set_schedule_creation_rules(Box::new(move |s, _| s.max_depth = max_depth));
machine
}
#[test]
fn test_contract_address() {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
@ -2604,6 +2674,53 @@ mod tests {
}
}
evm_test! {test_transact_eip1559: test_transact_eip1559_int}
fn test_transact_eip1559(factory: Factory) {
let keypair = Random.generate();
let t = TypedTransaction::EIP1559Transaction(EIP1559TransactionTx {
transaction: AccessListTx::new(
Transaction {
action: Action::Create,
value: U256::from(17),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: U256::from(150),
nonce: U256::zero(),
},
vec![
(
H160::from_low_u64_be(10),
vec![H256::from_low_u64_be(102), H256::from_low_u64_be(103)],
),
(H160::from_low_u64_be(400), vec![]),
],
),
max_priority_fee_per_gas: U256::from(30),
})
.sign(keypair.secret(), None);
let sender = t.sender();
let mut state = get_temp_state_with_factory(factory);
state
.add_balance(&sender, &U256::from(15000017), CleanupMode::NoEmpty)
.unwrap();
let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000);
info.base_fee = Some(U256::from(100));
let machine = make_london_machine(0);
let schedule = machine.schedule(info.number);
let res = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
let opts = TransactOptions::with_no_tracing();
ex.transact(&t, opts).unwrap()
};
assert_eq!(res.gas, U256::from(100_000));
assert_eq!(res.gas_used, U256::from(83873));
}
evm_test! {test_not_enough_cash: test_not_enough_cash_int}
fn test_not_enough_cash(factory: Factory) {
let keypair = Random.generate();
@ -2643,6 +2760,127 @@ mod tests {
}
}
evm_test! {test_too_big_max_priority_fee_with_not_enough_cash: test_too_big_max_priority_fee_with_not_enough_cash_int}
fn test_too_big_max_priority_fee_with_not_enough_cash(factory: Factory) {
let keypair = Random.generate();
let max_priority_fee_per_gas /* 2**256 - 1 */ = U256::from(340282366920938463463374607431768211455u128)
* U256::from(340282366920938463463374607431768211455u128)
+ U256::from(340282366920938463463374607431768211455u128)
+ U256::from(340282366920938463463374607431768211455u128);
let t = TypedTransaction::EIP1559Transaction(EIP1559TransactionTx {
transaction: AccessListTx::new(
Transaction {
action: Action::Create,
value: U256::from(17),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: max_priority_fee_per_gas,
nonce: U256::zero(),
},
vec![
(
H160::from_low_u64_be(10),
vec![H256::from_low_u64_be(102), H256::from_low_u64_be(103)],
),
(H160::from_low_u64_be(400), vec![]),
],
),
max_priority_fee_per_gas,
})
.sign(keypair.secret(), None);
let sender = t.sender();
let mut state = get_temp_state_with_factory(factory);
state
.add_balance(&sender, &U256::from(15000017), CleanupMode::NoEmpty)
.unwrap();
let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000);
info.base_fee = Some(U256::from(100));
let machine = make_london_machine(0);
let schedule = machine.schedule(info.number);
let res = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
let opts = TransactOptions::with_no_tracing();
ex.transact(&t, opts)
};
match res {
Err(ExecutionError::NotEnoughCash { required, got })
if required
== U512::from(max_priority_fee_per_gas) * U512::from(100_000)
+ U512::from(17)
&& got == U512::from(15000017) =>
{
()
}
_ => assert!(false, "Expected not enough cash error. {:?}", res),
}
}
evm_test! {test_too_big_max_priority_fee_with_less_max_fee_per_gas: test_too_big_max_priority_fee_with_less_max_fee_per_gas_int}
fn test_too_big_max_priority_fee_with_less_max_fee_per_gas(factory: Factory) {
let keypair = Random.generate();
let max_priority_fee_per_gas /* 2**256 - 1 */ = U256::from(340282366920938463463374607431768211455u128)
* U256::from(340282366920938463463374607431768211455u128)
+ U256::from(340282366920938463463374607431768211455u128)
+ U256::from(340282366920938463463374607431768211455u128);
let t = TypedTransaction::EIP1559Transaction(EIP1559TransactionTx {
transaction: AccessListTx::new(
Transaction {
action: Action::Create,
value: U256::from(17),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: U256::from(150),
nonce: U256::zero(),
},
vec![
(
H160::from_low_u64_be(10),
vec![H256::from_low_u64_be(102), H256::from_low_u64_be(103)],
),
(H160::from_low_u64_be(400), vec![]),
],
),
max_priority_fee_per_gas,
})
.sign(keypair.secret(), None);
let sender = t.sender();
let mut state = get_temp_state_with_factory(factory);
state
.add_balance(&sender, &U256::from(15000017), CleanupMode::NoEmpty)
.unwrap();
let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000);
info.base_fee = Some(U256::from(100));
let machine = make_london_machine(0);
let schedule = machine.schedule(info.number);
let res = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
let opts = TransactOptions::with_no_tracing();
ex.transact(&t, opts)
};
match res {
Err(ExecutionError::TransactionMalformed(err))
if err.contains("maxPriorityFeePerGas higher than maxFeePerGas") =>
{
()
}
_ => assert!(
false,
"Expected maxPriorityFeePerGas higher than maxFeePerGas error. {:?}",
res
),
}
}
evm_test! {test_keccak: test_keccak_int}
fn test_keccak(factory: Factory) {
let code = "6064640fffffffff20600055".from_hex().unwrap();

View File

@ -431,6 +431,12 @@ where
false => Ok(*gas),
};
}
if self.schedule.eip3541 && data.get(0) == Some(&0xefu8) {
return match self.schedule.exceptional_failed_code_deposit {
true => Err(vm::Error::InvalidCode),
false => Ok(*gas),
};
}
self.state
.init_code(&self.origin_info.address, data.to_vec())?;
Ok(*gas - return_cost)
@ -582,6 +588,7 @@ mod tests {
last_hashes: Arc::new(vec![]),
gas_used: 0.into(),
gas_limit: 0.into(),
base_fee: None,
}
}
@ -913,4 +920,46 @@ mod tests {
Address::from_str("e33c0c7f7df4809055c3eba6c09cfe4baf1bd9e0").unwrap()
);
}
#[test]
fn eip_3541() {
let call_ret = |schedule: Schedule, data: &ReturnData| {
let mut setup = TestSetup::default();
setup.schedule = schedule;
let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer;
let origin = get_test_origin();
let ext = Externalities::new(
&mut setup.state,
&setup.env_info,
&setup.machine,
&setup.schedule,
0,
0,
&origin,
&mut setup.sub_state,
OutputPolicy::InitContract,
&mut tracer,
&mut vm_tracer,
false,
);
ext.ret(&U256::from(10000), &data, true)
};
let data = ReturnData::new(vec![0xefu8], 0, 1);
let result = call_ret(Schedule::new_berlin(), &data);
assert!(result.is_ok());
let result = call_ret(Schedule::new_london(), &data);
assert!(result.is_err());
let data = ReturnData::new(vec![0xefu8, 0x00u8, 0x00u8], 0, 3);
let result = call_ret(Schedule::new_london(), &data);
assert!(result.is_err());
let data = ReturnData::new(vec![0xee], 0, 1);
let result = call_ret(Schedule::new_london(), &data);
assert!(result.is_ok());
}
}

View File

@ -204,7 +204,7 @@ pub fn json_chain_test<H: FnMut(&str, HookType)>(
for b in blockchain.blocks_rlp() {
let bytes_len = b.len();
let block = Unverified::from_rlp(b);
let block = Unverified::from_rlp(b, spec.params().eip1559_transition);
match block {
Ok(block) => {
let num = block.header.number();

View File

@ -4,7 +4,10 @@ use ethjson::{self, blockchain::Block};
use log::warn;
use rlp::RlpStream;
use std::path::Path;
use types::transaction::{TypedTransaction, TypedTxId, UnverifiedTransaction};
use types::{
transaction::{TypedTransaction, TypedTxId, UnverifiedTransaction},
BlockNumber,
};
use verification::queue::kind::blocks::Unverified;
pub fn json_local_block_en_de_test<H: FnMut(&str, HookType)>(
@ -22,7 +25,7 @@ pub fn json_local_block_en_de_test<H: FnMut(&str, HookType)>(
for (name, ref_block) in tests.into_iter() {
start_stop_hook(&name, HookType::OnStart);
let block = Unverified::from_rlp(ref_block.rlp());
let block = Unverified::from_rlp(ref_block.rlp(), BlockNumber::max_value());
let block = match block {
Ok(block) => block,
Err(decoder_err) => {
@ -131,8 +134,24 @@ pub fn is_same_block(ref_block: &Block, block: &Unverified) -> bool {
TypedTxId::Legacy
};
is_ok = is_ok
&& {
match ref_tx.gas_price {
Some(gas_price) => {
test_exp(tx.tx().gas_price == gas_price.0, "Tx gas price")
}
None => {
test_exp(
tx.tx().gas_price == ref_tx.max_fee_per_gas.unwrap_or_default().0,
"Tx max fee per gas",
) && test_exp(
tx.max_priority_fee_per_gas()
== ref_tx.max_priority_fee_per_gas.unwrap_or_default().0,
"Tx max priority fee per gas",
)
}
}
}
&& test_exp(tx.tx().nonce == ref_tx.nonce.0, "Tx nonce")
&& test_exp(tx.tx().gas_price == ref_tx.gas_price.0, "Tx gas price")
&& test_exp(tx.tx().gas == ref_tx.gas_limit.0, "Tx gas")
&& test_exp(tx.tx().value == ref_tx.value.0, "Tx value")
&& test_exp(tx.tx().data == ref_tx.data.0, "Tx data")
@ -148,10 +167,11 @@ pub fn is_same_block(ref_block: &Block, block: &Unverified) -> bool {
TypedTxId::Legacy => {
test_exp(tx.legacy_v() == ref_tx.v.0.as_u64(), "Original Sig V")
}
TypedTxId::AccessList => {
TypedTxId::AccessList | TypedTxId::EIP1559Transaction => {
test_exp(tx.standard_v() as u64 == ref_tx.v.0.as_u64(), "Sig V");
let al = match tx.as_unsigned() {
TypedTransaction::AccessList(tx) => &tx.access_list,
TypedTransaction::EIP1559Transaction(tx) => &tx.transaction.access_list,
_ => {
println!("Wrong data in tx type");
continue;

View File

@ -16,7 +16,7 @@
use super::{test_common::*, HookType};
use client::{EvmTestClient, EvmTestError, TransactErr, TransactSuccess};
use ethjson;
use ethjson::{self, spec::ForkSpec};
use pod_state::PodState;
use std::path::Path;
use trace;
@ -77,6 +77,14 @@ pub fn json_state_test<H: FnMut(&str, HookType)>(
}
};
//hardcode base fee for part of the london tests, that miss base fee field in env
let mut test_env = env.clone();
if spec_name >= ForkSpec::London {
if test_env.base_fee.is_none() {
test_env.base_fee = Some(0x0a.into());
}
}
for (i, state) in states.into_iter().enumerate() {
let info = format!(
"TestState/{}/{:?}/{}/trie",
@ -94,7 +102,7 @@ pub fn json_state_test<H: FnMut(&str, HookType)>(
let result = || -> Result<_, EvmTestError> {
Ok(EvmTestClient::from_pod_state(&spec, pre.clone())?.transact(
&env,
&test_env,
transaction,
trace::NoopTracer,
trace::NoopVMTracer,

View File

@ -17,7 +17,7 @@
//! Ethereum-like state machine definition.
use std::{
cmp,
cmp::{self, max},
collections::{BTreeMap, HashMap},
sync::Arc,
};
@ -47,9 +47,6 @@ use state::{CleanupMode, Substate};
use trace::{NoopTracer, NoopVMTracer};
use tx_filter::TransactionFilter;
/// Open tries to round block.gas_limit to multiple of this constant
pub const GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]);
/// Ethash-specific extensions.
#[derive(Debug, Clone)]
pub struct EthashExtensions {
@ -269,55 +266,31 @@ impl EthereumMachine {
gas_ceil_target: U256,
) {
header.set_difficulty(parent.difficulty().clone());
let gas_limit = parent.gas_limit().clone();
let gas_limit = parent.gas_limit() * self.schedule(header.number()).eip1559_gas_limit_bump;
assert!(!gas_limit.is_zero(), "Gas limit should be > 0");
if let Some(ref ethash_params) = self.ethash_extensions {
let gas_limit = {
let bound_divisor = self.params().gas_limit_bound_divisor;
let lower_limit = gas_limit - gas_limit / bound_divisor + 1;
let upper_limit = gas_limit + gas_limit / bound_divisor - 1;
let gas_limit = if gas_limit < gas_floor_target {
let gas_limit = cmp::min(gas_floor_target, upper_limit);
round_block_gas_limit(gas_limit, lower_limit, upper_limit)
} else if gas_limit > gas_ceil_target {
let gas_limit = cmp::max(gas_ceil_target, lower_limit);
round_block_gas_limit(gas_limit, lower_limit, upper_limit)
} else {
let total_lower_limit = cmp::max(lower_limit, gas_floor_target);
let total_upper_limit = cmp::min(upper_limit, gas_ceil_target);
let gas_limit = cmp::max(
gas_floor_target,
cmp::min(
total_upper_limit,
lower_limit + (header.gas_used().clone() * 6u32 / 5) / bound_divisor,
),
);
round_block_gas_limit(gas_limit, total_lower_limit, total_upper_limit)
};
// ensure that we are not violating protocol limits
debug_assert!(gas_limit >= lower_limit);
debug_assert!(gas_limit <= upper_limit);
gas_limit
};
let gas_limit_target = if self.schedule(header.number()).eip1559 {
gas_ceil_target
} else {
gas_floor_target
};
header.set_gas_limit(gas_limit);
header.set_gas_limit({
let bound_divisor = self.params().gas_limit_bound_divisor;
if gas_limit < gas_limit_target {
cmp::min(gas_limit_target, gas_limit + gas_limit / bound_divisor - 1)
} else {
cmp::max(gas_limit_target, gas_limit - gas_limit / bound_divisor + 1)
}
});
if let Some(ref ethash_params) = self.ethash_extensions {
if header.number() >= ethash_params.dao_hardfork_transition
&& header.number() <= ethash_params.dao_hardfork_transition + 9
{
header.set_extra_data(b"dao-hard-fork"[..].to_owned());
}
return;
}
header.set_gas_limit({
let bound_divisor = self.params().gas_limit_bound_divisor;
if gas_limit < gas_floor_target {
cmp::min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1)
} else {
cmp::max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1)
}
});
}
/// Get the general parameters of the chain.
@ -400,8 +373,16 @@ impl EthereumMachine {
pub fn verify_transaction_unordered(
&self,
t: UnverifiedTransaction,
_header: &Header,
header: &Header,
) -> Result<SignedTransaction, transaction::Error> {
// ensure that the user was willing to at least pay the base fee
if t.tx().gas_price < header.base_fee().unwrap_or_default() && !t.has_zero_gas_price() {
return Err(transaction::Error::GasPriceLowerThanBaseFee {
gas_price: t.tx().gas_price,
base_fee: header.base_fee().unwrap_or_default(),
});
}
Ok(SignedTransaction::new(t)?)
}
@ -472,11 +453,80 @@ impl EthereumMachine {
transaction::TypedTxId::AccessList if !schedule.eip2930 => {
return Err(transaction::Error::TransactionTypeNotEnabled)
}
transaction::TypedTxId::EIP1559Transaction if !schedule.eip1559 => {
return Err(transaction::Error::TransactionTypeNotEnabled)
}
_ => (),
};
Ok(tx)
}
/// Calculates base fee for the block that should be mined next.
/// Base fee is calculated based on the parent header (last block in blockchain / best block).
///
/// Introduced by EIP1559 to support new market fee mechanism.
///
/// Modified for xDai chain to have an ability to set min base fee
/// through eip1559BaseFeeMinValue spec option. The modification made
/// in v3.3.0-rc.14
pub fn calc_base_fee(&self, parent: &Header) -> Option<U256> {
// Block eip1559_transition - 1 has base_fee = None
if parent.number() + 1 < self.params().eip1559_transition {
return None;
}
let base_fee_min_value =
if parent.number() + 1 >= self.params().eip1559_base_fee_min_value_transition {
match self.params().eip1559_base_fee_min_value {
None => panic!("Base fee min value must be set in spec."),
Some(min_value) => min_value,
}
} else {
U256::zero()
};
// Block eip1559_transition has base_fee = self.params().eip1559_base_fee_initial_value
if parent.number() + 1 == self.params().eip1559_transition {
return Some(max(
self.params().eip1559_base_fee_initial_value,
base_fee_min_value,
));
}
// Block eip1559_transition + 1 has base_fee = calculated
let base_fee_denominator = match self.params().eip1559_base_fee_max_change_denominator {
None => panic!("Can't calculate base fee if base fee denominator does not exist."),
Some(denominator) if denominator == U256::from(0) => {
panic!("Can't calculate base fee if base fee denominator is zero.")
}
Some(denominator) => denominator,
};
let parent_base_fee = parent.base_fee().unwrap_or_default();
let parent_gas_target = parent.gas_limit() / self.params().eip1559_elasticity_multiplier;
if parent_gas_target == U256::zero() {
panic!("Can't calculate base fee if parent gas target is zero.");
}
let result = if parent.gas_used() == &parent_gas_target {
parent_base_fee
} else if parent.gas_used() > &parent_gas_target {
let gas_used_delta = parent.gas_used() - parent_gas_target;
let base_fee_per_gas_delta = max(
parent_base_fee * gas_used_delta / parent_gas_target / base_fee_denominator,
U256::from(1),
);
parent_base_fee + base_fee_per_gas_delta
} else {
let gas_used_delta = parent_gas_target - parent.gas_used();
let base_fee_per_gas_delta =
parent_base_fee * gas_used_delta / parent_gas_target / base_fee_denominator;
max(parent_base_fee - base_fee_per_gas_delta, U256::zero())
};
Some(max(result, base_fee_min_value))
}
}
/// Auxiliary data fetcher for an Ethereum machine. In Ethereum-like machines
@ -525,27 +575,10 @@ impl super::Machine for EthereumMachine {
}
}
// Try to round gas_limit a bit so that:
// 1) it will still be in desired range
// 2) it will be a nearest (with tendency to increase) multiple of GAS_LIMIT_DETERMINANT
fn round_block_gas_limit(gas_limit: U256, lower_limit: U256, upper_limit: U256) -> U256 {
let increased_gas_limit =
gas_limit + (GAS_LIMIT_DETERMINANT - gas_limit % GAS_LIMIT_DETERMINANT);
if increased_gas_limit > upper_limit {
let decreased_gas_limit = increased_gas_limit - GAS_LIMIT_DETERMINANT;
if decreased_gas_limit < lower_limit {
gas_limit
} else {
decreased_gas_limit
}
} else {
increased_gas_limit
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ethereum::new_london_test_machine;
use ethereum_types::H160;
use std::str::FromStr;
@ -585,79 +618,65 @@ mod tests {
}
#[test]
fn ethash_gas_limit_is_multiple_of_determinant() {
use ethereum_types::U256;
fn calculate_base_fee_success() {
let machine = new_london_test_machine();
let parent_base_fees = [
U256::from(1000000000),
U256::from(1000000000),
U256::from(1000000000),
U256::from(1072671875),
U256::from(1059263476),
U256::from(1049238967),
U256::from(1049238967),
U256::from(0),
U256::from(1),
U256::from(2),
];
let parent_gas_used = [
U256::from(10000000),
U256::from(10000000),
U256::from(10000000),
U256::from(9000000),
U256::from(10001000),
U256::from(0),
U256::from(10000000),
U256::from(10000000),
U256::from(10000000),
U256::from(10000000),
];
let parent_gas_limit = [
U256::from(10000000),
U256::from(12000000),
U256::from(14000000),
U256::from(10000000),
U256::from(14000000),
U256::from(2000000),
U256::from(18000000),
U256::from(18000000),
U256::from(18000000),
U256::from(18000000),
];
let expected_base_fee = [
U256::from(1125000000),
U256::from(1083333333),
U256::from(1053571428),
U256::from(1179939062),
U256::from(1116028649),
U256::from(918084097),
U256::from(1063811730),
U256::from(1),
U256::from(2),
U256::from(3),
];
let spec = ::ethereum::new_homestead_test();
let ethparams = get_default_ethash_extensions();
for i in 0..parent_base_fees.len() {
let mut parent_header = Header::default();
parent_header.set_base_fee(Some(parent_base_fees[i]));
parent_header.set_gas_used(parent_gas_used[i]);
parent_header.set_gas_limit(parent_gas_limit[i]);
let machine = EthereumMachine::with_ethash_extensions(
spec.params().clone(),
Default::default(),
ethparams,
);
let mut parent = ::types::header::Header::new();
let mut header = ::types::header::Header::new();
header.set_number(1);
// this test will work for this constant only
assert_eq!(GAS_LIMIT_DETERMINANT, U256::from(37));
// when parent.gas_limit < gas_floor_target:
parent.set_gas_limit(U256::from(50_000));
machine.populate_from_parent(
&mut header,
&parent,
U256::from(100_000),
U256::from(200_000),
);
assert_eq!(*header.gas_limit(), U256::from(50_024));
// when parent.gas_limit > gas_ceil_target:
parent.set_gas_limit(U256::from(250_000));
machine.populate_from_parent(
&mut header,
&parent,
U256::from(100_000),
U256::from(200_000),
);
assert_eq!(*header.gas_limit(), U256::from(249_787));
// when parent.gas_limit is in miner's range
header.set_gas_used(U256::from(150_000));
parent.set_gas_limit(U256::from(150_000));
machine.populate_from_parent(
&mut header,
&parent,
U256::from(100_000),
U256::from(200_000),
);
assert_eq!(*header.gas_limit(), U256::from(150_035));
// when parent.gas_limit is in miner's range
// && we can NOT increase it to be multiple of constant
header.set_gas_used(U256::from(150_000));
parent.set_gas_limit(U256::from(150_000));
machine.populate_from_parent(
&mut header,
&parent,
U256::from(100_000),
U256::from(150_002),
);
assert_eq!(*header.gas_limit(), U256::from(149_998));
// when parent.gas_limit is in miner's range
// && we can NOT increase it to be multiple of constant
// && we can NOT decrease it to be multiple of constant
header.set_gas_used(U256::from(150_000));
parent.set_gas_limit(U256::from(150_000));
machine.populate_from_parent(
&mut header,
&parent,
U256::from(150_000),
U256::from(150_002),
);
assert_eq!(*header.gas_limit(), U256::from(150_002));
let base_fee = machine.calc_base_fee(&parent_header);
assert_eq!(expected_base_fee[i], base_fee.unwrap());
}
}
}

View File

@ -187,8 +187,10 @@ impl Default for MinerOptions {
pool_verification_options: pool::verifier::Options {
minimal_gas_price: DEFAULT_MINIMAL_GAS_PRICE.into(),
block_gas_limit: U256::max_value(),
block_base_fee: None,
tx_gas_limit: U256::max_value(),
no_early_reject: false,
allow_non_eoa_sender: false,
},
}
}
@ -337,8 +339,10 @@ impl Miner {
pool_verification_options: pool::verifier::Options {
minimal_gas_price,
block_gas_limit: U256::max_value(),
block_base_fee: None,
tx_gas_limit: U256::max_value(),
no_early_reject: false,
allow_non_eoa_sender: false,
},
reseal_min_period: Duration::from_secs(0),
force_sealing,
@ -376,7 +380,12 @@ impl Miner {
/// Updates transaction queue verification limits.
///
/// Limits consist of current block gas limit and minimal gas price.
pub fn update_transaction_queue_limits(&self, block_gas_limit: U256) {
pub fn update_transaction_queue_limits(
&self,
block_gas_limit: U256,
block_base_fee: Option<U256>,
allow_non_eoa_sender: bool,
) {
trace!(target: "miner", "minimal_gas_price: recalibrating...");
let txq = self.transaction_queue.clone();
let mut options = self.options.pool_verification_options.clone();
@ -384,8 +393,15 @@ impl Miner {
debug!(target: "miner", "minimal_gas_price: Got gas price! {}", gas_price);
options.minimal_gas_price = gas_price;
options.block_gas_limit = block_gas_limit;
options.block_base_fee = block_base_fee;
options.allow_non_eoa_sender = allow_non_eoa_sender;
txq.set_verifier_options(options);
});
match block_base_fee {
Some(block_base_fee) => self.transaction_queue.update_scoring(block_base_fee),
None => (),
}
}
/// Returns ServiceTransactionChecker
@ -498,11 +514,9 @@ impl Miner {
let client = self.pool_client(chain);
let engine_params = self.engine.params();
let min_tx_gas: U256 = self
.engine
.schedule(chain_info.best_block_number)
.tx_gas
.into();
let schedule = self.engine.schedule(block_number);
let min_tx_gas: U256 = schedule.tx_gas.into();
let gas_limit = open_block.header.gas_limit();
let nonce_cap: Option<U256> = if chain_info.best_block_number + 1
>= engine_params.dust_protection_transition
{
@ -515,11 +529,7 @@ impl Miner {
usize::max_value()
} else {
MAX_SKIPPED_TRANSACTIONS.saturating_add(
cmp::min(
*open_block.header.gas_limit() / min_tx_gas,
u64::max_value().into(),
)
.as_u64() as usize,
cmp::min(gas_limit / min_tx_gas, u64::max_value().into()).as_u64() as usize,
)
};
@ -531,6 +541,10 @@ impl Miner {
nonce_cap,
max_len: max_transactions.saturating_sub(engine_txs.len()),
ordering: miner::PendingOrdering::Priority,
includable_boundary: self
.engine
.calculate_base_fee(&chain.best_block_header())
.unwrap_or_default(),
},
);
@ -740,7 +754,7 @@ impl Miner {
trace!(target: "miner", "seal_block_internally: attempting internal seal.");
let parent_header = match chain.block_header(BlockId::Hash(*block.header.parent_hash())) {
Some(h) => match h.decode() {
Some(h) => match h.decode(self.engine.params().eip1559_transition) {
Ok(decoded_hdr) => decoded_hdr,
Err(_) => return false,
},
@ -996,6 +1010,14 @@ impl miner::MinerService for Miner {
self.transaction_queue.current_worst_gas_price() * 110u32 / 100
}
fn sensible_max_priority_fee(&self) -> U256 {
// 10% above our minimum.
self.transaction_queue
.current_worst_effective_priority_fee()
* 110u32
/ 100
}
fn sensible_gas_limit(&self) -> U256 {
self.params.read().gas_range_target.0 / 5
}
@ -1159,7 +1181,7 @@ impl miner::MinerService for Miner {
ordering: miner::PendingOrdering,
) -> Vec<Arc<VerifiedTransaction>>
where
C: ChainInfo + Nonce + Sync,
C: BlockChain + Nonce + Sync,
{
let chain_info = chain.chain_info();
@ -1176,6 +1198,10 @@ impl miner::MinerService for Miner {
nonce_cap,
max_len,
ordering,
includable_boundary: self
.engine
.calculate_base_fee(&chain.best_block_header())
.unwrap_or_default(),
};
if let Some(ref f) = filter {
@ -1281,6 +1307,7 @@ impl miner::MinerService for Miner {
logs: receipt.logs.clone(),
log_bloom: receipt.log_bloom,
outcome: receipt.outcome.clone(),
effective_gas_price: tx.effective_gas_price(pending.header.base_fee()),
}
})
.collect()
@ -1354,7 +1381,7 @@ impl miner::MinerService for Miner {
}
fn is_currently_sealing(&self) -> bool {
self.sealing.lock().enabled
self.sealing.lock().enabled && self.engine.is_allowed_to_seal()
}
fn work_package<C>(&self, chain: &C) -> Option<(H256, BlockNumber, u64, U256)>
@ -1432,8 +1459,21 @@ impl miner::MinerService for Miner {
}
// t_nb 10.1 First update gas limit in transaction queue and minimal gas price.
let gas_limit = *chain.best_block_header().gas_limit();
self.update_transaction_queue_limits(gas_limit);
let base_fee = self.engine.calculate_base_fee(&chain.best_block_header());
let gas_limit = chain.best_block_header().gas_limit()
// multiplication neccesary only if OE nodes are the only miners in network, not really essential but wont hurt
* if self.engine.gas_limit_override(&chain.best_block_header()).is_none() {
self
.engine
.schedule(chain.best_block_header().number() + 1)
.eip1559_gas_limit_bump
} else {
1
};
let allow_non_eoa_sender = self
.engine
.allow_non_eoa_sender(chain.best_block_header().number() + 1);
self.update_transaction_queue_limits(gas_limit, base_fee, allow_non_eoa_sender);
// t_nb 10.2 Then import all transactions from retracted blocks (retracted means from side chain).
let client = self.pool_client(chain);
@ -1575,7 +1615,9 @@ mod tests {
use client::{ChainInfo, EachBlockWith, ImportSealedBlock, TestBlockChainClient};
use miner::{MinerService, PendingOrdering};
use test_helpers::{generate_dummy_client, generate_dummy_client_with_spec};
use test_helpers::{
dummy_engine_signer_with_address, generate_dummy_client, generate_dummy_client_with_spec,
};
use types::transaction::{Transaction, TypedTransaction};
#[test]
@ -1632,8 +1674,10 @@ mod tests {
pool_verification_options: pool::verifier::Options {
minimal_gas_price: 0.into(),
block_gas_limit: U256::max_value(),
block_base_fee: None,
tx_gas_limit: U256::max_value(),
no_early_reject: false,
allow_non_eoa_sender: false,
},
},
GasPricer::new_fixed(0u64.into()),
@ -1779,6 +1823,40 @@ mod tests {
);
}
#[test]
fn should_activate_eip_3607_according_to_spec() {
// given
let spec = Spec::new_test_eip3607();
let miner = Miner::new_for_tests(&spec, None);
let client = TestBlockChainClient::new_with_spec(spec);
let imported = [H256::zero()];
let empty = &[];
// the client best block is below EIP-3607 transition number
miner.chain_new_blocks(&client, &imported, empty, &imported, empty, false);
assert!(
miner.queue_status().options.allow_non_eoa_sender,
"The client best block is below EIP-3607 transition number. Non EOA senders should be allowed"
);
// the client best block equals EIP-3607 transition number
client.add_block(EachBlockWith::Nothing, |header| header);
miner.chain_new_blocks(&client, &imported, empty, &imported, empty, false);
assert!(
!miner.queue_status().options.allow_non_eoa_sender,
"The client best block equals EIP-3607 transition number. Non EOA senders should not be allowed"
);
// the client best block is above EIP-3607 transition number
client.add_block(EachBlockWith::Nothing, |header| header);
miner.chain_new_blocks(&client, &imported, empty, &imported, empty, false);
assert!(
!miner.queue_status().options.allow_non_eoa_sender,
"The client best block is above EIP-3607 transition number. Non EOA senders should not be allowed"
);
}
#[test]
fn should_treat_unfamiliar_locals_selectively() {
// given
@ -2044,6 +2122,31 @@ mod tests {
assert!(miner.is_currently_sealing());
}
#[test]
fn should_not_mine_if_is_not_allowed_to_seal() {
let spec = Spec::new_test_round();
let miner = Miner::new_for_tests_force_sealing(&spec, None, true);
assert!(!miner.is_currently_sealing());
}
#[test]
fn should_mine_if_is_allowed_to_seal() {
let verifier: Address = [
0x7d, 0x57, 0x7a, 0x59, 0x7b, 0x27, 0x42, 0xb4, 0x98, 0xcb, 0x5c, 0xf0, 0xc2, 0x6c,
0xdc, 0xd7, 0x26, 0xd3, 0x9e, 0x6e,
]
.into();
let spec = Spec::new_test_round();
let client: Arc<dyn EngineClient> = generate_dummy_client(2);
let miner = Miner::new_for_tests_force_sealing(&spec, None, true);
miner.engine.register_client(Arc::downgrade(&client));
miner.set_author(Author::Sealer(dummy_engine_signer_with_address(verifier)));
assert!(miner.is_currently_sealing());
}
#[test]
fn should_set_new_minimum_gas_price() {
// Creates a new GasPricer::Fixed behind the scenes

View File

@ -226,7 +226,7 @@ pub trait MinerService: Send + Sync {
ordering: PendingOrdering,
) -> Vec<Arc<VerifiedTransaction>>
where
C: ChainInfo + Nonce + Sync;
C: BlockChain + Nonce + Sync;
/// Get an unfiltered list of all ready transactions.
fn ready_transactions<C>(
@ -236,7 +236,7 @@ pub trait MinerService: Send + Sync {
ordering: PendingOrdering,
) -> Vec<Arc<VerifiedTransaction>>
where
C: ChainInfo + Nonce + Sync,
C: BlockChain + Nonce + Sync,
{
self.ready_transactions_filtered(chain, max_len, None, ordering)
}
@ -260,6 +260,9 @@ pub trait MinerService: Send + Sync {
/// Suggested gas price.
fn sensible_gas_price(&self) -> U256;
/// Suggested max priority fee gas price
fn sensible_max_priority_fee(&self) -> U256;
/// Suggested gas limit.
fn sensible_gas_limit(&self) -> U256;

View File

@ -30,7 +30,7 @@ use types::{
};
use call_contract::CallContract;
use client::{BlockInfo, Nonce, TransactionId};
use client::{BlockId, BlockInfo, Nonce, TransactionId};
use engines::EthEngine;
use miner;
use transaction_ext::Transaction;
@ -155,9 +155,8 @@ where
) -> Result<SignedTransaction, transaction::Error> {
self.engine
.verify_transaction_basic(&tx, &self.best_block_header)?;
let tx = self
.engine
.verify_transaction_unordered(tx, &self.best_block_header)?;
let tx = SignedTransaction::new(tx)?;
self.engine
.machine()
@ -169,6 +168,7 @@ where
pool::client::AccountDetails {
nonce: self.cached_nonces.account_nonce(address),
balance: self.chain.latest_balance(address),
code_hash: self.chain.code_hash(address, BlockId::Latest),
is_local: self.accounts.is_local(address),
}
}

View File

@ -17,15 +17,17 @@
//! Block RLP compression.
use bytes::Bytes;
use ethereum_types::H256;
use ethereum_types::{H256, U256};
use hash::keccak;
use rlp::{DecoderError, Rlp, RlpStream};
use triehash::ordered_trie_root;
use types::{block::Block, header::Header, transaction::TypedTransaction, views::BlockView};
use types::{
block::Block, header::Header, transaction::TypedTransaction, views::BlockView, BlockNumber,
};
const HEADER_FIELDS: usize = 8;
const BLOCK_FIELDS: usize = 2;
#[derive(Debug)]
pub struct AbridgedBlock {
rlp: Bytes,
}
@ -43,12 +45,19 @@ impl AbridgedBlock {
/// Given a full block view, trim out the parent hash and block number,
/// producing new rlp.
pub fn from_block_view(block_view: &BlockView) -> Self {
pub fn from_block_view(block_view: &BlockView, eip1559_transition: BlockNumber) -> Self {
let header = block_view.header_view();
let seal_fields = header.seal();
let eip1559 = header.number() >= eip1559_transition;
let seal_fields = header.seal(eip1559);
let nmb_of_elements = if eip1559 {
HEADER_FIELDS + seal_fields.len() + BLOCK_FIELDS + 1
} else {
HEADER_FIELDS + seal_fields.len() + BLOCK_FIELDS
};
// 10 header fields, unknown number of seal fields, and 2 block fields.
let mut stream = RlpStream::new_list(HEADER_FIELDS + seal_fields.len() + BLOCK_FIELDS);
let mut stream = RlpStream::new_list(nmb_of_elements);
// write header values.
stream
@ -64,13 +73,17 @@ impl AbridgedBlock {
// write block values.
TypedTransaction::rlp_append_list(&mut stream, &block_view.transactions());
stream.append_list(&block_view.uncles());
stream.append_list(&block_view.uncles(eip1559_transition));
// write seal fields.
for field in seal_fields {
stream.append_raw(&field, 1);
}
if eip1559 {
stream.append(&header.base_fee());
}
AbridgedBlock { rlp: stream.out() }
}
@ -82,6 +95,7 @@ impl AbridgedBlock {
parent_hash: H256,
number: u64,
receipts_root: H256,
eip1559_transition: BlockNumber,
) -> Result<Block, DecoderError> {
let rlp = Rlp::new(&self.rlp);
@ -98,7 +112,7 @@ impl AbridgedBlock {
header.set_extra_data(rlp.val_at(7)?);
let transactions = TypedTransaction::decode_rlp_list(&rlp.at(8)?)?;
let uncles: Vec<Header> = rlp.list_at(9)?;
let uncles = Header::decode_rlp_list(&rlp.at(9)?, eip1559_transition)?;
header.set_transactions_root(ordered_trie_root(rlp.at(8)?.iter().map(|r| {
if r.is_list() {
@ -115,13 +129,21 @@ impl AbridgedBlock {
header.set_uncles_hash(keccak(uncles_rlp.as_raw()));
let mut seal_fields = Vec::new();
for i in (HEADER_FIELDS + BLOCK_FIELDS)..rlp.item_count()? {
let last_seal_index = if number >= eip1559_transition {
rlp.item_count()? - 1
} else {
rlp.item_count()?
};
for i in (HEADER_FIELDS + BLOCK_FIELDS)..last_seal_index {
let seal_rlp = rlp.at(i)?;
seal_fields.push(seal_rlp.as_raw().to_owned());
}
header.set_seal(seal_fields);
if number >= eip1559_transition {
header.set_base_fee(Some(rlp.val_at::<U256>(rlp.item_count()? - 1)?));
}
Ok(Block {
header: header,
transactions: transactions,
@ -141,6 +163,7 @@ mod tests {
transaction::{Action, Transaction, TypedTransaction},
view,
views::BlockView,
BlockNumber,
};
fn encode_block(b: &Block) -> Bytes {
@ -153,10 +176,29 @@ mod tests {
let receipts_root = b.header.receipts_root().clone();
let encoded = encode_block(&b);
let abridged = AbridgedBlock::from_block_view(&view!(BlockView, &encoded));
let abridged =
AbridgedBlock::from_block_view(&view!(BlockView, &encoded), BlockNumber::max_value());
assert_eq!(
abridged
.to_block(H256::default(), 0, receipts_root)
.to_block(H256::default(), 0, receipts_root, BlockNumber::max_value())
.unwrap(),
b
);
}
#[test]
fn eip1559_block_abridging() {
let mut b = Block::default();
b.header.set_base_fee(Some(U256::from(100)));
b.header.set_seal(vec![vec![50u8], vec![60u8]]);
let receipts_root = b.header.receipts_root().clone();
let encoded = encode_block(&b);
let abridged =
AbridgedBlock::from_block_view(&view!(BlockView, &encoded), BlockNumber::default());
assert_eq!(
abridged
.to_block(H256::default(), 0, receipts_root, BlockNumber::default())
.unwrap(),
b
);
@ -169,10 +211,11 @@ mod tests {
let receipts_root = b.header.receipts_root().clone();
let encoded = encode_block(&b);
let abridged = AbridgedBlock::from_block_view(&view!(BlockView, &encoded));
let abridged =
AbridgedBlock::from_block_view(&view!(BlockView, &encoded), BlockNumber::max_value());
assert_eq!(
abridged
.to_block(H256::default(), 2, receipts_root)
.to_block(H256::default(), 2, receipts_root, BlockNumber::max_value())
.unwrap(),
b
);
@ -213,10 +256,13 @@ mod tests {
let encoded = encode_block(&b);
let abridged = AbridgedBlock::from_block_view(&view!(BlockView, &encoded[..]));
let abridged = AbridgedBlock::from_block_view(
&view!(BlockView, &encoded[..]),
BlockNumber::max_value(),
);
assert_eq!(
abridged
.to_block(H256::default(), 0, receipts_root)
.to_block(H256::default(), 0, receipts_root, BlockNumber::max_value())
.unwrap(),
b
);

View File

@ -38,6 +38,7 @@ use itertools::{Itertools, Position};
use rlp::{Rlp, RlpStream};
use types::{
encoded, header::Header, ids::BlockId, receipt::TypedReceipt, transaction::TypedTransaction,
BlockNumber,
};
/// Snapshot creation and restoration for PoA chains.
@ -61,6 +62,7 @@ impl SnapshotComponents for PoaSnapshot {
sink: &mut ChunkSink,
_progress: &Progress,
preferred_size: usize,
eip1559_transition: BlockNumber,
) -> Result<(), Error> {
let number = chain
.block_number(&block_at)
@ -107,7 +109,7 @@ impl SnapshotComponents for PoaSnapshot {
.block(&block_at)
.and_then(|b| chain.block_receipts(&block_at).map(|r| (b, r)))
.ok_or_else(|| Error::BlockNotFound(block_at))?;
let block = block.decode()?;
let block = block.decode(eip1559_transition)?;
let parent_td = chain
.block_details(block.header.parent_hash())
@ -200,7 +202,8 @@ impl ChunkRebuilder {
use engines::ConstructedVerifier;
// decode.
let header: Header = transition_rlp.val_at(0)?;
let header =
Header::decode_rlp(&transition_rlp.at(0)?, engine.params().eip1559_transition)?;
let epoch_data: Bytes = transition_rlp.val_at(1)?;
trace!(target: "snapshot", "verifying transition to epoch at block {}", header.number());
@ -350,9 +353,12 @@ impl Rebuilder for ChunkRebuilder {
let last_rlp = rlp.at(num_items - 1)?;
let block = Block {
header: last_rlp.val_at(0)?,
header: Header::decode_rlp(&last_rlp.at(0)?, engine.params().eip1559_transition)?,
transactions: TypedTransaction::decode_rlp_list(&last_rlp.at(1)?)?,
uncles: last_rlp.list_at(2)?,
uncles: Header::decode_rlp_list(
&last_rlp.at(2)?,
engine.params().eip1559_transition,
)?,
};
let block_data = block.rlp_bytes();
let receipts = TypedReceipt::decode_rlp_list(&last_rlp.at(3)?)?;

View File

@ -22,6 +22,7 @@ use std::sync::{atomic::AtomicBool, Arc};
use blockchain::{BlockChain, BlockChainDB};
use engines::EthEngine;
use snapshot::{Error, ManifestData, Progress};
use types::BlockNumber;
use ethereum_types::H256;
@ -49,6 +50,7 @@ pub trait SnapshotComponents: Send {
chunk_sink: &mut ChunkSink,
progress: &Progress,
preferred_size: usize,
eip1559_transition: BlockNumber,
) -> Result<(), Error>;
/// Create a rebuilder, which will have chunks fed into it in aribtrary

View File

@ -38,7 +38,7 @@ use ethereum_types::H256;
use rand::rngs::OsRng;
use rlp::{Rlp, RlpStream};
use snapshot::{block::AbridgedBlock, Error, ManifestData, Progress};
use types::encoded;
use types::{encoded, BlockNumber};
/// Snapshot creation and restoration for PoW chains.
/// This includes blocks from the head of the chain as a
@ -70,6 +70,7 @@ impl SnapshotComponents for PowSnapshot {
chunk_sink: &mut ChunkSink,
progress: &Progress,
preferred_size: usize,
eip1559_transition: BlockNumber,
) -> Result<(), Error> {
PowWorker {
chain: chain,
@ -79,7 +80,7 @@ impl SnapshotComponents for PowSnapshot {
progress: progress,
preferred_size: preferred_size,
}
.chunk_all(self.blocks)
.chunk_all(self.blocks, eip1559_transition)
}
fn rebuilder(
@ -119,7 +120,11 @@ struct PowWorker<'a> {
impl<'a> PowWorker<'a> {
// Repeatedly fill the buffers and writes out chunks, moving backwards from starting block hash.
// Loops until we reach the first desired block, and writes out the remainder.
fn chunk_all(&mut self, snapshot_blocks: u64) -> Result<(), Error> {
fn chunk_all(
&mut self,
snapshot_blocks: u64,
eip1559_transition: BlockNumber,
) -> Result<(), Error> {
let mut loaded_size = 0;
let mut last = self.current_hash;
@ -140,7 +145,8 @@ impl<'a> PowWorker<'a> {
})
.ok_or_else(|| Error::BlockNotFound(self.current_hash))?;
let abridged_rlp = AbridgedBlock::from_block_view(&block.view()).into_inner();
let abridged_rlp =
AbridgedBlock::from_block_view(&block.view(), eip1559_transition).into_inner();
let pair = {
let mut pair_stream = RlpStream::new_list(2);
@ -301,7 +307,12 @@ impl Rebuilder for PowRebuilder {
}
}));
let block = abridged_block.to_block(parent_hash, cur_number, receipts_root)?;
let block = abridged_block.to_block(
parent_hash,
cur_number,
receipts_root,
engine.params().eip1559_transition,
)?;
let block_bytes = encoded::Block::new(block.rlp_bytes());
let is_best = cur_number == self.best_number;

View File

@ -273,6 +273,7 @@ pub fn chunk_secondary<'a>(
&mut chunk_sink,
progress,
PREFERRED_CHUNK_SIZE,
chain.eip1559_transition,
)?;
}
@ -621,7 +622,8 @@ pub fn verify_old_block(
if always || rng.gen::<f32>() <= POW_VERIFY_RATE {
engine.verify_block_unordered(header)?;
match chain.block_header_data(header.parent_hash()) {
Some(parent) => engine.verify_block_family(header, &parent.decode()?),
Some(parent) => engine
.verify_block_family(header, &parent.decode(engine.params().eip1559_transition)?),
None => Ok(()),
}
} else {

View File

@ -117,7 +117,12 @@ impl Restoration {
let raw_db = params.db;
let chain = BlockChain::new(Default::default(), params.genesis, raw_db.clone());
let chain = BlockChain::new(
Default::default(),
params.genesis,
raw_db.clone(),
params.engine.params().eip1559_transition,
);
let components = params
.engine
.snapshot_components()
@ -386,7 +391,12 @@ impl Service {
let cur_chain_info = self.client.chain_info();
let next_db = self.restoration_db_handler.open(&rest_db)?;
let next_chain = BlockChain::new(Default::default(), &[], next_db.clone());
let next_chain = BlockChain::new(
Default::default(),
&[],
next_db.clone(),
self.engine.params().eip1559_transition,
);
let next_chain_info = next_chain.chain_info();
// The old database looks like this:

View File

@ -171,7 +171,12 @@ pub fn restore(
let mut state = StateRebuilder::new(db.key_value().clone(), journaldb::Algorithm::Archive);
let mut secondary = {
let chain = BlockChain::new(Default::default(), genesis, db.clone());
let chain = BlockChain::new(
Default::default(),
genesis,
db.clone(),
engine.params().eip1559_transition,
);
components.rebuilder(chain, db, manifest).unwrap()
};

View File

@ -51,7 +51,12 @@ fn chunk_and_restore(amount: u64) {
let snapshot_path = tempdir.path().join("SNAP");
let old_db = test_helpers::new_db();
let bc = BlockChain::new(Default::default(), genesis.encoded().raw(), old_db.clone());
let bc = BlockChain::new(
Default::default(),
genesis.encoded().raw(),
old_db.clone(),
engine.params().eip1559_transition,
);
// build the blockchain.
let mut batch = DBTransaction::new();
@ -96,7 +101,12 @@ fn chunk_and_restore(amount: u64) {
// restore it.
let new_db = test_helpers::new_db();
let new_chain = BlockChain::new(Default::default(), genesis.encoded().raw(), new_db.clone());
let new_chain = BlockChain::new(
Default::default(),
genesis.encoded().raw(),
new_db.clone(),
engine.params().eip1559_transition,
);
let mut rebuilder = SNAPSHOT_MODE
.rebuilder(new_chain, new_db.clone(), &manifest)
.unwrap();
@ -113,7 +123,12 @@ fn chunk_and_restore(amount: u64) {
drop(rebuilder);
// and test it.
let new_chain = BlockChain::new(Default::default(), genesis.encoded().raw(), new_db);
let new_chain = BlockChain::new(
Default::default(),
genesis.encoded().raw(),
new_db,
engine.params().eip1559_transition,
);
assert_eq!(new_chain.best_block_hash(), best_hash);
}
@ -150,6 +165,7 @@ fn checks_flag() {
Default::default(),
genesis.last().encoded().raw(),
db.clone(),
engine.params().eip1559_transition,
);
let manifest = ::snapshot::ManifestData {

View File

@ -240,7 +240,9 @@ fn keep_ancient_blocks() {
let block_hash = bc.block_hash(block_number).unwrap();
let block = bc.block(&block_hash).unwrap();
client2
.import_block(Unverified::from_rlp(block.into_inner()).unwrap())
.import_block(
Unverified::from_rlp(block.into_inner(), spec.params().eip1559_transition).unwrap(),
)
.unwrap();
}

View File

@ -43,6 +43,8 @@ pub struct Genesis {
pub gas_used: U256,
/// Extra data.
pub extra_data: Vec<u8>,
/// Base fee.
pub base_fee: Option<U256>,
}
impl From<ethjson::spec::Genesis> for Genesis {
@ -63,6 +65,7 @@ impl From<ethjson::spec::Genesis> for Genesis {
state_root: g.state_root.map(Into::into),
gas_used: g.gas_used.map_or_else(U256::zero, Into::into),
extra_data: g.extra_data.map_or_else(Vec::new, Into::into),
base_fee: g.base_fee_per_gas.map(Into::into),
}
}
}

View File

@ -139,6 +139,16 @@ pub struct CommonParams {
pub eip2929_transition: BlockNumber,
/// Number of first block where EIP-2930 rules begin.
pub eip2930_transition: BlockNumber,
/// Number of first block where EIP-1559 rules begin.
pub eip1559_transition: BlockNumber,
/// Number of first block where EIP-3198 rules begin. Basefee opcode.
pub eip3198_transition: BlockNumber,
/// Number of first block where EIP-3529 rules begin.
pub eip3529_transition: BlockNumber,
/// Number of first block where EIP-3541 rule begins.
pub eip3541_transition: BlockNumber,
/// Number of first block where EIP-3607 rule begins.
pub eip3607_transition: BlockNumber,
/// Number of first block where dust cleanup rules (EIP-168 and EIP169) begin.
pub dust_protection_transition: BlockNumber,
/// Nonce cap increase per block. Nonce cap is only checked if dust protection is enabled.
@ -169,6 +179,22 @@ pub struct CommonParams {
pub transaction_permission_contract_transition: BlockNumber,
/// Maximum size of transaction's RLP payload
pub max_transaction_size: usize,
/// Base fee max change denominator
pub eip1559_base_fee_max_change_denominator: Option<U256>,
/// Elasticity multiplier
pub eip1559_elasticity_multiplier: U256,
/// Default value for the block base fee
pub eip1559_base_fee_initial_value: U256,
/// Min value for the block base fee.
pub eip1559_base_fee_min_value: Option<U256>,
/// Block at which the min value for the base fee starts to be used.
pub eip1559_base_fee_min_value_transition: BlockNumber,
/// Address where EIP-1559 burnt fee will be accrued to.
pub eip1559_fee_collector: Option<Address>,
/// Block at which the fee collector should start being used.
pub eip1559_fee_collector_transition: BlockNumber,
/// Block at which zero gas price transactions start being checked with Certifier contract.
pub validate_service_transactions_transition: BlockNumber,
}
impl CommonParams {
@ -215,6 +241,18 @@ impl CommonParams {
schedule.have_subs = block_number >= self.eip2315_transition;
schedule.eip2929 = block_number >= self.eip2929_transition;
schedule.eip2930 = block_number >= self.eip2930_transition;
schedule.eip3541 = block_number >= self.eip3541_transition;
schedule.eip1559 = block_number >= self.eip1559_transition;
schedule.eip3198 = block_number >= self.eip3198_transition;
if schedule.eip1559 {
schedule.eip1559_elasticity_multiplier = self.eip1559_elasticity_multiplier.as_usize();
schedule.eip1559_gas_limit_bump = if block_number == self.eip1559_transition {
schedule.eip1559_elasticity_multiplier
} else {
1
};
}
if block_number >= self.eip1884_transition {
schedule.have_selfbalance = true;
@ -245,6 +283,11 @@ impl CommonParams {
schedule.sload_gas = ::vm::schedule::EIP2929_WARM_STORAGE_READ_COST;
schedule.sstore_reset_gas = ::vm::schedule::EIP2929_SSTORE_RESET_GAS;
}
if block_number >= self.eip3529_transition {
schedule.suicide_refund_gas = 0;
schedule.sstore_refund_gas = ::vm::schedule::EIP3529_SSTORE_CLEARS_SCHEDULE;
schedule.max_refund_quotient = ::vm::schedule::EIP3529_MAX_REFUND_QUOTIENT;
}
if block_number >= self.dust_protection_transition {
schedule.kill_dust = match self.remove_dust_contracts {
@ -378,9 +421,22 @@ impl From<ethjson::spec::Params> for CommonParams {
eip2930_transition: p
.eip2930_transition
.map_or_else(BlockNumber::max_value, Into::into),
eip1559_transition: p
.eip1559_transition
.map_or_else(BlockNumber::max_value, Into::into),
eip3198_transition: p
.eip3198_transition
.map_or_else(BlockNumber::max_value, Into::into),
eip3529_transition: p
.eip3529_transition
.map_or_else(BlockNumber::max_value, Into::into),
eip3541_transition: p
.eip3541_transition
.map_or_else(BlockNumber::max_value, Into::into),
dust_protection_transition: p
.dust_protection_transition
.map_or_else(BlockNumber::max_value, Into::into),
eip3607_transition: p.eip3607_transition.map_or(0, Into::into),
nonce_cap_increment: p.nonce_cap_increment.map_or(64, Into::into),
remove_dust_contracts: p.remove_dust_contracts.unwrap_or(false),
gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(),
@ -407,6 +463,26 @@ impl From<ethjson::spec::Params> for CommonParams {
kip6_transition: p
.kip6_transition
.map_or_else(BlockNumber::max_value, Into::into),
eip1559_base_fee_max_change_denominator: p
.eip1559_base_fee_max_change_denominator
.map(Into::into),
eip1559_elasticity_multiplier: p
.eip1559_elasticity_multiplier
.map_or_else(U256::zero, Into::into),
eip1559_base_fee_initial_value: p
.eip1559_base_fee_initial_value
.map_or_else(U256::zero, Into::into),
eip1559_base_fee_min_value: p.eip1559_base_fee_min_value.map(Into::into),
eip1559_base_fee_min_value_transition: p
.eip1559_base_fee_min_value_transition
.map_or_else(BlockNumber::max_value, Into::into),
eip1559_fee_collector: p.eip1559_fee_collector.map(Into::into),
eip1559_fee_collector_transition: p
.eip1559_fee_collector_transition
.map_or_else(BlockNumber::max_value, Into::into),
validate_service_transactions_transition: p
.validate_service_transactions_transition
.map_or_else(BlockNumber::max_value, Into::into),
}
}
}
@ -481,6 +557,8 @@ pub struct Spec {
pub extra_data: Bytes,
/// Each seal field, expressed as RLP, concatenated.
pub seal_rlp: Bytes,
/// Base fee,
pub base_fee: Option<U256>,
/// List of hard forks in the network.
pub hard_forks: BTreeSet<BlockNumber>,
@ -517,6 +595,7 @@ impl Clone for Spec {
constructors: self.constructors.clone(),
state_root_memo: RwLock::new(*self.state_root_memo.read()),
genesis_state: self.genesis_state.clone(),
base_fee: self.base_fee.clone(),
}
}
}
@ -575,6 +654,7 @@ fn load_from(spec_params: SpecParams, s: ethjson::spec::Spec) -> Result<Spec, Er
timestamp: g.timestamp,
extra_data: g.extra_data,
seal_rlp: seal_rlp,
base_fee: g.base_fee,
hard_forks,
constructors: s
.accounts
@ -667,6 +747,10 @@ impl Spec {
params.eip2315_transition,
params.eip2929_transition,
params.eip2930_transition,
params.eip1559_transition,
params.eip3198_transition,
params.eip3529_transition,
params.eip3541_transition,
params.dust_protection_transition,
params.wasm_activation_transition,
params.wasm_disable_transition,
@ -674,6 +758,9 @@ impl Spec {
params.kip6_transition,
params.max_code_size_transition,
params.transaction_permission_contract_transition,
params.eip1559_fee_collector_transition,
params.eip1559_base_fee_min_value_transition,
params.validate_service_transactions_transition,
];
// BUG: Rinkeby has homestead transition at block 1 but we can't reflect that in specs for non-Ethash networks
if params.network_id == 0x4 {
@ -771,6 +858,7 @@ impl Spec {
last_hashes: Default::default(),
gas_used: U256::zero(),
gas_limit: U256::max_value(),
base_fee: None,
};
if !self.constructors.is_empty() {
@ -879,6 +967,7 @@ impl Spec {
let r = Rlp::new(&self.seal_rlp);
r.iter().map(|f| f.as_raw().to_vec()).collect()
});
header.set_base_fee(self.base_fee.clone());
trace!(target: "spec", "Header hash is {}", header.hash());
header
}
@ -907,6 +996,7 @@ impl Spec {
self.timestamp = g.timestamp;
self.extra_data = g.extra_data;
self.seal_rlp = seal_rlp;
self.base_fee = g.base_fee;
}
/// Alter the value of the genesis state.
@ -990,6 +1080,7 @@ impl Spec {
gas_limit: U256::max_value(),
last_hashes: Arc::new(Vec::new()),
gas_used: 0.into(),
base_fee: genesis.base_fee(),
};
let from = Address::default();
@ -1063,6 +1154,13 @@ impl Spec {
load_bundled!("test/constructor")
}
/// Create a new Spec which is a NullEngine consensus with EIP3607 transition equal to 2,
/// and with a contract at address '0x71562b71999873DB5b286dF957af199Ec94617F7'.
#[cfg(any(test, feature = "test-helpers"))]
pub fn new_test_eip3607() -> Self {
load_bundled!("test/eip3607_test")
}
/// Create a new Spec with Autority Round randomness contract
#[cfg(any(test, feature = "test-helpers"))]
pub fn new_test_round_randomness_contract() -> Spec {

View File

@ -39,12 +39,15 @@ use types::{
transaction::{Action, SignedTransaction, Transaction, TypedTransaction},
view,
views::BlockView,
BlockNumber,
};
use block::{Drain, OpenBlock};
use client::{
ChainInfo, ChainMessageType, ChainNotify, Client, ClientConfig, ImportBlock, PrepareOpenBlock,
};
use engines::EngineSigner;
use ethjson::crypto::publickey::{Public, Signature};
use factory::Factories;
use miner::Miner;
use spec::Spec;
@ -222,14 +225,17 @@ where
.seal(test_engine, vec![])
.unwrap();
if let Err(e) = client.import_block(Unverified::from_rlp(b.rlp_bytes()).unwrap()) {
if let Err(e) = client.import_block(
Unverified::from_rlp(b.rlp_bytes(), test_engine.params().eip1559_transition).unwrap(),
) {
panic!(
"error importing block which is valid by definition: {:?}",
e
);
}
last_header = view!(BlockView, &b.rlp_bytes()).header();
last_header =
view!(BlockView, &b.rlp_bytes()).header(test_engine.params().eip1559_transition);
db = b.drain().state.drop().1;
}
client.flush_queue();
@ -266,9 +272,13 @@ pub fn push_blocks_to_client(
rolling_block_number = rolling_block_number + 1;
rolling_timestamp = rolling_timestamp + 10;
if let Err(e) =
client.import_block(Unverified::from_rlp(create_test_block(&header)).unwrap())
{
if let Err(e) = client.import_block(
Unverified::from_rlp(
create_test_block(&header),
test_spec.params().eip1559_transition,
)
.unwrap(),
) {
panic!(
"error importing block which is valid by definition: {:?}",
e
@ -297,7 +307,9 @@ pub fn push_block_with_transactions(client: &Arc<Client>, transactions: &[Signed
.seal(test_engine, vec![])
.unwrap();
if let Err(e) = client.import_block(Unverified::from_rlp(b.rlp_bytes()).unwrap()) {
if let Err(e) = client.import_block(
Unverified::from_rlp(b.rlp_bytes(), test_spec.params().eip1559_transition).unwrap(),
) {
panic!(
"error importing block which is valid by definition: {:?}",
e
@ -323,7 +335,9 @@ pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> Arc<Client> {
.unwrap();
for block in blocks {
if let Err(e) = client.import_block(Unverified::from_rlp(block).unwrap()) {
if let Err(e) = client.import_block(
Unverified::from_rlp(block, test_spec.params().eip1559_transition).unwrap(),
) {
panic!("error importing block which is well-formed: {:?}", e);
}
}
@ -456,6 +470,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain {
BlockChainConfig::default(),
&create_unverifiable_block(0, H256::zero()),
db.clone(),
BlockNumber::max_value(),
);
let mut batch = db.key_value().transaction();
@ -483,6 +498,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain {
BlockChainConfig::default(),
&create_unverifiable_block(0, H256::zero()),
db.clone(),
BlockNumber::max_value(),
);
let mut batch = db.key_value().transaction();
@ -514,6 +530,7 @@ pub fn generate_dummy_empty_blockchain() -> BlockChain {
BlockChainConfig::default(),
&create_unverifiable_block(0, H256::zero()),
db.clone(),
BlockNumber::max_value(),
);
bc
}
@ -629,3 +646,38 @@ impl ChainNotify for TestNotify {
self.messages.write().push(data);
}
}
/// Returns engine signer with specified address
pub fn dummy_engine_signer_with_address(addr: Address) -> Box<dyn EngineSigner> {
struct TestEngineSigner(Address);
impl TestEngineSigner {
fn with_address(addr: Address) -> Self {
Self(addr)
}
}
impl EngineSigner for TestEngineSigner {
fn sign(&self, _hash: H256) -> Result<Signature, ethjson::crypto::publickey::Error> {
unimplemented!()
}
fn address(&self) -> Address {
self.0
}
fn decrypt(
&self,
_auth_data: &[u8],
_cipher: &[u8],
) -> Result<Vec<u8>, parity_crypto::publickey::Error> {
unimplemented!()
}
fn public(&self) -> Option<Public> {
unimplemented!()
}
}
Box::new(TestEngineSigner::with_address(addr))
}

View File

@ -104,7 +104,7 @@ fn imports_good_block() {
.unwrap();
let good_block = get_good_dummy_block();
if client
.import_block(Unverified::from_rlp(good_block).unwrap())
.import_block(Unverified::from_rlp(good_block, spec.params().eip1559_transition).unwrap())
.is_err()
{
panic!("error importing block being good by definition");
@ -147,7 +147,12 @@ fn returns_chain_info() {
let client = get_test_client_with_blocks(vec![dummy_block.clone()]);
let block = view!(BlockView, &dummy_block);
let info = client.chain_info();
assert_eq!(info.best_block_hash, block.header().hash());
assert_eq!(
info.best_block_hash,
block
.header(client.engine().params().eip1559_transition)
.hash()
);
}
#[test]
@ -188,7 +193,11 @@ fn returns_block_body() {
let client = get_test_client_with_blocks(vec![dummy_block.clone()]);
let block = view!(BlockView, &dummy_block);
let body = client
.block_body(BlockId::Hash(block.header().hash()))
.block_body(BlockId::Hash(
block
.header(client.engine().params().eip1559_transition)
.hash(),
))
.unwrap();
let body = body.rlp();
assert_eq!(body.item_count().unwrap(), 2);
@ -582,3 +591,12 @@ fn import_export_binary() {
assert!(client.block_header(BlockId::Number(17)).is_some());
assert!(client.block_header(BlockId::Number(16)).is_some());
}
#[test]
fn returns_state_root_basic() {
let client = generate_dummy_client(6);
let test_spec = Spec::new_test();
let genesis_header = test_spec.genesis_header();
assert!(client.state_data(genesis_header.state_root()).is_some());
}

View File

@ -100,14 +100,17 @@ fn can_trace_block_and_uncle_reward() {
.seal(engine, vec![])
.unwrap();
if let Err(e) = client.import_block(Unverified::from_rlp(root_block.rlp_bytes()).unwrap()) {
if let Err(e) = client.import_block(
Unverified::from_rlp(root_block.rlp_bytes(), spec.params().eip1559_transition).unwrap(),
) {
panic!(
"error importing block which is valid by definition: {:?}",
e
);
}
last_header = view!(BlockView, &root_block.rlp_bytes()).header();
last_header =
view!(BlockView, &root_block.rlp_bytes()).header(spec.params().eip1559_transition);
let root_header = last_header.clone();
db = root_block.drain().state.drop().1;
@ -137,14 +140,17 @@ fn can_trace_block_and_uncle_reward() {
.seal(engine, vec![])
.unwrap();
if let Err(e) = client.import_block(Unverified::from_rlp(parent_block.rlp_bytes()).unwrap()) {
if let Err(e) = client.import_block(
Unverified::from_rlp(parent_block.rlp_bytes(), spec.params().eip1559_transition).unwrap(),
) {
panic!(
"error importing block which is valid by definition: {:?}",
e
);
}
last_header = view!(BlockView, &parent_block.rlp_bytes()).header();
last_header =
view!(BlockView, &parent_block.rlp_bytes()).header(spec.params().eip1559_transition);
db = parent_block.drain().state.drop().1;
last_hashes.push(last_header.hash());
@ -201,7 +207,9 @@ fn can_trace_block_and_uncle_reward() {
.seal(engine, vec![])
.unwrap();
let res = client.import_block(Unverified::from_rlp(block.rlp_bytes()).unwrap());
let res = client.import_block(
Unverified::from_rlp(block.rlp_bytes(), spec.params().eip1559_transition).unwrap(),
);
if res.is_err() {
panic!("error importing block: {:#?}", res.err().unwrap());
}

View File

@ -48,6 +48,8 @@ pub enum Error {
Internal,
/// When execution tries to modify the state in static context
MutableCallInStaticContext,
/// When invalid code was attempted to deploy
InvalidCode,
/// Wasm error
Wasm,
/// Contract tried to access past the return data buffer.
@ -68,6 +70,7 @@ impl<'a> From<&'a VmError> for Error {
VmError::OutOfSubStack { .. } => Error::OutOfSubStack,
VmError::InvalidSubEntry { .. } => Error::InvalidSubEntry,
VmError::BuiltIn { .. } => Error::BuiltIn,
VmError::InvalidCode => Error::InvalidCode,
VmError::Wasm { .. } => Error::Wasm,
VmError::Internal(_) => Error::Internal,
VmError::MutableCallInStaticContext => Error::MutableCallInStaticContext,
@ -96,6 +99,7 @@ impl fmt::Display for Error {
OutOfSubStack => "Subroutine stack overflow",
BuiltIn => "Built-in failed",
InvalidSubEntry => "Invalid subroutine entry",
InvalidCode => "Invalid code",
Wasm => "Wasm runtime error",
Internal => "Internal error",
MutableCallInStaticContext => "Mutable Call In Static Context",
@ -124,6 +128,7 @@ impl Encodable for Error {
SubStackUnderflow => 11,
OutOfSubStack => 12,
InvalidSubEntry => 13,
InvalidCode => 14,
};
s.append_internal(&value);
@ -149,6 +154,7 @@ impl Decodable for Error {
11 => Ok(SubStackUnderflow),
12 => Ok(OutOfSubStack),
13 => Ok(InvalidSubEntry),
14 => Ok(InvalidCode),
_ => Err(DecoderError::Custom("Invalid error type")),
}
}

View File

@ -39,6 +39,7 @@ use_contract!(
transact_acl_gas_price,
"res/contracts/tx_acl_gas_price.json"
);
use_contract!(transact_acl_1559, "res/contracts/tx_acl_1559.json");
const MAX_CACHE_SIZE: usize = 4096;
@ -104,6 +105,8 @@ impl TransactionFilter {
let sender = transaction.sender();
let value = transaction.tx().value;
let gas_price = transaction.tx().gas_price;
let max_priority_fee_per_gas = transaction.max_priority_fee_per_gas();
let gas_limit = transaction.tx().gas;
let key = (*parent_hash, sender);
if let Some(permissions) = permission_cache.get_mut(&key) {
@ -161,6 +164,25 @@ impl TransactionFilter {
(tx_permissions::NONE, true)
})
}
4 => {
trace!(target: "tx_filter", "Using filter with maxFeePerGas and maxPriorityFeePerGas and data");
let (data, decoder) = transact_acl_1559::functions::allowed_tx_types::call(
sender,
to,
value,
gas_price,
max_priority_fee_per_gas,
gas_limit,
transaction.tx().data.clone(),
);
client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)
.and_then(|value| decoder.decode(&value).map_err(|e| e.to_string()))
.map(|(p, f)| (p.low_u32(), f))
.unwrap_or_else(|e| {
error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e);
(tx_permissions::NONE, true)
})
}
_ => {
error!(target: "tx_filter", "Unknown version of tx permissions contract is used");
(tx_permissions::NONE, true)
@ -201,7 +223,9 @@ mod test {
use std::{str::FromStr, sync::Arc};
use tempdir::TempDir;
use test_helpers;
use types::transaction::{Action, Transaction, TypedTransaction};
use types::transaction::{
AccessListTx, Action, EIP1559TransactionTx, Transaction, TypedTransaction,
};
/// Contract code: https://gist.github.com/VladLupashevskyi/84f18eabb1e4afadf572cf92af3e7e7f
#[test]
@ -438,7 +462,7 @@ mod test {
));
}
/// Contract code: res/tx_permission_tests/contract_ver_3.sol
/// Contract code: res/chainspec/test/contract_ver_3.sol
#[test]
fn transaction_filter_ver_3() {
let spec_data = include_str!("../res/chainspec/test/contract_ver_3_genesis.json");
@ -506,6 +530,145 @@ mod test {
));
}
/// Contract code: res/chainspec/test/contract_ver_4.sol
#[test]
fn transaction_filter_ver_4_legacy() {
let spec_data = include_str!("../res/chainspec/test/contract_ver_4_genesis.json");
let db = test_helpers::new_db();
let tempdir = TempDir::new("").unwrap();
let spec = Spec::load(&tempdir.path(), spec_data.as_bytes()).unwrap();
let client = Client::new(
ClientConfig::default(),
&spec,
db,
Arc::new(Miner::new_for_tests(&spec, None)),
IoChannel::disconnected(),
)
.unwrap();
let key1 = KeyPair::from_secret(
Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001")
.unwrap(),
)
.unwrap();
// The only difference to version 2 is that the contract now knows the transaction's gas price and data.
// So we only test those: The contract allows only transactions with either nonzero gas price or short data.
let filter = TransactionFilter::from_params(spec.params()).unwrap();
let mut tx = TypedTransaction::Legacy(Transaction::default());
tx.tx_mut().action =
Action::Call(Address::from_str("0000000000000000000000000000000000000042").unwrap());
tx.tx_mut().data = b"01234567".to_vec();
tx.tx_mut().gas_price = 0.into();
let genesis = client.block_hash(BlockId::Latest).unwrap();
let block_number = 1;
// Data too long and gas price zero. This transaction is not allowed.
assert!(!filter.transaction_allowed(
&genesis,
block_number,
&tx.clone().sign(key1.secret(), None),
&*client
));
// But if we either set a nonzero gas price or short data or both, it is allowed.
tx.tx_mut().gas_price = 1.into();
assert!(filter.transaction_allowed(
&genesis,
block_number,
&tx.clone().sign(key1.secret(), None),
&*client
));
tx.tx_mut().data = b"01".to_vec();
assert!(filter.transaction_allowed(
&genesis,
block_number,
&tx.clone().sign(key1.secret(), None),
&*client
));
tx.tx_mut().gas_price = 0.into();
assert!(filter.transaction_allowed(
&genesis,
block_number,
&tx.clone().sign(key1.secret(), None),
&*client
));
}
/// Contract code: res/chainspec/test/contract_ver_4.sol
#[test]
fn transaction_filter_ver_4_1559() {
let spec_data = include_str!("../res/chainspec/test/contract_ver_4_genesis.json");
let db = test_helpers::new_db();
let tempdir = TempDir::new("").unwrap();
let spec = Spec::load(&tempdir.path(), spec_data.as_bytes()).unwrap();
let client = Client::new(
ClientConfig::default(),
&spec,
db,
Arc::new(Miner::new_for_tests(&spec, None)),
IoChannel::disconnected(),
)
.unwrap();
let key1 = KeyPair::from_secret(
Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001")
.unwrap(),
)
.unwrap();
// The only difference to version 2 is that the contract now knows the transaction's gas price and data.
// So we only test those: The contract allows only transactions with either nonzero gas price or short data.
let filter = TransactionFilter::from_params(spec.params()).unwrap();
let mut tx = TypedTransaction::EIP1559Transaction(EIP1559TransactionTx {
transaction: AccessListTx::new(Transaction::default(), vec![]),
max_priority_fee_per_gas: U256::from(0),
});
tx.tx_mut().action =
Action::Call(Address::from_str("0000000000000000000000000000000000000042").unwrap());
tx.tx_mut().data = b"01234567".to_vec();
tx.tx_mut().gas_price = 0.into();
let genesis = client.block_hash(BlockId::Latest).unwrap();
let block_number = 1;
// Data too long and gas price zero. This transaction is not allowed.
assert!(!filter.transaction_allowed(
&genesis,
block_number,
&tx.clone().sign(key1.secret(), None),
&*client
));
// But if we either set a nonzero gas price or short data or both, it is allowed.
tx.tx_mut().gas_price = 1.into();
assert!(filter.transaction_allowed(
&genesis,
block_number,
&tx.clone().sign(key1.secret(), None),
&*client
));
tx.tx_mut().data = b"01".to_vec();
assert!(filter.transaction_allowed(
&genesis,
block_number,
&tx.clone().sign(key1.secret(), None),
&*client
));
tx.tx_mut().gas_price = 0.into();
assert!(filter.transaction_allowed(
&genesis,
block_number,
&tx.clone().sign(key1.secret(), None),
&*client
));
}
/// Contract code: https://gist.github.com/arkpar/38a87cb50165b7e683585eec71acb05a
#[test]
fn transaction_filter_deprecated() {

View File

@ -83,6 +83,7 @@ pub mod blocks {
use types::{
header::Header,
transaction::{TypedTransaction, UnverifiedTransaction},
BlockNumber,
};
use verification::{verify_block_basic, verify_block_unordered, PreverifiedBlock};
@ -149,13 +150,16 @@ pub mod blocks {
impl Unverified {
/// Create an `Unverified` from raw bytes.
pub fn from_rlp(bytes: Bytes) -> Result<Self, ::rlp::DecoderError> {
pub fn from_rlp(
bytes: Bytes,
eip1559_transition: BlockNumber,
) -> Result<Self, ::rlp::DecoderError> {
use rlp::Rlp;
let (header, transactions, uncles) = {
let rlp = Rlp::new(&bytes);
let header = rlp.val_at(0)?;
let header = Header::decode_rlp(&rlp.at(0)?, eip1559_transition)?;
let transactions = TypedTransaction::decode_rlp_list(&rlp.at(1)?)?;
let uncles = rlp.list_at(2)?;
let uncles = Header::decode_rlp_list(&rlp.at(2)?, eip1559_transition)?;
(header, transactions, uncles)
};

View File

@ -876,7 +876,7 @@ mod tests {
use io::*;
use spec::Spec;
use test_helpers::{get_good_dummy_block, get_good_dummy_block_seq};
use types::{view, views::BlockView};
use types::{view, views::BlockView, BlockNumber};
// create a test block queue.
// auto_scaling enables verifier adjustment.
@ -897,7 +897,7 @@ mod tests {
}
fn new_unverified(bytes: Bytes) -> Unverified {
Unverified::from_rlp(bytes).expect("Should be valid rlp")
Unverified::from_rlp(bytes, BlockNumber::max_value()).expect("Should be valid rlp")
}
#[test]
@ -941,7 +941,10 @@ mod tests {
fn returns_total_difficulty() {
let queue = get_test_queue(false);
let block = get_good_dummy_block();
let hash = view!(BlockView, &block).header().hash().clone();
let hash = view!(BlockView, &block)
.header(BlockNumber::max_value())
.hash()
.clone();
if let Err(e) = queue.import(new_unverified(block)) {
panic!("error importing block that is valid by definition({:?})", e);
}
@ -957,7 +960,10 @@ mod tests {
fn returns_ok_for_drained_duplicates() {
let queue = get_test_queue(false);
let block = get_good_dummy_block();
let hash = view!(BlockView, &block).header().hash().clone();
let hash = view!(BlockView, &block)
.header(BlockNumber::max_value())
.hash()
.clone();
if let Err(e) = queue.import(new_unverified(block)) {
panic!("error importing block that is valid by definition({:?})", e);
}

View File

@ -84,11 +84,11 @@ pub fn verify_block_basic(
}
// t_nb 4.6 call engine.gas_limit_override (Used only by Aura)
if let Some(gas_limit) = engine.gas_limit_override(&block.header) {
if *block.header.gas_limit() != gas_limit {
if let Some(expected_gas_limit) = engine.gas_limit_override(&block.header) {
if block.header.gas_limit() != &expected_gas_limit {
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds {
min: Some(gas_limit),
max: Some(gas_limit),
min: Some(expected_gas_limit),
max: Some(expected_gas_limit),
found: *block.header.gas_limit(),
})));
}
@ -295,7 +295,7 @@ fn verify_uncles(
)));
}
let uncle_parent = uncle_parent.decode()?;
let uncle_parent = uncle_parent.decode(engine.params().eip1559_transition)?;
verify_parent(&uncle, &uncle_parent, engine)?;
engine.verify_block_family(&uncle, &uncle_parent)?;
verified.insert(uncle.hash());
@ -360,6 +360,8 @@ pub fn verify_header_params(
found: header.number(),
})));
}
// check if the block used too much gas
if header.gas_used() > header.gas_limit() {
return Err(From::from(BlockError::TooMuchGasUsed(OutOfBounds {
max: Some(*header.gas_limit()),
@ -476,9 +478,11 @@ fn verify_parent(header: &Header, parent: &Header, engine: &dyn EthEngine) -> Re
.into());
}
// check if the block changed the gas limit too much
if engine.gas_limit_override(header).is_none() {
let gas_limit_divisor = engine.params().gas_limit_bound_divisor;
let parent_gas_limit = *parent.gas_limit();
let parent_gas_limit =
parent.gas_limit() * engine.schedule(header.number()).eip1559_gas_limit_bump;
let min_gas = parent_gas_limit - parent_gas_limit / gas_limit_divisor;
let max_gas = parent_gas_limit + parent_gas_limit / gas_limit_divisor;
if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
@ -490,6 +494,15 @@ fn verify_parent(header: &Header, parent: &Header, engine: &dyn EthEngine) -> Re
}
}
// check if the base fee is correct
let expected_base_fee = engine.calculate_base_fee(parent);
if expected_base_fee != header.base_fee() {
return Err(From::from(BlockError::IncorrectBaseFee(Mismatch {
expected: expected_base_fee.unwrap_or_default(),
found: header.base_fee().unwrap_or_default(),
})));
};
Ok(())
}
@ -599,7 +612,9 @@ mod tests {
}
pub fn insert(&mut self, bytes: Bytes) {
let header = Unverified::from_rlp(bytes.clone()).unwrap().header;
let header = Unverified::from_rlp(bytes.clone(), BlockNumber::max_value())
.unwrap()
.header;
let hash = header.hash();
self.blocks.insert(hash, bytes);
self.numbers.insert(header.number(), hash);
@ -639,7 +654,9 @@ mod tests {
/// Get the familial details concerning a block.
fn block_details(&self, hash: &H256) -> Option<BlockDetails> {
self.blocks.get(hash).map(|bytes| {
let header = Unverified::from_rlp(bytes.to_vec()).unwrap().header;
let header = Unverified::from_rlp(bytes.to_vec(), BlockNumber::max_value())
.unwrap()
.header;
BlockDetails {
number: header.number(),
total_difficulty: *header.difficulty(),
@ -693,7 +710,7 @@ mod tests {
}
fn basic_test(bytes: &[u8], engine: &dyn EthEngine) -> Result<(), Error> {
let unverified = Unverified::from_rlp(bytes.to_vec())?;
let unverified = Unverified::from_rlp(bytes.to_vec(), engine.params().eip1559_transition)?;
verify_block_basic(&unverified, engine, true)
}
@ -701,7 +718,8 @@ mod tests {
where
BC: BlockProvider,
{
let block = Unverified::from_rlp(bytes.to_vec()).unwrap();
let block =
Unverified::from_rlp(bytes.to_vec(), engine.params().eip1559_transition).unwrap();
let header = block.header;
let transactions: Vec<_> = block
.transactions
@ -717,7 +735,7 @@ mod tests {
let parent = bc
.block_header_data(header.parent_hash())
.ok_or(BlockError::UnknownParent(*header.parent_hash()))?
.decode()?;
.decode(engine.params().eip1559_transition)?;
let block = PreverifiedBlock {
header,
@ -735,7 +753,7 @@ mod tests {
}
fn unordered_test(bytes: &[u8], engine: &dyn EthEngine) -> Result<(), Error> {
let un = Unverified::from_rlp(bytes.to_vec())?;
let un = Unverified::from_rlp(bytes.to_vec(), engine.params().eip1559_transition)?;
verify_block_unordered(un, engine, false)?;
Ok(())
}

View File

@ -33,7 +33,7 @@ use std::{
use chain::{
fork_filter::ForkFilterApi, ChainSyncApi, SyncState, SyncStatus as EthSyncStatus,
ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_64, ETH_PROTOCOL_VERSION_65,
PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2,
ETH_PROTOCOL_VERSION_66, PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2,
};
use ethcore::{
client::{BlockChainClient, ChainMessageType, ChainNotify, NewBlocks},
@ -110,6 +110,8 @@ pub struct SyncConfig {
pub fork_block: Option<(BlockNumber, H256)>,
/// Enable snapshot sync
pub warp_sync: WarpSync,
/// Number of first block where EIP-1559 rules begin. New encoding/decoding block format.
pub eip1559_transition: BlockNumber,
}
impl Default for SyncConfig {
@ -121,6 +123,7 @@ impl Default for SyncConfig {
subprotocol_name: ETH_PROTOCOL,
fork_block: None,
warp_sync: WarpSync::Disabled,
eip1559_transition: BlockNumber::max_value(),
}
}
}
@ -568,6 +571,7 @@ impl ChainNotify for EthSync {
ETH_PROTOCOL_VERSION_63,
ETH_PROTOCOL_VERSION_64,
ETH_PROTOCOL_VERSION_65,
ETH_PROTOCOL_VERSION_66,
],
)
.unwrap_or_else(|e| warn!("Error registering ethereum protocol: {:?}", e));

View File

@ -250,6 +250,7 @@ impl BlockDownloader {
io: &mut dyn SyncIo,
r: &Rlp,
expected_hash: H256,
eip1559_transition: BlockNumber,
) -> Result<DownloadAction, BlockDownloaderImportError> {
let item_count = r.item_count().unwrap_or(0);
if self.state == State::Idle {
@ -276,7 +277,7 @@ impl BlockDownloader {
let mut hashes = Vec::new();
let mut last_header = None;
for i in 0..item_count {
let info = SyncHeader::from_rlp(r.at(i)?.as_raw().to_vec())?;
let info = SyncHeader::from_rlp(r.at(i)?.as_raw().to_vec(), eip1559_transition)?;
let number = BlockNumber::from(info.header.number());
let hash = info.header.hash();
@ -421,6 +422,7 @@ impl BlockDownloader {
&mut self,
r: &Rlp,
expected_hashes: &[H256],
eip1559_transition: BlockNumber,
) -> Result<(), BlockDownloaderImportError> {
let item_count = r.item_count().unwrap_or(0);
if item_count == 0 {
@ -430,7 +432,7 @@ impl BlockDownloader {
} else {
let mut bodies = Vec::with_capacity(item_count);
for i in 0..item_count {
let body = SyncBody::from_rlp(r.at(i)?.as_raw())?;
let body = SyncBody::from_rlp(r.at(i)?.as_raw(), eip1559_transition)?;
bodies.push(body);
}
@ -796,21 +798,23 @@ mod tests {
headers: &[BlockHeader],
downloader: &mut BlockDownloader,
io: &mut dyn SyncIo,
eip1559_transition: BlockNumber,
) -> Result<DownloadAction, BlockDownloaderImportError> {
let mut stream = RlpStream::new();
stream.append_list(headers);
let bytes = stream.out();
let rlp = Rlp::new(&bytes);
let expected_hash = headers.first().unwrap().hash();
downloader.import_headers(io, &rlp, expected_hash)
downloader.import_headers(io, &rlp, expected_hash, eip1559_transition)
}
fn import_headers_ok(
headers: &[BlockHeader],
downloader: &mut BlockDownloader,
io: &mut dyn SyncIo,
eip1559_transition: BlockNumber,
) {
let res = import_headers(headers, downloader, io);
let res = import_headers(headers, downloader, io, eip1559_transition);
assert!(res.is_ok());
}
@ -838,7 +842,12 @@ mod tests {
let rlp_data = encode_list(&valid_headers);
let valid_rlp = Rlp::new(&rlp_data);
match downloader.import_headers(&mut io, &valid_rlp, genesis_hash) {
match downloader.import_headers(
&mut io,
&valid_rlp,
genesis_hash,
spec.params().eip1559_transition,
) {
Ok(DownloadAction::Reset) => assert_eq!(downloader.state, State::Blocks),
_ => panic!("expected transition to Blocks state"),
};
@ -852,7 +861,12 @@ mod tests {
let rlp_data = encode_list(&invalid_start_block_headers);
let invalid_start_block_rlp = Rlp::new(&rlp_data);
match downloader.import_headers(&mut io, &invalid_start_block_rlp, genesis_hash) {
match downloader.import_headers(
&mut io,
&invalid_start_block_rlp,
genesis_hash,
spec.params().eip1559_transition,
) {
Err(BlockDownloaderImportError::Invalid) => (),
_ => panic!("expected BlockDownloaderImportError"),
};
@ -866,7 +880,12 @@ mod tests {
let rlp_data = encode_list(&invalid_skip_headers);
let invalid_skip_rlp = Rlp::new(&rlp_data);
match downloader.import_headers(&mut io, &invalid_skip_rlp, genesis_hash) {
match downloader.import_headers(
&mut io,
&invalid_skip_rlp,
genesis_hash,
spec.params().eip1559_transition,
) {
Err(BlockDownloaderImportError::Invalid) => (),
_ => panic!("expected BlockDownloaderImportError"),
};
@ -883,7 +902,12 @@ mod tests {
let rlp_data = encode_list(&too_many_headers);
let too_many_rlp = Rlp::new(&rlp_data);
match downloader.import_headers(&mut io, &too_many_rlp, genesis_hash) {
match downloader.import_headers(
&mut io,
&too_many_rlp,
genesis_hash,
spec.params().eip1559_transition,
) {
Err(BlockDownloaderImportError::Invalid) => (),
_ => panic!("expected BlockDownloaderImportError"),
};
@ -894,6 +918,7 @@ mod tests {
::env_logger::try_init().ok();
let mut chain = TestBlockChainClient::new();
let eip1559_transition = BlockNumber::default();
let snapshot_service = TestSnapshotService::new();
let queue = RwLock::new(VecDeque::new());
let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None);
@ -913,7 +938,12 @@ mod tests {
let rlp_data = encode_list(&headers);
let headers_rlp = Rlp::new(&rlp_data);
match downloader.import_headers(&mut io, &headers_rlp, headers[0].hash()) {
match downloader.import_headers(
&mut io,
&headers_rlp,
headers[0].hash(),
eip1559_transition,
) {
Ok(DownloadAction::None) => (),
_ => panic!("expected successful import"),
};
@ -923,7 +953,12 @@ mod tests {
let rlp_data = encode_list(&headers);
let headers_rlp = Rlp::new(&rlp_data);
match downloader.import_headers(&mut io, &headers_rlp, headers[0].hash()) {
match downloader.import_headers(
&mut io,
&headers_rlp,
headers[0].hash(),
eip1559_transition,
) {
Err(BlockDownloaderImportError::Invalid) => (),
_ => panic!("expected BlockDownloaderImportError"),
};
@ -933,7 +968,12 @@ mod tests {
let rlp_data = encode_list(&headers);
let headers_rlp = Rlp::new(&rlp_data);
match downloader.import_headers(&mut io, &headers_rlp, headers[0].hash()) {
match downloader.import_headers(
&mut io,
&headers_rlp,
headers[0].hash(),
eip1559_transition,
) {
Err(BlockDownloaderImportError::Invalid) => (),
_ => panic!("expected BlockDownloaderImportError"),
};
@ -944,6 +984,7 @@ mod tests {
::env_logger::try_init().ok();
let mut chain = TestBlockChainClient::new();
let eip1559_transition = chain.spec.params().eip1559_transition;
let snapshot_service = TestSnapshotService::new();
let queue = RwLock::new(VecDeque::new());
let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None);
@ -992,7 +1033,7 @@ mod tests {
let rlp_data = encode_list(&headers[0..3]);
let headers_rlp = Rlp::new(&rlp_data);
assert!(downloader
.import_headers(&mut io, &headers_rlp, headers[0].hash())
.import_headers(&mut io, &headers_rlp, headers[0].hash(), eip1559_transition)
.is_ok());
// Import first body successfully.
@ -1000,7 +1041,11 @@ mod tests {
rlp_data.append_raw(&bodies[0], 1);
let bodies_rlp = Rlp::new(rlp_data.as_raw());
assert!(downloader
.import_bodies(&bodies_rlp, &[headers[0].hash(), headers[1].hash()])
.import_bodies(
&bodies_rlp,
&[headers[0].hash(), headers[1].hash()],
eip1559_transition
)
.is_ok());
// Import second body successfully.
@ -1008,14 +1053,22 @@ mod tests {
rlp_data.append_raw(&bodies[1], 1);
let bodies_rlp = Rlp::new(rlp_data.as_raw());
assert!(downloader
.import_bodies(&bodies_rlp, &[headers[0].hash(), headers[1].hash()])
.import_bodies(
&bodies_rlp,
&[headers[0].hash(), headers[1].hash()],
eip1559_transition
)
.is_ok());
// Import unexpected third body.
let mut rlp_data = RlpStream::new_list(1);
rlp_data.append_raw(&bodies[2], 1);
let bodies_rlp = Rlp::new(rlp_data.as_raw());
match downloader.import_bodies(&bodies_rlp, &[headers[0].hash(), headers[1].hash()]) {
match downloader.import_bodies(
&bodies_rlp,
&[headers[0].hash(), headers[1].hash()],
eip1559_transition,
) {
Err(BlockDownloaderImportError::Invalid) => (),
_ => panic!("expected BlockDownloaderImportError"),
};
@ -1026,6 +1079,7 @@ mod tests {
::env_logger::try_init().ok();
let mut chain = TestBlockChainClient::new();
let eip1559_transition = chain.spec.params().eip1559_transition;
let snapshot_service = TestSnapshotService::new();
let queue = RwLock::new(VecDeque::new());
let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None);
@ -1069,7 +1123,7 @@ mod tests {
let rlp_data = encode_list(&headers[0..3]);
let headers_rlp = Rlp::new(&rlp_data);
assert!(downloader
.import_headers(&mut io, &headers_rlp, headers[0].hash())
.import_headers(&mut io, &headers_rlp, headers[0].hash(), eip1559_transition)
.is_ok());
// Import second and third receipts successfully.
@ -1085,7 +1139,11 @@ mod tests {
let mut rlp_data = RlpStream::new_list(1);
rlp_data.append_raw(&receipts[3], 1);
let bodies_rlp = Rlp::new(rlp_data.as_raw());
match downloader.import_bodies(&bodies_rlp, &[headers[1].hash(), headers[2].hash()]) {
match downloader.import_bodies(
&bodies_rlp,
&[headers[1].hash(), headers[2].hash()],
eip1559_transition,
) {
Err(BlockDownloaderImportError::Invalid) => (),
_ => panic!("expected BlockDownloaderImportError"),
};
@ -1114,8 +1172,18 @@ mod tests {
let short_subchain = [dummy_header(1, genesis_hash)];
import_headers_ok(&heads, &mut downloader, &mut io);
import_headers_ok(&short_subchain, &mut downloader, &mut io);
import_headers_ok(
&heads,
&mut downloader,
&mut io,
spec.params().eip1559_transition,
);
import_headers_ok(
&short_subchain,
&mut downloader,
&mut io,
spec.params().eip1559_transition,
);
assert_eq!(downloader.state, State::Blocks);
assert!(!downloader.blocks.is_empty());
@ -1123,7 +1191,12 @@ mod tests {
// simulate receiving useless headers
let head = vec![short_subchain.last().unwrap().clone()];
for _ in 0..MAX_USELESS_HEADERS_PER_ROUND {
let res = import_headers(&head, &mut downloader, &mut io);
let res = import_headers(
&head,
&mut downloader,
&mut io,
spec.params().eip1559_transition,
);
assert!(res.is_err());
}
@ -1150,8 +1223,18 @@ mod tests {
let short_subchain = [dummy_header(1, genesis_hash)];
import_headers_ok(&heads, &mut downloader, &mut io);
import_headers_ok(&short_subchain, &mut downloader, &mut io);
import_headers_ok(
&heads,
&mut downloader,
&mut io,
spec.params().eip1559_transition,
);
import_headers_ok(
&short_subchain,
&mut downloader,
&mut io,
spec.params().eip1559_transition,
);
assert_eq!(downloader.state, State::Blocks);
assert!(!downloader.blocks.is_empty());
@ -1159,7 +1242,12 @@ mod tests {
// simulate receiving useless headers
let head = vec![short_subchain.last().unwrap().clone()];
for _ in 0..MAX_USELESS_HEADERS_PER_ROUND {
let res = import_headers(&head, &mut downloader, &mut io);
let res = import_headers(
&head,
&mut downloader,
&mut io,
spec.params().eip1559_transition,
);
assert!(res.is_err());
}

View File

@ -26,6 +26,7 @@ use triehash_ethereum::ordered_trie_root;
use types::{
header::Header as BlockHeader,
transaction::{TypedTransaction, UnverifiedTransaction},
BlockNumber,
};
malloc_size_of_is_0!(HeaderId);
@ -37,9 +38,10 @@ pub struct SyncHeader {
}
impl SyncHeader {
pub fn from_rlp(bytes: Bytes) -> Result<Self, DecoderError> {
pub fn from_rlp(bytes: Bytes, eip1559_transition: BlockNumber) -> Result<Self, DecoderError> {
let rlp = Rlp::new(&bytes);
let result = SyncHeader {
header: ::rlp::decode(&bytes)?,
header: BlockHeader::decode_rlp(&rlp, eip1559_transition)?,
bytes,
};
@ -56,7 +58,7 @@ pub struct SyncBody {
}
impl SyncBody {
pub fn from_rlp(bytes: &[u8]) -> Result<Self, DecoderError> {
pub fn from_rlp(bytes: &[u8], eip1559_transition: BlockNumber) -> Result<Self, DecoderError> {
let rlp = Rlp::new(bytes);
let transactions_rlp = rlp.at(0)?;
let uncles_rlp = rlp.at(1)?;
@ -65,7 +67,7 @@ impl SyncBody {
transactions_bytes: transactions_rlp.as_raw().to_vec(),
transactions: TypedTransaction::decode_rlp_list(&transactions_rlp)?,
uncles_bytes: uncles_rlp.as_raw().to_vec(),
uncles: uncles_rlp.as_list()?,
uncles: BlockHeader::decode_rlp_list(&uncles_rlp, eip1559_transition)?,
};
Ok(result)
@ -672,7 +674,13 @@ mod test {
.collect();
let headers: Vec<_> = blocks
.iter()
.map(|b| SyncHeader::from_rlp(Rlp::new(b).at(0).unwrap().as_raw().to_vec()).unwrap())
.map(|b| {
SyncHeader::from_rlp(
Rlp::new(b).at(0).unwrap().as_raw().to_vec(),
client.spec.params().eip1559_transition,
)
.unwrap()
})
.collect();
let hashes: Vec<_> = headers.iter().map(|h| h.header.hash()).collect();
let heads: Vec<_> = hashes
@ -707,7 +715,10 @@ mod test {
bc.drain().into_iter().map(|b| b.block).collect::<Vec<_>>(),
blocks[0..6]
.iter()
.map(|b| Unverified::from_rlp(b.to_vec()).unwrap())
.map(
|b| Unverified::from_rlp(b.to_vec(), client.spec.params().eip1559_transition)
.unwrap()
)
.collect::<Vec<_>>()
);
assert!(!bc.contains(&hashes[0]));
@ -724,7 +735,10 @@ mod test {
bc.drain().into_iter().map(|b| b.block).collect::<Vec<_>>(),
blocks[6..16]
.iter()
.map(|b| Unverified::from_rlp(b.to_vec()).unwrap())
.map(
|b| Unverified::from_rlp(b.to_vec(), client.spec.params().eip1559_transition)
.unwrap()
)
.collect::<Vec<_>>()
);
@ -752,7 +766,13 @@ mod test {
.collect();
let headers: Vec<_> = blocks
.iter()
.map(|b| SyncHeader::from_rlp(Rlp::new(b).at(0).unwrap().as_raw().to_vec()).unwrap())
.map(|b| {
SyncHeader::from_rlp(
Rlp::new(b).at(0).unwrap().as_raw().to_vec(),
client.spec.params().eip1559_transition,
)
.unwrap()
})
.collect();
let hashes: Vec<_> = headers.iter().map(|h| h.header.hash()).collect();
let heads: Vec<_> = hashes
@ -788,7 +808,13 @@ mod test {
.collect();
let headers: Vec<_> = blocks
.iter()
.map(|b| SyncHeader::from_rlp(Rlp::new(b).at(0).unwrap().as_raw().to_vec()).unwrap())
.map(|b| {
SyncHeader::from_rlp(
Rlp::new(b).at(0).unwrap().as_raw().to_vec(),
client.spec.params().eip1559_transition,
)
.unwrap()
})
.collect();
let hashes: Vec<_> = headers.iter().map(|h| h.header.hash()).collect();
let heads: Vec<_> = hashes

View File

@ -86,7 +86,7 @@ mod tests {
|| ethereum::new_foundation(&String::new()),
vec![
1_150_000, 1_920_000, 2_463_000, 2_675_000, 4_370_000, 7_280_000, 9_069_000,
9_200_000, 12_244_000,
9_200_000, 12_244_000, 12_965_000, 13_773_000,
],
)
}
@ -96,7 +96,7 @@ mod tests {
test_spec(
|| ethereum::new_ropsten(&String::new()),
vec![
10, 1_700_000, 4_230_000, 4_939_394, 6_485_846, 7_117_117, 9_812_189,
10, 1_700_000, 4_230_000, 4_939_394, 6_485_846, 7_117_117, 9_812_189, 10_499_401,
],
)
}
@ -106,7 +106,7 @@ mod tests {
test_spec(
|| ethereum::new_rinkeby(&String::new()),
vec![
1, 2, 3, 1_035_301, 3_660_663, 4_321_234, 5_435_345, 8_290_928,
1, 2, 3, 1_035_301, 3_660_663, 4_321_234, 5_435_345, 8_290_928, 8_897_988,
],
)
}
@ -115,7 +115,7 @@ mod tests {
fn goerli_spec() {
test_spec(
|| ethereum::new_goerli(&String::new()),
vec![1_561_651, 4_460_644],
vec![1_561_651, 4_460_644, 5_062_605],
)
}
}

View File

@ -32,14 +32,17 @@ use std::{cmp, mem, time::Instant};
use sync_io::SyncIo;
use types::{block_status::BlockStatus, ids::BlockId, BlockNumber};
use super::sync_packet::{
PacketInfo,
SyncPacket::{self, *},
use super::{
request_id::strip_request_id,
sync_packet::{
PacketInfo,
SyncPacket::{self, *},
},
};
use super::{
BlockSet, ChainSync, ForkConfirmation, PacketProcessError, PeerAsking, PeerInfo, SyncRequester,
SyncState, ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_64, ETH_PROTOCOL_VERSION_65,
SyncState, ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_64, ETH_PROTOCOL_VERSION_66,
MAX_NEW_BLOCK_AGE, MAX_NEW_HASHES, PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2,
};
@ -55,27 +58,33 @@ impl SyncHandler {
packet_id: u8,
data: &[u8],
) {
let rlp = Rlp::new(data);
if let Some(packet_id) = SyncPacket::from_u8(packet_id) {
let result = match packet_id {
StatusPacket => SyncHandler::on_peer_status(sync, io, peer, &rlp),
BlockHeadersPacket => SyncHandler::on_peer_block_headers(sync, io, peer, &rlp),
BlockBodiesPacket => SyncHandler::on_peer_block_bodies(sync, io, peer, &rlp),
ReceiptsPacket => SyncHandler::on_peer_block_receipts(sync, io, peer, &rlp),
NewBlockPacket => SyncHandler::on_peer_new_block(sync, io, peer, &rlp),
NewBlockHashesPacket => SyncHandler::on_peer_new_hashes(sync, io, peer, &rlp),
NewPooledTransactionHashesPacket => {
SyncHandler::on_peer_new_pooled_transaction_hashes(sync, io, peer, &rlp)
}
PooledTransactionsPacket => {
SyncHandler::on_peer_pooled_transactions(sync, io, peer, &rlp)
}
SnapshotManifestPacket => SyncHandler::on_snapshot_manifest(sync, io, peer, &rlp),
SnapshotDataPacket => SyncHandler::on_snapshot_data(sync, io, peer, &rlp),
_ => {
debug!(target: "sync", "{}: Unknown packet {}", peer, packet_id.id());
Ok(())
}
let rlp_result = strip_request_id(data, sync, &peer, &packet_id);
let result = match rlp_result {
Ok((rlp, _)) => match packet_id {
StatusPacket => SyncHandler::on_peer_status(sync, io, peer, &rlp),
BlockHeadersPacket => SyncHandler::on_peer_block_headers(sync, io, peer, &rlp),
BlockBodiesPacket => SyncHandler::on_peer_block_bodies(sync, io, peer, &rlp),
ReceiptsPacket => SyncHandler::on_peer_block_receipts(sync, io, peer, &rlp),
NewBlockPacket => SyncHandler::on_peer_new_block(sync, io, peer, &rlp),
NewBlockHashesPacket => SyncHandler::on_peer_new_hashes(sync, io, peer, &rlp),
NewPooledTransactionHashesPacket => {
SyncHandler::on_peer_new_pooled_transaction_hashes(sync, io, peer, &rlp)
}
PooledTransactionsPacket => {
SyncHandler::on_peer_pooled_transactions(sync, io, peer, &rlp)
}
SnapshotManifestPacket => {
SyncHandler::on_snapshot_manifest(sync, io, peer, &rlp)
}
SnapshotDataPacket => SyncHandler::on_snapshot_data(sync, io, peer, &rlp),
_ => {
debug!(target: "sync", "{}: Unknown packet {}", peer, packet_id.id());
Ok(())
}
},
Err(e) => Err(e.into()),
};
match result {
@ -159,7 +168,7 @@ impl SyncHandler {
return Ok(());
}
// t_nb 1.0 decode RLP
let block = Unverified::from_rlp(r.at(0)?.as_raw().to_vec())?;
let block = Unverified::from_rlp(r.at(0)?.as_raw().to_vec(), sync.eip1559_transition)?;
let hash = block.header.hash();
let number = block.header.number();
trace!(target: "sync", "{} -> NewBlock ({})", peer_id, hash);
@ -360,7 +369,7 @@ impl SyncHandler {
Some(ref mut blocks) => blocks,
},
};
downloader.import_bodies(r, expected_blocks.as_slice())?;
downloader.import_bodies(r, expected_blocks.as_slice(), sync.eip1559_transition)?;
}
sync.collect_blocks(io, block_set);
Ok(())
@ -479,7 +488,7 @@ impl SyncHandler {
Some(ref mut blocks) => blocks,
},
};
downloader.import_headers(io, r, expected_hash)?
downloader.import_headers(io, r, expected_hash, sync.eip1559_transition)?
};
if result == DownloadAction::Reset {
@ -797,7 +806,7 @@ impl SyncHandler {
|| peer.protocol_version > PAR_PROTOCOL_VERSION_2.0))
|| (!warp_protocol
&& (peer.protocol_version < ETH_PROTOCOL_VERSION_63.0
|| peer.protocol_version > ETH_PROTOCOL_VERSION_65.0))
|| peer.protocol_version > ETH_PROTOCOL_VERSION_66.0))
{
trace!(target: "sync", "Peer {} unsupported eth protocol ({})", peer_id, peer.protocol_version);
return Err(DownloaderImportError::Invalid);

View File

@ -90,6 +90,7 @@
pub mod fork_filter;
mod handler;
mod propagator;
pub mod request_id;
mod requester;
mod supplier;
pub mod sync_packet;
@ -153,6 +154,8 @@ impl From<DecoderError> for PacketProcessError {
}
}
/// Version 66 of the Ethereum protocol and number of packet IDs reserved by the protocol (packet count).
pub const ETH_PROTOCOL_VERSION_66: (u8, u8) = (66, 0x11);
/// Version 65 of the Ethereum protocol and number of packet IDs reserved by the protocol (packet count).
pub const ETH_PROTOCOL_VERSION_65: (u8, u8) = (65, 0x11);
/// 64 version of Ethereum protocol.
@ -166,6 +169,7 @@ pub const PAR_PROTOCOL_VERSION_2: (u8, u8) = (2, 0x16);
pub const MAX_BODIES_TO_SEND: usize = 256;
pub const MAX_HEADERS_TO_SEND: usize = 512;
pub const MAX_NODE_DATA_TO_SEND: usize = 1024;
pub const MAX_RECEIPTS_HEADERS_TO_SEND: usize = 256;
pub const MAX_TRANSACTIONS_TO_REQUEST: usize = 256;
const MIN_PEERS_PROPAGATION: usize = 4;
@ -693,6 +697,8 @@ pub struct ChainSync {
download_old_blocks: bool,
/// Enable warp sync.
warp_sync: WarpSync,
/// New block encoding/decoding format is introduced by the EIP1559
eip1559_transition: BlockNumber,
}
#[derive(Debug, Default)]
@ -778,6 +784,7 @@ impl ChainSync {
sync_start_time: None,
transactions_stats: TransactionsStats::default(),
warp_sync: config.warp_sync,
eip1559_transition: config.eip1559_transition,
};
sync.update_targets(chain);
sync
@ -1697,6 +1704,14 @@ pub mod tests {
assert!(!sync_status(SyncState::Idle).is_syncing(queue_info(0, 0)));
}
pub fn dummy_sync(client: &dyn BlockChainClient) -> ChainSync {
ChainSync::new(
SyncConfig::default(),
client,
ForkFilterApi::new_dummy(client),
)
}
pub fn dummy_sync_with_peer(
peer_latest_hash: H256,
client: &dyn BlockChainClient,

View File

@ -0,0 +1,148 @@
use bytes::Bytes;
use chain::{
sync_packet::{PacketInfo, SyncPacket},
ChainSync, PeerInfo,
};
use network::PeerId;
use rlp::{DecoderError, Rlp, RlpStream};
pub type RequestId = u64;
// Separate the eth/66 request id from a packet, if it exists.
pub fn strip_request_id<'a>(
data: &'a [u8],
sync: &ChainSync,
peer: &PeerId,
packet_id: &SyncPacket,
) -> Result<(Rlp<'a>, Option<RequestId>), DecoderError> {
let protocol_version = if let Some(peer_info) = sync.peers.get(peer) {
peer_info.protocol_version
} else {
trace!(
"Peer info missing for peer {}, assuming protocol version 66",
peer
);
66
};
let has_request_id = protocol_version >= 66 && packet_id.has_request_id_in_eth_66();
do_strip_request_id(data, has_request_id)
}
fn do_strip_request_id<'a>(
data: &'a [u8],
has_request_id: bool,
) -> Result<(Rlp<'a>, Option<RequestId>), DecoderError> {
let rlp = Rlp::new(data);
if has_request_id {
let request_id: RequestId = rlp.val_at(0)?;
let stripped_rlp = rlp.at(1)?;
Ok((stripped_rlp, Some(request_id)))
} else {
Ok((rlp, None))
}
}
// Add a given eth/66 request id to a packet being built.
pub fn prepend_request_id(rlp: RlpStream, request_id: Option<RequestId>) -> RlpStream {
match request_id {
Some(ref id) => {
let mut stream = RlpStream::new_list(2);
stream.append(id);
stream.append_raw(&rlp.out(), 1);
stream
}
None => rlp,
}
}
/// Prepend a new eth/66 request id to the packet if appropriate.
pub fn generate_request_id(
packet: Bytes,
peer: &PeerInfo,
packet_id: SyncPacket,
) -> (Bytes, Option<RequestId>) {
if peer.protocol_version >= 66 && packet_id.has_request_id_in_eth_66() {
do_generate_request_id(&packet)
} else {
(packet, None)
}
}
fn do_generate_request_id(packet: &Bytes) -> (Bytes, Option<RequestId>) {
let request_id: RequestId = rand::random();
let mut rlp = RlpStream::new_list(2);
rlp.append(&request_id);
rlp.append_raw(packet, 1);
(rlp.out(), Some(request_id))
}
#[cfg(test)]
mod tests {
use super::*;
use ethereum_types::H256;
#[test]
fn test_prepend_request_id() {
let mut request = RlpStream::new_list(2);
request.append(&H256::from_low_u64_be(1));
request.append(&H256::from_low_u64_be(2));
let with_id = prepend_request_id(request, Some(10));
let rlp = Rlp::new(with_id.as_raw());
let recovered_id: RequestId = rlp.val_at(0).unwrap();
let recovered_request: Vec<H256> = rlp.at(1).unwrap().as_list().unwrap();
assert_eq!(recovered_id, 10);
assert_eq!(
recovered_request,
[H256::from_low_u64_be(1), H256::from_low_u64_be(2)]
);
}
#[test]
fn test_strip_request_id() {
let request = vec![
H256::from_low_u64_be(1),
H256::from_low_u64_be(2),
H256::from_low_u64_be(3),
];
let mut request_with_id = RlpStream::new_list(2);
request_with_id.append(&20u64);
request_with_id.append_list(&request);
let data = request_with_id.out();
let (rlp, id) = do_strip_request_id(&data, true).unwrap();
assert_eq!(id, Some(20));
assert_eq!(rlp.as_list::<H256>().unwrap(), request);
}
#[test]
fn test_generate_request_id() {
let request = vec![
H256::from_low_u64_be(1),
H256::from_low_u64_be(2),
H256::from_low_u64_be(3),
];
let mut stream = RlpStream::new_list(3);
for hash in &request {
stream.append(hash);
}
let data = stream.out();
let (new_data, id) = do_generate_request_id(&data);
let recovered = Rlp::new(&new_data);
let recovered_id: RequestId = recovered.val_at(0).unwrap();
let recovered_request: Vec<H256> = recovered.at(1).unwrap().as_list().unwrap();
assert_eq!(recovered_id, id.unwrap());
assert_eq!(recovered_request, request);
}
}

View File

@ -23,7 +23,10 @@ use std::time::Instant;
use sync_io::SyncIo;
use types::BlockNumber;
use super::sync_packet::{SyncPacket::*, *};
use super::{
request_id::generate_request_id,
sync_packet::{SyncPacket::*, *},
};
use super::{BlockSet, ChainSync, PeerAsking};
@ -121,7 +124,7 @@ impl SyncRequester {
io,
peer_id,
PeerAsking::PooledTransactions,
PooledTransactionsPacket,
GetPooledTransactionsPacket,
rlp.out(),
)
}
@ -243,6 +246,8 @@ impl SyncRequester {
peer.asking = asking;
peer.ask_time = Instant::now();
let (packet, _) = generate_request_id(packet, peer, packet_id);
let result = io.send(peer_id, packet_id, packet);
if let Err(e) = result {

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