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
This commit is contained in:
parent
144b2293a2
commit
5e7086d54c
198
Cargo.lock
generated
198
Cargo.lock
generated
@ -284,7 +284,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"criterion 0.3.0",
|
"criterion 0.3.0",
|
||||||
"ethbloom",
|
"ethbloom 0.9.2",
|
||||||
"parking_lot 0.11.1",
|
"parking_lot 0.11.1",
|
||||||
"tempdir",
|
"tempdir",
|
||||||
"tiny-keccak 1.5.0",
|
"tiny-keccak 1.5.0",
|
||||||
@ -421,7 +421,7 @@ dependencies = [
|
|||||||
name = "cli-signer"
|
name = "cli-signer"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"futures",
|
"futures",
|
||||||
"parity-rpc",
|
"parity-rpc",
|
||||||
"parity-rpc-client",
|
"parity-rpc-client",
|
||||||
@ -450,7 +450,7 @@ dependencies = [
|
|||||||
name = "common-types"
|
name = "common-types"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethkey",
|
"ethkey",
|
||||||
"hex",
|
"hex",
|
||||||
"inflate",
|
"inflate",
|
||||||
@ -750,7 +750,7 @@ name = "dir"
|
|||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"app_dirs",
|
"app_dirs",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"home 0.3.4",
|
"home 0.3.4",
|
||||||
"journaldb",
|
"journaldb",
|
||||||
]
|
]
|
||||||
@ -785,7 +785,7 @@ name = "eip-712"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethabi",
|
"ethabi",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"failure",
|
"failure",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"itertools 0.7.11",
|
"itertools 0.7.11",
|
||||||
@ -871,7 +871,7 @@ dependencies = [
|
|||||||
"num-bigint 0.2.3",
|
"num-bigint 0.2.3",
|
||||||
"num-traits 0.2.8",
|
"num-traits 0.2.8",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"static_assertions",
|
"static_assertions 1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -891,7 +891,7 @@ version = "12.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "052a565e3de82944527d6d10a465697e6bb92476b772ca7141080c901f6a63c6"
|
checksum = "052a565e3de82944527d6d10a465697e6bb92476b772ca7141080c901f6a63c6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"rustc-hex 2.1.0",
|
"rustc-hex 2.1.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -925,7 +925,7 @@ dependencies = [
|
|||||||
"criterion 0.2.11",
|
"criterion 0.2.11",
|
||||||
"crunchy 0.1.6",
|
"crunchy 0.1.6",
|
||||||
"either",
|
"either",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"keccak-hash",
|
"keccak-hash",
|
||||||
"log",
|
"log",
|
||||||
"memmap",
|
"memmap",
|
||||||
@ -937,6 +937,19 @@ dependencies = [
|
|||||||
"tiny-keccak 2.0.2",
|
"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]]
|
[[package]]
|
||||||
name = "ethbloom"
|
name = "ethbloom"
|
||||||
version = "0.9.2"
|
version = "0.9.2"
|
||||||
@ -944,9 +957,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "71a6567e6fd35589fea0c63b94b4cf2e55573e413901bdbe60ab15cf0e25e5df"
|
checksum = "71a6567e6fd35589fea0c63b94b4cf2e55573e413901bdbe60ab15cf0e25e5df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crunchy 0.2.2",
|
"crunchy 0.2.2",
|
||||||
"fixed-hash",
|
"fixed-hash 0.6.1",
|
||||||
"impl-rlp",
|
"impl-rlp",
|
||||||
"impl-serde",
|
"impl-serde 0.3.1",
|
||||||
"tiny-keccak 2.0.2",
|
"tiny-keccak 2.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -976,7 +989,7 @@ dependencies = [
|
|||||||
"ethcore-io",
|
"ethcore-io",
|
||||||
"ethcore-miner",
|
"ethcore-miner",
|
||||||
"ethcore-stratum",
|
"ethcore-stratum",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethjson",
|
"ethjson",
|
||||||
"ethkey",
|
"ethkey",
|
||||||
"evm",
|
"evm",
|
||||||
@ -1040,7 +1053,7 @@ name = "ethcore-accounts"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"common-types",
|
"common-types",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethkey",
|
"ethkey",
|
||||||
"ethstore",
|
"ethstore",
|
||||||
"log",
|
"log",
|
||||||
@ -1061,7 +1074,7 @@ dependencies = [
|
|||||||
"common-types",
|
"common-types",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"ethcore-db",
|
"ethcore-db",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethkey",
|
"ethkey",
|
||||||
"itertools 0.5.10",
|
"itertools 0.5.10",
|
||||||
"keccak-hash",
|
"keccak-hash",
|
||||||
@ -1098,7 +1111,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"eip-152",
|
"eip-152",
|
||||||
"eth_pairings",
|
"eth_pairings",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethjson",
|
"ethjson",
|
||||||
"ethkey",
|
"ethkey",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
@ -1117,7 +1130,7 @@ name = "ethcore-call-contract"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"common-types",
|
"common-types",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"parity-bytes",
|
"parity-bytes",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1126,7 +1139,7 @@ name = "ethcore-db"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"common-types",
|
"common-types",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"kvdb",
|
"kvdb",
|
||||||
"kvdb-memorydb",
|
"kvdb-memorydb",
|
||||||
"kvdb-rocksdb",
|
"kvdb-rocksdb",
|
||||||
@ -1182,7 +1195,7 @@ dependencies = [
|
|||||||
"ethabi-derive",
|
"ethabi-derive",
|
||||||
"ethash",
|
"ethash",
|
||||||
"ethcore-call-contract",
|
"ethcore-call-contract",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethkey",
|
"ethkey",
|
||||||
"fetch",
|
"fetch",
|
||||||
"futures",
|
"futures",
|
||||||
@ -1201,7 +1214,7 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"trace-time",
|
"trace-time",
|
||||||
"transaction-pool",
|
"txpool",
|
||||||
"url 2.1.0",
|
"url 2.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1212,7 +1225,7 @@ dependencies = [
|
|||||||
"assert_matches",
|
"assert_matches",
|
||||||
"error-chain",
|
"error-chain",
|
||||||
"ethcore-io",
|
"ethcore-io",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethkey",
|
"ethkey",
|
||||||
"ipnetwork",
|
"ipnetwork",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -1236,7 +1249,7 @@ dependencies = [
|
|||||||
"error-chain",
|
"error-chain",
|
||||||
"ethcore-io",
|
"ethcore-io",
|
||||||
"ethcore-network",
|
"ethcore-network",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethkey",
|
"ethkey",
|
||||||
"igd",
|
"igd",
|
||||||
"ipnetwork",
|
"ipnetwork",
|
||||||
@ -1273,7 +1286,7 @@ dependencies = [
|
|||||||
"ethcore-db",
|
"ethcore-db",
|
||||||
"ethcore-io",
|
"ethcore-io",
|
||||||
"ethcore-sync",
|
"ethcore-sync",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"kvdb",
|
"kvdb",
|
||||||
"kvdb-rocksdb",
|
"kvdb-rocksdb",
|
||||||
"log",
|
"log",
|
||||||
@ -1286,7 +1299,7 @@ name = "ethcore-stratum"
|
|||||||
version = "1.12.0"
|
version = "1.12.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"jsonrpc-core",
|
"jsonrpc-core",
|
||||||
"jsonrpc-tcp-server",
|
"jsonrpc-tcp-server",
|
||||||
"keccak-hash",
|
"keccak-hash",
|
||||||
@ -1309,7 +1322,7 @@ dependencies = [
|
|||||||
"ethcore-network",
|
"ethcore-network",
|
||||||
"ethcore-network-devp2p",
|
"ethcore-network-devp2p",
|
||||||
"ethereum-forkid",
|
"ethereum-forkid",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethkey",
|
"ethkey",
|
||||||
"ethstore",
|
"ethstore",
|
||||||
"fastmap",
|
"fastmap",
|
||||||
@ -1324,7 +1337,7 @@ dependencies = [
|
|||||||
"parity-crypto",
|
"parity-crypto",
|
||||||
"parity-util-mem",
|
"parity-util-mem",
|
||||||
"parking_lot 0.11.1",
|
"parking_lot 0.11.1",
|
||||||
"primitive-types",
|
"primitive-types 0.7.2",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"rand_xorshift 0.2.0",
|
"rand_xorshift 0.2.0",
|
||||||
"rlp",
|
"rlp",
|
||||||
@ -1341,24 +1354,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "3010d8372e3a76d4e2c44de0a080257ab62b6d108857ee7bd70fe8dfb2815f13"
|
checksum = "3010d8372e3a76d4e2c44de0a080257ab62b6d108857ee7bd70fe8dfb2815f13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc",
|
"crc",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"maplit",
|
"maplit",
|
||||||
"parity-util-mem",
|
"parity-util-mem",
|
||||||
"rlp",
|
"rlp",
|
||||||
"rlp-derive",
|
"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]]
|
[[package]]
|
||||||
name = "ethereum-types"
|
name = "ethereum-types"
|
||||||
version = "0.9.2"
|
version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "473aecff686bd8e7b9db0165cbbb53562376b39bf35b427f0c60446a9e1634b0"
|
checksum = "473aecff686bd8e7b9db0165cbbb53562376b39bf35b427f0c60446a9e1634b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethbloom",
|
"ethbloom 0.9.2",
|
||||||
"fixed-hash",
|
"fixed-hash 0.6.1",
|
||||||
"impl-rlp",
|
"impl-rlp",
|
||||||
"impl-serde",
|
"impl-serde 0.3.1",
|
||||||
"primitive-types",
|
"primitive-types 0.7.2",
|
||||||
"uint",
|
"uint",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1367,7 +1394,7 @@ name = "ethjson"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"common-types",
|
"common-types",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"macros",
|
"macros",
|
||||||
"maplit",
|
"maplit",
|
||||||
"parity-crypto",
|
"parity-crypto",
|
||||||
@ -1383,7 +1410,7 @@ version = "0.3.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"edit-distance",
|
"edit-distance",
|
||||||
"eth-secp256k1",
|
"eth-secp256k1",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"memzero",
|
"memzero",
|
||||||
@ -1417,7 +1444,7 @@ dependencies = [
|
|||||||
name = "ethstore"
|
name = "ethstore"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethkey",
|
"ethkey",
|
||||||
"itertools 0.5.10",
|
"itertools 0.5.10",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -1461,7 +1488,7 @@ dependencies = [
|
|||||||
"bit-set",
|
"bit-set",
|
||||||
"criterion 0.2.11",
|
"criterion 0.2.11",
|
||||||
"ethcore-builtin",
|
"ethcore-builtin",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
"keccak-hash",
|
"keccak-hash",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -1484,7 +1511,7 @@ dependencies = [
|
|||||||
"docopt",
|
"docopt",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"ethcore",
|
"ethcore",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethjson",
|
"ethjson",
|
||||||
"evm",
|
"evm",
|
||||||
"panic_hook",
|
"panic_hook",
|
||||||
@ -1539,7 +1566,7 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
|||||||
name = "fastmap"
|
name = "fastmap"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"plain_hasher",
|
"plain_hasher",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1566,6 +1593,18 @@ dependencies = [
|
|||||||
"url 2.1.0",
|
"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]]
|
[[package]]
|
||||||
name = "fixed-hash"
|
name = "fixed-hash"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
@ -1575,7 +1614,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"rustc-hex 2.1.0",
|
"rustc-hex 2.1.0",
|
||||||
"static_assertions",
|
"static_assertions 1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2060,6 +2099,15 @@ dependencies = [
|
|||||||
"rlp",
|
"rlp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "impl-serde"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "impl-serde"
|
name = "impl-serde"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -2167,7 +2215,7 @@ version = "0.2.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"ethcore-db",
|
"ethcore-db",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"fastmap",
|
"fastmap",
|
||||||
"hash-db 0.11.0",
|
"hash-db 0.11.0",
|
||||||
"keccak-hash",
|
"keccak-hash",
|
||||||
@ -2298,7 +2346,7 @@ version = "0.5.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1f58a51ef3df9398cf2434bea8d4eb61fb748d0feb1571f87388579a120a4c8f"
|
checksum = "1f58a51ef3df9398cf2434bea8d4eb61fb748d0feb1571f87388579a120a4c8f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"primitive-types",
|
"primitive-types 0.7.2",
|
||||||
"tiny-keccak 2.0.2",
|
"tiny-keccak 2.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2306,7 +2354,7 @@ dependencies = [
|
|||||||
name = "keccak-hasher"
|
name = "keccak-hasher"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"hash-db 0.11.0",
|
"hash-db 0.11.0",
|
||||||
"plain_hasher",
|
"plain_hasher",
|
||||||
"tiny-keccak 1.5.0",
|
"tiny-keccak 1.5.0",
|
||||||
@ -2745,7 +2793,7 @@ dependencies = [
|
|||||||
"ethcore-io",
|
"ethcore-io",
|
||||||
"ethcore-network",
|
"ethcore-network",
|
||||||
"ethcore-network-devp2p",
|
"ethcore-network-devp2p",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"kvdb-memorydb",
|
"kvdb-memorydb",
|
||||||
"log",
|
"log",
|
||||||
"lru-cache",
|
"lru-cache",
|
||||||
@ -2904,7 +2952,7 @@ dependencies = [
|
|||||||
"ethcore-network",
|
"ethcore-network",
|
||||||
"ethcore-service",
|
"ethcore-service",
|
||||||
"ethcore-sync",
|
"ethcore-sync",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethkey",
|
"ethkey",
|
||||||
"ethstore",
|
"ethstore",
|
||||||
"fake-fetch",
|
"fake-fetch",
|
||||||
@ -2991,7 +3039,7 @@ dependencies = [
|
|||||||
"aes-ctr",
|
"aes-ctr",
|
||||||
"block-modes",
|
"block-modes",
|
||||||
"digest",
|
"digest",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"hmac",
|
"hmac",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"pbkdf2",
|
"pbkdf2",
|
||||||
@ -3084,7 +3132,7 @@ dependencies = [
|
|||||||
"ethcore-miner",
|
"ethcore-miner",
|
||||||
"ethcore-network",
|
"ethcore-network",
|
||||||
"ethcore-sync",
|
"ethcore-sync",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethjson",
|
"ethjson",
|
||||||
"ethkey",
|
"ethkey",
|
||||||
"ethstore",
|
"ethstore",
|
||||||
@ -3119,8 +3167,8 @@ dependencies = [
|
|||||||
"tempdir",
|
"tempdir",
|
||||||
"tiny-keccak 1.5.0",
|
"tiny-keccak 1.5.0",
|
||||||
"tokio-timer 0.1.2",
|
"tokio-timer 0.1.2",
|
||||||
"transaction-pool",
|
|
||||||
"transient-hashmap",
|
"transient-hashmap",
|
||||||
|
"txpool",
|
||||||
"vm",
|
"vm",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3128,7 +3176,7 @@ dependencies = [
|
|||||||
name = "parity-rpc-client"
|
name = "parity-rpc-client"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"futures",
|
"futures",
|
||||||
"jsonrpc-core",
|
"jsonrpc-core",
|
||||||
"jsonrpc-ws-server",
|
"jsonrpc-ws-server",
|
||||||
@ -3208,13 +3256,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "297ff91fa36aec49ce183484b102f6b75b46776822bd81525bfc4cc9b0dd0f5c"
|
checksum = "297ff91fa36aec49ce183484b102f6b75b46776822bd81525bfc4cc9b0dd0f5c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if 0.1.10",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"hashbrown 0.8.2",
|
"hashbrown 0.8.2",
|
||||||
"impl-trait-for-tuples",
|
"impl-trait-for-tuples",
|
||||||
"lru",
|
"lru",
|
||||||
"parity-util-mem-derive",
|
"parity-util-mem-derive",
|
||||||
"parking_lot 0.10.2",
|
"parking_lot 0.10.2",
|
||||||
"primitive-types",
|
"primitive-types 0.7.2",
|
||||||
"smallvec 1.6.1",
|
"smallvec 1.6.1",
|
||||||
"winapi 0.3.8",
|
"winapi 0.3.8",
|
||||||
]
|
]
|
||||||
@ -3385,7 +3433,7 @@ name = "patricia-trie-ethereum"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"elastic-array",
|
"elastic-array",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"hash-db 0.11.0",
|
"hash-db 0.11.0",
|
||||||
"journaldb",
|
"journaldb",
|
||||||
"keccak-hash",
|
"keccak-hash",
|
||||||
@ -3517,16 +3565,29 @@ dependencies = [
|
|||||||
"smallvec 0.6.13",
|
"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]]
|
[[package]]
|
||||||
name = "primitive-types"
|
name = "primitive-types"
|
||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c55c21c64d0eaa4d7ed885d959ef2d62d9e488c27c0e02d9aa5ce6c877b7d5f8"
|
checksum = "c55c21c64d0eaa4d7ed885d959ef2d62d9e488c27c0e02d9aa5ce6c877b7d5f8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fixed-hash",
|
"fixed-hash 0.6.1",
|
||||||
"impl-codec",
|
"impl-codec",
|
||||||
"impl-rlp",
|
"impl-rlp",
|
||||||
"impl-serde",
|
"impl-serde 0.3.1",
|
||||||
"uint",
|
"uint",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4297,7 +4358,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"crunchy 0.2.2",
|
"crunchy 0.2.2",
|
||||||
"rustc-hex 2.1.0",
|
"rustc-hex 2.1.0",
|
||||||
"static_assertions",
|
"static_assertions 1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4373,6 +4434,12 @@ version = "1.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_assertions"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "static_assertions"
|
name = "static_assertions"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -4945,17 +5012,6 @@ dependencies = [
|
|||||||
"log",
|
"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]]
|
[[package]]
|
||||||
name = "transient-hashmap"
|
name = "transient-hashmap"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@ -4998,7 +5054,7 @@ dependencies = [
|
|||||||
name = "triehash-ethereum"
|
name = "triehash-ethereum"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"keccak-hasher 0.1.1",
|
"keccak-hasher 0.1.1",
|
||||||
"triehash",
|
"triehash",
|
||||||
]
|
]
|
||||||
@ -5015,6 +5071,16 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
|
checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "txpool"
|
||||||
|
version = "1.0.0-alpha"
|
||||||
|
dependencies = [
|
||||||
|
"ethereum-types 0.7.0",
|
||||||
|
"log",
|
||||||
|
"smallvec 0.6.13",
|
||||||
|
"trace-time",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.11.2"
|
version = "1.11.2"
|
||||||
@ -5036,7 +5102,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"crunchy 0.2.2",
|
"crunchy 0.2.2",
|
||||||
"rustc-hex 2.1.0",
|
"rustc-hex 2.1.0",
|
||||||
"static_assertions",
|
"static_assertions 1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5188,7 +5254,7 @@ checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
|||||||
name = "vm"
|
name = "vm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"ethjson",
|
"ethjson",
|
||||||
"keccak-hash",
|
"keccak-hash",
|
||||||
"parity-bytes",
|
"parity-bytes",
|
||||||
@ -5247,7 +5313,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"ethereum-types",
|
"ethereum-types 0.9.2",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"parity-wasm",
|
"parity-wasm",
|
||||||
|
@ -640,9 +640,10 @@ impl Configuration {
|
|||||||
|
|
||||||
fn pool_verification_options(&self) -> Result<pool::verifier::Options, String> {
|
fn pool_verification_options(&self) -> Result<pool::verifier::Options, String> {
|
||||||
Ok(pool::verifier::Options {
|
Ok(pool::verifier::Options {
|
||||||
// NOTE min_gas_price and block_gas_limit will be overwritten right after start.
|
// NOTE min_gas_price,block_gas_limit and block_base_fee will be overwritten right after start.
|
||||||
minimal_gas_price: U256::from(20_000_000) * 1_000u32,
|
minimal_gas_price: U256::from(20_000_000) * 1_000u32,
|
||||||
block_gas_limit: U256::max_value(),
|
block_gas_limit: U256::max_value(),
|
||||||
|
block_base_fee: None,
|
||||||
tx_gas_limit: match self.args.arg_tx_gas_limit {
|
tx_gas_limit: match self.args.arg_tx_gas_limit {
|
||||||
Some(ref d) => to_u256(d)?,
|
Some(ref d) => to_u256(d)?,
|
||||||
None => U256::max_value(),
|
None => U256::max_value(),
|
||||||
|
@ -254,6 +254,7 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<RunningClient
|
|||||||
_ => sync::WarpSync::Disabled,
|
_ => sync::WarpSync::Disabled,
|
||||||
};
|
};
|
||||||
sync_config.download_old_blocks = cmd.download_old_blocks;
|
sync_config.download_old_blocks = cmd.download_old_blocks;
|
||||||
|
sync_config.eip1559_transition = spec.params().eip1559_transition;
|
||||||
|
|
||||||
let passwords = passwords_from_files(&cmd.acc_conf.password_files)?;
|
let passwords = passwords_from_files(&cmd.acc_conf.password_files)?;
|
||||||
|
|
||||||
@ -365,8 +366,11 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<RunningClient
|
|||||||
|
|
||||||
// take handle to client
|
// take handle to client
|
||||||
let client = service.client();
|
let client = service.client();
|
||||||
// Update miners block gas limit
|
// Update miners block gas limit and base_fee
|
||||||
miner.update_transaction_queue_limits(*client.best_block_header().gas_limit());
|
let base_fee = client
|
||||||
|
.engine()
|
||||||
|
.calculate_base_fee(&client.best_block_header());
|
||||||
|
miner.update_transaction_queue_limits(*client.best_block_header().gas_limit(), base_fee);
|
||||||
|
|
||||||
let connection_filter = connection_filter_address.map(|a| {
|
let connection_filter = connection_filter_address.map(|a| {
|
||||||
Arc::new(NodeFilter::new(
|
Arc::new(NodeFilter::new(
|
||||||
|
@ -36,7 +36,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
trace-time = "0.1"
|
trace-time = "0.1"
|
||||||
transaction-pool = "2.0.1"
|
txpool = { path = "../../transaction-pool" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.5"
|
env_logger = "0.5"
|
||||||
|
@ -35,7 +35,7 @@ extern crate parking_lot;
|
|||||||
#[cfg(feature = "price-info")]
|
#[cfg(feature = "price-info")]
|
||||||
extern crate price_info;
|
extern crate price_info;
|
||||||
extern crate rlp;
|
extern crate rlp;
|
||||||
extern crate transaction_pool as txpool;
|
extern crate txpool;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate ethabi_contract;
|
extern crate ethabi_contract;
|
||||||
|
@ -71,6 +71,9 @@ pub struct PendingSettings {
|
|||||||
pub max_len: usize,
|
pub max_len: usize,
|
||||||
/// Ordering of transactions.
|
/// Ordering of transactions.
|
||||||
pub ordering: PendingOrdering,
|
pub ordering: PendingOrdering,
|
||||||
|
/// Value of score that is a boundary between includable and non-includable transactions
|
||||||
|
/// Before EIP1559 it should be equal to zero, after EIP1559 it should be equal to block_base_fee
|
||||||
|
pub includable_boundary: U256,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PendingSettings {
|
impl PendingSettings {
|
||||||
@ -82,6 +85,7 @@ impl PendingSettings {
|
|||||||
nonce_cap: None,
|
nonce_cap: None,
|
||||||
max_len: usize::max_value(),
|
max_len: usize::max_value(),
|
||||||
ordering: PendingOrdering::Priority,
|
ordering: PendingOrdering::Priority,
|
||||||
|
includable_boundary: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,7 +122,7 @@ pub trait ScoredTransaction {
|
|||||||
fn priority(&self) -> Priority;
|
fn priority(&self) -> Priority;
|
||||||
|
|
||||||
/// Gets transaction gas price.
|
/// Gets transaction gas price.
|
||||||
fn gas_price(&self) -> &U256;
|
fn effective_gas_price(&self, block_base_fee: Option<U256>) -> U256;
|
||||||
|
|
||||||
/// Gets transaction nonce.
|
/// Gets transaction nonce.
|
||||||
fn nonce(&self) -> U256;
|
fn nonce(&self) -> U256;
|
||||||
@ -191,9 +195,8 @@ impl ScoredTransaction for VerifiedTransaction {
|
|||||||
self.priority
|
self.priority
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets transaction gas price.
|
fn effective_gas_price(&self, block_base_fee: Option<U256>) -> U256 {
|
||||||
fn gas_price(&self) -> &U256 {
|
self.transaction.effective_gas_price(block_base_fee)
|
||||||
&self.transaction.tx().gas_price
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets transaction nonce.
|
/// Gets transaction nonce.
|
||||||
|
@ -26,6 +26,7 @@ use std::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use self::scoring::ScoringEvent;
|
||||||
use ethereum_types::{Address, H256, U256};
|
use ethereum_types::{Address, H256, U256};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use txpool::{self, Verifier};
|
use txpool::{self, Verifier};
|
||||||
@ -245,7 +246,10 @@ impl TransactionQueue {
|
|||||||
insertion_id: Default::default(),
|
insertion_id: Default::default(),
|
||||||
pool: RwLock::new(txpool::Pool::new(
|
pool: RwLock::new(txpool::Pool::new(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
scoring::NonceAndGasPrice(strategy),
|
scoring::NonceAndGasPrice {
|
||||||
|
strategy,
|
||||||
|
block_base_fee: verification_options.block_base_fee,
|
||||||
|
},
|
||||||
limits,
|
limits,
|
||||||
)),
|
)),
|
||||||
options: RwLock::new(verification_options),
|
options: RwLock::new(verification_options),
|
||||||
@ -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
|
/// Update verification options
|
||||||
///
|
///
|
||||||
/// Some parameters of verification may vary in time (like block gas limit or minimal gas price).
|
/// Some parameters of verification may vary in time (like block gas limit or minimal gas price).
|
||||||
@ -307,8 +331,11 @@ impl TransactionQueue {
|
|||||||
transaction_to_replace,
|
transaction_to_replace,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut replace =
|
let mut replace = replace::ReplaceByScoreAndReadiness::new(
|
||||||
replace::ReplaceByScoreAndReadiness::new(self.pool.read().scoring().clone(), client);
|
self.pool.read().scoring().clone(),
|
||||||
|
client,
|
||||||
|
self.options.read().block_base_fee,
|
||||||
|
);
|
||||||
|
|
||||||
let results = transactions
|
let results = transactions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -353,7 +380,10 @@ impl TransactionQueue {
|
|||||||
/// Returns all transactions in the queue without explicit ordering.
|
/// Returns all transactions in the queue without explicit ordering.
|
||||||
pub fn all_transactions(&self) -> Vec<Arc<pool::VerifiedTransaction>> {
|
pub fn all_transactions(&self) -> Vec<Arc<pool::VerifiedTransaction>> {
|
||||||
let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready;
|
let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready;
|
||||||
self.pool.read().unordered_pending(ready).collect()
|
self.pool
|
||||||
|
.read()
|
||||||
|
.unordered_pending(ready, Default::default())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all transaction hashes in the queue without explicit ordering.
|
/// Returns all transaction hashes in the queue without explicit ordering.
|
||||||
@ -361,7 +391,7 @@ impl TransactionQueue {
|
|||||||
let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready;
|
let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready;
|
||||||
self.pool
|
self.pool
|
||||||
.read()
|
.read()
|
||||||
.unordered_pending(ready)
|
.unordered_pending(ready, Default::default())
|
||||||
.map(|tx| tx.hash)
|
.map(|tx| tx.hash)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -376,7 +406,7 @@ impl TransactionQueue {
|
|||||||
let ready = ready::OptionalState::new(nonce);
|
let ready = ready::OptionalState::new(nonce);
|
||||||
self.pool
|
self.pool
|
||||||
.read()
|
.read()
|
||||||
.unordered_pending(ready)
|
.unordered_pending(ready, Default::default())
|
||||||
.map(|tx| tx.hash)
|
.map(|tx| tx.hash)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -400,6 +430,7 @@ impl TransactionQueue {
|
|||||||
nonce_cap,
|
nonce_cap,
|
||||||
max_len,
|
max_len,
|
||||||
ordering,
|
ordering,
|
||||||
|
includable_boundary,
|
||||||
} = settings;
|
} = settings;
|
||||||
if let Some(pending) = self.cached_pending.read().pending(
|
if let Some(pending) = self.cached_pending.read().pending(
|
||||||
block_number,
|
block_number,
|
||||||
@ -425,15 +456,19 @@ impl TransactionQueue {
|
|||||||
return self
|
return self
|
||||||
.pool
|
.pool
|
||||||
.read()
|
.read()
|
||||||
.unordered_pending(ready)
|
.unordered_pending(ready, includable_boundary)
|
||||||
.take(max_len)
|
.take(max_len)
|
||||||
.collect();
|
.collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
let pending: Vec<_> =
|
let pending: Vec<_> = self.collect_pending(
|
||||||
self.collect_pending(client, block_number, current_timestamp, nonce_cap, |i| {
|
client,
|
||||||
i.take(max_len).collect()
|
includable_boundary,
|
||||||
});
|
block_number,
|
||||||
|
current_timestamp,
|
||||||
|
nonce_cap,
|
||||||
|
|i| i.take(max_len).collect(),
|
||||||
|
);
|
||||||
|
|
||||||
*cached_pending = CachedPending {
|
*cached_pending = CachedPending {
|
||||||
block_number,
|
block_number,
|
||||||
@ -461,6 +496,7 @@ impl TransactionQueue {
|
|||||||
{
|
{
|
||||||
self.collect_pending(
|
self.collect_pending(
|
||||||
client,
|
client,
|
||||||
|
settings.includable_boundary,
|
||||||
settings.block_number,
|
settings.block_number,
|
||||||
settings.current_timestamp,
|
settings.current_timestamp,
|
||||||
settings.nonce_cap,
|
settings.nonce_cap,
|
||||||
@ -479,6 +515,7 @@ impl TransactionQueue {
|
|||||||
pub fn collect_pending<C, F, T>(
|
pub fn collect_pending<C, F, T>(
|
||||||
&self,
|
&self,
|
||||||
client: C,
|
client: C,
|
||||||
|
includable_boundary: U256,
|
||||||
block_number: u64,
|
block_number: u64,
|
||||||
current_timestamp: u64,
|
current_timestamp: u64,
|
||||||
nonce_cap: Option<U256>,
|
nonce_cap: Option<U256>,
|
||||||
@ -498,7 +535,7 @@ impl TransactionQueue {
|
|||||||
debug!(target: "txqueue", "Re-computing pending set for block: {}", block_number);
|
debug!(target: "txqueue", "Re-computing pending set for block: {}", block_number);
|
||||||
trace_time!("pool::collect_pending");
|
trace_time!("pool::collect_pending");
|
||||||
let ready = Self::ready(client, block_number, current_timestamp, nonce_cap);
|
let ready = Self::ready(client, block_number, current_timestamp, nonce_cap);
|
||||||
collect(self.pool.read().pending(ready))
|
collect(self.pool.read().pending(ready, includable_boundary))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ready<C>(
|
fn ready<C>(
|
||||||
@ -563,7 +600,7 @@ impl TransactionQueue {
|
|||||||
|
|
||||||
self.pool
|
self.pool
|
||||||
.read()
|
.read()
|
||||||
.pending_from_sender(state_readiness, address)
|
.pending_from_sender(state_readiness, address, Default::default())
|
||||||
.last()
|
.last()
|
||||||
.map(|tx| tx.signed().tx().nonce.saturating_add(U256::from(1)))
|
.map(|tx| tx.signed().tx().nonce.saturating_add(U256::from(1)))
|
||||||
}
|
}
|
||||||
@ -612,7 +649,7 @@ impl TransactionQueue {
|
|||||||
pub fn penalize<'a, T: IntoIterator<Item = &'a Address>>(&self, senders: T) {
|
pub fn penalize<'a, T: IntoIterator<Item = &'a Address>>(&self, senders: T) {
|
||||||
let mut pool = self.pool.write();
|
let mut pool = self.pool.write();
|
||||||
for sender in senders {
|
for sender in senders {
|
||||||
pool.update_scores(sender, ());
|
pool.update_scores(sender, ScoringEvent::Penalize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,12 +39,18 @@ use txpool::{
|
|||||||
pub struct ReplaceByScoreAndReadiness<S, C> {
|
pub struct ReplaceByScoreAndReadiness<S, C> {
|
||||||
scoring: S,
|
scoring: S,
|
||||||
client: C,
|
client: C,
|
||||||
|
/// Block base fee of the latest block, exists if the EIP 1559 is activated
|
||||||
|
block_base_fee: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, C> ReplaceByScoreAndReadiness<S, C> {
|
impl<S, C> ReplaceByScoreAndReadiness<S, C> {
|
||||||
/// Create a new `ReplaceByScoreAndReadiness`
|
/// Create a new `ReplaceByScoreAndReadiness`
|
||||||
pub fn new(scoring: S, client: C) -> Self {
|
pub fn new(scoring: S, client: C, block_base_fee: Option<U256>) -> Self {
|
||||||
ReplaceByScoreAndReadiness { scoring, client }
|
ReplaceByScoreAndReadiness {
|
||||||
|
scoring,
|
||||||
|
client,
|
||||||
|
block_base_fee,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,8 +73,9 @@ where
|
|||||||
} else if both_local {
|
} else if both_local {
|
||||||
Choice::InsertNew
|
Choice::InsertNew
|
||||||
} else {
|
} else {
|
||||||
let old_score = (old.priority(), old.gas_price());
|
let old_score = (old.priority(), old.effective_gas_price(self.block_base_fee));
|
||||||
let new_score = (new.priority(), new.gas_price());
|
let new_score = (new.priority(), new.effective_gas_price(self.block_base_fee));
|
||||||
|
|
||||||
if new_score > old_score {
|
if new_score > old_score {
|
||||||
// Check if this is a replacement transaction.
|
// Check if this is a replacement transaction.
|
||||||
//
|
//
|
||||||
@ -155,9 +162,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_always_accept_local_transactions_unless_same_sender_and_nonce() {
|
fn should_always_accept_local_transactions_unless_same_sender_and_nonce() {
|
||||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
let scoring = NonceAndGasPrice {
|
||||||
|
strategy: PrioritizationStrategy::GasPriceOnly,
|
||||||
|
block_base_fee: None,
|
||||||
|
};
|
||||||
let client = TestClient::new().with_nonce(1);
|
let client = TestClient::new().with_nonce(1);
|
||||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
|
||||||
|
|
||||||
// same sender txs
|
// same sender txs
|
||||||
let keypair = Random.generate();
|
let keypair = Random.generate();
|
||||||
@ -249,9 +259,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_replace_same_sender_by_nonce() {
|
fn should_replace_same_sender_by_nonce() {
|
||||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
let scoring = NonceAndGasPrice {
|
||||||
|
strategy: PrioritizationStrategy::GasPriceOnly,
|
||||||
|
block_base_fee: None,
|
||||||
|
};
|
||||||
let client = TestClient::new().with_nonce(1);
|
let client = TestClient::new().with_nonce(1);
|
||||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
|
||||||
|
|
||||||
let tx1 = Tx {
|
let tx1 = Tx {
|
||||||
nonce: 1,
|
nonce: 1,
|
||||||
@ -311,9 +324,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_replace_different_sender_by_priority_and_gas_price() {
|
fn should_replace_different_sender_by_priority_and_gas_price() {
|
||||||
// given
|
// given
|
||||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
let scoring = NonceAndGasPrice {
|
||||||
|
strategy: PrioritizationStrategy::GasPriceOnly,
|
||||||
|
block_base_fee: None,
|
||||||
|
};
|
||||||
let client = TestClient::new().with_nonce(0);
|
let client = TestClient::new().with_nonce(0);
|
||||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
|
||||||
|
|
||||||
let tx_regular_low_gas = {
|
let tx_regular_low_gas = {
|
||||||
let tx = Tx {
|
let tx = Tx {
|
||||||
@ -406,9 +422,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_replace_ready_transaction_with_future_transaction() {
|
fn should_not_replace_ready_transaction_with_future_transaction() {
|
||||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
let scoring = NonceAndGasPrice {
|
||||||
|
strategy: PrioritizationStrategy::GasPriceOnly,
|
||||||
|
block_base_fee: None,
|
||||||
|
};
|
||||||
let client = TestClient::new().with_nonce(1);
|
let client = TestClient::new().with_nonce(1);
|
||||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
|
||||||
|
|
||||||
let tx_ready_low_score = {
|
let tx_ready_low_score = {
|
||||||
let tx = Tx {
|
let tx = Tx {
|
||||||
@ -436,9 +455,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_compute_readiness_with_pooled_transactions_from_the_same_sender_as_the_existing_transaction(
|
fn should_compute_readiness_with_pooled_transactions_from_the_same_sender_as_the_existing_transaction(
|
||||||
) {
|
) {
|
||||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
let scoring = NonceAndGasPrice {
|
||||||
|
strategy: PrioritizationStrategy::GasPriceOnly,
|
||||||
|
block_base_fee: None,
|
||||||
|
};
|
||||||
let client = TestClient::new().with_nonce(1);
|
let client = TestClient::new().with_nonce(1);
|
||||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
|
||||||
|
|
||||||
let old_sender = Random.generate();
|
let old_sender = Random.generate();
|
||||||
let tx_old_ready_1 = {
|
let tx_old_ready_1 = {
|
||||||
@ -504,9 +526,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_compute_readiness_with_pooled_transactions_from_the_same_sender_as_the_new_transaction(
|
fn should_compute_readiness_with_pooled_transactions_from_the_same_sender_as_the_new_transaction(
|
||||||
) {
|
) {
|
||||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
let scoring = NonceAndGasPrice {
|
||||||
|
strategy: PrioritizationStrategy::GasPriceOnly,
|
||||||
|
block_base_fee: None,
|
||||||
|
};
|
||||||
let client = TestClient::new().with_nonce(1);
|
let client = TestClient::new().with_nonce(1);
|
||||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
|
||||||
|
|
||||||
// current transaction is ready but has a lower gas price than the new one
|
// current transaction is ready but has a lower gas price than the new one
|
||||||
let old_tx = {
|
let old_tx = {
|
||||||
@ -572,9 +597,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_accept_local_tx_with_same_sender_and_nonce_with_better_gas_price() {
|
fn should_accept_local_tx_with_same_sender_and_nonce_with_better_gas_price() {
|
||||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
let scoring = NonceAndGasPrice {
|
||||||
|
strategy: PrioritizationStrategy::GasPriceOnly,
|
||||||
|
block_base_fee: None,
|
||||||
|
};
|
||||||
let client = TestClient::new().with_nonce(1);
|
let client = TestClient::new().with_nonce(1);
|
||||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
|
||||||
|
|
||||||
// current transaction is ready
|
// current transaction is ready
|
||||||
let old_tx = {
|
let old_tx = {
|
||||||
@ -627,9 +655,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_reject_local_tx_with_same_sender_and_nonce_with_worse_gas_price() {
|
fn should_reject_local_tx_with_same_sender_and_nonce_with_worse_gas_price() {
|
||||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
let scoring = NonceAndGasPrice {
|
||||||
|
strategy: PrioritizationStrategy::GasPriceOnly,
|
||||||
|
block_base_fee: None,
|
||||||
|
};
|
||||||
let client = TestClient::new().with_nonce(1);
|
let client = TestClient::new().with_nonce(1);
|
||||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
|
||||||
|
|
||||||
// current transaction is ready
|
// current transaction is ready
|
||||||
let old_tx = {
|
let old_tx = {
|
||||||
|
@ -42,13 +42,25 @@ const GAS_PRICE_BUMP_SHIFT: usize = 3; // 2 = 25%, 3 = 12.5%, 4 = 6.25%
|
|||||||
fn bump_gas_price(old_gp: U256) -> U256 {
|
fn bump_gas_price(old_gp: U256) -> U256 {
|
||||||
old_gp.saturating_add(old_gp >> GAS_PRICE_BUMP_SHIFT)
|
old_gp.saturating_add(old_gp >> GAS_PRICE_BUMP_SHIFT)
|
||||||
}
|
}
|
||||||
|
/// List of events that trigger updating of scores
|
||||||
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
|
pub enum ScoringEvent {
|
||||||
|
/// Penalize transactions
|
||||||
|
Penalize,
|
||||||
|
/// Every time new block is added to blockchain, block base fee is changed and triggers score change.
|
||||||
|
BlockBaseFeeChanged,
|
||||||
|
}
|
||||||
/// Simple, gas-price based scoring for transactions.
|
/// Simple, gas-price based scoring for transactions.
|
||||||
///
|
///
|
||||||
/// NOTE: Currently penalization does not apply to new transactions that enter the pool.
|
/// NOTE: Currently penalization does not apply to new transactions that enter the pool.
|
||||||
/// We might want to store penalization status in some persistent state.
|
/// We might want to store penalization status in some persistent state.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NonceAndGasPrice(pub PrioritizationStrategy);
|
pub struct NonceAndGasPrice {
|
||||||
|
/// Strategy for prioritization
|
||||||
|
pub strategy: PrioritizationStrategy,
|
||||||
|
/// Block base fee. Exists if the EIP 1559 is activated.
|
||||||
|
pub block_base_fee: Option<U256>,
|
||||||
|
}
|
||||||
|
|
||||||
impl NonceAndGasPrice {
|
impl NonceAndGasPrice {
|
||||||
/// Decide if the transaction should even be considered into the pool (if the pool is full).
|
/// Decide if the transaction should even be considered into the pool (if the pool is full).
|
||||||
@ -67,7 +79,7 @@ impl NonceAndGasPrice {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
&old.transaction.tx().gas_price > new.gas_price()
|
old.effective_gas_price(self.block_base_fee) > new.effective_gas_price(self.block_base_fee)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +88,7 @@ where
|
|||||||
P: ScoredTransaction + txpool::VerifiedTransaction,
|
P: ScoredTransaction + txpool::VerifiedTransaction,
|
||||||
{
|
{
|
||||||
type Score = U256;
|
type Score = U256;
|
||||||
type Event = ();
|
type Event = ScoringEvent;
|
||||||
|
|
||||||
fn compare(&self, old: &P, other: &P) -> cmp::Ordering {
|
fn compare(&self, old: &P, other: &P) -> cmp::Ordering {
|
||||||
old.nonce().cmp(&other.nonce())
|
old.nonce().cmp(&other.nonce())
|
||||||
@ -87,10 +99,10 @@ where
|
|||||||
return scoring::Choice::InsertNew;
|
return scoring::Choice::InsertNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_gp = old.gas_price();
|
let old_gp = old.effective_gas_price(self.block_base_fee);
|
||||||
let new_gp = new.gas_price();
|
let new_gp = new.effective_gas_price(self.block_base_fee);
|
||||||
|
|
||||||
let min_required_gp = bump_gas_price(*old_gp);
|
let min_required_gp = bump_gas_price(old_gp);
|
||||||
|
|
||||||
match min_required_gp.cmp(&new_gp) {
|
match min_required_gp.cmp(&new_gp) {
|
||||||
cmp::Ordering::Greater => scoring::Choice::RejectNew,
|
cmp::Ordering::Greater => scoring::Choice::RejectNew,
|
||||||
@ -102,7 +114,7 @@ where
|
|||||||
&self,
|
&self,
|
||||||
txs: &[txpool::Transaction<P>],
|
txs: &[txpool::Transaction<P>],
|
||||||
scores: &mut [U256],
|
scores: &mut [U256],
|
||||||
change: scoring::Change,
|
change: scoring::Change<ScoringEvent>,
|
||||||
) {
|
) {
|
||||||
use self::scoring::Change;
|
use self::scoring::Change;
|
||||||
|
|
||||||
@ -113,7 +125,7 @@ where
|
|||||||
assert!(i < txs.len());
|
assert!(i < txs.len());
|
||||||
assert!(i < scores.len());
|
assert!(i < scores.len());
|
||||||
|
|
||||||
scores[i] = *txs[i].transaction.gas_price();
|
scores[i] = txs[i].effective_gas_price(self.block_base_fee);
|
||||||
let boost = match txs[i].priority() {
|
let boost = match txs[i].priority() {
|
||||||
super::Priority::Local => 15,
|
super::Priority::Local => 15,
|
||||||
super::Priority::Retracted => 10,
|
super::Priority::Retracted => 10,
|
||||||
@ -123,11 +135,20 @@ where
|
|||||||
}
|
}
|
||||||
// We are only sending an event in case of penalization.
|
// We are only sending an event in case of penalization.
|
||||||
// So just lower the priority of all non-local transactions.
|
// So just lower the priority of all non-local transactions.
|
||||||
Change::Event(_) => {
|
Change::Event(event) => {
|
||||||
for (score, tx) in scores.iter_mut().zip(txs) {
|
match event {
|
||||||
// Never penalize local transactions.
|
ScoringEvent::Penalize => {
|
||||||
if !tx.priority().is_local() {
|
for (score, tx) in scores.iter_mut().zip(txs) {
|
||||||
*score = *score >> 3;
|
// Never penalize local transactions.
|
||||||
|
if !tx.priority().is_local() {
|
||||||
|
*score = *score >> 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ScoringEvent::BlockBaseFeeChanged => {
|
||||||
|
for i in 0..txs.len() {
|
||||||
|
scores[i] = txs[i].transaction.effective_gas_price(self.block_base_fee);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,7 +171,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_calculate_score_correctly() {
|
fn should_calculate_score_correctly() {
|
||||||
// given
|
// given
|
||||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
let scoring = NonceAndGasPrice {
|
||||||
|
strategy: PrioritizationStrategy::GasPriceOnly,
|
||||||
|
block_base_fee: None,
|
||||||
|
};
|
||||||
let (tx1, tx2, tx3) = Tx::default().signed_triple();
|
let (tx1, tx2, tx3) = Tx::default().signed_triple();
|
||||||
let transactions = vec![tx1, tx2, tx3]
|
let transactions = vec![tx1, tx2, tx3]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -200,7 +224,11 @@ mod tests {
|
|||||||
assert_eq!(scores, vec![32768.into(), 1024.into(), 1.into()]);
|
assert_eq!(scores, vec![32768.into(), 1024.into(), 1.into()]);
|
||||||
|
|
||||||
// Check penalization
|
// Check penalization
|
||||||
scoring.update_scores(&transactions, &mut *scores, scoring::Change::Event(()));
|
scoring.update_scores(
|
||||||
|
&transactions,
|
||||||
|
&mut *scores,
|
||||||
|
scoring::Change::Event(ScoringEvent::Penalize),
|
||||||
|
);
|
||||||
assert_eq!(scores, vec![32768.into(), 128.into(), 0.into()]);
|
assert_eq!(scores, vec![32768.into(), 128.into(), 0.into()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ fn new_queue() -> TransactionQueue {
|
|||||||
block_gas_limit: 1_000_000.into(),
|
block_gas_limit: 1_000_000.into(),
|
||||||
tx_gas_limit: 1_000_000.into(),
|
tx_gas_limit: 1_000_000.into(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
|
block_base_fee: None,
|
||||||
},
|
},
|
||||||
PrioritizationStrategy::GasPriceOnly,
|
PrioritizationStrategy::GasPriceOnly,
|
||||||
)
|
)
|
||||||
@ -64,6 +65,7 @@ fn should_return_correct_nonces_when_dropped_because_of_limit() {
|
|||||||
block_gas_limit: 1_000_000.into(),
|
block_gas_limit: 1_000_000.into(),
|
||||||
tx_gas_limit: 1_000_000.into(),
|
tx_gas_limit: 1_000_000.into(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
|
block_base_fee: None,
|
||||||
},
|
},
|
||||||
PrioritizationStrategy::GasPriceOnly,
|
PrioritizationStrategy::GasPriceOnly,
|
||||||
);
|
);
|
||||||
@ -124,6 +126,7 @@ fn should_never_drop_local_transactions_from_different_senders() {
|
|||||||
block_gas_limit: 1_000_000.into(),
|
block_gas_limit: 1_000_000.into(),
|
||||||
tx_gas_limit: 1_000_000.into(),
|
tx_gas_limit: 1_000_000.into(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
|
block_base_fee: None,
|
||||||
},
|
},
|
||||||
PrioritizationStrategy::GasPriceOnly,
|
PrioritizationStrategy::GasPriceOnly,
|
||||||
);
|
);
|
||||||
@ -541,6 +544,7 @@ fn should_prefer_current_transactions_when_hitting_the_limit() {
|
|||||||
block_gas_limit: 1_000_000.into(),
|
block_gas_limit: 1_000_000.into(),
|
||||||
tx_gas_limit: 1_000_000.into(),
|
tx_gas_limit: 1_000_000.into(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
|
block_base_fee: None,
|
||||||
},
|
},
|
||||||
PrioritizationStrategy::GasPriceOnly,
|
PrioritizationStrategy::GasPriceOnly,
|
||||||
);
|
);
|
||||||
@ -898,6 +902,7 @@ fn should_not_return_transactions_over_nonce_cap() {
|
|||||||
nonce_cap: Some(123.into()),
|
nonce_cap: Some(123.into()),
|
||||||
max_len: usize::max_value(),
|
max_len: usize::max_value(),
|
||||||
ordering: PendingOrdering::Priority,
|
ordering: PendingOrdering::Priority,
|
||||||
|
includable_boundary: Default::default(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -932,6 +937,7 @@ fn should_return_cached_pending_even_if_unordered_is_requested() {
|
|||||||
nonce_cap: None,
|
nonce_cap: None,
|
||||||
max_len: 3,
|
max_len: 3,
|
||||||
ordering: PendingOrdering::Unordered,
|
ordering: PendingOrdering::Unordered,
|
||||||
|
includable_boundary: Default::default(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -960,6 +966,7 @@ fn should_return_unordered_and_not_populate_the_cache() {
|
|||||||
nonce_cap: None,
|
nonce_cap: None,
|
||||||
max_len: usize::max_value(),
|
max_len: usize::max_value(),
|
||||||
ordering: PendingOrdering::Unordered,
|
ordering: PendingOrdering::Unordered,
|
||||||
|
includable_boundary: Default::default(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1035,6 +1042,7 @@ fn should_include_local_transaction_to_a_full_pool() {
|
|||||||
block_gas_limit: 1_000_000.into(),
|
block_gas_limit: 1_000_000.into(),
|
||||||
tx_gas_limit: 1_000_000.into(),
|
tx_gas_limit: 1_000_000.into(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
|
block_base_fee: None,
|
||||||
},
|
},
|
||||||
PrioritizationStrategy::GasPriceOnly,
|
PrioritizationStrategy::GasPriceOnly,
|
||||||
);
|
);
|
||||||
@ -1067,6 +1075,7 @@ fn should_avoid_verifying_transaction_already_in_pool() {
|
|||||||
block_gas_limit: 1_000_000.into(),
|
block_gas_limit: 1_000_000.into(),
|
||||||
tx_gas_limit: 1_000_000.into(),
|
tx_gas_limit: 1_000_000.into(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
|
block_base_fee: None,
|
||||||
},
|
},
|
||||||
PrioritizationStrategy::GasPriceOnly,
|
PrioritizationStrategy::GasPriceOnly,
|
||||||
);
|
);
|
||||||
@ -1102,6 +1111,7 @@ fn should_avoid_reverifying_recently_rejected_transactions() {
|
|||||||
block_gas_limit: 1_000_000.into(),
|
block_gas_limit: 1_000_000.into(),
|
||||||
tx_gas_limit: 1_000_000.into(),
|
tx_gas_limit: 1_000_000.into(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
|
block_base_fee: None,
|
||||||
},
|
},
|
||||||
PrioritizationStrategy::GasPriceOnly,
|
PrioritizationStrategy::GasPriceOnly,
|
||||||
);
|
);
|
||||||
@ -1150,6 +1160,7 @@ fn should_reject_early_in_case_gas_price_is_less_than_min_effective() {
|
|||||||
block_gas_limit: 1_000_000.into(),
|
block_gas_limit: 1_000_000.into(),
|
||||||
tx_gas_limit: 1_000_000.into(),
|
tx_gas_limit: 1_000_000.into(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
|
block_base_fee: None,
|
||||||
},
|
},
|
||||||
PrioritizationStrategy::GasPriceOnly,
|
PrioritizationStrategy::GasPriceOnly,
|
||||||
);
|
);
|
||||||
@ -1192,6 +1203,7 @@ fn should_not_reject_early_in_case_gas_price_is_less_than_min_effective() {
|
|||||||
block_gas_limit: 1_000_000.into(),
|
block_gas_limit: 1_000_000.into(),
|
||||||
tx_gas_limit: 1_000_000.into(),
|
tx_gas_limit: 1_000_000.into(),
|
||||||
no_early_reject: true,
|
no_early_reject: true,
|
||||||
|
block_base_fee: None,
|
||||||
},
|
},
|
||||||
PrioritizationStrategy::GasPriceOnly,
|
PrioritizationStrategy::GasPriceOnly,
|
||||||
);
|
);
|
||||||
|
@ -46,6 +46,8 @@ pub struct Options {
|
|||||||
pub minimal_gas_price: U256,
|
pub minimal_gas_price: U256,
|
||||||
/// Current block gas limit.
|
/// Current block gas limit.
|
||||||
pub block_gas_limit: U256,
|
pub block_gas_limit: U256,
|
||||||
|
/// Block base fee. Exists if the EIP 1559 is activated.
|
||||||
|
pub block_base_fee: Option<U256>,
|
||||||
/// Maximal gas limit for a single transaction.
|
/// Maximal gas limit for a single transaction.
|
||||||
pub tx_gas_limit: U256,
|
pub tx_gas_limit: U256,
|
||||||
/// Skip checks for early rejection, to make sure that local transactions are always imported.
|
/// Skip checks for early rejection, to make sure that local transactions are always imported.
|
||||||
@ -58,6 +60,7 @@ impl Default for Options {
|
|||||||
Options {
|
Options {
|
||||||
minimal_gas_price: 0.into(),
|
minimal_gas_price: 0.into(),
|
||||||
block_gas_limit: U256::max_value(),
|
block_gas_limit: U256::max_value(),
|
||||||
|
block_base_fee: None,
|
||||||
tx_gas_limit: U256::max_value(),
|
tx_gas_limit: U256::max_value(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
}
|
}
|
||||||
@ -93,7 +96,7 @@ impl Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return transaction gas price
|
/// Return transaction gas price for non 1559 transactions or maxFeePerGas for 1559 transactions.
|
||||||
pub fn gas_price(&self) -> &U256 {
|
pub fn gas_price(&self) -> &U256 {
|
||||||
match *self {
|
match *self {
|
||||||
Transaction::Unverified(ref tx) => &tx.tx().gas_price,
|
Transaction::Unverified(ref tx) => &tx.tx().gas_price,
|
||||||
@ -110,6 +113,15 @@ 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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn transaction(&self) -> &transaction::TypedTransaction {
|
fn transaction(&self) -> &transaction::TypedTransaction {
|
||||||
match *self {
|
match *self {
|
||||||
Transaction::Unverified(ref tx) => &*tx,
|
Transaction::Unverified(ref tx) => &*tx,
|
||||||
@ -213,22 +225,24 @@ impl<C: Client> txpool::Verifier<Transaction>
|
|||||||
}
|
}
|
||||||
|
|
||||||
let is_own = tx.is_local();
|
let is_own = tx.is_local();
|
||||||
|
let gas_price = tx.effective_gas_price(self.options.block_base_fee);
|
||||||
// Quick exit for non-service and non-local transactions
|
// Quick exit for non-service and non-local transactions
|
||||||
//
|
//
|
||||||
// We're checking if the transaction is below configured minimal gas price
|
// We're checking if the transaction is below configured minimal gas price
|
||||||
// or the effective minimal gas price in case the pool is full.
|
// or the effective minimal gas price in case the pool is full.
|
||||||
if !tx.gas_price().is_zero() && !is_own {
|
|
||||||
if tx.gas_price() < &self.options.minimal_gas_price {
|
if !gas_price.is_zero() && !is_own {
|
||||||
|
if gas_price < self.options.minimal_gas_price {
|
||||||
trace!(
|
trace!(
|
||||||
target: "txqueue",
|
target: "txqueue",
|
||||||
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
|
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
|
||||||
hash,
|
hash,
|
||||||
tx.gas_price(),
|
gas_price,
|
||||||
self.options.minimal_gas_price,
|
self.options.minimal_gas_price,
|
||||||
);
|
);
|
||||||
bail!(transaction::Error::InsufficientGasPrice {
|
bail!(transaction::Error::InsufficientGasPrice {
|
||||||
minimal: self.options.minimal_gas_price,
|
minimal: self.options.minimal_gas_price,
|
||||||
got: *tx.gas_price(),
|
got: gas_price,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,12 +252,15 @@ impl<C: Client> txpool::Verifier<Transaction>
|
|||||||
target: "txqueue",
|
target: "txqueue",
|
||||||
"[{:?}] Rejected tx early, cause it doesn't have any chance to get to the pool: (gas price: {} < {})",
|
"[{:?}] Rejected tx early, cause it doesn't have any chance to get to the pool: (gas price: {} < {})",
|
||||||
hash,
|
hash,
|
||||||
tx.gas_price(),
|
gas_price,
|
||||||
vtx.transaction.tx().gas_price,
|
vtx.transaction.effective_gas_price(self.options.block_base_fee),
|
||||||
);
|
);
|
||||||
return Err(transaction::Error::TooCheapToReplace {
|
return Err(transaction::Error::TooCheapToReplace {
|
||||||
prev: Some(vtx.transaction.tx().gas_price),
|
prev: Some(
|
||||||
new: Some(*tx.gas_price()),
|
vtx.transaction
|
||||||
|
.effective_gas_price(self.options.block_base_fee),
|
||||||
|
),
|
||||||
|
new: Some(gas_price),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,7 +297,9 @@ impl<C: Client> txpool::Verifier<Transaction>
|
|||||||
let sender = transaction.sender();
|
let sender = transaction.sender();
|
||||||
let account_details = self.client.account_details(&sender);
|
let account_details = self.client.account_details(&sender);
|
||||||
|
|
||||||
if transaction.tx().gas_price < self.options.minimal_gas_price {
|
let gas_price = transaction.tx().gas_price;
|
||||||
|
|
||||||
|
if gas_price < self.options.minimal_gas_price {
|
||||||
let transaction_type = self.client.transaction_type(&transaction);
|
let transaction_type = self.client.transaction_type(&transaction);
|
||||||
if let TransactionType::Service = transaction_type {
|
if let TransactionType::Service = transaction_type {
|
||||||
debug!(target: "txqueue", "Service tx {:?} below minimal gas price accepted", hash);
|
debug!(target: "txqueue", "Service tx {:?} below minimal gas price accepted", hash);
|
||||||
@ -291,20 +310,24 @@ impl<C: Client> txpool::Verifier<Transaction>
|
|||||||
target: "txqueue",
|
target: "txqueue",
|
||||||
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
|
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
|
||||||
hash,
|
hash,
|
||||||
transaction.tx().gas_price,
|
gas_price,
|
||||||
self.options.minimal_gas_price,
|
self.options.minimal_gas_price,
|
||||||
);
|
);
|
||||||
bail!(transaction::Error::InsufficientGasPrice {
|
bail!(transaction::Error::InsufficientGasPrice {
|
||||||
minimal: self.options.minimal_gas_price,
|
minimal: self.options.minimal_gas_price,
|
||||||
got: transaction.tx().gas_price,
|
got: gas_price,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (full_gas_price, overflow_1) = transaction
|
if gas_price < transaction.max_priority_fee_per_gas() {
|
||||||
.tx()
|
bail!(transaction::Error::InsufficientGasPrice {
|
||||||
.gas_price
|
minimal: transaction.max_priority_fee_per_gas(),
|
||||||
.overflowing_mul(transaction.tx().gas);
|
got: gas_price,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let (full_gas_price, overflow_1) = gas_price.overflowing_mul(transaction.tx().gas);
|
||||||
let (cost, overflow_2) = transaction.tx().value.overflowing_add(full_gas_price);
|
let (cost, overflow_2) = transaction.tx().value.overflowing_add(full_gas_price);
|
||||||
if overflow_1 || overflow_2 {
|
if overflow_1 || overflow_2 {
|
||||||
trace!(
|
trace!(
|
||||||
|
@ -153,8 +153,9 @@ pub trait BlockProvider {
|
|||||||
|
|
||||||
/// Get a list of uncles for a given block.
|
/// Get a list of uncles for a given block.
|
||||||
/// Returns None if block does not exist.
|
/// Returns None if block does not exist.
|
||||||
fn uncles(&self, hash: &H256) -> Option<Vec<Header>> {
|
fn uncles(&self, hash: &H256, eip1559_transition: BlockNumber) -> Option<Vec<Header>> {
|
||||||
self.block_body(hash).map(|body| body.uncles())
|
self.block_body(hash)
|
||||||
|
.map(|body| body.uncles(eip1559_transition))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a list of uncle hashes for a given block.
|
/// 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_hashes: RwLock<HashMap<BlockNumber, H256>>,
|
||||||
pending_block_details: RwLock<HashMap<H256, BlockDetails>>,
|
pending_block_details: RwLock<HashMap<H256, BlockDetails>>,
|
||||||
pending_transaction_addresses: RwLock<HashMap<H256, Option<TransactionAddress>>>,
|
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 {
|
impl BlockProvider for BlockChain {
|
||||||
@ -559,7 +563,7 @@ impl<'a> Iterator for AncestryWithMetadataIter<'a> {
|
|||||||
} else {
|
} else {
|
||||||
let details = self.chain.block_details(&self.current);
|
let details = self.chain.block_details(&self.current);
|
||||||
let header = self.chain.block_header_data(&self.current).map(|h| {
|
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")
|
.expect("Stored block header data is valid RLP; qed")
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -630,7 +634,12 @@ impl<'a> Iterator for EpochTransitionIter<'a> {
|
|||||||
|
|
||||||
impl BlockChain {
|
impl BlockChain {
|
||||||
/// Create new instance of blockchain from given Genesis.
|
/// 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
|
// 400 is the average size of the key
|
||||||
let cache_man = CacheManager::new(config.pref_cache_size, config.max_cache_size, 400);
|
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_hashes: RwLock::new(HashMap::new()),
|
||||||
pending_block_details: RwLock::new(HashMap::new()),
|
pending_block_details: RwLock::new(HashMap::new()),
|
||||||
pending_transaction_addresses: RwLock::new(HashMap::new()),
|
pending_transaction_addresses: RwLock::new(HashMap::new()),
|
||||||
|
eip1559_transition,
|
||||||
};
|
};
|
||||||
|
|
||||||
// load best block
|
// load best block
|
||||||
@ -715,7 +725,7 @@ impl BlockChain {
|
|||||||
let mut best_block = bc.best_block.write();
|
let mut best_block = bc.best_block.write();
|
||||||
*best_block = BestBlock {
|
*best_block = BestBlock {
|
||||||
total_difficulty: best_block_total_difficulty,
|
total_difficulty: best_block_total_difficulty,
|
||||||
header: best_block_rlp.decode_header(),
|
header: best_block_rlp.decode_header(eip1559_transition),
|
||||||
block: best_block_rlp,
|
block: best_block_rlp,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1044,7 +1054,7 @@ impl BlockChain {
|
|||||||
let mut best_block = self.best_block.write();
|
let mut best_block = self.best_block.write();
|
||||||
*best_block = BestBlock {
|
*best_block = BestBlock {
|
||||||
total_difficulty: best_block_total_difficulty,
|
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,
|
block: best_block_rlp,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1463,7 +1473,7 @@ impl BlockChain {
|
|||||||
batch.put(db::COL_EXTRA, b"best", update.info.hash.as_bytes());
|
batch.put(db::COL_EXTRA, b"best", update.info.hash.as_bytes());
|
||||||
*best_block = Some(BestBlock {
|
*best_block = Some(BestBlock {
|
||||||
total_difficulty: update.info.total_difficulty,
|
total_difficulty: update.info.total_difficulty,
|
||||||
header: update.block.decode_header(),
|
header: update.block.decode_header(self.eip1559_transition),
|
||||||
block: update.block,
|
block: update.block,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1991,8 +2001,12 @@ mod tests {
|
|||||||
Arc::new(db)
|
Arc::new(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_chain(genesis: encoded::Block, db: Arc<dyn BlockChainDB>) -> BlockChain {
|
fn new_chain(
|
||||||
BlockChain::new(Config::default(), genesis.raw(), db)
|
genesis: encoded::Block,
|
||||||
|
db: Arc<dyn BlockChainDB>,
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
|
) -> BlockChain {
|
||||||
|
BlockChain::new(Config::default(), genesis.raw(), db, eip1559_transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_block(
|
fn insert_block(
|
||||||
@ -2058,7 +2072,11 @@ mod tests {
|
|||||||
let first = genesis.add_block();
|
let first = genesis.add_block();
|
||||||
|
|
||||||
let db = new_db();
|
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);
|
assert_eq!(bc.best_block_number(), 0);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -2086,7 +2104,7 @@ mod tests {
|
|||||||
let first_hash = first.hash();
|
let first_hash = first.hash();
|
||||||
|
|
||||||
let db = new_db();
|
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.genesis_hash(), genesis_hash);
|
||||||
assert_eq!(bc.best_block_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 generator = BlockGenerator::new(vec![first_10]);
|
||||||
|
|
||||||
let db = new_db();
|
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 block_hashes = vec![genesis.last().hash()];
|
||||||
let mut batch = db.key_value().transaction();
|
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 generator = BlockGenerator::new(vec![b1a, b1b, b2a, b2b, b3a, b3b, b4a, b4b, b5a, b5b]);
|
||||||
|
|
||||||
let db = new_db();
|
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 {
|
for b in generator {
|
||||||
insert_block(&db, &bc, b.encoded(), vec![]);
|
insert_block(&db, &bc, b.encoded(), vec![]);
|
||||||
@ -2204,7 +2230,11 @@ mod tests {
|
|||||||
let b2_hash = b2.last().hash();
|
let b2_hash = b2.last().hash();
|
||||||
|
|
||||||
let db = new_db();
|
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 mut batch = db.key_value().transaction();
|
||||||
let _ = insert_block_batch(&mut batch, &bc, b1a.last().encoded(), vec![]);
|
let _ = insert_block_batch(&mut batch, &bc, b1a.last().encoded(), vec![]);
|
||||||
@ -2291,7 +2321,11 @@ mod tests {
|
|||||||
let t3_hash = t3.hash();
|
let t3_hash = t3.hash();
|
||||||
|
|
||||||
let db = new_db();
|
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 mut batch = db.key_value().transaction();
|
||||||
let _ = insert_block_batch(&mut batch, &bc, b1a.last().encoded(), vec![]);
|
let _ = insert_block_batch(&mut batch, &bc, b1a.last().encoded(), vec![]);
|
||||||
@ -2364,7 +2398,11 @@ mod tests {
|
|||||||
let best_block_hash = b3a_hash;
|
let best_block_hash = b3a_hash;
|
||||||
|
|
||||||
let db = new_db();
|
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 mut batch = db.key_value().transaction();
|
||||||
let ir1 = insert_block_batch(&mut batch, &bc, b1.last().encoded(), vec![]);
|
let ir1 = insert_block_batch(&mut batch, &bc, b1.last().encoded(), vec![]);
|
||||||
@ -2490,7 +2528,11 @@ mod tests {
|
|||||||
let db = new_db();
|
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);
|
assert_eq!(bc.best_block_hash(), genesis_hash);
|
||||||
let mut batch = db.key_value().transaction();
|
let mut batch = db.key_value().transaction();
|
||||||
insert_block_batch(&mut batch, &bc, first.last().encoded(), vec![]);
|
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);
|
assert_eq!(bc.best_block_hash(), first_hash);
|
||||||
}
|
}
|
||||||
@ -2515,7 +2561,11 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let db = new_db();
|
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();
|
let mut batch = db.key_value().transaction();
|
||||||
insert_block_batch(&mut batch, &bc, encoded::Block::new(b1), vec![]);
|
insert_block_batch(&mut batch, &bc, encoded::Block::new(b1), vec![]);
|
||||||
db.key_value().write(batch).unwrap();
|
db.key_value().write(batch).unwrap();
|
||||||
@ -2599,7 +2649,11 @@ mod tests {
|
|||||||
let b3_number = b3.last().number();
|
let b3_number = b3.last().number();
|
||||||
|
|
||||||
let db = new_db();
|
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(
|
insert_block(
|
||||||
&db,
|
&db,
|
||||||
&bc,
|
&bc,
|
||||||
@ -2783,7 +2837,11 @@ mod tests {
|
|||||||
let b2a = b1a.add_block_with_bloom(bloom_ba);
|
let b2a = b1a.add_block_with_bloom(bloom_ba);
|
||||||
|
|
||||||
let db = new_db();
|
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_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5);
|
||||||
let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 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 b1_total_difficulty = genesis.last().difficulty() + b1.last().difficulty();
|
||||||
|
|
||||||
let db = new_db();
|
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 mut batch = db.key_value().transaction();
|
||||||
bc.insert_unordered_block(
|
bc.insert_unordered_block(
|
||||||
&mut batch,
|
&mut batch,
|
||||||
@ -2885,7 +2947,11 @@ mod tests {
|
|||||||
|
|
||||||
let db = new_db();
|
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 mut batch = db.key_value().transaction();
|
||||||
// create a longer fork
|
// create a longer fork
|
||||||
@ -2901,7 +2967,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// re-loading the blockchain should load the correct best block.
|
// 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!(bc.best_block_number(), 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2916,7 +2982,11 @@ mod tests {
|
|||||||
|
|
||||||
let db = new_db();
|
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 mut batch = db.key_value().transaction();
|
||||||
// create a longer fork
|
// create a longer fork
|
||||||
@ -2958,7 +3028,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// re-loading the blockchain should load the correct best block.
|
// 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!(bc.best_block_number(), 5);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -2982,7 +3052,11 @@ mod tests {
|
|||||||
|
|
||||||
let db = new_db();
|
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 mut batch = db.key_value().transaction();
|
||||||
bc.insert_epoch_transition(
|
bc.insert_epoch_transition(
|
||||||
@ -3067,7 +3141,11 @@ mod tests {
|
|||||||
|
|
||||||
let bootstrap_chain = |blocks: Vec<&BlockBuilder>| {
|
let bootstrap_chain = |blocks: Vec<&BlockBuilder>| {
|
||||||
let db = new_db();
|
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 mut batch = db.key_value().transaction();
|
||||||
for block in blocks {
|
for block in blocks {
|
||||||
insert_block_batch(&mut batch, &bc, block.last().encoded(), vec![]);
|
insert_block_batch(&mut batch, &bc, block.last().encoded(), vec![]);
|
||||||
|
195
crates/ethcore/res/chainspec/aleut.json
Normal file
195
crates/ethcore/res/chainspec/aleut.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
953
crates/ethcore/res/chainspec/baikal.json
Normal file
953
crates/ethcore/res/chainspec/baikal.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
212
crates/ethcore/res/chainspec/test/london_test.json
Normal file
212
crates/ethcore/res/chainspec/test/london_test.json
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
Subproject commit 644967e345bbc6642fab613e1b1737abbe131f78
|
Subproject commit 8a81997b22475f1dd90f0d01128c43b18f8877b2
|
@ -139,7 +139,8 @@ impl ExecutedBlock {
|
|||||||
difficulty: self.header.difficulty().clone(),
|
difficulty: self.header.difficulty().clone(),
|
||||||
last_hashes: self.last_hashes.clone(),
|
last_hashes: self.last_hashes.clone(),
|
||||||
gas_used: self.receipts.last().map_or(U256::zero(), |r| r.gas_used),
|
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
|
.header
|
||||||
.set_timestamp(engine.open_block_header_timestamp(parent.timestamp()));
|
.set_timestamp(engine.open_block_header_timestamp(parent.timestamp()));
|
||||||
r.block.header.set_extra_data(extra_data);
|
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_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);
|
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());
|
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.
|
// 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
|
/// 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 {
|
if let Some(ref s) = trace_state {
|
||||||
let env = b.env_info();
|
let author_balance = s.balance(&b.header.author())?;
|
||||||
let root = s.root();
|
|
||||||
let author_balance = s.balance(&env.author)?;
|
|
||||||
trace!(target: "enact", "num={}, root={}, author={}, author_balance={}\n",
|
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
|
// 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>,
|
last_hashes: Arc<LastHashes>,
|
||||||
factories: Factories,
|
factories: Factories,
|
||||||
) -> Result<LockedBlock, Error> {
|
) -> 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 header = block.header;
|
||||||
let transactions: Result<Vec<_>, Error> = block
|
let transactions: Result<Vec<_>, Error> = block
|
||||||
.transactions
|
.transactions
|
||||||
@ -689,7 +696,8 @@ mod tests {
|
|||||||
last_hashes: Arc<LastHashes>,
|
last_hashes: Arc<LastHashes>,
|
||||||
factories: Factories,
|
factories: Factories,
|
||||||
) -> Result<SealedBlock, Error> {
|
) -> 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(
|
Ok(enact_bytes(
|
||||||
block_bytes,
|
block_bytes,
|
||||||
engine,
|
engine,
|
||||||
@ -846,7 +854,7 @@ mod tests {
|
|||||||
|
|
||||||
let bytes = e.rlp_bytes();
|
let bytes = e.rlp_bytes();
|
||||||
assert_eq!(bytes, orig_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");
|
assert_eq!(uncles[1].extra_data(), b"uncle2");
|
||||||
|
|
||||||
let db = e.drain().state.drop().1;
|
let db = e.drain().state.drop().1;
|
||||||
|
@ -21,6 +21,7 @@ use ethereum_types::H256;
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use memory_cache::MemoryLruCache;
|
use memory_cache::MemoryLruCache;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
use types::BlockNumber;
|
||||||
use verification::queue::kind::blocks::Unverified;
|
use verification::queue::kind::blocks::Unverified;
|
||||||
|
|
||||||
/// Recently seen bad blocks.
|
/// Recently seen bad blocks.
|
||||||
@ -38,8 +39,8 @@ impl Default for BadBlocks {
|
|||||||
|
|
||||||
impl BadBlocks {
|
impl BadBlocks {
|
||||||
/// Reports given RLP as invalid block.
|
/// Reports given RLP as invalid block.
|
||||||
pub fn report(&self, raw: Bytes, message: String) {
|
pub fn report(&self, raw: Bytes, message: String, eip1559_transition: BlockNumber) {
|
||||||
match Unverified::from_rlp(raw) {
|
match Unverified::from_rlp(raw, eip1559_transition) {
|
||||||
Ok(unverified) => {
|
Ok(unverified) => {
|
||||||
error!(
|
error!(
|
||||||
target: "client",
|
target: "client",
|
||||||
@ -69,14 +70,14 @@ impl BadBlocks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of recently detected bad blocks with error descriptions.
|
/// 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
|
self.last_blocks
|
||||||
.read()
|
.read()
|
||||||
.backstore()
|
.backstore()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_k, (unverified, message))| {
|
.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"),
|
.expect("Bytes coming from UnverifiedBlock so decodable; qed"),
|
||||||
message.clone(),
|
message.clone(),
|
||||||
)
|
)
|
||||||
|
@ -355,7 +355,11 @@ impl Importer {
|
|||||||
.accrue_block(&header, transactions_len);
|
.accrue_block(&header, transactions_len);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
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);
|
invalid_blocks.insert(hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -629,7 +633,7 @@ impl Importer {
|
|||||||
let header = chain
|
let header = chain
|
||||||
.block_header_data(&hash)
|
.block_header_data(&hash)
|
||||||
.expect("Best block is in the database; qed")
|
.expect("Best block is in the database; qed")
|
||||||
.decode()
|
.decode(self.engine.params().eip1559_transition)
|
||||||
.expect("Stored block header is valid RLP; qed");
|
.expect("Stored block header is valid RLP; qed");
|
||||||
let details = chain
|
let details = chain
|
||||||
.block_details(&hash)
|
.block_details(&hash)
|
||||||
@ -767,6 +771,7 @@ impl Importer {
|
|||||||
last_hashes: client.build_last_hashes(header.parent_hash()),
|
last_hashes: client.build_last_hashes(header.parent_hash()),
|
||||||
gas_used: U256::default(),
|
gas_used: U256::default(),
|
||||||
gas_limit: u64::max_value().into(),
|
gas_limit: u64::max_value().into(),
|
||||||
|
base_fee: header.base_fee(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let call = move |addr, data| {
|
let call = move |addr, data| {
|
||||||
@ -905,7 +910,12 @@ impl Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let gb = spec.genesis_block();
|
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(
|
let tracedb = RwLock::new(TraceDB::new(
|
||||||
config.tracing.clone(),
|
config.tracing.clone(),
|
||||||
db.clone(),
|
db.clone(),
|
||||||
@ -1144,6 +1154,11 @@ impl Client {
|
|||||||
last_hashes: self.build_last_hashes(&header.parent_hash()),
|
last_hashes: self.build_last_hashes(&header.parent_hash()),
|
||||||
gas_used: U256::default(),
|
gas_used: U256::default(),
|
||||||
gas_limit: header.gas_limit(),
|
gas_limit: header.gas_limit(),
|
||||||
|
base_fee: if header.number() >= self.engine.params().eip1559_transition {
|
||||||
|
Some(header.base_fee())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1646,7 +1661,9 @@ impl Client {
|
|||||||
BlockId::Number(number) if number == self.chain.read().best_block_number() => {
|
BlockId::Number(number) if number == self.chain.read().best_block_number() => {
|
||||||
Some(self.chain.read().best_block_header())
|
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 +1690,7 @@ impl snapshot::DatabaseRestore for Client {
|
|||||||
self.config.blockchain.clone(),
|
self.config.blockchain.clone(),
|
||||||
&[],
|
&[],
|
||||||
db.clone(),
|
db.clone(),
|
||||||
|
self.engine.params().eip1559_transition,
|
||||||
));
|
));
|
||||||
*tracedb = TraceDB::new(self.config.tracing.clone(), db.clone(), chain.clone());
|
*tracedb = TraceDB::new(self.config.tracing.clone(), db.clone(), chain.clone());
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1884,9 +1902,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)
|
// 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), _))) => {
|
Err((Some(block), EthcoreError(EthcoreErrorKind::Block(err), _))) => {
|
||||||
self.importer
|
self.importer.bad_blocks.report(
|
||||||
.bad_blocks
|
block.bytes,
|
||||||
.report(block.bytes, err.to_string());
|
err.to_string(),
|
||||||
|
self.engine.params().eip1559_transition,
|
||||||
|
);
|
||||||
bail!(EthcoreErrorKind::Block(err))
|
bail!(EthcoreErrorKind::Block(err))
|
||||||
}
|
}
|
||||||
Err((None, EthcoreError(EthcoreErrorKind::Block(err), _))) => {
|
Err((None, EthcoreError(EthcoreErrorKind::Block(err), _))) => {
|
||||||
@ -1934,6 +1954,7 @@ impl Call for Client {
|
|||||||
last_hashes: self.build_last_hashes(header.parent_hash()),
|
last_hashes: self.build_last_hashes(header.parent_hash()),
|
||||||
gas_used: U256::default(),
|
gas_used: U256::default(),
|
||||||
gas_limit: U256::max_value(),
|
gas_limit: U256::max_value(),
|
||||||
|
base_fee: header.base_fee(),
|
||||||
};
|
};
|
||||||
let machine = self.engine.machine();
|
let machine = self.engine.machine();
|
||||||
|
|
||||||
@ -1954,6 +1975,7 @@ impl Call for Client {
|
|||||||
last_hashes: self.build_last_hashes(header.parent_hash()),
|
last_hashes: self.build_last_hashes(header.parent_hash()),
|
||||||
gas_used: U256::default(),
|
gas_used: U256::default(),
|
||||||
gas_limit: U256::max_value(),
|
gas_limit: U256::max_value(),
|
||||||
|
base_fee: header.base_fee(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut results = Vec::with_capacity(transactions.len());
|
let mut results = Vec::with_capacity(transactions.len());
|
||||||
@ -1986,6 +2008,7 @@ impl Call for Client {
|
|||||||
last_hashes: self.build_last_hashes(header.parent_hash()),
|
last_hashes: self.build_last_hashes(header.parent_hash()),
|
||||||
gas_used: U256::default(),
|
gas_used: U256::default(),
|
||||||
gas_limit: max,
|
gas_limit: max,
|
||||||
|
base_fee: header.base_fee(),
|
||||||
};
|
};
|
||||||
|
|
||||||
(init, max, env_info)
|
(init, max, env_info)
|
||||||
@ -2069,7 +2092,9 @@ impl EngineInfo for Client {
|
|||||||
|
|
||||||
impl BadBlocks for Client {
|
impl BadBlocks for Client {
|
||||||
fn bad_blocks(&self) -> Vec<(Unverified, String)> {
|
fn bad_blocks(&self) -> Vec<(Unverified, String)> {
|
||||||
self.importer.bad_blocks.bad_blocks()
|
self.importer
|
||||||
|
.bad_blocks
|
||||||
|
.bad_blocks(self.engine.params().eip1559_transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2654,8 +2679,11 @@ impl BlockChainClient for Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn uncle_extra_info(&self, id: UncleId) -> Option<BTreeMap<String, String>> {
|
fn uncle_extra_info(&self, id: UncleId) -> Option<BTreeMap<String, String>> {
|
||||||
self.uncle(id)
|
self.uncle(id).and_then(|h| {
|
||||||
.and_then(|h| h.decode().map(|dh| self.engine.extra_info(&dh)).ok())
|
h.decode(self.engine.params().eip1559_transition)
|
||||||
|
.map(|dh| self.engine.extra_info(&dh))
|
||||||
|
.ok()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pruning_info(&self) -> PruningInfo {
|
fn pruning_info(&self) -> PruningInfo {
|
||||||
@ -2837,7 +2865,9 @@ impl ReopenBlock for Client {
|
|||||||
let uncle = chain
|
let uncle = chain
|
||||||
.block_header_data(&h)
|
.block_header_data(&h)
|
||||||
.expect("find_uncle_hashes only returns hashes for existing headers; qed");
|
.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(
|
block.push_uncle(uncle).expect(
|
||||||
"pushing up to maximum_uncle_count;
|
"pushing up to maximum_uncle_count;
|
||||||
push_uncle is not ok only if more than maximum_uncle_count is pushed;
|
push_uncle is not ok only if more than maximum_uncle_count is pushed;
|
||||||
@ -2889,7 +2919,10 @@ impl PrepareOpenBlock for Client {
|
|||||||
.take(engine.maximum_uncle_count(open_block.header.number()))
|
.take(engine.maximum_uncle_count(open_block.header.number()))
|
||||||
.foreach(|h| {
|
.foreach(|h| {
|
||||||
open_block
|
open_block
|
||||||
.push_uncle(h.decode().expect("decoding failure"))
|
.push_uncle(
|
||||||
|
h.decode(engine.params().eip1559_transition)
|
||||||
|
.expect("decoding failure"),
|
||||||
|
)
|
||||||
.expect(
|
.expect(
|
||||||
"pushing maximum_uncle_count;
|
"pushing maximum_uncle_count;
|
||||||
open_block was just created;
|
open_block was just created;
|
||||||
@ -2925,6 +2958,7 @@ impl ImportSealedBlock for Client {
|
|||||||
self.importer.bad_blocks.report(
|
self.importer.bad_blocks.report(
|
||||||
block.rlp_bytes(),
|
block.rlp_bytes(),
|
||||||
format!("Detected an issue with locally sealed block: {}", e),
|
format!("Detected an issue with locally sealed block: {}", e),
|
||||||
|
self.engine.params().eip1559_transition,
|
||||||
);
|
);
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
@ -3155,7 +3189,8 @@ impl ImportExportBlocks for Client {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let do_import = |bytes: Vec<u8>| {
|
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();
|
let number = block.header.number();
|
||||||
while self.queue_info().is_full() {
|
while self.queue_info().is_full() {
|
||||||
std::thread::sleep(Duration::from_secs(1));
|
std::thread::sleep(Duration::from_secs(1));
|
||||||
|
@ -107,6 +107,7 @@ impl<'a> EvmTestClient<'a> {
|
|||||||
Some(ethereum::new_byzantium_to_constantinoplefixat5_test())
|
Some(ethereum::new_byzantium_to_constantinoplefixat5_test())
|
||||||
}
|
}
|
||||||
ForkSpec::Berlin => Some(ethereum::new_berlin_test()),
|
ForkSpec::Berlin => Some(ethereum::new_berlin_test()),
|
||||||
|
ForkSpec::London => Some(ethereum::new_london_test()),
|
||||||
ForkSpec::FrontierToHomesteadAt5
|
ForkSpec::FrontierToHomesteadAt5
|
||||||
| ForkSpec::HomesteadToDaoAt5
|
| ForkSpec::HomesteadToDaoAt5
|
||||||
| ForkSpec::HomesteadToEIP150At5
|
| ForkSpec::HomesteadToEIP150At5
|
||||||
@ -248,6 +249,7 @@ impl<'a> EvmTestClient<'a> {
|
|||||||
last_hashes: Arc::new([H256::default(); 256].to_vec()),
|
last_hashes: Arc::new([H256::default(); 256].to_vec()),
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
gas_limit: *genesis.gas_limit(),
|
gas_limit: *genesis.gas_limit(),
|
||||||
|
base_fee: genesis.base_fee(),
|
||||||
};
|
};
|
||||||
self.call_envinfo(params, tracer, vm_tracer, info)
|
self.call_envinfo(params, tracer, vm_tracer, info)
|
||||||
}
|
}
|
||||||
|
@ -322,7 +322,7 @@ impl TestBlockChainClient {
|
|||||||
rlp.append(&header);
|
rlp.append(&header);
|
||||||
rlp.append_raw(&txs, 1);
|
rlp.append_raw(&txs, 1);
|
||||||
rlp.append_raw(uncles.as_raw(), 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();
|
self.import_block(unverified).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +339,7 @@ impl TestBlockChainClient {
|
|||||||
let mut header: Header = self
|
let mut header: Header = self
|
||||||
.block_header(BlockId::Number(n))
|
.block_header(BlockId::Number(n))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.decode()
|
.decode(BlockNumber::max_value())
|
||||||
.expect("decoding failed");
|
.expect("decoding failed");
|
||||||
header.set_parent_hash(H256::from_low_u64_be(42));
|
header.set_parent_hash(H256::from_low_u64_be(42));
|
||||||
let mut rlp = RlpStream::new_list(3);
|
let mut rlp = RlpStream::new_list(3);
|
||||||
@ -550,7 +550,7 @@ impl BlockInfo for TestBlockChainClient {
|
|||||||
fn best_block_header(&self) -> Header {
|
fn best_block_header(&self) -> Header {
|
||||||
self.block_header(BlockId::Hash(self.chain_info().best_block_hash))
|
self.block_header(BlockId::Hash(self.chain_info().best_block_hash))
|
||||||
.expect("Best block always has header.")
|
.expect("Best block always has header.")
|
||||||
.decode()
|
.decode(BlockNumber::max_value())
|
||||||
.expect("decoding failed")
|
.expect("decoding failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,7 +608,7 @@ impl ImportBlock for TestBlockChainClient {
|
|||||||
if number > 0 {
|
if number > 0 {
|
||||||
match self.blocks.read().get(header.parent_hash()) {
|
match self.blocks.read().get(header.parent_hash()) {
|
||||||
Some(parent) => {
|
Some(parent) => {
|
||||||
let parent = view!(BlockView, parent).header();
|
let parent = view!(BlockView, parent).header(BlockNumber::max_value());
|
||||||
if parent.number() != (header.number() - 1) {
|
if parent.number() != (header.number() - 1) {
|
||||||
panic!("Unexpected block parent");
|
panic!("Unexpected block parent");
|
||||||
}
|
}
|
||||||
@ -638,7 +638,7 @@ impl ImportBlock for TestBlockChainClient {
|
|||||||
*self.numbers.write().get_mut(&n).unwrap() = parent_hash.clone();
|
*self.numbers.write().get_mut(&n).unwrap() = parent_hash.clone();
|
||||||
n -= 1;
|
n -= 1;
|
||||||
parent_hash = view!(BlockView, &self.blocks.read()[&parent_hash])
|
parent_hash = view!(BlockView, &self.blocks.read()[&parent_hash])
|
||||||
.header()
|
.header(BlockNumber::max_value())
|
||||||
.parent_hash()
|
.parent_hash()
|
||||||
.clone();
|
.clone();
|
||||||
}
|
}
|
||||||
@ -720,7 +720,7 @@ impl StateClient for TestBlockChainClient {
|
|||||||
|
|
||||||
impl EngineInfo for TestBlockChainClient {
|
impl EngineInfo for TestBlockChainClient {
|
||||||
fn engine(&self) -> &dyn EthEngine {
|
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>> {
|
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> {
|
||||||
self.block(id)
|
self.block(id)
|
||||||
.map(|block| block.view().header())
|
.map(|block| block.view().header(BlockNumber::max_value()))
|
||||||
.map(|header| self.spec.engine.extra_info(&header))
|
.map(|header| self.spec.engine.extra_info(&header))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ use self::finality::RollingFinality;
|
|||||||
use super::{
|
use super::{
|
||||||
signer::EngineSigner,
|
signer::EngineSigner,
|
||||||
validator_set::{new_validator_set_posdao, SimpleList, ValidatorSet},
|
validator_set::{new_validator_set_posdao, SimpleList, ValidatorSet},
|
||||||
|
EthEngine,
|
||||||
};
|
};
|
||||||
use block::*;
|
use block::*;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
@ -692,6 +693,7 @@ struct EpochVerifier {
|
|||||||
empty_steps_transition: u64,
|
empty_steps_transition: u64,
|
||||||
/// First block for which a 2/3 quorum (instead of 1/2) is required.
|
/// First block for which a 2/3 quorum (instead of 1/2) is required.
|
||||||
two_thirds_majority_transition: BlockNumber,
|
two_thirds_majority_transition: BlockNumber,
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
|
impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
|
||||||
@ -716,7 +718,9 @@ impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
|
|||||||
RollingFinality::blank(signers, self.two_thirds_majority_transition);
|
RollingFinality::blank(signers, self.two_thirds_majority_transition);
|
||||||
let mut finalized = Vec::new();
|
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>| {
|
let mut push_header = |parent_header: &Header, header: Option<&Header>| {
|
||||||
@ -1805,7 +1809,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
|||||||
let parent = client
|
let parent = client
|
||||||
.block_header(::client::BlockId::Hash(*block.header.parent_hash()))
|
.block_header(::client::BlockId::Hash(*block.header.parent_hash()))
|
||||||
.expect("hash is from parent; parent header must exist; qed")
|
.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 parent_step = header_step(&parent, self.empty_steps_transition)?;
|
||||||
let current_step = self.step.inner.load();
|
let current_step = self.step.inner.load();
|
||||||
@ -2200,6 +2204,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
|||||||
subchain_validators: list,
|
subchain_validators: list,
|
||||||
empty_steps_transition: self.empty_steps_transition,
|
empty_steps_transition: self.empty_steps_transition,
|
||||||
two_thirds_majority_transition: self.two_thirds_majority_transition,
|
two_thirds_majority_transition: self.two_thirds_majority_transition,
|
||||||
|
eip1559_transition: self.params().eip1559_transition,
|
||||||
});
|
});
|
||||||
|
|
||||||
match finalize {
|
match finalize {
|
||||||
|
@ -316,7 +316,8 @@ impl Clique {
|
|||||||
return Err(BlockError::UnknownParent(last_parent_hash))?;
|
return Err(BlockError::UnknownParent(last_parent_hash))?;
|
||||||
}
|
}
|
||||||
Some(next) => {
|
Some(next) => {
|
||||||
chain.push_front(next.decode()?);
|
chain
|
||||||
|
.push_front(next.decode(self.machine.params().eip1559_transition)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -332,7 +333,7 @@ impl Clique {
|
|||||||
None => {
|
None => {
|
||||||
return Err(EngineError::CliqueMissingCheckpoint(last_checkpoint_hash))?
|
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)
|
let last_checkpoint_state = match block_state_by_hash.get_mut(&last_checkpoint_hash)
|
||||||
|
@ -648,6 +648,14 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> {
|
|||||||
self.machine().decode_transaction(transaction, &schedule)
|
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.
|
/// The configured minimum gas limit. Used by AuRa Engine.
|
||||||
fn min_gas_limit(&self) -> U256 {
|
fn min_gas_limit(&self) -> U256 {
|
||||||
self.params().min_gas_limit
|
self.params().min_gas_limit
|
||||||
|
@ -287,8 +287,11 @@ mod tests {
|
|||||||
for i in 1..4 {
|
for i in 1..4 {
|
||||||
sync_client
|
sync_client
|
||||||
.import_block(
|
.import_block(
|
||||||
Unverified::from_rlp(client.block(BlockId::Number(i)).unwrap().into_inner())
|
Unverified::from_rlp(
|
||||||
.unwrap(),
|
client.block(BlockId::Number(i)).unwrap().into_inner(),
|
||||||
|
client.engine().params().eip1559_transition,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -70,8 +70,9 @@ impl ::engines::StateDependentProof<EthereumMachine> for StateProof {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_proof(&self, machine: &EthereumMachine, proof: &[u8]) -> Result<(), String> {
|
fn check_proof(&self, machine: &EthereumMachine, proof: &[u8]) -> Result<(), String> {
|
||||||
let (header, state_items) = decode_first_proof(&Rlp::new(proof))
|
let (header, state_items) =
|
||||||
.map_err(|e| format!("proof incorrectly encoded: {}", e))?;
|
decode_first_proof(&Rlp::new(proof), machine.params().eip1559_transition)
|
||||||
|
.map_err(|e| format!("proof incorrectly encoded: {}", e))?;
|
||||||
if &header != &self.header {
|
if &header != &self.header {
|
||||||
return Err("wrong header in proof".into());
|
return Err("wrong header in proof".into());
|
||||||
}
|
}
|
||||||
@ -129,6 +130,7 @@ fn check_first_proof(
|
|||||||
Arc::new(last_hashes)
|
Arc::new(last_hashes)
|
||||||
},
|
},
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
|
base_fee: old_header.base_fee(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// check state proof using given machine.
|
// 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> {
|
fn decode_first_proof(
|
||||||
let header = rlp.val_at(0)?;
|
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
|
let state_items = rlp
|
||||||
.at(1)?
|
.at(1)?
|
||||||
.iter()
|
.iter()
|
||||||
@ -188,8 +193,14 @@ fn encode_proof(header: &Header, receipts: &[TypedReceipt]) -> Bytes {
|
|||||||
stream.drain()
|
stream.drain()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_proof(rlp: &Rlp) -> Result<(Header, Vec<TypedReceipt>), ::error::Error> {
|
fn decode_proof(
|
||||||
Ok((rlp.val_at(0)?, TypedReceipt::decode_rlp_list(&rlp.at(1)?)?))
|
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
|
// given a provider and caller, generate proof. this will just be a state proof
|
||||||
@ -554,7 +565,8 @@ impl ValidatorSet for ValidatorSafeContract {
|
|||||||
if first {
|
if first {
|
||||||
trace!(target: "engine", "Recovering initial epoch set");
|
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 number = old_header.number();
|
||||||
let old_hash = old_header.hash();
|
let old_hash = old_header.hash();
|
||||||
let addresses =
|
let addresses =
|
||||||
@ -566,7 +578,7 @@ impl ValidatorSet for ValidatorSafeContract {
|
|||||||
|
|
||||||
Ok((SimpleList::new(addresses), Some(old_hash)))
|
Ok((SimpleList::new(addresses), Some(old_hash)))
|
||||||
} else {
|
} else {
|
||||||
let (old_header, receipts) = decode_proof(&rlp)?;
|
let (old_header, receipts) = decode_proof(&rlp, machine.params().eip1559_transition)?;
|
||||||
|
|
||||||
// ensure receipts match header.
|
// ensure receipts match header.
|
||||||
// TODO: optimize? these were just decoded.
|
// TODO: optimize? these were just decoded.
|
||||||
@ -830,8 +842,11 @@ mod tests {
|
|||||||
for i in 1..4 {
|
for i in 1..4 {
|
||||||
sync_client
|
sync_client
|
||||||
.import_block(
|
.import_block(
|
||||||
Unverified::from_rlp(client.block(BlockId::Number(i)).unwrap().into_inner())
|
Unverified::from_rlp(
|
||||||
.unwrap(),
|
client.block(BlockId::Number(i)).unwrap().into_inner(),
|
||||||
|
client.engine().params().eip1559_transition,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,10 @@ pub enum BlockError {
|
|||||||
InvalidSealArity(Mismatch<usize>),
|
InvalidSealArity(Mismatch<usize>),
|
||||||
/// Block has too much gas used.
|
/// Block has too much gas used.
|
||||||
TooMuchGasUsed(OutOfBounds<U256>),
|
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.
|
/// Uncles hash in header is invalid.
|
||||||
InvalidUnclesHash(Mismatch<H256>),
|
InvalidUnclesHash(Mismatch<H256>),
|
||||||
/// An uncle is from a generation too old.
|
/// An uncle is from a generation too old.
|
||||||
@ -79,6 +83,8 @@ pub enum BlockError {
|
|||||||
InvalidSeal,
|
InvalidSeal,
|
||||||
/// Gas limit header field is invalid.
|
/// Gas limit header field is invalid.
|
||||||
InvalidGasLimit(OutOfBounds<U256>),
|
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.
|
/// Receipts trie root header field is invalid.
|
||||||
InvalidReceiptsRoot(Mismatch<H256>),
|
InvalidReceiptsRoot(Mismatch<H256>),
|
||||||
/// Timestamp header field is invalid.
|
/// Timestamp header field is invalid.
|
||||||
@ -112,6 +118,8 @@ impl fmt::Display for BlockError {
|
|||||||
ExtraDataOutOfBounds(ref oob) => format!("Extra block data too long. {}", oob),
|
ExtraDataOutOfBounds(ref oob) => format!("Extra block data too long. {}", oob),
|
||||||
InvalidSealArity(ref mis) => format!("Block seal in incorrect format: {}", mis),
|
InvalidSealArity(ref mis) => format!("Block seal in incorrect format: {}", mis),
|
||||||
TooMuchGasUsed(ref oob) => format!("Block has too much gas used. {}", oob),
|
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),
|
InvalidUnclesHash(ref mis) => format!("Block has invalid uncles hash: {}", mis),
|
||||||
UncleTooOld(ref oob) => format!("Uncle block is too old. {}", oob),
|
UncleTooOld(ref oob) => format!("Uncle block is too old. {}", oob),
|
||||||
UncleIsBrother(ref oob) => format!("Uncle from same generation as block. {}", 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),
|
InvalidProofOfWork(ref oob) => format!("Block has invalid PoW: {}", oob),
|
||||||
InvalidSeal => "Block has invalid seal.".into(),
|
InvalidSeal => "Block has invalid seal.".into(),
|
||||||
InvalidGasLimit(ref oob) => format!("Invalid gas limit: {}", oob),
|
InvalidGasLimit(ref oob) => format!("Invalid gas limit: {}", oob),
|
||||||
|
IncorrectBaseFee(ref mis) => format!("Incorrect base fee: {}", mis),
|
||||||
InvalidReceiptsRoot(ref mis) => {
|
InvalidReceiptsRoot(ref mis) => {
|
||||||
format!("Invalid receipts trie root in header: {}", mis)
|
format!("Invalid receipts trie root in header: {}", mis)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,12 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use 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 ethereum_types::{H256, H64, U256};
|
||||||
use ethjson::{self, uint::Uint};
|
use ethjson::{self, uint::Uint};
|
||||||
|
@ -274,6 +274,14 @@ 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 Musicoin-MCIP3-era spec.
|
/// Create a new Musicoin-MCIP3-era spec.
|
||||||
pub fn new_mcip3_test() -> Spec {
|
pub fn new_mcip3_test() -> Spec {
|
||||||
load(
|
load(
|
||||||
@ -298,6 +306,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.
|
/// Create a new Foundation Homestead-EIP210-era chain spec as though it never changed from Homestead/Frontier.
|
||||||
pub fn new_eip210_test_machine() -> EthereumMachine {
|
pub fn new_eip210_test_machine() -> EthereumMachine {
|
||||||
load_machine(include_bytes!("../../res/chainspec/test/eip210_test.json"))
|
load_machine(include_bytes!("../../res/chainspec/test/eip210_test.json"))
|
||||||
|
@ -91,6 +91,13 @@ pub enum ExecutionError {
|
|||||||
/// Amount of gas in block.
|
/// Amount of gas in block.
|
||||||
gas: U256,
|
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.
|
/// Returned when transaction nonce does not match state nonce.
|
||||||
InvalidNonce {
|
InvalidNonce {
|
||||||
/// Nonce expected.
|
/// Nonce expected.
|
||||||
@ -148,6 +155,13 @@ impl fmt::Display for ExecutionError {
|
|||||||
already been used, and {} more is required",
|
already been used, and {} more is required",
|
||||||
gas_limit, gas_used, gas
|
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 {
|
InvalidNonce {
|
||||||
ref expected,
|
ref expected,
|
||||||
ref got,
|
ref got,
|
||||||
|
@ -1134,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
|
TypedTransaction::Legacy(_) => (), //legacy transactions are allways valid
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1151,17 +1158,15 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
access_list.insert_address(*address);
|
access_list.insert_address(*address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if schedule.eip2930 {
|
|
||||||
// optional access list
|
if let Some(al) = t.access_list() {
|
||||||
if let TypedTransaction::AccessList(al_tx) = t.as_unsigned() {
|
for item in al.iter() {
|
||||||
for item in al_tx.access_list.iter() {
|
access_list.insert_address(item.0);
|
||||||
access_list.insert_address(item.0);
|
base_gas_required += vm::schedule::EIP2930_ACCESS_LIST_ADDRESS_COST.into();
|
||||||
base_gas_required += vm::schedule::EIP2930_ACCESS_LIST_ADDRESS_COST.into();
|
for key in item.1.iter() {
|
||||||
for key in item.1.iter() {
|
access_list.insert_storage_key(item.0, *key);
|
||||||
access_list.insert_storage_key(item.0, *key);
|
base_gas_required +=
|
||||||
base_gas_required +=
|
vm::schedule::EIP2930_ACCESS_LIST_STORAGE_KEY_COST.into();
|
||||||
vm::schedule::EIP2930_ACCESS_LIST_STORAGE_KEY_COST.into();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1201,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() {
|
||||||
|
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.
|
// TODO: we might need bigints here, or at least check overflows.
|
||||||
let balance = self.state.balance(&sender)?;
|
let balance = self.state.balance(&sender)?;
|
||||||
let gas_cost = t.tx().gas.full_mul(t.tx().gas_price);
|
let gas_cost_effective = t
|
||||||
let total_cost = U512::from(t.tx().value) + gas_cost;
|
.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
|
// avoid unaffordable transactions
|
||||||
let balance512 = U512::from(balance);
|
let balance512 = U512::from(balance);
|
||||||
if balance512 < total_cost {
|
if balance512 < needed_balance {
|
||||||
return Err(ExecutionError::NotEnoughCash {
|
return Err(ExecutionError::NotEnoughCash {
|
||||||
required: total_cost,
|
required: needed_balance,
|
||||||
got: balance512,
|
got: balance512,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1223,7 +1247,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
}
|
}
|
||||||
self.state.sub_balance(
|
self.state.sub_balance(
|
||||||
&sender,
|
&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),
|
&mut substate.to_cleanup_mode(&schedule),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -1243,7 +1267,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
sender: sender.clone(),
|
sender: sender.clone(),
|
||||||
origin: sender.clone(),
|
origin: sender.clone(),
|
||||||
gas: init_gas,
|
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),
|
value: ActionValue::Transfer(t.tx().value),
|
||||||
code: Some(Arc::new(t.tx().data.clone())),
|
code: Some(Arc::new(t.tx().data.clone())),
|
||||||
data: None,
|
data: None,
|
||||||
@ -1266,7 +1290,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
sender: sender.clone(),
|
sender: sender.clone(),
|
||||||
origin: sender.clone(),
|
origin: sender.clone(),
|
||||||
gas: init_gas,
|
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),
|
value: ActionValue::Transfer(t.tx().value),
|
||||||
code: self.state.code(address)?,
|
code: self.state.code(address)?,
|
||||||
code_hash: self.state.code_hash(address)?,
|
code_hash: self.state.code_hash(address)?,
|
||||||
@ -1479,14 +1503,32 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
let gas_left = gas_left_prerefund + refunded;
|
let gas_left = gas_left_prerefund + refunded;
|
||||||
|
|
||||||
let gas_used = t.tx().gas.saturating_sub(gas_left);
|
let gas_used = t.tx().gas.saturating_sub(gas_left);
|
||||||
let (refund_value, overflow_1) = gas_left.overflowing_mul(t.tx().gas_price);
|
let (refund_value, overflow_1) =
|
||||||
let (fees_value, overflow_2) = gas_used.overflowing_mul(t.tx().gas_price);
|
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 {
|
if overflow_1 || overflow_2 {
|
||||||
return Err(ExecutionError::TransactionMalformed(
|
return Err(ExecutionError::TransactionMalformed(
|
||||||
"U256 Overflow".to_string(),
|
"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 fees_value = fees_value.saturating_sub(if schedule.eip1559 {
|
||||||
|
let (base_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(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
base_fee
|
||||||
|
} else {
|
||||||
|
U256::from(0)
|
||||||
|
});
|
||||||
|
|
||||||
trace!("exec::finalize: t.gas={}, sstore_refunds={}, suicide_refunds={}, refunds_bound={}, gas_left_prerefund={}, refunded={}, gas_left={}, gas_used={}, refund_value={}, fees_value={}\n",
|
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);
|
t.tx().gas, sstore_refunds, suicide_refunds, refunds_bound, gas_left_prerefund, refunded, gas_left, gas_used, refund_value, fees_value);
|
||||||
|
|
||||||
@ -1519,7 +1561,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
let min_balance = if schedule.kill_dust != CleanDustMode::Off {
|
let min_balance = if schedule.kill_dust != CleanDustMode::Off {
|
||||||
Some(
|
Some(
|
||||||
U256::from(schedule.tx_gas)
|
U256::from(schedule.tx_gas)
|
||||||
.overflowing_mul(t.tx().gas_price)
|
.overflowing_mul(t.effective_gas_price(self.info.base_fee))
|
||||||
.0,
|
.0,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -1585,7 +1627,9 @@ mod tests {
|
|||||||
trace, ExecutiveTracer, ExecutiveVMTracer, FlatTrace, MemoryDiff, NoopTracer, NoopVMTracer,
|
trace, ExecutiveTracer, ExecutiveVMTracer, FlatTrace, MemoryDiff, NoopTracer, NoopVMTracer,
|
||||||
StorageDiff, Tracer, VMExecutedOperation, VMOperation, VMTrace, VMTracer,
|
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};
|
use vm::{ActionParams, ActionValue, CallType, CreateContractAddress, EnvInfo};
|
||||||
|
|
||||||
fn make_frontier_machine(max_depth: usize) -> EthereumMachine {
|
fn make_frontier_machine(max_depth: usize) -> EthereumMachine {
|
||||||
@ -1600,6 +1644,12 @@ mod tests {
|
|||||||
machine
|
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]
|
#[test]
|
||||||
fn test_contract_address() {
|
fn test_contract_address() {
|
||||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||||
@ -2611,6 +2661,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}
|
evm_test! {test_not_enough_cash: test_not_enough_cash_int}
|
||||||
fn test_not_enough_cash(factory: Factory) {
|
fn test_not_enough_cash(factory: Factory) {
|
||||||
let keypair = Random.generate();
|
let keypair = Random.generate();
|
||||||
|
@ -588,6 +588,7 @@ mod tests {
|
|||||||
last_hashes: Arc::new(vec![]),
|
last_hashes: Arc::new(vec![]),
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
gas_limit: 0.into(),
|
gas_limit: 0.into(),
|
||||||
|
base_fee: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ pub fn json_chain_test<H: FnMut(&str, HookType)>(
|
|||||||
|
|
||||||
for b in blockchain.blocks_rlp() {
|
for b in blockchain.blocks_rlp() {
|
||||||
let bytes_len = b.len();
|
let bytes_len = b.len();
|
||||||
let block = Unverified::from_rlp(b);
|
let block = Unverified::from_rlp(b, spec.params().eip1559_transition);
|
||||||
match block {
|
match block {
|
||||||
Ok(block) => {
|
Ok(block) => {
|
||||||
let num = block.header.number();
|
let num = block.header.number();
|
||||||
|
@ -4,7 +4,10 @@ use ethjson::{self, blockchain::Block};
|
|||||||
use log::warn;
|
use log::warn;
|
||||||
use rlp::RlpStream;
|
use rlp::RlpStream;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use types::transaction::{TypedTransaction, TypedTxId, UnverifiedTransaction};
|
use types::{
|
||||||
|
transaction::{TypedTransaction, TypedTxId, UnverifiedTransaction},
|
||||||
|
BlockNumber,
|
||||||
|
};
|
||||||
use verification::queue::kind::blocks::Unverified;
|
use verification::queue::kind::blocks::Unverified;
|
||||||
|
|
||||||
pub fn json_local_block_en_de_test<H: FnMut(&str, HookType)>(
|
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() {
|
for (name, ref_block) in tests.into_iter() {
|
||||||
start_stop_hook(&name, HookType::OnStart);
|
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 {
|
let block = match block {
|
||||||
Ok(block) => block,
|
Ok(block) => block,
|
||||||
Err(decoder_err) => {
|
Err(decoder_err) => {
|
||||||
@ -148,10 +151,11 @@ pub fn is_same_block(ref_block: &Block, block: &Unverified) -> bool {
|
|||||||
TypedTxId::Legacy => {
|
TypedTxId::Legacy => {
|
||||||
test_exp(tx.legacy_v() == ref_tx.v.0.as_u64(), "Original Sig V")
|
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");
|
test_exp(tx.standard_v() as u64 == ref_tx.v.0.as_u64(), "Sig V");
|
||||||
let al = match tx.as_unsigned() {
|
let al = match tx.as_unsigned() {
|
||||||
TypedTransaction::AccessList(tx) => &tx.access_list,
|
TypedTransaction::AccessList(tx) => &tx.access_list,
|
||||||
|
TypedTransaction::EIP1559Transaction(tx) => &tx.transaction.access_list,
|
||||||
_ => {
|
_ => {
|
||||||
println!("Wrong data in tx type");
|
println!("Wrong data in tx type");
|
||||||
continue;
|
continue;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Ethereum-like state machine definition.
|
//! Ethereum-like state machine definition.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp,
|
cmp::{self, max},
|
||||||
collections::{BTreeMap, HashMap},
|
collections::{BTreeMap, HashMap},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
@ -47,9 +47,6 @@ use state::{CleanupMode, Substate};
|
|||||||
use trace::{NoopTracer, NoopVMTracer};
|
use trace::{NoopTracer, NoopVMTracer};
|
||||||
use tx_filter::TransactionFilter;
|
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.
|
/// Ethash-specific extensions.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct EthashExtensions {
|
pub struct EthashExtensions {
|
||||||
@ -269,55 +266,31 @@ impl EthereumMachine {
|
|||||||
gas_ceil_target: U256,
|
gas_ceil_target: U256,
|
||||||
) {
|
) {
|
||||||
header.set_difficulty(parent.difficulty().clone());
|
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");
|
assert!(!gas_limit.is_zero(), "Gas limit should be > 0");
|
||||||
|
|
||||||
if let Some(ref ethash_params) = self.ethash_extensions {
|
let gas_limit_target = if self.schedule(header.number()).eip1559 {
|
||||||
let gas_limit = {
|
gas_ceil_target
|
||||||
let bound_divisor = self.params().gas_limit_bound_divisor;
|
} else {
|
||||||
let lower_limit = gas_limit - gas_limit / bound_divisor + 1;
|
gas_floor_target
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
if header.number() >= ethash_params.dao_hardfork_transition
|
||||||
&& header.number() <= ethash_params.dao_hardfork_transition + 9
|
&& header.number() <= ethash_params.dao_hardfork_transition + 9
|
||||||
{
|
{
|
||||||
header.set_extra_data(b"dao-hard-fork"[..].to_owned());
|
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.
|
/// Get the general parameters of the chain.
|
||||||
@ -400,8 +373,16 @@ impl EthereumMachine {
|
|||||||
pub fn verify_transaction_unordered(
|
pub fn verify_transaction_unordered(
|
||||||
&self,
|
&self,
|
||||||
t: UnverifiedTransaction,
|
t: UnverifiedTransaction,
|
||||||
_header: &Header,
|
header: &Header,
|
||||||
) -> Result<SignedTransaction, transaction::Error> {
|
) -> 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() {
|
||||||
|
return Err(transaction::Error::GasPriceLowerThanBaseFee {
|
||||||
|
gas_price: t.tx().gas_price,
|
||||||
|
base_fee: header.base_fee().unwrap_or_default(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Ok(SignedTransaction::new(t)?)
|
Ok(SignedTransaction::new(t)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,11 +453,61 @@ impl EthereumMachine {
|
|||||||
transaction::TypedTxId::AccessList if !schedule.eip2930 => {
|
transaction::TypedTxId::AccessList if !schedule.eip2930 => {
|
||||||
return Err(transaction::Error::TransactionTypeNotEnabled)
|
return Err(transaction::Error::TransactionTypeNotEnabled)
|
||||||
}
|
}
|
||||||
|
transaction::TypedTxId::EIP1559Transaction if !schedule.eip1559 => {
|
||||||
|
return Err(transaction::Error::TransactionTypeNotEnabled)
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(tx)
|
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.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block eip1559_transition has base_fee = self.params().eip1559_base_fee_initial_value
|
||||||
|
if parent.number() + 1 == self.params().eip1559_transition {
|
||||||
|
return Some(self.params().eip1559_base_fee_initial_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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if parent.gas_used() == &parent_gas_target {
|
||||||
|
Some(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),
|
||||||
|
);
|
||||||
|
Some(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;
|
||||||
|
Some(max(parent_base_fee - base_fee_per_gas_delta, U256::zero()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Auxiliary data fetcher for an Ethereum machine. In Ethereum-like machines
|
/// Auxiliary data fetcher for an Ethereum machine. In Ethereum-like machines
|
||||||
@ -525,27 +556,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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::ethereum::new_london_test_machine;
|
||||||
use ethereum_types::H160;
|
use ethereum_types::H160;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
@ -585,79 +599,65 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ethash_gas_limit_is_multiple_of_determinant() {
|
fn calculate_base_fee_success() {
|
||||||
use ethereum_types::U256;
|
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();
|
for i in 0..parent_base_fees.len() {
|
||||||
let ethparams = get_default_ethash_extensions();
|
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(
|
let base_fee = machine.calc_base_fee(&parent_header);
|
||||||
spec.params().clone(),
|
assert_eq!(expected_base_fee[i], base_fee.unwrap());
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,6 +187,7 @@ impl Default for MinerOptions {
|
|||||||
pool_verification_options: pool::verifier::Options {
|
pool_verification_options: pool::verifier::Options {
|
||||||
minimal_gas_price: DEFAULT_MINIMAL_GAS_PRICE.into(),
|
minimal_gas_price: DEFAULT_MINIMAL_GAS_PRICE.into(),
|
||||||
block_gas_limit: U256::max_value(),
|
block_gas_limit: U256::max_value(),
|
||||||
|
block_base_fee: None,
|
||||||
tx_gas_limit: U256::max_value(),
|
tx_gas_limit: U256::max_value(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
},
|
},
|
||||||
@ -337,6 +338,7 @@ impl Miner {
|
|||||||
pool_verification_options: pool::verifier::Options {
|
pool_verification_options: pool::verifier::Options {
|
||||||
minimal_gas_price,
|
minimal_gas_price,
|
||||||
block_gas_limit: U256::max_value(),
|
block_gas_limit: U256::max_value(),
|
||||||
|
block_base_fee: None,
|
||||||
tx_gas_limit: U256::max_value(),
|
tx_gas_limit: U256::max_value(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
},
|
},
|
||||||
@ -376,7 +378,11 @@ impl Miner {
|
|||||||
/// Updates transaction queue verification limits.
|
/// Updates transaction queue verification limits.
|
||||||
///
|
///
|
||||||
/// Limits consist of current block gas limit and minimal gas price.
|
/// 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>,
|
||||||
|
) {
|
||||||
trace!(target: "miner", "minimal_gas_price: recalibrating...");
|
trace!(target: "miner", "minimal_gas_price: recalibrating...");
|
||||||
let txq = self.transaction_queue.clone();
|
let txq = self.transaction_queue.clone();
|
||||||
let mut options = self.options.pool_verification_options.clone();
|
let mut options = self.options.pool_verification_options.clone();
|
||||||
@ -384,8 +390,14 @@ impl Miner {
|
|||||||
debug!(target: "miner", "minimal_gas_price: Got gas price! {}", gas_price);
|
debug!(target: "miner", "minimal_gas_price: Got gas price! {}", gas_price);
|
||||||
options.minimal_gas_price = gas_price;
|
options.minimal_gas_price = gas_price;
|
||||||
options.block_gas_limit = block_gas_limit;
|
options.block_gas_limit = block_gas_limit;
|
||||||
|
options.block_base_fee = block_base_fee;
|
||||||
txq.set_verifier_options(options);
|
txq.set_verifier_options(options);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
match block_base_fee {
|
||||||
|
Some(block_base_fee) => self.transaction_queue.update_scoring(block_base_fee),
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns ServiceTransactionChecker
|
/// Returns ServiceTransactionChecker
|
||||||
@ -498,11 +510,9 @@ impl Miner {
|
|||||||
|
|
||||||
let client = self.pool_client(chain);
|
let client = self.pool_client(chain);
|
||||||
let engine_params = self.engine.params();
|
let engine_params = self.engine.params();
|
||||||
let min_tx_gas: U256 = self
|
let schedule = self.engine.schedule(block_number);
|
||||||
.engine
|
let min_tx_gas: U256 = schedule.tx_gas.into();
|
||||||
.schedule(chain_info.best_block_number)
|
let gas_limit = open_block.header.gas_limit();
|
||||||
.tx_gas
|
|
||||||
.into();
|
|
||||||
let nonce_cap: Option<U256> = if chain_info.best_block_number + 1
|
let nonce_cap: Option<U256> = if chain_info.best_block_number + 1
|
||||||
>= engine_params.dust_protection_transition
|
>= engine_params.dust_protection_transition
|
||||||
{
|
{
|
||||||
@ -515,11 +525,7 @@ impl Miner {
|
|||||||
usize::max_value()
|
usize::max_value()
|
||||||
} else {
|
} else {
|
||||||
MAX_SKIPPED_TRANSACTIONS.saturating_add(
|
MAX_SKIPPED_TRANSACTIONS.saturating_add(
|
||||||
cmp::min(
|
cmp::min(gas_limit / min_tx_gas, u64::max_value().into()).as_u64() as usize,
|
||||||
*open_block.header.gas_limit() / min_tx_gas,
|
|
||||||
u64::max_value().into(),
|
|
||||||
)
|
|
||||||
.as_u64() as usize,
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -531,6 +537,10 @@ impl Miner {
|
|||||||
nonce_cap,
|
nonce_cap,
|
||||||
max_len: max_transactions.saturating_sub(engine_txs.len()),
|
max_len: max_transactions.saturating_sub(engine_txs.len()),
|
||||||
ordering: miner::PendingOrdering::Priority,
|
ordering: miner::PendingOrdering::Priority,
|
||||||
|
includable_boundary: self
|
||||||
|
.engine
|
||||||
|
.calculate_base_fee(&chain.best_block_header())
|
||||||
|
.unwrap_or_default(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -740,7 +750,7 @@ impl Miner {
|
|||||||
trace!(target: "miner", "seal_block_internally: attempting internal seal.");
|
trace!(target: "miner", "seal_block_internally: attempting internal seal.");
|
||||||
|
|
||||||
let parent_header = match chain.block_header(BlockId::Hash(*block.header.parent_hash())) {
|
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,
|
Ok(decoded_hdr) => decoded_hdr,
|
||||||
Err(_) => return false,
|
Err(_) => return false,
|
||||||
},
|
},
|
||||||
@ -1176,6 +1186,7 @@ impl miner::MinerService for Miner {
|
|||||||
nonce_cap,
|
nonce_cap,
|
||||||
max_len,
|
max_len,
|
||||||
ordering,
|
ordering,
|
||||||
|
includable_boundary: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ref f) = filter {
|
if let Some(ref f) = filter {
|
||||||
@ -1432,8 +1443,18 @@ impl miner::MinerService for Miner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// t_nb 10.1 First update gas limit in transaction queue and minimal gas price.
|
// t_nb 10.1 First update gas limit in transaction queue and minimal gas price.
|
||||||
let gas_limit = *chain.best_block_header().gas_limit();
|
let base_fee = self.engine.calculate_base_fee(&chain.best_block_header());
|
||||||
self.update_transaction_queue_limits(gas_limit);
|
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
|
||||||
|
};
|
||||||
|
self.update_transaction_queue_limits(gas_limit, base_fee);
|
||||||
|
|
||||||
// t_nb 10.2 Then import all transactions from retracted blocks (retracted means from side chain).
|
// t_nb 10.2 Then import all transactions from retracted blocks (retracted means from side chain).
|
||||||
let client = self.pool_client(chain);
|
let client = self.pool_client(chain);
|
||||||
@ -1632,6 +1653,7 @@ mod tests {
|
|||||||
pool_verification_options: pool::verifier::Options {
|
pool_verification_options: pool::verifier::Options {
|
||||||
minimal_gas_price: 0.into(),
|
minimal_gas_price: 0.into(),
|
||||||
block_gas_limit: U256::max_value(),
|
block_gas_limit: U256::max_value(),
|
||||||
|
block_base_fee: None,
|
||||||
tx_gas_limit: U256::max_value(),
|
tx_gas_limit: U256::max_value(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
},
|
},
|
||||||
|
@ -155,9 +155,8 @@ where
|
|||||||
) -> Result<SignedTransaction, transaction::Error> {
|
) -> Result<SignedTransaction, transaction::Error> {
|
||||||
self.engine
|
self.engine
|
||||||
.verify_transaction_basic(&tx, &self.best_block_header)?;
|
.verify_transaction_basic(&tx, &self.best_block_header)?;
|
||||||
let tx = self
|
|
||||||
.engine
|
let tx = SignedTransaction::new(tx)?;
|
||||||
.verify_transaction_unordered(tx, &self.best_block_header)?;
|
|
||||||
|
|
||||||
self.engine
|
self.engine
|
||||||
.machine()
|
.machine()
|
||||||
|
@ -17,15 +17,17 @@
|
|||||||
//! Block RLP compression.
|
//! Block RLP compression.
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use ethereum_types::H256;
|
use ethereum_types::{H256, U256};
|
||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use rlp::{DecoderError, Rlp, RlpStream};
|
use rlp::{DecoderError, Rlp, RlpStream};
|
||||||
use triehash::ordered_trie_root;
|
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 HEADER_FIELDS: usize = 8;
|
||||||
const BLOCK_FIELDS: usize = 2;
|
const BLOCK_FIELDS: usize = 2;
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct AbridgedBlock {
|
pub struct AbridgedBlock {
|
||||||
rlp: Bytes,
|
rlp: Bytes,
|
||||||
}
|
}
|
||||||
@ -43,12 +45,19 @@ impl AbridgedBlock {
|
|||||||
|
|
||||||
/// Given a full block view, trim out the parent hash and block number,
|
/// Given a full block view, trim out the parent hash and block number,
|
||||||
/// producing new rlp.
|
/// 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 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.
|
// 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.
|
// write header values.
|
||||||
stream
|
stream
|
||||||
@ -64,13 +73,17 @@ impl AbridgedBlock {
|
|||||||
// write block values.
|
// write block values.
|
||||||
|
|
||||||
TypedTransaction::rlp_append_list(&mut stream, &block_view.transactions());
|
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.
|
// write seal fields.
|
||||||
for field in seal_fields {
|
for field in seal_fields {
|
||||||
stream.append_raw(&field, 1);
|
stream.append_raw(&field, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if eip1559 {
|
||||||
|
stream.append(&header.base_fee());
|
||||||
|
}
|
||||||
|
|
||||||
AbridgedBlock { rlp: stream.out() }
|
AbridgedBlock { rlp: stream.out() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +95,7 @@ impl AbridgedBlock {
|
|||||||
parent_hash: H256,
|
parent_hash: H256,
|
||||||
number: u64,
|
number: u64,
|
||||||
receipts_root: H256,
|
receipts_root: H256,
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
) -> Result<Block, DecoderError> {
|
) -> Result<Block, DecoderError> {
|
||||||
let rlp = Rlp::new(&self.rlp);
|
let rlp = Rlp::new(&self.rlp);
|
||||||
|
|
||||||
@ -98,7 +112,7 @@ impl AbridgedBlock {
|
|||||||
header.set_extra_data(rlp.val_at(7)?);
|
header.set_extra_data(rlp.val_at(7)?);
|
||||||
|
|
||||||
let transactions = TypedTransaction::decode_rlp_list(&rlp.at(8)?)?;
|
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| {
|
header.set_transactions_root(ordered_trie_root(rlp.at(8)?.iter().map(|r| {
|
||||||
if r.is_list() {
|
if r.is_list() {
|
||||||
@ -115,13 +129,21 @@ impl AbridgedBlock {
|
|||||||
header.set_uncles_hash(keccak(uncles_rlp.as_raw()));
|
header.set_uncles_hash(keccak(uncles_rlp.as_raw()));
|
||||||
|
|
||||||
let mut seal_fields = Vec::new();
|
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)?;
|
let seal_rlp = rlp.at(i)?;
|
||||||
seal_fields.push(seal_rlp.as_raw().to_owned());
|
seal_fields.push(seal_rlp.as_raw().to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
header.set_seal(seal_fields);
|
header.set_seal(seal_fields);
|
||||||
|
|
||||||
|
if number >= eip1559_transition {
|
||||||
|
header.set_base_fee(Some(rlp.val_at::<U256>(rlp.item_count()? - 1)?));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Block {
|
Ok(Block {
|
||||||
header: header,
|
header: header,
|
||||||
transactions: transactions,
|
transactions: transactions,
|
||||||
@ -141,6 +163,7 @@ mod tests {
|
|||||||
transaction::{Action, Transaction, TypedTransaction},
|
transaction::{Action, Transaction, TypedTransaction},
|
||||||
view,
|
view,
|
||||||
views::BlockView,
|
views::BlockView,
|
||||||
|
BlockNumber,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn encode_block(b: &Block) -> Bytes {
|
fn encode_block(b: &Block) -> Bytes {
|
||||||
@ -153,10 +176,29 @@ mod tests {
|
|||||||
let receipts_root = b.header.receipts_root().clone();
|
let receipts_root = b.header.receipts_root().clone();
|
||||||
let encoded = encode_block(&b);
|
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!(
|
assert_eq!(
|
||||||
abridged
|
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(),
|
.unwrap(),
|
||||||
b
|
b
|
||||||
);
|
);
|
||||||
@ -169,10 +211,11 @@ mod tests {
|
|||||||
let receipts_root = b.header.receipts_root().clone();
|
let receipts_root = b.header.receipts_root().clone();
|
||||||
let encoded = encode_block(&b);
|
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!(
|
assert_eq!(
|
||||||
abridged
|
abridged
|
||||||
.to_block(H256::default(), 2, receipts_root)
|
.to_block(H256::default(), 2, receipts_root, BlockNumber::max_value())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
b
|
b
|
||||||
);
|
);
|
||||||
@ -213,10 +256,13 @@ mod tests {
|
|||||||
|
|
||||||
let encoded = encode_block(&b);
|
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!(
|
assert_eq!(
|
||||||
abridged
|
abridged
|
||||||
.to_block(H256::default(), 0, receipts_root)
|
.to_block(H256::default(), 0, receipts_root, BlockNumber::max_value())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
b
|
b
|
||||||
);
|
);
|
||||||
|
@ -38,6 +38,7 @@ use itertools::{Itertools, Position};
|
|||||||
use rlp::{Rlp, RlpStream};
|
use rlp::{Rlp, RlpStream};
|
||||||
use types::{
|
use types::{
|
||||||
encoded, header::Header, ids::BlockId, receipt::TypedReceipt, transaction::TypedTransaction,
|
encoded, header::Header, ids::BlockId, receipt::TypedReceipt, transaction::TypedTransaction,
|
||||||
|
BlockNumber,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Snapshot creation and restoration for PoA chains.
|
/// Snapshot creation and restoration for PoA chains.
|
||||||
@ -61,6 +62,7 @@ impl SnapshotComponents for PoaSnapshot {
|
|||||||
sink: &mut ChunkSink,
|
sink: &mut ChunkSink,
|
||||||
_progress: &Progress,
|
_progress: &Progress,
|
||||||
preferred_size: usize,
|
preferred_size: usize,
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let number = chain
|
let number = chain
|
||||||
.block_number(&block_at)
|
.block_number(&block_at)
|
||||||
@ -107,7 +109,7 @@ impl SnapshotComponents for PoaSnapshot {
|
|||||||
.block(&block_at)
|
.block(&block_at)
|
||||||
.and_then(|b| chain.block_receipts(&block_at).map(|r| (b, r)))
|
.and_then(|b| chain.block_receipts(&block_at).map(|r| (b, r)))
|
||||||
.ok_or_else(|| Error::BlockNotFound(block_at))?;
|
.ok_or_else(|| Error::BlockNotFound(block_at))?;
|
||||||
let block = block.decode()?;
|
let block = block.decode(eip1559_transition)?;
|
||||||
|
|
||||||
let parent_td = chain
|
let parent_td = chain
|
||||||
.block_details(block.header.parent_hash())
|
.block_details(block.header.parent_hash())
|
||||||
@ -200,7 +202,8 @@ impl ChunkRebuilder {
|
|||||||
use engines::ConstructedVerifier;
|
use engines::ConstructedVerifier;
|
||||||
|
|
||||||
// decode.
|
// 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)?;
|
let epoch_data: Bytes = transition_rlp.val_at(1)?;
|
||||||
|
|
||||||
trace!(target: "snapshot", "verifying transition to epoch at block {}", header.number());
|
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 last_rlp = rlp.at(num_items - 1)?;
|
||||||
let block = Block {
|
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)?)?,
|
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 block_data = block.rlp_bytes();
|
||||||
let receipts = TypedReceipt::decode_rlp_list(&last_rlp.at(3)?)?;
|
let receipts = TypedReceipt::decode_rlp_list(&last_rlp.at(3)?)?;
|
||||||
|
@ -22,6 +22,7 @@ use std::sync::{atomic::AtomicBool, Arc};
|
|||||||
use blockchain::{BlockChain, BlockChainDB};
|
use blockchain::{BlockChain, BlockChainDB};
|
||||||
use engines::EthEngine;
|
use engines::EthEngine;
|
||||||
use snapshot::{Error, ManifestData, Progress};
|
use snapshot::{Error, ManifestData, Progress};
|
||||||
|
use types::BlockNumber;
|
||||||
|
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ pub trait SnapshotComponents: Send {
|
|||||||
chunk_sink: &mut ChunkSink,
|
chunk_sink: &mut ChunkSink,
|
||||||
progress: &Progress,
|
progress: &Progress,
|
||||||
preferred_size: usize,
|
preferred_size: usize,
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
/// Create a rebuilder, which will have chunks fed into it in aribtrary
|
/// Create a rebuilder, which will have chunks fed into it in aribtrary
|
||||||
|
@ -38,7 +38,7 @@ use ethereum_types::H256;
|
|||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use rlp::{Rlp, RlpStream};
|
use rlp::{Rlp, RlpStream};
|
||||||
use snapshot::{block::AbridgedBlock, Error, ManifestData, Progress};
|
use snapshot::{block::AbridgedBlock, Error, ManifestData, Progress};
|
||||||
use types::encoded;
|
use types::{encoded, BlockNumber};
|
||||||
|
|
||||||
/// Snapshot creation and restoration for PoW chains.
|
/// Snapshot creation and restoration for PoW chains.
|
||||||
/// This includes blocks from the head of the chain as a
|
/// This includes blocks from the head of the chain as a
|
||||||
@ -70,6 +70,7 @@ impl SnapshotComponents for PowSnapshot {
|
|||||||
chunk_sink: &mut ChunkSink,
|
chunk_sink: &mut ChunkSink,
|
||||||
progress: &Progress,
|
progress: &Progress,
|
||||||
preferred_size: usize,
|
preferred_size: usize,
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
PowWorker {
|
PowWorker {
|
||||||
chain: chain,
|
chain: chain,
|
||||||
@ -79,7 +80,7 @@ impl SnapshotComponents for PowSnapshot {
|
|||||||
progress: progress,
|
progress: progress,
|
||||||
preferred_size: preferred_size,
|
preferred_size: preferred_size,
|
||||||
}
|
}
|
||||||
.chunk_all(self.blocks)
|
.chunk_all(self.blocks, eip1559_transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rebuilder(
|
fn rebuilder(
|
||||||
@ -119,7 +120,11 @@ struct PowWorker<'a> {
|
|||||||
impl<'a> PowWorker<'a> {
|
impl<'a> PowWorker<'a> {
|
||||||
// Repeatedly fill the buffers and writes out chunks, moving backwards from starting block hash.
|
// 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.
|
// 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 loaded_size = 0;
|
||||||
let mut last = self.current_hash;
|
let mut last = self.current_hash;
|
||||||
|
|
||||||
@ -140,7 +145,8 @@ impl<'a> PowWorker<'a> {
|
|||||||
})
|
})
|
||||||
.ok_or_else(|| Error::BlockNotFound(self.current_hash))?;
|
.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 pair = {
|
||||||
let mut pair_stream = RlpStream::new_list(2);
|
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 block_bytes = encoded::Block::new(block.rlp_bytes());
|
||||||
let is_best = cur_number == self.best_number;
|
let is_best = cur_number == self.best_number;
|
||||||
|
|
||||||
|
@ -273,6 +273,7 @@ pub fn chunk_secondary<'a>(
|
|||||||
&mut chunk_sink,
|
&mut chunk_sink,
|
||||||
progress,
|
progress,
|
||||||
PREFERRED_CHUNK_SIZE,
|
PREFERRED_CHUNK_SIZE,
|
||||||
|
chain.eip1559_transition,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -621,7 +622,8 @@ pub fn verify_old_block(
|
|||||||
if always || rng.gen::<f32>() <= POW_VERIFY_RATE {
|
if always || rng.gen::<f32>() <= POW_VERIFY_RATE {
|
||||||
engine.verify_block_unordered(header)?;
|
engine.verify_block_unordered(header)?;
|
||||||
match chain.block_header_data(header.parent_hash()) {
|
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(()),
|
None => Ok(()),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -117,7 +117,12 @@ impl Restoration {
|
|||||||
|
|
||||||
let raw_db = params.db;
|
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
|
let components = params
|
||||||
.engine
|
.engine
|
||||||
.snapshot_components()
|
.snapshot_components()
|
||||||
@ -386,7 +391,12 @@ impl Service {
|
|||||||
let cur_chain_info = self.client.chain_info();
|
let cur_chain_info = self.client.chain_info();
|
||||||
|
|
||||||
let next_db = self.restoration_db_handler.open(&rest_db)?;
|
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();
|
let next_chain_info = next_chain.chain_info();
|
||||||
|
|
||||||
// The old database looks like this:
|
// The old database looks like this:
|
||||||
|
@ -171,7 +171,12 @@ pub fn restore(
|
|||||||
|
|
||||||
let mut state = StateRebuilder::new(db.key_value().clone(), journaldb::Algorithm::Archive);
|
let mut state = StateRebuilder::new(db.key_value().clone(), journaldb::Algorithm::Archive);
|
||||||
let mut secondary = {
|
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()
|
components.rebuilder(chain, db, manifest).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,7 +51,12 @@ fn chunk_and_restore(amount: u64) {
|
|||||||
let snapshot_path = tempdir.path().join("SNAP");
|
let snapshot_path = tempdir.path().join("SNAP");
|
||||||
|
|
||||||
let old_db = test_helpers::new_db();
|
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.
|
// build the blockchain.
|
||||||
let mut batch = DBTransaction::new();
|
let mut batch = DBTransaction::new();
|
||||||
@ -96,7 +101,12 @@ fn chunk_and_restore(amount: u64) {
|
|||||||
|
|
||||||
// restore it.
|
// restore it.
|
||||||
let new_db = test_helpers::new_db();
|
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
|
let mut rebuilder = SNAPSHOT_MODE
|
||||||
.rebuilder(new_chain, new_db.clone(), &manifest)
|
.rebuilder(new_chain, new_db.clone(), &manifest)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -113,7 +123,12 @@ fn chunk_and_restore(amount: u64) {
|
|||||||
drop(rebuilder);
|
drop(rebuilder);
|
||||||
|
|
||||||
// and test it.
|
// 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);
|
assert_eq!(new_chain.best_block_hash(), best_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +165,7 @@ fn checks_flag() {
|
|||||||
Default::default(),
|
Default::default(),
|
||||||
genesis.last().encoded().raw(),
|
genesis.last().encoded().raw(),
|
||||||
db.clone(),
|
db.clone(),
|
||||||
|
engine.params().eip1559_transition,
|
||||||
);
|
);
|
||||||
|
|
||||||
let manifest = ::snapshot::ManifestData {
|
let manifest = ::snapshot::ManifestData {
|
||||||
|
@ -240,7 +240,9 @@ fn keep_ancient_blocks() {
|
|||||||
let block_hash = bc.block_hash(block_number).unwrap();
|
let block_hash = bc.block_hash(block_number).unwrap();
|
||||||
let block = bc.block(&block_hash).unwrap();
|
let block = bc.block(&block_hash).unwrap();
|
||||||
client2
|
client2
|
||||||
.import_block(Unverified::from_rlp(block.into_inner()).unwrap())
|
.import_block(
|
||||||
|
Unverified::from_rlp(block.into_inner(), spec.params().eip1559_transition).unwrap(),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,8 @@ pub struct Genesis {
|
|||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
/// Extra data.
|
/// Extra data.
|
||||||
pub extra_data: Vec<u8>,
|
pub extra_data: Vec<u8>,
|
||||||
|
/// Base fee.
|
||||||
|
pub base_fee: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethjson::spec::Genesis> for Genesis {
|
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),
|
state_root: g.state_root.map(Into::into),
|
||||||
gas_used: g.gas_used.map_or_else(U256::zero, 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),
|
extra_data: g.extra_data.map_or_else(Vec::new, Into::into),
|
||||||
|
base_fee: g.base_fee.map(Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,6 +139,10 @@ pub struct CommonParams {
|
|||||||
pub eip2929_transition: BlockNumber,
|
pub eip2929_transition: BlockNumber,
|
||||||
/// Number of first block where EIP-2930 rules begin.
|
/// Number of first block where EIP-2930 rules begin.
|
||||||
pub eip2930_transition: BlockNumber,
|
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.
|
/// Number of first block where EIP-3529 rules begin.
|
||||||
pub eip3529_transition: BlockNumber,
|
pub eip3529_transition: BlockNumber,
|
||||||
/// Number of first block where EIP-3541 rule begins.
|
/// Number of first block where EIP-3541 rule begins.
|
||||||
@ -173,6 +177,12 @@ pub struct CommonParams {
|
|||||||
pub transaction_permission_contract_transition: BlockNumber,
|
pub transaction_permission_contract_transition: BlockNumber,
|
||||||
/// Maximum size of transaction's RLP payload
|
/// Maximum size of transaction's RLP payload
|
||||||
pub max_transaction_size: usize,
|
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommonParams {
|
impl CommonParams {
|
||||||
@ -220,6 +230,17 @@ impl CommonParams {
|
|||||||
schedule.eip2929 = block_number >= self.eip2929_transition;
|
schedule.eip2929 = block_number >= self.eip2929_transition;
|
||||||
schedule.eip2930 = block_number >= self.eip2930_transition;
|
schedule.eip2930 = block_number >= self.eip2930_transition;
|
||||||
schedule.eip3541 = block_number >= self.eip3541_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 {
|
if block_number >= self.eip1884_transition {
|
||||||
schedule.have_selfbalance = true;
|
schedule.have_selfbalance = true;
|
||||||
@ -388,6 +409,12 @@ impl From<ethjson::spec::Params> for CommonParams {
|
|||||||
eip2930_transition: p
|
eip2930_transition: p
|
||||||
.eip2930_transition
|
.eip2930_transition
|
||||||
.map_or_else(BlockNumber::max_value, Into::into),
|
.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: p
|
||||||
.eip3529_transition
|
.eip3529_transition
|
||||||
.map_or_else(BlockNumber::max_value, Into::into),
|
.map_or_else(BlockNumber::max_value, Into::into),
|
||||||
@ -423,6 +450,15 @@ impl From<ethjson::spec::Params> for CommonParams {
|
|||||||
kip6_transition: p
|
kip6_transition: p
|
||||||
.kip6_transition
|
.kip6_transition
|
||||||
.map_or_else(BlockNumber::max_value, Into::into),
|
.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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -497,6 +533,8 @@ pub struct Spec {
|
|||||||
pub extra_data: Bytes,
|
pub extra_data: Bytes,
|
||||||
/// Each seal field, expressed as RLP, concatenated.
|
/// Each seal field, expressed as RLP, concatenated.
|
||||||
pub seal_rlp: Bytes,
|
pub seal_rlp: Bytes,
|
||||||
|
/// Base fee,
|
||||||
|
pub base_fee: Option<U256>,
|
||||||
|
|
||||||
/// List of hard forks in the network.
|
/// List of hard forks in the network.
|
||||||
pub hard_forks: BTreeSet<BlockNumber>,
|
pub hard_forks: BTreeSet<BlockNumber>,
|
||||||
@ -533,6 +571,7 @@ impl Clone for Spec {
|
|||||||
constructors: self.constructors.clone(),
|
constructors: self.constructors.clone(),
|
||||||
state_root_memo: RwLock::new(*self.state_root_memo.read()),
|
state_root_memo: RwLock::new(*self.state_root_memo.read()),
|
||||||
genesis_state: self.genesis_state.clone(),
|
genesis_state: self.genesis_state.clone(),
|
||||||
|
base_fee: self.base_fee.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -591,6 +630,7 @@ fn load_from(spec_params: SpecParams, s: ethjson::spec::Spec) -> Result<Spec, Er
|
|||||||
timestamp: g.timestamp,
|
timestamp: g.timestamp,
|
||||||
extra_data: g.extra_data,
|
extra_data: g.extra_data,
|
||||||
seal_rlp: seal_rlp,
|
seal_rlp: seal_rlp,
|
||||||
|
base_fee: g.base_fee,
|
||||||
hard_forks,
|
hard_forks,
|
||||||
constructors: s
|
constructors: s
|
||||||
.accounts
|
.accounts
|
||||||
@ -683,6 +723,8 @@ impl Spec {
|
|||||||
params.eip2315_transition,
|
params.eip2315_transition,
|
||||||
params.eip2929_transition,
|
params.eip2929_transition,
|
||||||
params.eip2930_transition,
|
params.eip2930_transition,
|
||||||
|
params.eip1559_transition,
|
||||||
|
params.eip3198_transition,
|
||||||
params.eip3529_transition,
|
params.eip3529_transition,
|
||||||
params.eip3541_transition,
|
params.eip3541_transition,
|
||||||
params.dust_protection_transition,
|
params.dust_protection_transition,
|
||||||
@ -789,6 +831,7 @@ impl Spec {
|
|||||||
last_hashes: Default::default(),
|
last_hashes: Default::default(),
|
||||||
gas_used: U256::zero(),
|
gas_used: U256::zero(),
|
||||||
gas_limit: U256::max_value(),
|
gas_limit: U256::max_value(),
|
||||||
|
base_fee: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if !self.constructors.is_empty() {
|
if !self.constructors.is_empty() {
|
||||||
@ -897,6 +940,7 @@ impl Spec {
|
|||||||
let r = Rlp::new(&self.seal_rlp);
|
let r = Rlp::new(&self.seal_rlp);
|
||||||
r.iter().map(|f| f.as_raw().to_vec()).collect()
|
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());
|
trace!(target: "spec", "Header hash is {}", header.hash());
|
||||||
header
|
header
|
||||||
}
|
}
|
||||||
@ -925,6 +969,7 @@ impl Spec {
|
|||||||
self.timestamp = g.timestamp;
|
self.timestamp = g.timestamp;
|
||||||
self.extra_data = g.extra_data;
|
self.extra_data = g.extra_data;
|
||||||
self.seal_rlp = seal_rlp;
|
self.seal_rlp = seal_rlp;
|
||||||
|
self.base_fee = g.base_fee;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alter the value of the genesis state.
|
/// Alter the value of the genesis state.
|
||||||
@ -1008,6 +1053,7 @@ impl Spec {
|
|||||||
gas_limit: U256::max_value(),
|
gas_limit: U256::max_value(),
|
||||||
last_hashes: Arc::new(Vec::new()),
|
last_hashes: Arc::new(Vec::new()),
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
|
base_fee: genesis.base_fee(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let from = Address::default();
|
let from = Address::default();
|
||||||
|
@ -39,6 +39,7 @@ use types::{
|
|||||||
transaction::{Action, SignedTransaction, Transaction, TypedTransaction},
|
transaction::{Action, SignedTransaction, Transaction, TypedTransaction},
|
||||||
view,
|
view,
|
||||||
views::BlockView,
|
views::BlockView,
|
||||||
|
BlockNumber,
|
||||||
};
|
};
|
||||||
|
|
||||||
use block::{Drain, OpenBlock};
|
use block::{Drain, OpenBlock};
|
||||||
@ -222,14 +223,17 @@ where
|
|||||||
.seal(test_engine, vec![])
|
.seal(test_engine, vec![])
|
||||||
.unwrap();
|
.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!(
|
panic!(
|
||||||
"error importing block which is valid by definition: {:?}",
|
"error importing block which is valid by definition: {:?}",
|
||||||
e
|
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;
|
db = b.drain().state.drop().1;
|
||||||
}
|
}
|
||||||
client.flush_queue();
|
client.flush_queue();
|
||||||
@ -266,9 +270,13 @@ pub fn push_blocks_to_client(
|
|||||||
rolling_block_number = rolling_block_number + 1;
|
rolling_block_number = rolling_block_number + 1;
|
||||||
rolling_timestamp = rolling_timestamp + 10;
|
rolling_timestamp = rolling_timestamp + 10;
|
||||||
|
|
||||||
if let Err(e) =
|
if let Err(e) = client.import_block(
|
||||||
client.import_block(Unverified::from_rlp(create_test_block(&header)).unwrap())
|
Unverified::from_rlp(
|
||||||
{
|
create_test_block(&header),
|
||||||
|
test_spec.params().eip1559_transition,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
) {
|
||||||
panic!(
|
panic!(
|
||||||
"error importing block which is valid by definition: {:?}",
|
"error importing block which is valid by definition: {:?}",
|
||||||
e
|
e
|
||||||
@ -297,7 +305,9 @@ pub fn push_block_with_transactions(client: &Arc<Client>, transactions: &[Signed
|
|||||||
.seal(test_engine, vec![])
|
.seal(test_engine, vec![])
|
||||||
.unwrap();
|
.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!(
|
panic!(
|
||||||
"error importing block which is valid by definition: {:?}",
|
"error importing block which is valid by definition: {:?}",
|
||||||
e
|
e
|
||||||
@ -323,7 +333,9 @@ pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> Arc<Client> {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
for block in blocks {
|
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);
|
panic!("error importing block which is well-formed: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -456,6 +468,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain {
|
|||||||
BlockChainConfig::default(),
|
BlockChainConfig::default(),
|
||||||
&create_unverifiable_block(0, H256::zero()),
|
&create_unverifiable_block(0, H256::zero()),
|
||||||
db.clone(),
|
db.clone(),
|
||||||
|
BlockNumber::max_value(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut batch = db.key_value().transaction();
|
let mut batch = db.key_value().transaction();
|
||||||
@ -483,6 +496,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain {
|
|||||||
BlockChainConfig::default(),
|
BlockChainConfig::default(),
|
||||||
&create_unverifiable_block(0, H256::zero()),
|
&create_unverifiable_block(0, H256::zero()),
|
||||||
db.clone(),
|
db.clone(),
|
||||||
|
BlockNumber::max_value(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut batch = db.key_value().transaction();
|
let mut batch = db.key_value().transaction();
|
||||||
@ -514,6 +528,7 @@ pub fn generate_dummy_empty_blockchain() -> BlockChain {
|
|||||||
BlockChainConfig::default(),
|
BlockChainConfig::default(),
|
||||||
&create_unverifiable_block(0, H256::zero()),
|
&create_unverifiable_block(0, H256::zero()),
|
||||||
db.clone(),
|
db.clone(),
|
||||||
|
BlockNumber::max_value(),
|
||||||
);
|
);
|
||||||
bc
|
bc
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ fn imports_good_block() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let good_block = get_good_dummy_block();
|
let good_block = get_good_dummy_block();
|
||||||
if client
|
if client
|
||||||
.import_block(Unverified::from_rlp(good_block).unwrap())
|
.import_block(Unverified::from_rlp(good_block, spec.params().eip1559_transition).unwrap())
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
panic!("error importing block being good by definition");
|
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 client = get_test_client_with_blocks(vec![dummy_block.clone()]);
|
||||||
let block = view!(BlockView, &dummy_block);
|
let block = view!(BlockView, &dummy_block);
|
||||||
let info = client.chain_info();
|
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]
|
#[test]
|
||||||
@ -188,7 +193,11 @@ fn returns_block_body() {
|
|||||||
let client = get_test_client_with_blocks(vec![dummy_block.clone()]);
|
let client = get_test_client_with_blocks(vec![dummy_block.clone()]);
|
||||||
let block = view!(BlockView, &dummy_block);
|
let block = view!(BlockView, &dummy_block);
|
||||||
let body = client
|
let body = client
|
||||||
.block_body(BlockId::Hash(block.header().hash()))
|
.block_body(BlockId::Hash(
|
||||||
|
block
|
||||||
|
.header(client.engine().params().eip1559_transition)
|
||||||
|
.hash(),
|
||||||
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let body = body.rlp();
|
let body = body.rlp();
|
||||||
assert_eq!(body.item_count().unwrap(), 2);
|
assert_eq!(body.item_count().unwrap(), 2);
|
||||||
|
@ -100,14 +100,17 @@ fn can_trace_block_and_uncle_reward() {
|
|||||||
.seal(engine, vec![])
|
.seal(engine, vec![])
|
||||||
.unwrap();
|
.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!(
|
panic!(
|
||||||
"error importing block which is valid by definition: {:?}",
|
"error importing block which is valid by definition: {:?}",
|
||||||
e
|
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();
|
let root_header = last_header.clone();
|
||||||
db = root_block.drain().state.drop().1;
|
db = root_block.drain().state.drop().1;
|
||||||
|
|
||||||
@ -137,14 +140,17 @@ fn can_trace_block_and_uncle_reward() {
|
|||||||
.seal(engine, vec![])
|
.seal(engine, vec![])
|
||||||
.unwrap();
|
.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!(
|
panic!(
|
||||||
"error importing block which is valid by definition: {:?}",
|
"error importing block which is valid by definition: {:?}",
|
||||||
e
|
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;
|
db = parent_block.drain().state.drop().1;
|
||||||
|
|
||||||
last_hashes.push(last_header.hash());
|
last_hashes.push(last_header.hash());
|
||||||
@ -201,7 +207,9 @@ fn can_trace_block_and_uncle_reward() {
|
|||||||
.seal(engine, vec![])
|
.seal(engine, vec![])
|
||||||
.unwrap();
|
.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() {
|
if res.is_err() {
|
||||||
panic!("error importing block: {:#?}", res.err().unwrap());
|
panic!("error importing block: {:#?}", res.err().unwrap());
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,7 @@ pub mod blocks {
|
|||||||
use types::{
|
use types::{
|
||||||
header::Header,
|
header::Header,
|
||||||
transaction::{TypedTransaction, UnverifiedTransaction},
|
transaction::{TypedTransaction, UnverifiedTransaction},
|
||||||
|
BlockNumber,
|
||||||
};
|
};
|
||||||
use verification::{verify_block_basic, verify_block_unordered, PreverifiedBlock};
|
use verification::{verify_block_basic, verify_block_unordered, PreverifiedBlock};
|
||||||
|
|
||||||
@ -149,13 +150,16 @@ pub mod blocks {
|
|||||||
|
|
||||||
impl Unverified {
|
impl Unverified {
|
||||||
/// Create an `Unverified` from raw bytes.
|
/// 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;
|
use rlp::Rlp;
|
||||||
let (header, transactions, uncles) = {
|
let (header, transactions, uncles) = {
|
||||||
let rlp = Rlp::new(&bytes);
|
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 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)
|
(header, transactions, uncles)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -876,7 +876,7 @@ mod tests {
|
|||||||
use io::*;
|
use io::*;
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use test_helpers::{get_good_dummy_block, get_good_dummy_block_seq};
|
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.
|
// create a test block queue.
|
||||||
// auto_scaling enables verifier adjustment.
|
// auto_scaling enables verifier adjustment.
|
||||||
@ -897,7 +897,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_unverified(bytes: Bytes) -> Unverified {
|
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]
|
#[test]
|
||||||
@ -941,7 +941,10 @@ mod tests {
|
|||||||
fn returns_total_difficulty() {
|
fn returns_total_difficulty() {
|
||||||
let queue = get_test_queue(false);
|
let queue = get_test_queue(false);
|
||||||
let block = get_good_dummy_block();
|
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)) {
|
if let Err(e) = queue.import(new_unverified(block)) {
|
||||||
panic!("error importing block that is valid by definition({:?})", e);
|
panic!("error importing block that is valid by definition({:?})", e);
|
||||||
}
|
}
|
||||||
@ -957,7 +960,10 @@ mod tests {
|
|||||||
fn returns_ok_for_drained_duplicates() {
|
fn returns_ok_for_drained_duplicates() {
|
||||||
let queue = get_test_queue(false);
|
let queue = get_test_queue(false);
|
||||||
let block = get_good_dummy_block();
|
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)) {
|
if let Err(e) = queue.import(new_unverified(block)) {
|
||||||
panic!("error importing block that is valid by definition({:?})", e);
|
panic!("error importing block that is valid by definition({:?})", e);
|
||||||
}
|
}
|
||||||
|
@ -84,11 +84,11 @@ pub fn verify_block_basic(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// t_nb 4.6 call engine.gas_limit_override (Used only by Aura)
|
// 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 let Some(expected_gas_limit) = engine.gas_limit_override(&block.header) {
|
||||||
if *block.header.gas_limit() != gas_limit {
|
if block.header.gas_limit() != &expected_gas_limit {
|
||||||
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds {
|
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds {
|
||||||
min: Some(gas_limit),
|
min: Some(expected_gas_limit),
|
||||||
max: Some(gas_limit),
|
max: Some(expected_gas_limit),
|
||||||
found: *block.header.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)?;
|
verify_parent(&uncle, &uncle_parent, engine)?;
|
||||||
engine.verify_block_family(&uncle, &uncle_parent)?;
|
engine.verify_block_family(&uncle, &uncle_parent)?;
|
||||||
verified.insert(uncle.hash());
|
verified.insert(uncle.hash());
|
||||||
@ -360,6 +360,8 @@ pub fn verify_header_params(
|
|||||||
found: header.number(),
|
found: header.number(),
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if the block used too much gas
|
||||||
if header.gas_used() > header.gas_limit() {
|
if header.gas_used() > header.gas_limit() {
|
||||||
return Err(From::from(BlockError::TooMuchGasUsed(OutOfBounds {
|
return Err(From::from(BlockError::TooMuchGasUsed(OutOfBounds {
|
||||||
max: Some(*header.gas_limit()),
|
max: Some(*header.gas_limit()),
|
||||||
@ -476,9 +478,11 @@ fn verify_parent(header: &Header, parent: &Header, engine: &dyn EthEngine) -> Re
|
|||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if the block changed the gas limit too much
|
||||||
if engine.gas_limit_override(header).is_none() {
|
if engine.gas_limit_override(header).is_none() {
|
||||||
let gas_limit_divisor = engine.params().gas_limit_bound_divisor;
|
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 min_gas = parent_gas_limit - parent_gas_limit / gas_limit_divisor;
|
||||||
let max_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 {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -599,7 +612,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, bytes: Bytes) {
|
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();
|
let hash = header.hash();
|
||||||
self.blocks.insert(hash, bytes);
|
self.blocks.insert(hash, bytes);
|
||||||
self.numbers.insert(header.number(), hash);
|
self.numbers.insert(header.number(), hash);
|
||||||
@ -639,7 +654,9 @@ mod tests {
|
|||||||
/// Get the familial details concerning a block.
|
/// Get the familial details concerning a block.
|
||||||
fn block_details(&self, hash: &H256) -> Option<BlockDetails> {
|
fn block_details(&self, hash: &H256) -> Option<BlockDetails> {
|
||||||
self.blocks.get(hash).map(|bytes| {
|
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 {
|
BlockDetails {
|
||||||
number: header.number(),
|
number: header.number(),
|
||||||
total_difficulty: *header.difficulty(),
|
total_difficulty: *header.difficulty(),
|
||||||
@ -693,7 +710,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn basic_test(bytes: &[u8], engine: &dyn EthEngine) -> Result<(), Error> {
|
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)
|
verify_block_basic(&unverified, engine, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,7 +718,8 @@ mod tests {
|
|||||||
where
|
where
|
||||||
BC: BlockProvider,
|
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 header = block.header;
|
||||||
let transactions: Vec<_> = block
|
let transactions: Vec<_> = block
|
||||||
.transactions
|
.transactions
|
||||||
@ -717,7 +735,7 @@ mod tests {
|
|||||||
let parent = bc
|
let parent = bc
|
||||||
.block_header_data(header.parent_hash())
|
.block_header_data(header.parent_hash())
|
||||||
.ok_or(BlockError::UnknownParent(*header.parent_hash()))?
|
.ok_or(BlockError::UnknownParent(*header.parent_hash()))?
|
||||||
.decode()?;
|
.decode(engine.params().eip1559_transition)?;
|
||||||
|
|
||||||
let block = PreverifiedBlock {
|
let block = PreverifiedBlock {
|
||||||
header,
|
header,
|
||||||
@ -735,7 +753,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn unordered_test(bytes: &[u8], engine: &dyn EthEngine) -> Result<(), Error> {
|
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)?;
|
verify_block_unordered(un, engine, false)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,8 @@ pub struct SyncConfig {
|
|||||||
pub fork_block: Option<(BlockNumber, H256)>,
|
pub fork_block: Option<(BlockNumber, H256)>,
|
||||||
/// Enable snapshot sync
|
/// Enable snapshot sync
|
||||||
pub warp_sync: WarpSync,
|
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 {
|
impl Default for SyncConfig {
|
||||||
@ -121,6 +123,7 @@ impl Default for SyncConfig {
|
|||||||
subprotocol_name: ETH_PROTOCOL,
|
subprotocol_name: ETH_PROTOCOL,
|
||||||
fork_block: None,
|
fork_block: None,
|
||||||
warp_sync: WarpSync::Disabled,
|
warp_sync: WarpSync::Disabled,
|
||||||
|
eip1559_transition: BlockNumber::max_value(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,6 +250,7 @@ impl BlockDownloader {
|
|||||||
io: &mut dyn SyncIo,
|
io: &mut dyn SyncIo,
|
||||||
r: &Rlp,
|
r: &Rlp,
|
||||||
expected_hash: H256,
|
expected_hash: H256,
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
) -> Result<DownloadAction, BlockDownloaderImportError> {
|
) -> Result<DownloadAction, BlockDownloaderImportError> {
|
||||||
let item_count = r.item_count().unwrap_or(0);
|
let item_count = r.item_count().unwrap_or(0);
|
||||||
if self.state == State::Idle {
|
if self.state == State::Idle {
|
||||||
@ -276,7 +277,7 @@ impl BlockDownloader {
|
|||||||
let mut hashes = Vec::new();
|
let mut hashes = Vec::new();
|
||||||
let mut last_header = None;
|
let mut last_header = None;
|
||||||
for i in 0..item_count {
|
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 number = BlockNumber::from(info.header.number());
|
||||||
let hash = info.header.hash();
|
let hash = info.header.hash();
|
||||||
|
|
||||||
@ -421,6 +422,7 @@ impl BlockDownloader {
|
|||||||
&mut self,
|
&mut self,
|
||||||
r: &Rlp,
|
r: &Rlp,
|
||||||
expected_hashes: &[H256],
|
expected_hashes: &[H256],
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
) -> Result<(), BlockDownloaderImportError> {
|
) -> Result<(), BlockDownloaderImportError> {
|
||||||
let item_count = r.item_count().unwrap_or(0);
|
let item_count = r.item_count().unwrap_or(0);
|
||||||
if item_count == 0 {
|
if item_count == 0 {
|
||||||
@ -430,7 +432,7 @@ impl BlockDownloader {
|
|||||||
} else {
|
} else {
|
||||||
let mut bodies = Vec::with_capacity(item_count);
|
let mut bodies = Vec::with_capacity(item_count);
|
||||||
for i in 0..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);
|
bodies.push(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -796,21 +798,23 @@ mod tests {
|
|||||||
headers: &[BlockHeader],
|
headers: &[BlockHeader],
|
||||||
downloader: &mut BlockDownloader,
|
downloader: &mut BlockDownloader,
|
||||||
io: &mut dyn SyncIo,
|
io: &mut dyn SyncIo,
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
) -> Result<DownloadAction, BlockDownloaderImportError> {
|
) -> Result<DownloadAction, BlockDownloaderImportError> {
|
||||||
let mut stream = RlpStream::new();
|
let mut stream = RlpStream::new();
|
||||||
stream.append_list(headers);
|
stream.append_list(headers);
|
||||||
let bytes = stream.out();
|
let bytes = stream.out();
|
||||||
let rlp = Rlp::new(&bytes);
|
let rlp = Rlp::new(&bytes);
|
||||||
let expected_hash = headers.first().unwrap().hash();
|
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(
|
fn import_headers_ok(
|
||||||
headers: &[BlockHeader],
|
headers: &[BlockHeader],
|
||||||
downloader: &mut BlockDownloader,
|
downloader: &mut BlockDownloader,
|
||||||
io: &mut dyn SyncIo,
|
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());
|
assert!(res.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,7 +842,12 @@ mod tests {
|
|||||||
let rlp_data = encode_list(&valid_headers);
|
let rlp_data = encode_list(&valid_headers);
|
||||||
let valid_rlp = Rlp::new(&rlp_data);
|
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),
|
Ok(DownloadAction::Reset) => assert_eq!(downloader.state, State::Blocks),
|
||||||
_ => panic!("expected transition to Blocks state"),
|
_ => panic!("expected transition to Blocks state"),
|
||||||
};
|
};
|
||||||
@ -852,7 +861,12 @@ mod tests {
|
|||||||
let rlp_data = encode_list(&invalid_start_block_headers);
|
let rlp_data = encode_list(&invalid_start_block_headers);
|
||||||
let invalid_start_block_rlp = Rlp::new(&rlp_data);
|
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) => (),
|
Err(BlockDownloaderImportError::Invalid) => (),
|
||||||
_ => panic!("expected BlockDownloaderImportError"),
|
_ => panic!("expected BlockDownloaderImportError"),
|
||||||
};
|
};
|
||||||
@ -866,7 +880,12 @@ mod tests {
|
|||||||
let rlp_data = encode_list(&invalid_skip_headers);
|
let rlp_data = encode_list(&invalid_skip_headers);
|
||||||
let invalid_skip_rlp = Rlp::new(&rlp_data);
|
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) => (),
|
Err(BlockDownloaderImportError::Invalid) => (),
|
||||||
_ => panic!("expected BlockDownloaderImportError"),
|
_ => panic!("expected BlockDownloaderImportError"),
|
||||||
};
|
};
|
||||||
@ -883,7 +902,12 @@ mod tests {
|
|||||||
let rlp_data = encode_list(&too_many_headers);
|
let rlp_data = encode_list(&too_many_headers);
|
||||||
|
|
||||||
let too_many_rlp = Rlp::new(&rlp_data);
|
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) => (),
|
Err(BlockDownloaderImportError::Invalid) => (),
|
||||||
_ => panic!("expected BlockDownloaderImportError"),
|
_ => panic!("expected BlockDownloaderImportError"),
|
||||||
};
|
};
|
||||||
@ -894,6 +918,7 @@ mod tests {
|
|||||||
::env_logger::try_init().ok();
|
::env_logger::try_init().ok();
|
||||||
|
|
||||||
let mut chain = TestBlockChainClient::new();
|
let mut chain = TestBlockChainClient::new();
|
||||||
|
let eip1559_transition = BlockNumber::default();
|
||||||
let snapshot_service = TestSnapshotService::new();
|
let snapshot_service = TestSnapshotService::new();
|
||||||
let queue = RwLock::new(VecDeque::new());
|
let queue = RwLock::new(VecDeque::new());
|
||||||
let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None);
|
let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None);
|
||||||
@ -913,7 +938,12 @@ mod tests {
|
|||||||
let rlp_data = encode_list(&headers);
|
let rlp_data = encode_list(&headers);
|
||||||
let headers_rlp = Rlp::new(&rlp_data);
|
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) => (),
|
Ok(DownloadAction::None) => (),
|
||||||
_ => panic!("expected successful import"),
|
_ => panic!("expected successful import"),
|
||||||
};
|
};
|
||||||
@ -923,7 +953,12 @@ mod tests {
|
|||||||
let rlp_data = encode_list(&headers);
|
let rlp_data = encode_list(&headers);
|
||||||
let headers_rlp = Rlp::new(&rlp_data);
|
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) => (),
|
Err(BlockDownloaderImportError::Invalid) => (),
|
||||||
_ => panic!("expected BlockDownloaderImportError"),
|
_ => panic!("expected BlockDownloaderImportError"),
|
||||||
};
|
};
|
||||||
@ -933,7 +968,12 @@ mod tests {
|
|||||||
let rlp_data = encode_list(&headers);
|
let rlp_data = encode_list(&headers);
|
||||||
let headers_rlp = Rlp::new(&rlp_data);
|
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) => (),
|
Err(BlockDownloaderImportError::Invalid) => (),
|
||||||
_ => panic!("expected BlockDownloaderImportError"),
|
_ => panic!("expected BlockDownloaderImportError"),
|
||||||
};
|
};
|
||||||
@ -944,6 +984,7 @@ mod tests {
|
|||||||
::env_logger::try_init().ok();
|
::env_logger::try_init().ok();
|
||||||
|
|
||||||
let mut chain = TestBlockChainClient::new();
|
let mut chain = TestBlockChainClient::new();
|
||||||
|
let eip1559_transition = chain.spec.params().eip1559_transition;
|
||||||
let snapshot_service = TestSnapshotService::new();
|
let snapshot_service = TestSnapshotService::new();
|
||||||
let queue = RwLock::new(VecDeque::new());
|
let queue = RwLock::new(VecDeque::new());
|
||||||
let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None);
|
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 rlp_data = encode_list(&headers[0..3]);
|
||||||
let headers_rlp = Rlp::new(&rlp_data);
|
let headers_rlp = Rlp::new(&rlp_data);
|
||||||
assert!(downloader
|
assert!(downloader
|
||||||
.import_headers(&mut io, &headers_rlp, headers[0].hash())
|
.import_headers(&mut io, &headers_rlp, headers[0].hash(), eip1559_transition)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// Import first body successfully.
|
// Import first body successfully.
|
||||||
@ -1000,7 +1041,11 @@ mod tests {
|
|||||||
rlp_data.append_raw(&bodies[0], 1);
|
rlp_data.append_raw(&bodies[0], 1);
|
||||||
let bodies_rlp = Rlp::new(rlp_data.as_raw());
|
let bodies_rlp = Rlp::new(rlp_data.as_raw());
|
||||||
assert!(downloader
|
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());
|
.is_ok());
|
||||||
|
|
||||||
// Import second body successfully.
|
// Import second body successfully.
|
||||||
@ -1008,14 +1053,22 @@ mod tests {
|
|||||||
rlp_data.append_raw(&bodies[1], 1);
|
rlp_data.append_raw(&bodies[1], 1);
|
||||||
let bodies_rlp = Rlp::new(rlp_data.as_raw());
|
let bodies_rlp = Rlp::new(rlp_data.as_raw());
|
||||||
assert!(downloader
|
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());
|
.is_ok());
|
||||||
|
|
||||||
// Import unexpected third body.
|
// Import unexpected third body.
|
||||||
let mut rlp_data = RlpStream::new_list(1);
|
let mut rlp_data = RlpStream::new_list(1);
|
||||||
rlp_data.append_raw(&bodies[2], 1);
|
rlp_data.append_raw(&bodies[2], 1);
|
||||||
let bodies_rlp = Rlp::new(rlp_data.as_raw());
|
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) => (),
|
Err(BlockDownloaderImportError::Invalid) => (),
|
||||||
_ => panic!("expected BlockDownloaderImportError"),
|
_ => panic!("expected BlockDownloaderImportError"),
|
||||||
};
|
};
|
||||||
@ -1026,6 +1079,7 @@ mod tests {
|
|||||||
::env_logger::try_init().ok();
|
::env_logger::try_init().ok();
|
||||||
|
|
||||||
let mut chain = TestBlockChainClient::new();
|
let mut chain = TestBlockChainClient::new();
|
||||||
|
let eip1559_transition = chain.spec.params().eip1559_transition;
|
||||||
let snapshot_service = TestSnapshotService::new();
|
let snapshot_service = TestSnapshotService::new();
|
||||||
let queue = RwLock::new(VecDeque::new());
|
let queue = RwLock::new(VecDeque::new());
|
||||||
let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None);
|
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 rlp_data = encode_list(&headers[0..3]);
|
||||||
let headers_rlp = Rlp::new(&rlp_data);
|
let headers_rlp = Rlp::new(&rlp_data);
|
||||||
assert!(downloader
|
assert!(downloader
|
||||||
.import_headers(&mut io, &headers_rlp, headers[0].hash())
|
.import_headers(&mut io, &headers_rlp, headers[0].hash(), eip1559_transition)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// Import second and third receipts successfully.
|
// Import second and third receipts successfully.
|
||||||
@ -1085,7 +1139,11 @@ mod tests {
|
|||||||
let mut rlp_data = RlpStream::new_list(1);
|
let mut rlp_data = RlpStream::new_list(1);
|
||||||
rlp_data.append_raw(&receipts[3], 1);
|
rlp_data.append_raw(&receipts[3], 1);
|
||||||
let bodies_rlp = Rlp::new(rlp_data.as_raw());
|
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) => (),
|
Err(BlockDownloaderImportError::Invalid) => (),
|
||||||
_ => panic!("expected BlockDownloaderImportError"),
|
_ => panic!("expected BlockDownloaderImportError"),
|
||||||
};
|
};
|
||||||
@ -1114,8 +1172,18 @@ mod tests {
|
|||||||
|
|
||||||
let short_subchain = [dummy_header(1, genesis_hash)];
|
let short_subchain = [dummy_header(1, genesis_hash)];
|
||||||
|
|
||||||
import_headers_ok(&heads, &mut downloader, &mut io);
|
import_headers_ok(
|
||||||
import_headers_ok(&short_subchain, &mut downloader, &mut io);
|
&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_eq!(downloader.state, State::Blocks);
|
||||||
assert!(!downloader.blocks.is_empty());
|
assert!(!downloader.blocks.is_empty());
|
||||||
@ -1123,7 +1191,12 @@ mod tests {
|
|||||||
// simulate receiving useless headers
|
// simulate receiving useless headers
|
||||||
let head = vec![short_subchain.last().unwrap().clone()];
|
let head = vec![short_subchain.last().unwrap().clone()];
|
||||||
for _ in 0..MAX_USELESS_HEADERS_PER_ROUND {
|
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());
|
assert!(res.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1150,8 +1223,18 @@ mod tests {
|
|||||||
|
|
||||||
let short_subchain = [dummy_header(1, genesis_hash)];
|
let short_subchain = [dummy_header(1, genesis_hash)];
|
||||||
|
|
||||||
import_headers_ok(&heads, &mut downloader, &mut io);
|
import_headers_ok(
|
||||||
import_headers_ok(&short_subchain, &mut downloader, &mut io);
|
&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_eq!(downloader.state, State::Blocks);
|
||||||
assert!(!downloader.blocks.is_empty());
|
assert!(!downloader.blocks.is_empty());
|
||||||
@ -1159,7 +1242,12 @@ mod tests {
|
|||||||
// simulate receiving useless headers
|
// simulate receiving useless headers
|
||||||
let head = vec![short_subchain.last().unwrap().clone()];
|
let head = vec![short_subchain.last().unwrap().clone()];
|
||||||
for _ in 0..MAX_USELESS_HEADERS_PER_ROUND {
|
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());
|
assert!(res.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ use triehash_ethereum::ordered_trie_root;
|
|||||||
use types::{
|
use types::{
|
||||||
header::Header as BlockHeader,
|
header::Header as BlockHeader,
|
||||||
transaction::{TypedTransaction, UnverifiedTransaction},
|
transaction::{TypedTransaction, UnverifiedTransaction},
|
||||||
|
BlockNumber,
|
||||||
};
|
};
|
||||||
|
|
||||||
malloc_size_of_is_0!(HeaderId);
|
malloc_size_of_is_0!(HeaderId);
|
||||||
@ -37,9 +38,10 @@ pub struct SyncHeader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
let result = SyncHeader {
|
||||||
header: ::rlp::decode(&bytes)?,
|
header: BlockHeader::decode_rlp(&rlp, eip1559_transition)?,
|
||||||
bytes,
|
bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,7 +58,7 @@ pub struct SyncBody {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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 rlp = Rlp::new(bytes);
|
||||||
let transactions_rlp = rlp.at(0)?;
|
let transactions_rlp = rlp.at(0)?;
|
||||||
let uncles_rlp = rlp.at(1)?;
|
let uncles_rlp = rlp.at(1)?;
|
||||||
@ -65,7 +67,7 @@ impl SyncBody {
|
|||||||
transactions_bytes: transactions_rlp.as_raw().to_vec(),
|
transactions_bytes: transactions_rlp.as_raw().to_vec(),
|
||||||
transactions: TypedTransaction::decode_rlp_list(&transactions_rlp)?,
|
transactions: TypedTransaction::decode_rlp_list(&transactions_rlp)?,
|
||||||
uncles_bytes: uncles_rlp.as_raw().to_vec(),
|
uncles_bytes: uncles_rlp.as_raw().to_vec(),
|
||||||
uncles: uncles_rlp.as_list()?,
|
uncles: BlockHeader::decode_rlp_list(&uncles_rlp, eip1559_transition)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
@ -672,7 +674,13 @@ mod test {
|
|||||||
.collect();
|
.collect();
|
||||||
let headers: Vec<_> = blocks
|
let headers: Vec<_> = blocks
|
||||||
.iter()
|
.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();
|
.collect();
|
||||||
let hashes: Vec<_> = headers.iter().map(|h| h.header.hash()).collect();
|
let hashes: Vec<_> = headers.iter().map(|h| h.header.hash()).collect();
|
||||||
let heads: Vec<_> = hashes
|
let heads: Vec<_> = hashes
|
||||||
@ -707,7 +715,10 @@ mod test {
|
|||||||
bc.drain().into_iter().map(|b| b.block).collect::<Vec<_>>(),
|
bc.drain().into_iter().map(|b| b.block).collect::<Vec<_>>(),
|
||||||
blocks[0..6]
|
blocks[0..6]
|
||||||
.iter()
|
.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<_>>()
|
.collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
assert!(!bc.contains(&hashes[0]));
|
assert!(!bc.contains(&hashes[0]));
|
||||||
@ -724,7 +735,10 @@ mod test {
|
|||||||
bc.drain().into_iter().map(|b| b.block).collect::<Vec<_>>(),
|
bc.drain().into_iter().map(|b| b.block).collect::<Vec<_>>(),
|
||||||
blocks[6..16]
|
blocks[6..16]
|
||||||
.iter()
|
.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<_>>()
|
.collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -752,7 +766,13 @@ mod test {
|
|||||||
.collect();
|
.collect();
|
||||||
let headers: Vec<_> = blocks
|
let headers: Vec<_> = blocks
|
||||||
.iter()
|
.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();
|
.collect();
|
||||||
let hashes: Vec<_> = headers.iter().map(|h| h.header.hash()).collect();
|
let hashes: Vec<_> = headers.iter().map(|h| h.header.hash()).collect();
|
||||||
let heads: Vec<_> = hashes
|
let heads: Vec<_> = hashes
|
||||||
@ -788,7 +808,13 @@ mod test {
|
|||||||
.collect();
|
.collect();
|
||||||
let headers: Vec<_> = blocks
|
let headers: Vec<_> = blocks
|
||||||
.iter()
|
.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();
|
.collect();
|
||||||
let hashes: Vec<_> = headers.iter().map(|h| h.header.hash()).collect();
|
let hashes: Vec<_> = headers.iter().map(|h| h.header.hash()).collect();
|
||||||
let heads: Vec<_> = hashes
|
let heads: Vec<_> = hashes
|
||||||
|
@ -159,7 +159,7 @@ impl SyncHandler {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// t_nb 1.0 decode RLP
|
// 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 hash = block.header.hash();
|
||||||
let number = block.header.number();
|
let number = block.header.number();
|
||||||
trace!(target: "sync", "{} -> NewBlock ({})", peer_id, hash);
|
trace!(target: "sync", "{} -> NewBlock ({})", peer_id, hash);
|
||||||
@ -360,7 +360,7 @@ impl SyncHandler {
|
|||||||
Some(ref mut blocks) => blocks,
|
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);
|
sync.collect_blocks(io, block_set);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -479,7 +479,7 @@ impl SyncHandler {
|
|||||||
Some(ref mut blocks) => blocks,
|
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 {
|
if result == DownloadAction::Reset {
|
||||||
|
@ -693,6 +693,8 @@ pub struct ChainSync {
|
|||||||
download_old_blocks: bool,
|
download_old_blocks: bool,
|
||||||
/// Enable warp sync.
|
/// Enable warp sync.
|
||||||
warp_sync: WarpSync,
|
warp_sync: WarpSync,
|
||||||
|
/// New block encoding/decoding format is introduced by the EIP1559
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
@ -778,6 +780,7 @@ impl ChainSync {
|
|||||||
sync_start_time: None,
|
sync_start_time: None,
|
||||||
transactions_stats: TransactionsStats::default(),
|
transactions_stats: TransactionsStats::default(),
|
||||||
warp_sync: config.warp_sync,
|
warp_sync: config.warp_sync,
|
||||||
|
eip1559_transition: config.eip1559_transition,
|
||||||
};
|
};
|
||||||
sync.update_targets(chain);
|
sync.update_targets(chain);
|
||||||
sync
|
sync
|
||||||
|
@ -464,14 +464,18 @@ mod test {
|
|||||||
rlp.append(&if reverse { 1u32 } else { 0u32 });
|
rlp.append(&if reverse { 1u32 } else { 0u32 });
|
||||||
rlp.out()
|
rlp.out()
|
||||||
}
|
}
|
||||||
fn to_header_vec(rlp: ::chain::RlpResponseResult) -> Vec<SyncHeader> {
|
fn to_header_vec(
|
||||||
|
rlp: ::chain::RlpResponseResult,
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
|
) -> Vec<SyncHeader> {
|
||||||
Rlp::new(&rlp.unwrap().unwrap().1.out())
|
Rlp::new(&rlp.unwrap().unwrap().1.out())
|
||||||
.iter()
|
.iter()
|
||||||
.map(|r| SyncHeader::from_rlp(r.as_raw().to_vec()).unwrap())
|
.map(|r| SyncHeader::from_rlp(r.as_raw().to_vec(), eip1559_transition).unwrap())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut client = TestBlockChainClient::new();
|
let mut client = TestBlockChainClient::new();
|
||||||
|
let eip1559_transition = client.spec.params().eip1559_transition;
|
||||||
client.add_blocks(100, EachBlockWith::Nothing);
|
client.add_blocks(100, EachBlockWith::Nothing);
|
||||||
let blocks: Vec<_> = (0..100)
|
let blocks: Vec<_> = (0..100)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
@ -483,7 +487,13 @@ mod test {
|
|||||||
.collect();
|
.collect();
|
||||||
let headers: Vec<_> = blocks
|
let headers: Vec<_> = blocks
|
||||||
.iter()
|
.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(),
|
||||||
|
eip1559_transition,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let hashes: Vec<_> = headers.iter().map(|h| h.header.hash()).collect();
|
let hashes: Vec<_> = headers.iter().map(|h| h.header.hash()).collect();
|
||||||
|
|
||||||
@ -497,27 +507,33 @@ mod test {
|
|||||||
&Rlp::new(&make_hash_req(&unknown, 1, 0, false)),
|
&Rlp::new(&make_hash_req(&unknown, 1, 0, false)),
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
assert!(to_header_vec(result).is_empty());
|
assert!(to_header_vec(result, eip1559_transition).is_empty(),);
|
||||||
let result = SyncSupplier::return_block_headers(
|
let result = SyncSupplier::return_block_headers(
|
||||||
&io,
|
&io,
|
||||||
&Rlp::new(&make_hash_req(&unknown, 1, 0, true)),
|
&Rlp::new(&make_hash_req(&unknown, 1, 0, true)),
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
assert!(to_header_vec(result).is_empty());
|
assert!(to_header_vec(result, eip1559_transition).is_empty());
|
||||||
|
|
||||||
let result = SyncSupplier::return_block_headers(
|
let result = SyncSupplier::return_block_headers(
|
||||||
&io,
|
&io,
|
||||||
&Rlp::new(&make_hash_req(&hashes[2], 1, 0, true)),
|
&Rlp::new(&make_hash_req(&hashes[2], 1, 0, true)),
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
assert_eq!(to_header_vec(result), vec![headers[2].clone()]);
|
assert_eq!(
|
||||||
|
to_header_vec(result, eip1559_transition),
|
||||||
|
vec![headers[2].clone()]
|
||||||
|
);
|
||||||
|
|
||||||
let result = SyncSupplier::return_block_headers(
|
let result = SyncSupplier::return_block_headers(
|
||||||
&io,
|
&io,
|
||||||
&Rlp::new(&make_hash_req(&hashes[2], 1, 0, false)),
|
&Rlp::new(&make_hash_req(&hashes[2], 1, 0, false)),
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
assert_eq!(to_header_vec(result), vec![headers[2].clone()]);
|
assert_eq!(
|
||||||
|
to_header_vec(result, eip1559_transition),
|
||||||
|
vec![headers[2].clone()]
|
||||||
|
);
|
||||||
|
|
||||||
let result = SyncSupplier::return_block_headers(
|
let result = SyncSupplier::return_block_headers(
|
||||||
&io,
|
&io,
|
||||||
@ -525,7 +541,7 @@ mod test {
|
|||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
to_header_vec(result),
|
to_header_vec(result, eip1559_transition),
|
||||||
vec![
|
vec![
|
||||||
headers[50].clone(),
|
headers[50].clone(),
|
||||||
headers[56].clone(),
|
headers[56].clone(),
|
||||||
@ -539,7 +555,7 @@ mod test {
|
|||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
to_header_vec(result),
|
to_header_vec(result, eip1559_transition),
|
||||||
vec![
|
vec![
|
||||||
headers[50].clone(),
|
headers[50].clone(),
|
||||||
headers[44].clone(),
|
headers[44].clone(),
|
||||||
@ -549,16 +565,22 @@ mod test {
|
|||||||
|
|
||||||
let result =
|
let result =
|
||||||
SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, true)), 0);
|
SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, true)), 0);
|
||||||
assert_eq!(to_header_vec(result), vec![headers[2].clone()]);
|
assert_eq!(
|
||||||
|
to_header_vec(result, eip1559_transition),
|
||||||
|
vec![headers[2].clone()]
|
||||||
|
);
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, false)), 0);
|
SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, false)), 0);
|
||||||
assert_eq!(to_header_vec(result), vec![headers[2].clone()]);
|
assert_eq!(
|
||||||
|
to_header_vec(result, eip1559_transition),
|
||||||
|
vec![headers[2].clone()]
|
||||||
|
);
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, false)), 0);
|
SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, false)), 0);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
to_header_vec(result),
|
to_header_vec(result, eip1559_transition),
|
||||||
vec![
|
vec![
|
||||||
headers[50].clone(),
|
headers[50].clone(),
|
||||||
headers[56].clone(),
|
headers[56].clone(),
|
||||||
@ -569,7 +591,7 @@ mod test {
|
|||||||
let result =
|
let result =
|
||||||
SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, true)), 0);
|
SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, true)), 0);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
to_header_vec(result),
|
to_header_vec(result, eip1559_transition),
|
||||||
vec![
|
vec![
|
||||||
headers[50].clone(),
|
headers[50].clone(),
|
||||||
headers[44].clone(),
|
headers[44].clone(),
|
||||||
|
@ -36,8 +36,9 @@ use crate::bytes::Bytes;
|
|||||||
use crate::{
|
use crate::{
|
||||||
header::Header,
|
header::Header,
|
||||||
transaction::{TypedTransaction, UnverifiedTransaction},
|
transaction::{TypedTransaction, UnverifiedTransaction},
|
||||||
|
BlockNumber,
|
||||||
};
|
};
|
||||||
use rlp::{Decodable, DecoderError, Rlp, RlpStream};
|
use rlp::{DecoderError, Rlp, RlpStream};
|
||||||
|
|
||||||
/// A block, encoded as it is on the block chain.
|
/// A block, encoded as it is on the block chain.
|
||||||
#[derive(Default, Debug, Clone, PartialEq)]
|
#[derive(Default, Debug, Clone, PartialEq)]
|
||||||
@ -59,10 +60,8 @@ impl Block {
|
|||||||
block_rlp.append_list(&self.uncles);
|
block_rlp.append_list(&self.uncles);
|
||||||
block_rlp.out()
|
block_rlp.out()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Decodable for Block {
|
pub fn decode_rlp(rlp: &Rlp, eip1559_transition: BlockNumber) -> Result<Self, DecoderError> {
|
||||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
|
||||||
if rlp.as_raw().len() != rlp.payload_info()?.total() {
|
if rlp.as_raw().len() != rlp.payload_info()?.total() {
|
||||||
return Err(DecoderError::RlpIsTooBig);
|
return Err(DecoderError::RlpIsTooBig);
|
||||||
}
|
}
|
||||||
@ -70,9 +69,9 @@ impl Decodable for Block {
|
|||||||
return Err(DecoderError::RlpIncorrectListLen);
|
return Err(DecoderError::RlpIncorrectListLen);
|
||||||
}
|
}
|
||||||
Ok(Block {
|
Ok(Block {
|
||||||
header: rlp.val_at(0)?,
|
header: Header::decode_rlp(&rlp.at(0)?, eip1559_transition)?,
|
||||||
transactions: TypedTransaction::decode_rlp_list(&rlp.at(1)?)?,
|
transactions: TypedTransaction::decode_rlp_list(&rlp.at(1)?)?,
|
||||||
uncles: rlp.list_at(2)?,
|
uncles: Header::decode_rlp_list(&rlp.at(2)?, eip1559_transition)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,8 +49,8 @@ impl Header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Upgrade this encoded view to a fully owned `Header` object.
|
/// Upgrade this encoded view to a fully owned `Header` object.
|
||||||
pub fn decode(&self) -> Result<FullHeader, rlp::DecoderError> {
|
pub fn decode(&self, eip1559_transition: BlockNumber) -> Result<FullHeader, rlp::DecoderError> {
|
||||||
rlp::decode(&self.0)
|
FullHeader::decode_rlp(&self.rlp(), eip1559_transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a borrowed header view onto the data.
|
/// Get a borrowed header view onto the data.
|
||||||
@ -144,8 +144,13 @@ impl Header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Engine-specific seal fields.
|
/// Engine-specific seal fields.
|
||||||
pub fn seal(&self) -> Vec<Vec<u8>> {
|
pub fn seal(&self, eip1559: bool) -> Vec<Vec<u8>> {
|
||||||
self.view().seal()
|
self.view().seal(eip1559)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Base fee.
|
||||||
|
pub fn base_fee(&self) -> U256 {
|
||||||
|
self.view().base_fee()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,8 +172,14 @@ impl Body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Fully decode this block body.
|
/// Fully decode this block body.
|
||||||
pub fn decode(&self) -> (Vec<UnverifiedTransaction>, Vec<FullHeader>) {
|
pub fn decode(
|
||||||
(self.view().transactions(), self.view().uncles())
|
&self,
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
|
) -> (Vec<UnverifiedTransaction>, Vec<FullHeader>) {
|
||||||
|
(
|
||||||
|
self.view().transactions(),
|
||||||
|
self.view().uncles(eip1559_transition),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the RLP of this block body.
|
/// Get the RLP of this block body.
|
||||||
@ -216,8 +227,8 @@ impl Body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decode uncle headers.
|
/// Decode uncle headers.
|
||||||
pub fn uncles(&self) -> Vec<FullHeader> {
|
pub fn uncles(&self, eip1559_transition: BlockNumber) -> Vec<FullHeader> {
|
||||||
self.view().uncles()
|
self.view().uncles(eip1559_transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of uncles.
|
/// Number of uncles.
|
||||||
@ -268,13 +279,20 @@ impl Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decode to a full block.
|
/// Decode to a full block.
|
||||||
pub fn decode(&self) -> Result<FullBlock, rlp::DecoderError> {
|
pub fn decode(&self, eip1559_transition: BlockNumber) -> Result<FullBlock, rlp::DecoderError> {
|
||||||
rlp::decode(&self.0)
|
FullBlock::decode_rlp(&self.rlp(), eip1559_transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decode the header.
|
/// Decode the header.
|
||||||
pub fn decode_header(&self) -> FullHeader {
|
pub fn decode_header(&self, eip1559_transition: BlockNumber) -> FullHeader {
|
||||||
self.view().rlp().val_at(0)
|
FullHeader::decode_rlp(&self.view().rlp().at(0).rlp, eip1559_transition).unwrap_or_else(
|
||||||
|
|e| {
|
||||||
|
panic!(
|
||||||
|
"block header, view rlp is trusted and should be valid: {:?}",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clone the encoded header.
|
/// Clone the encoded header.
|
||||||
@ -372,8 +390,8 @@ impl Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Engine-specific seal fields.
|
/// Engine-specific seal fields.
|
||||||
pub fn seal(&self) -> Vec<Vec<u8>> {
|
pub fn seal(&self, eip1559: bool) -> Vec<Vec<u8>> {
|
||||||
self.header_view().seal()
|
self.header_view().seal(eip1559)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,8 +418,8 @@ impl Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decode uncle headers.
|
/// Decode uncle headers.
|
||||||
pub fn uncles(&self) -> Vec<FullHeader> {
|
pub fn uncles(&self, eip1559_transition: BlockNumber) -> Vec<FullHeader> {
|
||||||
self.view().uncles()
|
self.view().uncles(eip1559_transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of uncles.
|
/// Number of uncles.
|
||||||
|
@ -23,7 +23,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use ethereum_types::{Address, Bloom, H256, U256};
|
use ethereum_types::{Address, Bloom, H256, U256};
|
||||||
use parity_util_mem::MallocSizeOf;
|
use parity_util_mem::MallocSizeOf;
|
||||||
use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};
|
use rlp::{DecoderError, Encodable, Rlp, RlpStream};
|
||||||
|
|
||||||
/// Semantic boolean for when a seal/signature is included.
|
/// Semantic boolean for when a seal/signature is included.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
@ -51,6 +51,9 @@ pub struct ExtendedHeader {
|
|||||||
/// which is non-specific.
|
/// which is non-specific.
|
||||||
///
|
///
|
||||||
/// Doesn't do all that much on its own.
|
/// Doesn't do all that much on its own.
|
||||||
|
///
|
||||||
|
/// Two versions of header exist. First one is before EIP1559. Second version is after EIP1559.
|
||||||
|
/// EIP1559 version added field base_fee_per_gas.
|
||||||
#[derive(Debug, Clone, Eq, MallocSizeOf)]
|
#[derive(Debug, Clone, Eq, MallocSizeOf)]
|
||||||
pub struct Header {
|
pub struct Header {
|
||||||
/// Parent hash.
|
/// Parent hash.
|
||||||
@ -79,12 +82,14 @@ pub struct Header {
|
|||||||
gas_used: U256,
|
gas_used: U256,
|
||||||
/// Block gas limit.
|
/// Block gas limit.
|
||||||
gas_limit: U256,
|
gas_limit: U256,
|
||||||
|
|
||||||
/// Block difficulty.
|
/// Block difficulty.
|
||||||
difficulty: U256,
|
difficulty: U256,
|
||||||
/// Vector of post-RLP-encoded fields.
|
/// Vector of post-RLP-encoded fields.
|
||||||
seal: Vec<Bytes>,
|
seal: Vec<Bytes>,
|
||||||
|
|
||||||
|
/// Base fee per gas. Introduced by EIP1559.
|
||||||
|
base_fee_per_gas: Option<U256>,
|
||||||
|
|
||||||
/// Memoized hash of that header and the seal.
|
/// Memoized hash of that header and the seal.
|
||||||
hash: Option<H256>,
|
hash: Option<H256>,
|
||||||
}
|
}
|
||||||
@ -111,6 +116,7 @@ impl PartialEq for Header {
|
|||||||
&& self.gas_limit == c.gas_limit
|
&& self.gas_limit == c.gas_limit
|
||||||
&& self.difficulty == c.difficulty
|
&& self.difficulty == c.difficulty
|
||||||
&& self.seal == c.seal
|
&& self.seal == c.seal
|
||||||
|
&& self.base_fee_per_gas == c.base_fee_per_gas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +141,7 @@ impl Default for Header {
|
|||||||
difficulty: U256::default(),
|
difficulty: U256::default(),
|
||||||
seal: vec![],
|
seal: vec![],
|
||||||
hash: None,
|
hash: None,
|
||||||
|
base_fee_per_gas: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,6 +222,11 @@ impl Header {
|
|||||||
&self.seal
|
&self.seal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the base fee field of the header.
|
||||||
|
pub fn base_fee(&self) -> Option<U256> {
|
||||||
|
self.base_fee_per_gas
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the seal field with RLP-decoded values as bytes.
|
/// Get the seal field with RLP-decoded values as bytes.
|
||||||
pub fn decode_seal<'a, T: ::std::iter::FromIterator<&'a [u8]>>(
|
pub fn decode_seal<'a, T: ::std::iter::FromIterator<&'a [u8]>>(
|
||||||
&'a self,
|
&'a self,
|
||||||
@ -298,6 +310,11 @@ impl Header {
|
|||||||
hash
|
hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the block base fee of the header.
|
||||||
|
pub fn set_base_fee(&mut self, a: Option<U256>) {
|
||||||
|
change_field(&mut self.hash, &mut self.base_fee_per_gas, a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the hash of this header (keccak of the RLP with seal).
|
/// Get the hash of this header (keccak of the RLP with seal).
|
||||||
pub fn hash(&self) -> H256 {
|
pub fn hash(&self) -> H256 {
|
||||||
self.hash.unwrap_or_else(|| keccak(self.rlp(Seal::With)))
|
self.hash.unwrap_or_else(|| keccak(self.rlp(Seal::With)))
|
||||||
@ -322,10 +339,16 @@ impl Header {
|
|||||||
|
|
||||||
/// Place this header into an RLP stream `s`, optionally `with_seal`.
|
/// Place this header into an RLP stream `s`, optionally `with_seal`.
|
||||||
fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) {
|
fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) {
|
||||||
if let Seal::With = with_seal {
|
let stream_length_without_seal = if self.base_fee_per_gas.is_some() {
|
||||||
s.begin_list(13 + self.seal.len());
|
14
|
||||||
} else {
|
} else {
|
||||||
s.begin_list(13);
|
13
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Seal::With = with_seal {
|
||||||
|
s.begin_list(stream_length_without_seal + self.seal.len());
|
||||||
|
} else {
|
||||||
|
s.begin_list(stream_length_without_seal);
|
||||||
}
|
}
|
||||||
|
|
||||||
s.append(&self.parent_hash);
|
s.append(&self.parent_hash);
|
||||||
@ -347,6 +370,10 @@ impl Header {
|
|||||||
s.append_raw(b, 1);
|
s.append_raw(b, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.base_fee_per_gas.is_some() {
|
||||||
|
s.append(&self.base_fee_per_gas.unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,8 +388,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decodable for Header {
|
impl Header {
|
||||||
fn decode(r: &Rlp) -> Result<Self, DecoderError> {
|
pub fn decode_rlp(r: &Rlp, eip1559_transition: BlockNumber) -> Result<Self, DecoderError> {
|
||||||
let mut blockheader = Header {
|
let mut blockheader = Header {
|
||||||
parent_hash: r.val_at(0)?,
|
parent_hash: r.val_at(0)?,
|
||||||
uncles_hash: r.val_at(1)?,
|
uncles_hash: r.val_at(1)?,
|
||||||
@ -379,14 +406,37 @@ impl Decodable for Header {
|
|||||||
extra_data: r.val_at(12)?,
|
extra_data: r.val_at(12)?,
|
||||||
seal: vec![],
|
seal: vec![],
|
||||||
hash: keccak(r.as_raw()).into(),
|
hash: keccak(r.as_raw()).into(),
|
||||||
|
base_fee_per_gas: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
for i in 13..r.item_count()? {
|
if blockheader.number >= eip1559_transition {
|
||||||
blockheader.seal.push(r.at(i)?.as_raw().to_vec())
|
for i in 13..r.item_count()? - 1 {
|
||||||
|
blockheader.seal.push(r.at(i)?.as_raw().to_vec())
|
||||||
|
}
|
||||||
|
blockheader.base_fee_per_gas = Some(r.val_at(r.item_count()? - 1)?);
|
||||||
|
} else {
|
||||||
|
for i in 13..r.item_count()? {
|
||||||
|
blockheader.seal.push(r.at(i)?.as_raw().to_vec())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(blockheader)
|
Ok(blockheader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decode_rlp_list(
|
||||||
|
rlp: &Rlp,
|
||||||
|
eip1559_transition: BlockNumber,
|
||||||
|
) -> Result<Vec<Self>, DecoderError> {
|
||||||
|
if !rlp.is_list() {
|
||||||
|
// at least one byte needs to be present
|
||||||
|
return Err(DecoderError::RlpIncorrectListLen);
|
||||||
|
}
|
||||||
|
let mut output = Vec::with_capacity(rlp.item_count()?);
|
||||||
|
for h in rlp.iter() {
|
||||||
|
output.push(Self::decode_rlp(&h, eip1559_transition)?);
|
||||||
|
}
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encodable for Header {
|
impl Encodable for Header {
|
||||||
@ -404,8 +454,11 @@ impl ExtendedHeader {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::BlockNumber;
|
||||||
|
|
||||||
use super::Header;
|
use super::Header;
|
||||||
use rlp;
|
use ethereum_types::U256;
|
||||||
|
use rlp::{self, Rlp};
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -421,7 +474,9 @@ mod tests {
|
|||||||
let nonce = "88ab4e252a7e8c2a23".from_hex().unwrap();
|
let nonce = "88ab4e252a7e8c2a23".from_hex().unwrap();
|
||||||
let nonce_decoded = "ab4e252a7e8c2a23".from_hex().unwrap();
|
let nonce_decoded = "ab4e252a7e8c2a23".from_hex().unwrap();
|
||||||
|
|
||||||
let header: Header = rlp::decode(&header_rlp).expect("error decoding header");
|
let rlp = Rlp::new(&header_rlp);
|
||||||
|
let header: Header =
|
||||||
|
Header::decode_rlp(&rlp, BlockNumber::max_value()).expect("error decoding header");
|
||||||
let seal_fields = header.seal.clone();
|
let seal_fields = header.seal.clone();
|
||||||
assert_eq!(seal_fields.len(), 2);
|
assert_eq!(seal_fields.len(), 2);
|
||||||
assert_eq!(seal_fields[0], mix_hash);
|
assert_eq!(seal_fields[0], mix_hash);
|
||||||
@ -433,12 +488,50 @@ mod tests {
|
|||||||
assert_eq!(decoded_seal[1], &*nonce_decoded);
|
assert_eq!(decoded_seal[1], &*nonce_decoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_header_seal_fields_after_1559() {
|
||||||
|
let header_rlp = "f901faa0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008011832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a2364".from_hex().unwrap();
|
||||||
|
let rlp = Rlp::new(&header_rlp);
|
||||||
|
let mut header: Header =
|
||||||
|
Header::decode_rlp(&rlp, BlockNumber::default()).expect("error decoding header");
|
||||||
|
|
||||||
|
assert_eq!(header.seal().len(), 2);
|
||||||
|
assert_eq!(header.base_fee().unwrap(), U256::from(100));
|
||||||
|
|
||||||
|
let new_base_fee = U256::from(200);
|
||||||
|
header.set_base_fee(Some(new_base_fee));
|
||||||
|
assert_eq!(header.base_fee().unwrap(), new_base_fee);
|
||||||
|
|
||||||
|
let seal = vec![vec![50u8], vec![60u8]];
|
||||||
|
header.set_seal(seal.clone());
|
||||||
|
assert_eq!(header.seal(), seal);
|
||||||
|
assert_eq!(header.base_fee().unwrap(), new_base_fee);
|
||||||
|
|
||||||
|
let decoded_seal = header.decode_seal::<Vec<_>>().unwrap();
|
||||||
|
assert_eq!(decoded_seal.len(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decode_and_encode_header() {
|
fn decode_and_encode_header() {
|
||||||
// that's rlp of block header created with ethash engine.
|
// that's rlp of block header created with ethash engine.
|
||||||
let header_rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap();
|
let header_rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap();
|
||||||
|
let rlp = Rlp::new(&header_rlp);
|
||||||
|
|
||||||
let header: Header = rlp::decode(&header_rlp).expect("error decoding header");
|
let header: Header =
|
||||||
|
Header::decode_rlp(&rlp, BlockNumber::max_value()).expect("error decoding header");
|
||||||
|
let encoded_header = rlp::encode(&header);
|
||||||
|
|
||||||
|
assert_eq!(header_rlp, encoded_header);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_and_encode_header_after_1559() {
|
||||||
|
// that's rlp of block header created with ethash engine.
|
||||||
|
let header_rlp = "f901faa0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008011832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a2364".from_hex().unwrap();
|
||||||
|
let rlp = Rlp::new(&header_rlp);
|
||||||
|
|
||||||
|
let header: Header =
|
||||||
|
Header::decode_rlp(&rlp, BlockNumber::default()).expect("error decoding header");
|
||||||
let encoded_header = rlp::encode(&header);
|
let encoded_header = rlp::encode(&header);
|
||||||
|
|
||||||
assert_eq!(header_rlp, encoded_header);
|
assert_eq!(header_rlp, encoded_header);
|
||||||
@ -449,9 +542,23 @@ mod tests {
|
|||||||
// that's rlp of block header created with ethash engine.
|
// that's rlp of block header created with ethash engine.
|
||||||
// The encoding contains a large timestamp (295147905179352825856)
|
// The encoding contains a large timestamp (295147905179352825856)
|
||||||
let header_rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d891000000000000000000080a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap();
|
let header_rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d891000000000000000000080a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap();
|
||||||
|
let rlp = Rlp::new(&header_rlp);
|
||||||
|
|
||||||
// This should fail decoding timestamp
|
// This should fail decoding timestamp
|
||||||
let header: Result<Header, _> = rlp::decode(&header_rlp);
|
let header: Result<Header, _> = Header::decode_rlp(&rlp, BlockNumber::max_value());
|
||||||
assert_eq!(header.unwrap_err(), rlp::DecoderError::RlpIsTooBig);
|
assert_eq!(header.unwrap_err(), rlp::DecoderError::RlpIsTooBig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hash_should_be_different() {
|
||||||
|
let header_legacy = Header::new();
|
||||||
|
let mut header_1559 = Header::new();
|
||||||
|
|
||||||
|
header_1559.set_base_fee(Some(U256::from(100)));
|
||||||
|
|
||||||
|
let hash_legacy = header_legacy.hash();
|
||||||
|
let hash_1559 = header_1559.hash();
|
||||||
|
|
||||||
|
assert_ne!(hash_legacy, hash_1559);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,7 @@ impl LegacyReceipt {
|
|||||||
pub enum TypedReceipt {
|
pub enum TypedReceipt {
|
||||||
Legacy(LegacyReceipt),
|
Legacy(LegacyReceipt),
|
||||||
AccessList(LegacyReceipt),
|
AccessList(LegacyReceipt),
|
||||||
|
EIP1559Transaction(LegacyReceipt),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedReceipt {
|
impl TypedReceipt {
|
||||||
@ -119,6 +120,7 @@ impl TypedReceipt {
|
|||||||
pub fn new(type_id: TypedTxId, legacy_receipt: LegacyReceipt) -> Self {
|
pub fn new(type_id: TypedTxId, legacy_receipt: LegacyReceipt) -> Self {
|
||||||
//curently we are using same receipt for both legacy and typed transaction
|
//curently we are using same receipt for both legacy and typed transaction
|
||||||
match type_id {
|
match type_id {
|
||||||
|
TypedTxId::EIP1559Transaction => Self::EIP1559Transaction(legacy_receipt),
|
||||||
TypedTxId::AccessList => Self::AccessList(legacy_receipt),
|
TypedTxId::AccessList => Self::AccessList(legacy_receipt),
|
||||||
TypedTxId::Legacy => Self::Legacy(legacy_receipt),
|
TypedTxId::Legacy => Self::Legacy(legacy_receipt),
|
||||||
}
|
}
|
||||||
@ -128,6 +130,7 @@ impl TypedReceipt {
|
|||||||
match self {
|
match self {
|
||||||
Self::Legacy(_) => TypedTxId::Legacy,
|
Self::Legacy(_) => TypedTxId::Legacy,
|
||||||
Self::AccessList(_) => TypedTxId::AccessList,
|
Self::AccessList(_) => TypedTxId::AccessList,
|
||||||
|
Self::EIP1559Transaction(_) => TypedTxId::EIP1559Transaction,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +138,7 @@ impl TypedReceipt {
|
|||||||
match self {
|
match self {
|
||||||
Self::Legacy(receipt) => receipt,
|
Self::Legacy(receipt) => receipt,
|
||||||
Self::AccessList(receipt) => receipt,
|
Self::AccessList(receipt) => receipt,
|
||||||
|
Self::EIP1559Transaction(receipt) => receipt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +146,7 @@ impl TypedReceipt {
|
|||||||
match self {
|
match self {
|
||||||
Self::Legacy(receipt) => receipt,
|
Self::Legacy(receipt) => receipt,
|
||||||
Self::AccessList(receipt) => receipt,
|
Self::AccessList(receipt) => receipt,
|
||||||
|
Self::EIP1559Transaction(receipt) => receipt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +161,10 @@ impl TypedReceipt {
|
|||||||
}
|
}
|
||||||
//other transaction types
|
//other transaction types
|
||||||
match id.unwrap() {
|
match id.unwrap() {
|
||||||
|
TypedTxId::EIP1559Transaction => {
|
||||||
|
let rlp = Rlp::new(&tx[1..]);
|
||||||
|
Ok(Self::EIP1559Transaction(LegacyReceipt::decode(&rlp)?))
|
||||||
|
}
|
||||||
TypedTxId::AccessList => {
|
TypedTxId::AccessList => {
|
||||||
let rlp = Rlp::new(&tx[1..]);
|
let rlp = Rlp::new(&tx[1..]);
|
||||||
Ok(Self::AccessList(LegacyReceipt::decode(&rlp)?))
|
Ok(Self::AccessList(LegacyReceipt::decode(&rlp)?))
|
||||||
@ -193,6 +202,11 @@ impl TypedReceipt {
|
|||||||
receipt.rlp_append(&mut rlps);
|
receipt.rlp_append(&mut rlps);
|
||||||
s.append(&[&[TypedTxId::AccessList as u8], rlps.as_raw()].concat());
|
s.append(&[&[TypedTxId::AccessList as u8], rlps.as_raw()].concat());
|
||||||
}
|
}
|
||||||
|
Self::EIP1559Transaction(receipt) => {
|
||||||
|
let mut rlps = RlpStream::new();
|
||||||
|
receipt.rlp_append(&mut rlps);
|
||||||
|
s.append(&[&[TypedTxId::EIP1559Transaction as u8], rlps.as_raw()].concat());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,6 +229,11 @@ impl TypedReceipt {
|
|||||||
receipt.rlp_append(&mut rlps);
|
receipt.rlp_append(&mut rlps);
|
||||||
[&[TypedTxId::AccessList as u8], rlps.as_raw()].concat()
|
[&[TypedTxId::AccessList as u8], rlps.as_raw()].concat()
|
||||||
}
|
}
|
||||||
|
Self::EIP1559Transaction(receipt) => {
|
||||||
|
let mut rlps = RlpStream::new();
|
||||||
|
receipt.rlp_append(&mut rlps);
|
||||||
|
[&[TypedTxId::EIP1559Transaction as u8], rlps.as_raw()].concat()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -372,6 +391,32 @@ mod tests {
|
|||||||
assert_eq!(decoded, r);
|
assert_eq!(decoded, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_basic_eip1559() {
|
||||||
|
let expected = ::rustc_hex::FromHex::from_hex("02f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||||
|
let r = TypedReceipt::new(
|
||||||
|
TypedTxId::EIP1559Transaction,
|
||||||
|
LegacyReceipt::new(
|
||||||
|
TransactionOutcome::StateRoot(
|
||||||
|
H256::from_str(
|
||||||
|
"2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
0x40cae.into(),
|
||||||
|
vec![LogEntry {
|
||||||
|
address: H160::from_str("dcf421d093428b096ca501a7cd1a740855a7976f").unwrap(),
|
||||||
|
topics: vec![],
|
||||||
|
data: vec![0u8; 32],
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let encoded = r.encode();
|
||||||
|
assert_eq!(&encoded, &expected);
|
||||||
|
let decoded = TypedReceipt::decode(&encoded).expect("decoding receipt failed");
|
||||||
|
assert_eq!(decoded, r);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_status_code() {
|
fn test_status_code() {
|
||||||
let expected = ::rustc_hex::FromHex::from_hex("f901428083040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
let expected = ::rustc_hex::FromHex::from_hex("f901428083040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||||
|
@ -37,6 +37,13 @@ pub enum Error {
|
|||||||
/// Transaction gas price
|
/// Transaction gas price
|
||||||
got: U256,
|
got: U256,
|
||||||
},
|
},
|
||||||
|
/// Transaction's max gas price is lower then block base fee.
|
||||||
|
GasPriceLowerThanBaseFee {
|
||||||
|
/// Transaction max gas price
|
||||||
|
gas_price: U256,
|
||||||
|
/// Current block base fee
|
||||||
|
base_fee: U256,
|
||||||
|
},
|
||||||
/// Transaction has too low fee
|
/// Transaction has too low fee
|
||||||
/// (there is already a transaction with the same sender-nonce but higher gas price)
|
/// (there is already a transaction with the same sender-nonce but higher gas price)
|
||||||
TooCheapToReplace {
|
TooCheapToReplace {
|
||||||
@ -114,6 +121,15 @@ impl fmt::Display for Error {
|
|||||||
InsufficientGasPrice { minimal, got } => {
|
InsufficientGasPrice { minimal, got } => {
|
||||||
format!("Insufficient gas price. Min={}, Given={}", minimal, got)
|
format!("Insufficient gas price. Min={}, Given={}", minimal, got)
|
||||||
}
|
}
|
||||||
|
GasPriceLowerThanBaseFee {
|
||||||
|
gas_price,
|
||||||
|
base_fee,
|
||||||
|
} => {
|
||||||
|
format!(
|
||||||
|
"Max gas price is lower then required base fee. Gas price={}, Base fee={}",
|
||||||
|
gas_price, base_fee
|
||||||
|
)
|
||||||
|
}
|
||||||
InsufficientGas { minimal, got } => {
|
InsufficientGas { minimal, got } => {
|
||||||
format!("Insufficient gas. Min={}, Given={}", minimal, got)
|
format!("Insufficient gas. Min={}, Given={}", minimal, got)
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ use ethereum_types::{Address, BigEndianHash, H160, H256, U256};
|
|||||||
use parity_util_mem::MallocSizeOf;
|
use parity_util_mem::MallocSizeOf;
|
||||||
|
|
||||||
use rlp::{self, DecoderError, Rlp, RlpStream};
|
use rlp::{self, DecoderError, Rlp, RlpStream};
|
||||||
use std::ops::Deref;
|
use std::{cmp::min, ops::Deref};
|
||||||
|
|
||||||
pub type AccessListItem = (H160, Vec<H256>);
|
pub type AccessListItem = (H160, Vec<H256>);
|
||||||
pub type AccessList = Vec<AccessListItem>;
|
pub type AccessList = Vec<AccessListItem>;
|
||||||
@ -130,7 +130,7 @@ pub mod signature {
|
|||||||
pub struct Transaction {
|
pub struct Transaction {
|
||||||
/// Nonce.
|
/// Nonce.
|
||||||
pub nonce: U256,
|
pub nonce: U256,
|
||||||
/// Gas price.
|
/// Gas price for non 1559 transactions. MaxFeePerGas for 1559 transactions.
|
||||||
pub gas_price: U256,
|
pub gas_price: U256,
|
||||||
/// Gas paid up front for transaction execution.
|
/// Gas paid up front for transaction execution.
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
@ -364,11 +364,149 @@ impl AccessListTx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq, MallocSizeOf)]
|
||||||
|
pub struct EIP1559TransactionTx {
|
||||||
|
pub transaction: AccessListTx,
|
||||||
|
pub max_priority_fee_per_gas: U256,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EIP1559TransactionTx {
|
||||||
|
pub fn tx_type(&self) -> TypedTxId {
|
||||||
|
TypedTxId::EIP1559Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tx(&self) -> &Transaction {
|
||||||
|
&self.transaction.tx()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tx_mut(&mut self) -> &mut Transaction {
|
||||||
|
self.transaction.tx_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode bytes by this payload spec: rlp([2, [chainId, nonce, maxPriorityFeePerGas, maxFeePerGas(gasPrice), gasLimit, to, value, data, access_list, senderV, senderR, senderS]])
|
||||||
|
pub fn decode(tx: &[u8]) -> Result<UnverifiedTransaction, DecoderError> {
|
||||||
|
let tx_rlp = &Rlp::new(tx);
|
||||||
|
|
||||||
|
// we need to have 12 items in this list
|
||||||
|
if tx_rlp.item_count()? != 12 {
|
||||||
|
return Err(DecoderError::RlpIncorrectListLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
let chain_id = Some(tx_rlp.val_at(0)?);
|
||||||
|
|
||||||
|
let max_priority_fee_per_gas = tx_rlp.val_at(2)?;
|
||||||
|
|
||||||
|
let tx = Transaction {
|
||||||
|
nonce: tx_rlp.val_at(1)?,
|
||||||
|
gas_price: tx_rlp.val_at(3)?, //taken from max_fee_per_gas
|
||||||
|
gas: tx_rlp.val_at(4)?,
|
||||||
|
action: tx_rlp.val_at(5)?,
|
||||||
|
value: tx_rlp.val_at(6)?,
|
||||||
|
data: tx_rlp.val_at(7)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
// access list we get from here
|
||||||
|
let accl_rlp = tx_rlp.at(8)?;
|
||||||
|
|
||||||
|
// access_list pattern: [[{20 bytes}, [{32 bytes}...]]...]
|
||||||
|
let mut accl: AccessList = Vec::new();
|
||||||
|
|
||||||
|
for i in 0..accl_rlp.item_count()? {
|
||||||
|
let accounts = accl_rlp.at(i)?;
|
||||||
|
|
||||||
|
// check if there is list of 2 items
|
||||||
|
if accounts.item_count()? != 2 {
|
||||||
|
return Err(DecoderError::Custom("Unknown access list length"));
|
||||||
|
}
|
||||||
|
accl.push((accounts.val_at(0)?, accounts.list_at(1)?));
|
||||||
|
}
|
||||||
|
|
||||||
|
// we get signature part from here
|
||||||
|
let signature = SignatureComponents {
|
||||||
|
standard_v: tx_rlp.val_at(9)?,
|
||||||
|
r: tx_rlp.val_at(10)?,
|
||||||
|
s: tx_rlp.val_at(11)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
// and here we create UnverifiedTransaction and calculate its hash
|
||||||
|
Ok(UnverifiedTransaction::new(
|
||||||
|
TypedTransaction::EIP1559Transaction(EIP1559TransactionTx {
|
||||||
|
transaction: AccessListTx::new(tx, accl),
|
||||||
|
max_priority_fee_per_gas,
|
||||||
|
}),
|
||||||
|
chain_id,
|
||||||
|
signature,
|
||||||
|
H256::zero(),
|
||||||
|
)
|
||||||
|
.compute_hash())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_payload(
|
||||||
|
&self,
|
||||||
|
chain_id: Option<u64>,
|
||||||
|
signature: Option<&SignatureComponents>,
|
||||||
|
) -> RlpStream {
|
||||||
|
let mut stream = RlpStream::new();
|
||||||
|
|
||||||
|
let list_size = if signature.is_some() { 12 } else { 9 };
|
||||||
|
stream.begin_list(list_size);
|
||||||
|
|
||||||
|
// append chain_id. from EIP-2930: chainId is defined to be an integer of arbitrary size.
|
||||||
|
stream.append(&(if let Some(n) = chain_id { n } else { 0 }));
|
||||||
|
|
||||||
|
stream.append(&self.tx().nonce);
|
||||||
|
stream.append(&self.max_priority_fee_per_gas);
|
||||||
|
stream.append(&self.tx().gas_price);
|
||||||
|
stream.append(&self.tx().gas);
|
||||||
|
stream.append(&self.tx().action);
|
||||||
|
stream.append(&self.tx().value);
|
||||||
|
stream.append(&self.tx().data);
|
||||||
|
|
||||||
|
// access list
|
||||||
|
stream.begin_list(self.transaction.access_list.len());
|
||||||
|
for access in self.transaction.access_list.iter() {
|
||||||
|
stream.begin_list(2);
|
||||||
|
stream.append(&access.0);
|
||||||
|
stream.begin_list(access.1.len());
|
||||||
|
for storage_key in access.1.iter() {
|
||||||
|
stream.append(storage_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// append signature if any
|
||||||
|
if let Some(signature) = signature {
|
||||||
|
signature.rlp_append(&mut stream);
|
||||||
|
}
|
||||||
|
stream
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode by this payload spec: 0x02 | rlp([2, [chainId, nonce, maxPriorityFeePerGas, maxFeePerGas(gasPrice), gasLimit, to, value, data, access_list, senderV, senderR, senderS]])
|
||||||
|
pub fn encode(
|
||||||
|
&self,
|
||||||
|
chain_id: Option<u64>,
|
||||||
|
signature: Option<&SignatureComponents>,
|
||||||
|
) -> Vec<u8> {
|
||||||
|
let stream = self.encode_payload(chain_id, signature);
|
||||||
|
// make as vector of bytes
|
||||||
|
[&[TypedTxId::EIP1559Transaction as u8], stream.as_raw()].concat()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rlp_append(
|
||||||
|
&self,
|
||||||
|
rlp: &mut RlpStream,
|
||||||
|
chain_id: Option<u64>,
|
||||||
|
signature: &SignatureComponents,
|
||||||
|
) {
|
||||||
|
rlp.append(&self.encode(chain_id, Some(signature)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, MallocSizeOf)]
|
#[derive(Debug, Clone, Eq, PartialEq, MallocSizeOf)]
|
||||||
pub enum TypedTransaction {
|
pub enum TypedTransaction {
|
||||||
Legacy(Transaction), // old legacy RLP encoded transaction
|
Legacy(Transaction), // old legacy RLP encoded transaction
|
||||||
AccessList(AccessListTx), // EIP-2930 Transaction with a list of addresses and storage keys that the transaction plans to access.
|
AccessList(AccessListTx), // EIP-2930 Transaction with a list of addresses and storage keys that the transaction plans to access.
|
||||||
// Accesses outside the list are possible, but become more expensive.
|
// Accesses outside the list are possible, but become more expensive.
|
||||||
|
EIP1559Transaction(EIP1559TransactionTx),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedTransaction {
|
impl TypedTransaction {
|
||||||
@ -376,6 +514,7 @@ impl TypedTransaction {
|
|||||||
match self {
|
match self {
|
||||||
Self::Legacy(_) => TypedTxId::Legacy,
|
Self::Legacy(_) => TypedTxId::Legacy,
|
||||||
Self::AccessList(_) => TypedTxId::AccessList,
|
Self::AccessList(_) => TypedTxId::AccessList,
|
||||||
|
Self::EIP1559Transaction(_) => TypedTxId::EIP1559Transaction,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,6 +523,7 @@ impl TypedTransaction {
|
|||||||
keccak(match self {
|
keccak(match self {
|
||||||
Self::Legacy(tx) => tx.encode(chain_id, None),
|
Self::Legacy(tx) => tx.encode(chain_id, None),
|
||||||
Self::AccessList(tx) => tx.encode(chain_id, None),
|
Self::AccessList(tx) => tx.encode(chain_id, None),
|
||||||
|
Self::EIP1559Transaction(tx) => tx.encode(chain_id, None),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,6 +612,7 @@ impl TypedTransaction {
|
|||||||
match self {
|
match self {
|
||||||
Self::Legacy(tx) => tx,
|
Self::Legacy(tx) => tx,
|
||||||
Self::AccessList(ocl) => ocl.tx(),
|
Self::AccessList(ocl) => ocl.tx(),
|
||||||
|
Self::EIP1559Transaction(tx) => tx.tx(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,6 +620,34 @@ impl TypedTransaction {
|
|||||||
match self {
|
match self {
|
||||||
Self::Legacy(tx) => tx,
|
Self::Legacy(tx) => tx,
|
||||||
Self::AccessList(ocl) => ocl.tx_mut(),
|
Self::AccessList(ocl) => ocl.tx_mut(),
|
||||||
|
Self::EIP1559Transaction(tx) => tx.tx_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn access_list(&self) -> Option<&AccessList> {
|
||||||
|
match self {
|
||||||
|
Self::EIP1559Transaction(tx) => Some(&tx.transaction.access_list),
|
||||||
|
Self::AccessList(tx) => Some(&tx.access_list),
|
||||||
|
Self::Legacy(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn effective_gas_price(&self, block_base_fee: Option<U256>) -> U256 {
|
||||||
|
match self {
|
||||||
|
Self::EIP1559Transaction(tx) => min(
|
||||||
|
self.tx().gas_price,
|
||||||
|
tx.max_priority_fee_per_gas + block_base_fee.unwrap_or_default(),
|
||||||
|
),
|
||||||
|
Self::AccessList(_) => self.tx().gas_price,
|
||||||
|
Self::Legacy(_) => self.tx().gas_price,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_priority_fee_per_gas(&self) -> U256 {
|
||||||
|
match self {
|
||||||
|
Self::EIP1559Transaction(tx) => tx.max_priority_fee_per_gas,
|
||||||
|
Self::AccessList(tx) => tx.tx().gas_price,
|
||||||
|
Self::Legacy(tx) => tx.gas_price,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,6 +662,7 @@ impl TypedTransaction {
|
|||||||
}
|
}
|
||||||
// other transaction types
|
// other transaction types
|
||||||
match id.unwrap() {
|
match id.unwrap() {
|
||||||
|
TypedTxId::EIP1559Transaction => EIP1559TransactionTx::decode(&tx[1..]),
|
||||||
TypedTxId::AccessList => AccessListTx::decode(&tx[1..]),
|
TypedTxId::AccessList => AccessListTx::decode(&tx[1..]),
|
||||||
TypedTxId::Legacy => return Err(DecoderError::Custom("Unknown transaction legacy")),
|
TypedTxId::Legacy => return Err(DecoderError::Custom("Unknown transaction legacy")),
|
||||||
}
|
}
|
||||||
@ -543,6 +713,7 @@ impl TypedTransaction {
|
|||||||
match self {
|
match self {
|
||||||
Self::Legacy(tx) => tx.rlp_append(s, chain_id, signature),
|
Self::Legacy(tx) => tx.rlp_append(s, chain_id, signature),
|
||||||
Self::AccessList(opt) => opt.rlp_append(s, chain_id, signature),
|
Self::AccessList(opt) => opt.rlp_append(s, chain_id, signature),
|
||||||
|
Self::EIP1559Transaction(tx) => tx.rlp_append(s, chain_id, signature),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,6 +729,7 @@ impl TypedTransaction {
|
|||||||
match self {
|
match self {
|
||||||
Self::Legacy(tx) => tx.encode(chain_id, signature),
|
Self::Legacy(tx) => tx.encode(chain_id, signature),
|
||||||
Self::AccessList(opt) => opt.encode(chain_id, signature),
|
Self::AccessList(opt) => opt.encode(chain_id, signature),
|
||||||
|
Self::EIP1559Transaction(tx) => tx.encode(chain_id, signature),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -990,8 +1162,6 @@ mod tests {
|
|||||||
})
|
})
|
||||||
.null_sign(1);
|
.null_sign(1);
|
||||||
|
|
||||||
println!("transaction {:?}", t);
|
|
||||||
|
|
||||||
let res = SignedTransaction::new(t.transaction);
|
let res = SignedTransaction::new(t.transaction);
|
||||||
match res {
|
match res {
|
||||||
Err(publickey::Error::InvalidSignature) => {}
|
Err(publickey::Error::InvalidSignature) => {}
|
||||||
@ -1047,6 +1217,40 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_encode_decode_eip1559_tx() {
|
||||||
|
use self::publickey::{Generator, Random};
|
||||||
|
let key = Random.generate();
|
||||||
|
let t = TypedTransaction::EIP1559Transaction(EIP1559TransactionTx {
|
||||||
|
transaction: AccessListTx::new(
|
||||||
|
Transaction {
|
||||||
|
action: Action::Create,
|
||||||
|
nonce: U256::from(42),
|
||||||
|
gas_price: U256::from(3000),
|
||||||
|
gas: U256::from(50_000),
|
||||||
|
value: U256::from(1),
|
||||||
|
data: b"Hello!".to_vec(),
|
||||||
|
},
|
||||||
|
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(100),
|
||||||
|
})
|
||||||
|
.sign(&key.secret(), Some(69));
|
||||||
|
let encoded = t.encode();
|
||||||
|
|
||||||
|
let t_new =
|
||||||
|
TypedTransaction::decode(&encoded).expect("Error on UnverifiedTransaction decoder");
|
||||||
|
if t_new.unsigned != t.unsigned {
|
||||||
|
assert!(true, "encoded/decoded tx differs from original");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_decode_access_list_in_rlp() {
|
fn should_decode_access_list_in_rlp() {
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
@ -1055,6 +1259,14 @@ mod tests {
|
|||||||
.expect("decoding tx data failed");
|
.expect("decoding tx data failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_decode_eip1559_in_rlp() {
|
||||||
|
use rustc_hex::FromHex;
|
||||||
|
let encoded_tx = "b8cb01f8a7802a820bb882c35080018648656c6c6f21f872f85994000000000000000000000000000000000000000af842a00000000000000000000000000000000000000000000000000000000000000066a00000000000000000000000000000000000000000000000000000000000000067d6940000000000000000000000000000000000000190c080a00ea0f1fda860320f51e182fe68ea90a8e7611653d3975b9301580adade6b8aa4a023530a1a96e0f15f90959baf1cd2d9114f7c7568ac7d77f4413c0a6ca6cdac74";
|
||||||
|
let _ = TypedTransaction::decode_rlp(&Rlp::new(&FromHex::from_hex(encoded_tx).unwrap()))
|
||||||
|
.expect("decoding tx data failed");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_decode_access_list_solo() {
|
fn should_decode_access_list_solo() {
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
@ -1096,7 +1308,6 @@ mod tests {
|
|||||||
.expect("decoding tx data failed");
|
.expect("decoding tx data failed");
|
||||||
let signed = SignedTransaction::new(signed).unwrap();
|
let signed = SignedTransaction::new(signed).unwrap();
|
||||||
assert_eq!(signed.sender(), H160::from_str(address).unwrap());
|
assert_eq!(signed.sender(), H160::from_str(address).unwrap());
|
||||||
println!("chainid: {:?}", signed.chain_id());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "f0f6f18bca1b28cd68e4357452947e021241e9ce");
|
test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "f0f6f18bca1b28cd68e4357452947e021241e9ce");
|
||||||
|
@ -22,6 +22,7 @@ use serde_repr::*;
|
|||||||
#[derive(Serialize_repr, Eq, Hash, Deserialize_repr, Debug, Copy, Clone, PartialEq)]
|
#[derive(Serialize_repr, Eq, Hash, Deserialize_repr, Debug, Copy, Clone, PartialEq)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum TypedTxId {
|
pub enum TypedTxId {
|
||||||
|
EIP1559Transaction = 0x02,
|
||||||
AccessList = 0x01,
|
AccessList = 0x01,
|
||||||
Legacy = 0x00,
|
Legacy = 0x00,
|
||||||
}
|
}
|
||||||
@ -32,12 +33,14 @@ impl TypedTxId {
|
|||||||
match n {
|
match n {
|
||||||
0 => Some(Self::Legacy),
|
0 => Some(Self::Legacy),
|
||||||
1 => Some(Self::AccessList),
|
1 => Some(Self::AccessList),
|
||||||
|
2 => Some(Self::EIP1559Transaction),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_from_wire_byte(n: u8) -> Result<Self, ()> {
|
pub fn try_from_wire_byte(n: u8) -> Result<Self, ()> {
|
||||||
match n {
|
match n {
|
||||||
|
x if x == TypedTxId::EIP1559Transaction as u8 => Ok(TypedTxId::EIP1559Transaction),
|
||||||
x if x == TypedTxId::AccessList as u8 => Ok(TypedTxId::AccessList),
|
x if x == TypedTxId::AccessList as u8 => Ok(TypedTxId::AccessList),
|
||||||
x if (x & 0x80) != 0x00 => Ok(TypedTxId::Legacy),
|
x if (x & 0x80) != 0x00 => Ok(TypedTxId::Legacy),
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
@ -49,6 +52,7 @@ impl TypedTxId {
|
|||||||
match n.map(|t| t.as_u64()) {
|
match n.map(|t| t.as_u64()) {
|
||||||
None => Some(Self::Legacy),
|
None => Some(Self::Legacy),
|
||||||
Some(0x01) => Some(Self::AccessList),
|
Some(0x01) => Some(Self::AccessList),
|
||||||
|
Some(0x02) => Some(Self::EIP1559Transaction),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,13 +78,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn typed_tx_id_try_from_wire() {
|
fn typed_tx_id_try_from_wire() {
|
||||||
|
assert_eq!(
|
||||||
|
Ok(TypedTxId::EIP1559Transaction),
|
||||||
|
TypedTxId::try_from_wire_byte(0x02)
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok(TypedTxId::AccessList),
|
Ok(TypedTxId::AccessList),
|
||||||
TypedTxId::try_from_wire_byte(0x01)
|
TypedTxId::try_from_wire_byte(0x01)
|
||||||
);
|
);
|
||||||
assert_eq!(Ok(TypedTxId::Legacy), TypedTxId::try_from_wire_byte(0x81));
|
assert_eq!(Ok(TypedTxId::Legacy), TypedTxId::try_from_wire_byte(0x81));
|
||||||
assert_eq!(Err(()), TypedTxId::try_from_wire_byte(0x00));
|
assert_eq!(Err(()), TypedTxId::try_from_wire_byte(0x00));
|
||||||
assert_eq!(Err(()), TypedTxId::try_from_wire_byte(0x02));
|
assert_eq!(Err(()), TypedTxId::try_from_wire_byte(0x03));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -90,6 +98,10 @@ mod tests {
|
|||||||
Some(U64::from(0x01)),
|
Some(U64::from(0x01)),
|
||||||
TypedTxId::AccessList.to_U64_option_id()
|
TypedTxId::AccessList.to_U64_option_id()
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Some(U64::from(0x02)),
|
||||||
|
TypedTxId::EIP1559Transaction.to_U64_option_id()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -99,13 +111,21 @@ mod tests {
|
|||||||
Some(TypedTxId::AccessList),
|
Some(TypedTxId::AccessList),
|
||||||
TypedTxId::from_U64_option_id(Some(U64::from(0x01)))
|
TypedTxId::from_U64_option_id(Some(U64::from(0x01)))
|
||||||
);
|
);
|
||||||
assert_eq!(None, TypedTxId::from_U64_option_id(Some(U64::from(0x02))));
|
assert_eq!(
|
||||||
|
Some(TypedTxId::EIP1559Transaction),
|
||||||
|
TypedTxId::from_U64_option_id(Some(U64::from(0x02)))
|
||||||
|
);
|
||||||
|
assert_eq!(None, TypedTxId::from_U64_option_id(Some(U64::from(0x03))));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn typed_tx_id_from_u8_id() {
|
fn typed_tx_id_from_u8_id() {
|
||||||
assert_eq!(Some(TypedTxId::Legacy), TypedTxId::from_u8_id(0));
|
assert_eq!(Some(TypedTxId::Legacy), TypedTxId::from_u8_id(0));
|
||||||
assert_eq!(Some(TypedTxId::AccessList), TypedTxId::from_u8_id(1));
|
assert_eq!(Some(TypedTxId::AccessList), TypedTxId::from_u8_id(1));
|
||||||
|
assert_eq!(
|
||||||
|
Some(TypedTxId::EIP1559Transaction),
|
||||||
|
TypedTxId::from_u8_id(2)
|
||||||
|
);
|
||||||
assert_eq!(None, TypedTxId::from_u8_id(3));
|
assert_eq!(None, TypedTxId::from_u8_id(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
//! View onto block rlp.
|
//! View onto block rlp.
|
||||||
|
|
||||||
|
use crate::BlockNumber;
|
||||||
|
|
||||||
use super::ViewRlp;
|
use super::ViewRlp;
|
||||||
use crate::{
|
use crate::{
|
||||||
bytes::Bytes,
|
bytes::Bytes,
|
||||||
@ -64,8 +66,13 @@ impl<'a> BlockView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create new Header object from header rlp.
|
/// Create new Header object from header rlp.
|
||||||
pub fn header(&self) -> Header {
|
pub fn header(&self, eip1559_transition: BlockNumber) -> Header {
|
||||||
self.rlp.val_at(0)
|
Header::decode_rlp(&self.rlp.at(0).rlp, eip1559_transition).unwrap_or_else(|e| {
|
||||||
|
panic!(
|
||||||
|
"block header, view rlp is trusted and should be valid: {:?}",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return header rlp.
|
/// Return header rlp.
|
||||||
@ -165,8 +172,13 @@ impl<'a> BlockView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return list of uncles of given block.
|
/// Return list of uncles of given block.
|
||||||
pub fn uncles(&self) -> Vec<Header> {
|
pub fn uncles(&self, eip1559_transition: BlockNumber) -> Vec<Header> {
|
||||||
self.rlp.list_at(2)
|
Header::decode_rlp_list(&self.rlp.at(2).rlp, eip1559_transition).unwrap_or_else(|e| {
|
||||||
|
panic!(
|
||||||
|
"block uncles, view rlp is trusted and should be valid: {:?}",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return number of uncles in given block, without deserializing them.
|
/// Return number of uncles in given block, without deserializing them.
|
||||||
@ -188,8 +200,15 @@ impl<'a> BlockView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return nth uncle.
|
/// Return nth uncle.
|
||||||
pub fn uncle_at(&self, index: usize) -> Option<Header> {
|
pub fn uncle_at(&self, index: usize, eip1559_transition: BlockNumber) -> Option<Header> {
|
||||||
self.uncles_rlp().iter().nth(index).map(|rlp| rlp.as_val())
|
self.uncles_rlp().iter().nth(index).map(|rlp| {
|
||||||
|
Header::decode_rlp(&rlp.rlp, eip1559_transition).unwrap_or_else(|e| {
|
||||||
|
panic!(
|
||||||
|
"block uncle_at, view rlp is trusted and should be valid.{:?}",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return nth uncle rlp.
|
/// Return nth uncle rlp.
|
||||||
|
@ -147,8 +147,13 @@ impl<'a> BodyView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return list of uncles of given block.
|
/// Return list of uncles of given block.
|
||||||
pub fn uncles(&self) -> Vec<Header> {
|
pub fn uncles(&self, eip1559_transition: BlockNumber) -> Vec<Header> {
|
||||||
self.rlp.list_at(1)
|
Header::decode_rlp_list(&self.rlp.at(1).rlp, eip1559_transition).unwrap_or_else(|e| {
|
||||||
|
panic!(
|
||||||
|
"block uncles, view rlp is trusted and should be valid: {:?}",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return number of uncles in given block, without deserializing them.
|
/// Return number of uncles in given block, without deserializing them.
|
||||||
@ -170,8 +175,15 @@ impl<'a> BodyView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return nth uncle.
|
/// Return nth uncle.
|
||||||
pub fn uncle_at(&self, index: usize) -> Option<Header> {
|
pub fn uncle_at(&self, index: usize, eip1559_transition: BlockNumber) -> Option<Header> {
|
||||||
self.uncles_rlp().iter().nth(index).map(|rlp| rlp.as_val())
|
self.uncles_rlp().iter().nth(index).map(|rlp| {
|
||||||
|
Header::decode_rlp(&rlp.rlp, eip1559_transition).unwrap_or_else(|e| {
|
||||||
|
panic!(
|
||||||
|
"block uncle_at, view rlp is trusted and should be valid.{:?}",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return nth uncle rlp.
|
/// Return nth uncle rlp.
|
||||||
|
@ -123,17 +123,33 @@ impl<'a> HeaderView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a vector of post-RLP-encoded seal fields.
|
/// Returns a vector of post-RLP-encoded seal fields.
|
||||||
pub fn seal(&self) -> Vec<Bytes> {
|
/// If eip1559 is true, seal contains also base_fee_per_gas. Otherwise, it contains only seal fields.
|
||||||
|
pub fn seal(&self, eip1559: bool) -> Vec<Bytes> {
|
||||||
|
let last_seal_index = if eip1559 {
|
||||||
|
self.rlp.item_count() - 1
|
||||||
|
} else {
|
||||||
|
self.rlp.item_count()
|
||||||
|
};
|
||||||
let mut seal = vec![];
|
let mut seal = vec![];
|
||||||
for i in 13..self.rlp.item_count() {
|
for i in 13..last_seal_index {
|
||||||
seal.push(self.rlp.at(i).as_raw().to_vec());
|
seal.push(self.rlp.at(i).as_raw().to_vec());
|
||||||
}
|
}
|
||||||
seal
|
seal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns block base fee. Should be called only for EIP1559 headers.
|
||||||
|
/// If called for non EIP1559 header, returns garbage
|
||||||
|
pub fn base_fee(&self) -> U256 {
|
||||||
|
match self.rlp.rlp.val_at::<U256>(self.rlp.item_count() - 1) {
|
||||||
|
Ok(base_fee) => base_fee,
|
||||||
|
Err(_) => Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a vector of seal fields (RLP-decoded).
|
/// Returns a vector of seal fields (RLP-decoded).
|
||||||
pub fn decode_seal(&self) -> Result<Vec<Bytes>, rlp::DecoderError> {
|
/// If eip1559 is true, seal contains also base_fee_per_gas. Otherwise, it contains only seal fields.
|
||||||
let seal = self.seal();
|
pub fn decode_seal(&self, eip1559: bool) -> Result<Vec<Bytes>, rlp::DecoderError> {
|
||||||
|
let seal = self.seal(eip1559);
|
||||||
seal.into_iter()
|
seal.into_iter()
|
||||||
.map(|s| rlp::Rlp::new(&s).data().map(|x| x.to_vec()))
|
.map(|s| rlp::Rlp::new(&s).data().map(|x| x.to_vec()))
|
||||||
.collect()
|
.collect()
|
||||||
@ -198,6 +214,6 @@ mod tests {
|
|||||||
assert_eq!(view.gas_used(), 0x524d.into());
|
assert_eq!(view.gas_used(), 0x524d.into());
|
||||||
assert_eq!(view.timestamp(), 0x56_8e_93_2a);
|
assert_eq!(view.timestamp(), 0x56_8e_93_2a);
|
||||||
assert_eq!(view.extra_data(), vec![] as Vec<u8>);
|
assert_eq!(view.extra_data(), vec![] as Vec<u8>);
|
||||||
assert_eq!(view.seal(), vec![mix_hash, nonce]);
|
assert_eq!(view.seal(false), vec![mix_hash, nonce]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ use rlp::Rlp;
|
|||||||
|
|
||||||
/// View onto transaction rlp. Assumption is this is part of block.
|
/// View onto transaction rlp. Assumption is this is part of block.
|
||||||
/// Typed Transaction View. It handles raw bytes to search for particular field.
|
/// Typed Transaction View. It handles raw bytes to search for particular field.
|
||||||
|
/// EIP1559 tx:
|
||||||
|
/// 2 | [chainId, nonce, maxPriorityFeePerGas, maxFeePerGas(gasPrice), gasLimit, to, value, data, access_list, senderV, senderR, senderS]
|
||||||
/// Access tx:
|
/// Access tx:
|
||||||
/// 1 | [chainId, nonce, gasPrice, gasLimit, to, value, data, access_list, senderV, senderR, senderS]
|
/// 1 | [chainId, nonce, gasPrice, gasLimit, to, value, data, access_list, senderV, senderR, senderS]
|
||||||
/// Legacy tx:
|
/// Legacy tx:
|
||||||
@ -81,7 +83,10 @@ impl<'a> TypedTransactionView<'a> {
|
|||||||
}
|
}
|
||||||
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
.rlp
|
.rlp
|
||||||
.val_at(1),
|
.val_at(0),
|
||||||
|
TypedTxId::EIP1559Transaction => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
|
.rlp
|
||||||
|
.val_at(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +97,9 @@ impl<'a> TypedTransactionView<'a> {
|
|||||||
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
.rlp
|
.rlp
|
||||||
.val_at(1),
|
.val_at(1),
|
||||||
|
TypedTxId::EIP1559Transaction => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
|
.rlp
|
||||||
|
.val_at(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +110,9 @@ impl<'a> TypedTransactionView<'a> {
|
|||||||
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
.rlp
|
.rlp
|
||||||
.val_at(2),
|
.val_at(2),
|
||||||
|
TypedTxId::EIP1559Transaction => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
|
.rlp
|
||||||
|
.val_at(3),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +123,9 @@ impl<'a> TypedTransactionView<'a> {
|
|||||||
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
.rlp
|
.rlp
|
||||||
.val_at(3),
|
.val_at(3),
|
||||||
|
TypedTxId::EIP1559Transaction => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
|
.rlp
|
||||||
|
.val_at(4),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,6 +136,9 @@ impl<'a> TypedTransactionView<'a> {
|
|||||||
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
.rlp
|
.rlp
|
||||||
.val_at(5),
|
.val_at(5),
|
||||||
|
TypedTxId::EIP1559Transaction => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
|
.rlp
|
||||||
|
.val_at(6),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +149,9 @@ impl<'a> TypedTransactionView<'a> {
|
|||||||
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
.rlp
|
.rlp
|
||||||
.val_at(6),
|
.val_at(6),
|
||||||
|
TypedTxId::EIP1559Transaction => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
|
.rlp
|
||||||
|
.val_at(7),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +171,18 @@ impl<'a> TypedTransactionView<'a> {
|
|||||||
chain_id,
|
chain_id,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
TypedTxId::EIP1559Transaction => {
|
||||||
|
let chain_id = match self.chain_id() {
|
||||||
|
0 => None,
|
||||||
|
n => Some(n),
|
||||||
|
};
|
||||||
|
signature::add_chain_replay_protection(
|
||||||
|
view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
|
.rlp
|
||||||
|
.val_at(9),
|
||||||
|
chain_id,
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
r as u8
|
r as u8
|
||||||
}
|
}
|
||||||
@ -161,6 +193,9 @@ impl<'a> TypedTransactionView<'a> {
|
|||||||
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
.rlp
|
.rlp
|
||||||
.val_at(8),
|
.val_at(8),
|
||||||
|
TypedTxId::EIP1559Transaction => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
|
.rlp
|
||||||
|
.val_at(9),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,6 +206,9 @@ impl<'a> TypedTransactionView<'a> {
|
|||||||
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
.rlp
|
.rlp
|
||||||
.val_at(9),
|
.val_at(9),
|
||||||
|
TypedTxId::EIP1559Transaction => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
|
.rlp
|
||||||
|
.val_at(10),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,6 +219,9 @@ impl<'a> TypedTransactionView<'a> {
|
|||||||
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
TypedTxId::AccessList => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
.rlp
|
.rlp
|
||||||
.val_at(10),
|
.val_at(10),
|
||||||
|
TypedTxId::EIP1559Transaction => view!(Self, &self.rlp.rlp.data().unwrap()[1..])
|
||||||
|
.rlp
|
||||||
|
.val_at(11),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,7 +260,26 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_access_list_transaction_view() {
|
fn test_access_list_transaction_view() {
|
||||||
let rlp = "b8c101f8be01010a8301e24194000000000000000000000000000000000000aaaa8080f85bf859940000000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000080a082dc119130f280bd72e3fd4e10220e35b767031b84b8dd1f64085e0158f234dba072228551e678a8a6c6e9bae0ae786b8839c7fda0a994caddd23910f45f385cc0".from_hex().unwrap();
|
let rlp = "b8c101f8be01010a8301e24194000000000000000000000000000000000000aaaa8080f85bf859940000000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000080a082dc119130f280bd72e3fd4e10220e35b767031b84b8dd1f64085e0158f234dba072228551e678a8a6c6e9bae0ae786b8839c7fda0a994caddd23910f45f385cc0".from_hex().unwrap();
|
||||||
|
let view = view!(TypedTransactionView, &rlp);
|
||||||
|
assert_eq!(view.nonce(), 0x1.into());
|
||||||
|
assert_eq!(view.gas_price(), 0xa.into());
|
||||||
|
assert_eq!(view.gas(), 0x1e241.into());
|
||||||
|
assert_eq!(view.value(), 0x0.into());
|
||||||
|
assert_eq!(view.data(), "".from_hex().unwrap());
|
||||||
|
assert_eq!(
|
||||||
|
view.r(),
|
||||||
|
"82dc119130f280bd72e3fd4e10220e35b767031b84b8dd1f64085e0158f234db".into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
view.s(),
|
||||||
|
"72228551e678a8a6c6e9bae0ae786b8839c7fda0a994caddd23910f45f385cc0".into()
|
||||||
|
);
|
||||||
|
assert_eq!(view.standard_v(), 0x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_eip1559_transaction_view() {
|
||||||
|
let rlp = "b8c202f8bf01010a0a8301e24194000000000000000000000000000000000000aaaa8080f85bf859940000000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000080a082dc119130f280bd72e3fd4e10220e35b767031b84b8dd1f64085e0158f234dba072228551e678a8a6c6e9bae0ae786b8839c7fda0a994caddd23910f45f385cc0".from_hex().unwrap();
|
||||||
let view = view!(TypedTransactionView, &rlp);
|
let view = view!(TypedTransactionView, &rlp);
|
||||||
assert_eq!(view.nonce(), 0x1.into());
|
assert_eq!(view.nonce(), 0x1.into());
|
||||||
assert_eq!(view.gas_price(), 0xa.into());
|
assert_eq!(view.gas_price(), 0xa.into());
|
||||||
|
@ -89,6 +89,7 @@ impl BlockChain {
|
|||||||
state_root: Some(self.genesis_block.state_root.clone()),
|
state_root: Some(self.genesis_block.state_root.clone()),
|
||||||
gas_used: Some(self.genesis_block.gas_used),
|
gas_used: Some(self.genesis_block.gas_used),
|
||||||
extra_data: Some(self.genesis_block.extra_data.clone()),
|
extra_data: Some(self.genesis_block.extra_data.clone()),
|
||||||
|
base_fee: self.genesis_block.base_fee,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,8 @@ pub struct Header {
|
|||||||
/// Uncles hash.
|
/// Uncles hash.
|
||||||
#[serde(rename = "uncleHash")]
|
#[serde(rename = "uncleHash")]
|
||||||
pub uncles_hash: H256,
|
pub uncles_hash: H256,
|
||||||
|
/// Base fee
|
||||||
|
pub base_fee: Option<Uint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -51,6 +51,8 @@ pub struct Genesis {
|
|||||||
pub gas_used: Option<Uint>,
|
pub gas_used: Option<Uint>,
|
||||||
/// Extra data.
|
/// Extra data.
|
||||||
pub extra_data: Option<Bytes>,
|
pub extra_data: Option<Bytes>,
|
||||||
|
/// Base fee.
|
||||||
|
pub base_fee: Option<Uint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -122,6 +124,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
),
|
),
|
||||||
|
base_fee: None,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,10 @@ pub struct Params {
|
|||||||
/// See `CommonParams` docs.
|
/// See `CommonParams` docs.
|
||||||
pub eip2930_transition: Option<Uint>,
|
pub eip2930_transition: Option<Uint>,
|
||||||
/// See `CommonParams` docs.
|
/// See `CommonParams` docs.
|
||||||
|
pub eip1559_transition: Option<Uint>,
|
||||||
|
/// See `CommonParams` docs.
|
||||||
|
pub eip3198_transition: Option<Uint>,
|
||||||
|
/// See `CommonParams` docs.
|
||||||
pub eip3529_transition: Option<Uint>,
|
pub eip3529_transition: Option<Uint>,
|
||||||
/// See `CommonParams` docs.
|
/// See `CommonParams` docs.
|
||||||
pub eip3541_transition: Option<Uint>,
|
pub eip3541_transition: Option<Uint>,
|
||||||
@ -148,6 +152,12 @@ pub struct Params {
|
|||||||
pub kip4_transition: Option<Uint>,
|
pub kip4_transition: Option<Uint>,
|
||||||
/// KIP6 activiation block height.
|
/// KIP6 activiation block height.
|
||||||
pub kip6_transition: Option<Uint>,
|
pub kip6_transition: Option<Uint>,
|
||||||
|
/// Base fee max change denominator
|
||||||
|
pub eip1559_base_fee_max_change_denominator: Option<Uint>,
|
||||||
|
/// Elasticity multiplier
|
||||||
|
pub eip1559_elasticity_multiplier: Option<Uint>,
|
||||||
|
/// Default value for the block base fee
|
||||||
|
pub eip1559_base_fee_initial_value: Option<Uint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -38,6 +38,7 @@ pub enum ForkSpec {
|
|||||||
ByzantiumToConstantinopleAt5,
|
ByzantiumToConstantinopleAt5,
|
||||||
ByzantiumToConstantinopleFixAt5,
|
ByzantiumToConstantinopleFixAt5,
|
||||||
Berlin,
|
Berlin,
|
||||||
|
London,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spec deserialization.
|
/// Spec deserialization.
|
||||||
|
@ -35,6 +35,9 @@ pub struct Env {
|
|||||||
/// Timestamp.
|
/// Timestamp.
|
||||||
#[serde(rename = "currentTimestamp")]
|
#[serde(rename = "currentTimestamp")]
|
||||||
pub timestamp: Uint,
|
pub timestamp: Uint,
|
||||||
|
/// Block base fee.
|
||||||
|
#[serde(rename = "currentBlockBaseFee")]
|
||||||
|
pub base_fee: Option<Uint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -64,7 +64,7 @@ ethcore-network = { path = "../net/network" }
|
|||||||
fake-fetch = { path = "../net/fake-fetch" }
|
fake-fetch = { path = "../net/fake-fetch" }
|
||||||
macros = { path = "../util/macros" }
|
macros = { path = "../util/macros" }
|
||||||
pretty_assertions = "0.1"
|
pretty_assertions = "0.1"
|
||||||
transaction-pool = "2.0.1"
|
txpool = { path = "../transaction-pool" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
accounts = ["ethcore-accounts"]
|
accounts = ["ethcore-accounts"]
|
||||||
|
@ -92,8 +92,6 @@ extern crate serde_derive;
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate ethjson;
|
extern crate ethjson;
|
||||||
#[cfg(test)]
|
|
||||||
extern crate transaction_pool as txpool;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -125,9 +125,10 @@ impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher
|
|||||||
used_default_from: request.from.is_none(),
|
used_default_from: request.from.is_none(),
|
||||||
to: request.to,
|
to: request.to,
|
||||||
nonce,
|
nonce,
|
||||||
gas_price: request.gas_price.unwrap_or_else(|| {
|
gas_price: Some(request.gas_price.unwrap_or_else(|| {
|
||||||
default_gas_price(&*self.client, &*self.miner, self.gas_price_percentile)
|
default_gas_price(&*self.client, &*self.miner, self.gas_price_percentile)
|
||||||
}),
|
})),
|
||||||
|
max_fee_per_gas: request.max_fee_per_gas,
|
||||||
gas: request
|
gas: request
|
||||||
.gas
|
.gas
|
||||||
.unwrap_or_else(|| self.miner.sensible_gas_limit()),
|
.unwrap_or_else(|| self.miner.sensible_gas_limit()),
|
||||||
@ -135,6 +136,7 @@ impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher
|
|||||||
data: request.data.unwrap_or_else(Vec::new),
|
data: request.data.unwrap_or_else(Vec::new),
|
||||||
condition: request.condition,
|
condition: request.condition,
|
||||||
access_list: request.access_list,
|
access_list: request.access_list,
|
||||||
|
max_priority_fee_per_gas: request.max_priority_fee_per_gas,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,8 @@ use crypto::{publickey::Signature, DEFAULT_MAC};
|
|||||||
use ethereum_types::{Address, H256, U256};
|
use ethereum_types::{Address, H256, U256};
|
||||||
use jsonrpc_core::{Error, ErrorCode};
|
use jsonrpc_core::{Error, ErrorCode};
|
||||||
use types::transaction::{
|
use types::transaction::{
|
||||||
AccessListTx, Action, SignedTransaction, Transaction, TypedTransaction, TypedTxId,
|
AccessListTx, Action, EIP1559TransactionTx, SignedTransaction, Transaction, TypedTransaction,
|
||||||
|
TypedTxId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use jsonrpc_core::Result;
|
use jsonrpc_core::Result;
|
||||||
@ -50,11 +51,11 @@ impl super::Accounts for Signer {
|
|||||||
nonce: U256,
|
nonce: U256,
|
||||||
password: SignWith,
|
password: SignWith,
|
||||||
) -> Result<WithToken<SignedTransaction>> {
|
) -> Result<WithToken<SignedTransaction>> {
|
||||||
let legacy_tx = Transaction {
|
let mut legacy_tx = Transaction {
|
||||||
nonce,
|
nonce,
|
||||||
action: filled.to.map_or(Action::Create, Action::Call),
|
action: filled.to.map_or(Action::Create, Action::Call),
|
||||||
gas: filled.gas,
|
gas: filled.gas,
|
||||||
gas_price: filled.gas_price,
|
gas_price: filled.gas_price.unwrap_or_default(),
|
||||||
value: filled.value,
|
value: filled.value,
|
||||||
data: filled.data,
|
data: filled.data,
|
||||||
};
|
};
|
||||||
@ -74,6 +75,31 @@ impl super::Accounts for Signer {
|
|||||||
.collect(),
|
.collect(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
Some(TypedTxId::EIP1559Transaction) => {
|
||||||
|
if let Some(max_fee_per_gas) = filled.max_fee_per_gas {
|
||||||
|
legacy_tx.gas_price = max_fee_per_gas;
|
||||||
|
} else {
|
||||||
|
return Err(Error::new(ErrorCode::InvalidParams));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(max_priority_fee_per_gas) = filled.max_priority_fee_per_gas {
|
||||||
|
let transaction = AccessListTx::new(
|
||||||
|
legacy_tx,
|
||||||
|
filled
|
||||||
|
.access_list
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
TypedTransaction::EIP1559Transaction(EIP1559TransactionTx {
|
||||||
|
transaction,
|
||||||
|
max_priority_fee_per_gas,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return Err(Error::new(ErrorCode::InvalidParams));
|
||||||
|
}
|
||||||
|
}
|
||||||
None => return Err(Error::new(ErrorCode::InvalidParams)),
|
None => return Err(Error::new(ErrorCode::InvalidParams)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -385,6 +385,9 @@ pub fn transaction_message(error: &TransactionError) -> String {
|
|||||||
InsufficientGasPrice { minimal, got } => {
|
InsufficientGasPrice { minimal, got } => {
|
||||||
format!("Transaction gas price is too low. It does not satisfy your node's minimal gas price (minimal: {}, got: {}). Try increasing the gas price.", minimal, got)
|
format!("Transaction gas price is too low. It does not satisfy your node's minimal gas price (minimal: {}, got: {}). Try increasing the gas price.", minimal, got)
|
||||||
}
|
}
|
||||||
|
GasPriceLowerThanBaseFee { gas_price, base_fee} => {
|
||||||
|
format!("Transaction max gas price is lower then the required base fee (gas_price: {}, base_fee: {}). Try increasing the max gas price.", gas_price, base_fee)
|
||||||
|
}
|
||||||
InsufficientBalance { balance, cost } => {
|
InsufficientBalance { balance, cost } => {
|
||||||
format!("Insufficient funds. The account you tried to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance)
|
format!("Insufficient funds. The account you tried to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance)
|
||||||
}
|
}
|
||||||
|
@ -260,13 +260,15 @@ mod test {
|
|||||||
from: Address::from_low_u64_be(1),
|
from: Address::from_low_u64_be(1),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(Address::from_low_u64_be(2)),
|
to: Some(Address::from_low_u64_be(2)),
|
||||||
gas_price: 0.into(),
|
gas_price: Some(U256::from(0)),
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: 10_000.into(),
|
gas: 10_000.into(),
|
||||||
value: 10_000_000.into(),
|
value: 10_000_000.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
|
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use types::transaction::{
|
use types::transaction::{
|
||||||
AccessListTx, Action, SignedTransaction, Transaction, TypedTransaction, TypedTxId,
|
AccessListTx, Action, EIP1559TransactionTx, SignedTransaction, Transaction, TypedTransaction,
|
||||||
|
TypedTxId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ethereum_types::U256;
|
use ethereum_types::U256;
|
||||||
@ -27,7 +28,7 @@ pub fn sign_call(request: CallRequest) -> Result<SignedTransaction, Error> {
|
|||||||
let max_gas = U256::from(500_000_000);
|
let max_gas = U256::from(500_000_000);
|
||||||
let gas = min(request.gas.unwrap_or(max_gas), max_gas);
|
let gas = min(request.gas.unwrap_or(max_gas), max_gas);
|
||||||
let from = request.from.unwrap_or_default();
|
let from = request.from.unwrap_or_default();
|
||||||
let tx_legacy = Transaction {
|
let mut tx_legacy = Transaction {
|
||||||
nonce: request.nonce.unwrap_or_default(),
|
nonce: request.nonce.unwrap_or_default(),
|
||||||
action: request.to.map_or(Action::Create, Action::Call),
|
action: request.to.map_or(Action::Create, Action::Call),
|
||||||
gas,
|
gas,
|
||||||
@ -51,6 +52,31 @@ pub fn sign_call(request: CallRequest) -> Result<SignedTransaction, Error> {
|
|||||||
.collect(),
|
.collect(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
Some(TypedTxId::EIP1559Transaction) => {
|
||||||
|
if let Some(max_fee_per_gas) = request.max_fee_per_gas {
|
||||||
|
tx_legacy.gas_price = max_fee_per_gas;
|
||||||
|
} else {
|
||||||
|
return Err(Error::new(ErrorCode::InvalidParams));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(max_priority_fee_per_gas) = request.max_priority_fee_per_gas {
|
||||||
|
let transaction = AccessListTx::new(
|
||||||
|
tx_legacy,
|
||||||
|
request
|
||||||
|
.access_list
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
TypedTransaction::EIP1559Transaction(EIP1559TransactionTx {
|
||||||
|
transaction,
|
||||||
|
max_priority_fee_per_gas,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return Err(Error::new(ErrorCode::InvalidParams));
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => return Err(Error::new(ErrorCode::InvalidParams)),
|
_ => return Err(Error::new(ErrorCode::InvalidParams)),
|
||||||
};
|
};
|
||||||
Ok(tx_typed.fake_sign(from))
|
Ok(tx_typed.fake_sign(from))
|
||||||
|
@ -30,6 +30,8 @@ pub struct TransactionRequest {
|
|||||||
pub to: Option<Address>,
|
pub to: Option<Address>,
|
||||||
/// Gas Price
|
/// Gas Price
|
||||||
pub gas_price: Option<U256>,
|
pub gas_price: Option<U256>,
|
||||||
|
/// Max fee per gas
|
||||||
|
pub max_fee_per_gas: Option<U256>,
|
||||||
/// Gas
|
/// Gas
|
||||||
pub gas: Option<U256>,
|
pub gas: Option<U256>,
|
||||||
/// Value of transaction in wei
|
/// Value of transaction in wei
|
||||||
@ -42,6 +44,8 @@ pub struct TransactionRequest {
|
|||||||
pub condition: Option<TransactionCondition>,
|
pub condition: Option<TransactionCondition>,
|
||||||
/// Access list
|
/// Access list
|
||||||
pub access_list: Option<AccessList>,
|
pub access_list: Option<AccessList>,
|
||||||
|
/// Miner bribe
|
||||||
|
pub max_priority_fee_per_gas: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transaction request coming from RPC with default values filled in.
|
/// Transaction request coming from RPC with default values filled in.
|
||||||
@ -56,7 +60,9 @@ pub struct FilledTransactionRequest {
|
|||||||
/// Recipient
|
/// Recipient
|
||||||
pub to: Option<Address>,
|
pub to: Option<Address>,
|
||||||
/// Gas Price
|
/// Gas Price
|
||||||
pub gas_price: U256,
|
pub gas_price: Option<U256>,
|
||||||
|
/// Max fee per gas
|
||||||
|
pub max_fee_per_gas: Option<U256>,
|
||||||
/// Gas
|
/// Gas
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
/// Value of transaction in wei
|
/// Value of transaction in wei
|
||||||
@ -69,6 +75,8 @@ pub struct FilledTransactionRequest {
|
|||||||
pub condition: Option<TransactionCondition>,
|
pub condition: Option<TransactionCondition>,
|
||||||
/// Access list
|
/// Access list
|
||||||
pub access_list: Option<AccessList>,
|
pub access_list: Option<AccessList>,
|
||||||
|
/// Miner bribe
|
||||||
|
pub max_priority_fee_per_gas: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FilledTransactionRequest> for TransactionRequest {
|
impl From<FilledTransactionRequest> for TransactionRequest {
|
||||||
@ -77,13 +85,15 @@ impl From<FilledTransactionRequest> for TransactionRequest {
|
|||||||
transaction_type: r.transaction_type,
|
transaction_type: r.transaction_type,
|
||||||
from: Some(r.from),
|
from: Some(r.from),
|
||||||
to: r.to,
|
to: r.to,
|
||||||
gas_price: Some(r.gas_price),
|
gas_price: r.gas_price,
|
||||||
|
max_fee_per_gas: r.max_fee_per_gas,
|
||||||
gas: Some(r.gas),
|
gas: Some(r.gas),
|
||||||
value: Some(r.value),
|
value: Some(r.value),
|
||||||
data: Some(r.data),
|
data: Some(r.data),
|
||||||
nonce: r.nonce,
|
nonce: r.nonce,
|
||||||
condition: r.condition,
|
condition: r.condition,
|
||||||
access_list: r.access_list.map(Into::into),
|
access_list: r.access_list.map(Into::into),
|
||||||
|
max_priority_fee_per_gas: r.max_priority_fee_per_gas,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,6 +109,8 @@ pub struct CallRequest {
|
|||||||
pub to: Option<Address>,
|
pub to: Option<Address>,
|
||||||
/// Gas Price
|
/// Gas Price
|
||||||
pub gas_price: Option<U256>,
|
pub gas_price: Option<U256>,
|
||||||
|
/// Max fee per gas
|
||||||
|
pub max_fee_per_gas: Option<U256>,
|
||||||
/// Gas
|
/// Gas
|
||||||
pub gas: Option<U256>,
|
pub gas: Option<U256>,
|
||||||
/// Value
|
/// Value
|
||||||
@ -109,6 +121,8 @@ pub struct CallRequest {
|
|||||||
pub nonce: Option<U256>,
|
pub nonce: Option<U256>,
|
||||||
/// Access list
|
/// Access list
|
||||||
pub access_list: Option<AccessList>,
|
pub access_list: Option<AccessList>,
|
||||||
|
/// Miner bribe
|
||||||
|
pub max_priority_fee_per_gas: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Confirmation object
|
/// Confirmation object
|
||||||
|
@ -76,6 +76,7 @@ impl<C: BlockChainClient + 'static> Debug for DebugClient<C> {
|
|||||||
.cloned()
|
.cloned()
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.collect(),
|
.collect(),
|
||||||
|
base_fee_per_gas: block.header.base_fee(),
|
||||||
uncles: block.uncles.iter().map(Header::hash).collect(),
|
uncles: block.uncles.iter().map(Header::hash).collect(),
|
||||||
transactions: BlockTransactions::Full(
|
transactions: BlockTransactions::Full(
|
||||||
block
|
block
|
||||||
|
@ -259,6 +259,7 @@ where
|
|||||||
match (block, difficulty) {
|
match (block, difficulty) {
|
||||||
(Some(block), Some(total_difficulty)) => {
|
(Some(block), Some(total_difficulty)) => {
|
||||||
let view = block.header_view();
|
let view = block.header_view();
|
||||||
|
let eip1559_enabled = client.engine().schedule(view.number()).eip1559;
|
||||||
Ok(Some(RichBlock {
|
Ok(Some(RichBlock {
|
||||||
inner: Block {
|
inner: Block {
|
||||||
hash: match is_pending {
|
hash: match is_pending {
|
||||||
@ -286,7 +287,18 @@ where
|
|||||||
timestamp: view.timestamp().into(),
|
timestamp: view.timestamp().into(),
|
||||||
difficulty: view.difficulty(),
|
difficulty: view.difficulty(),
|
||||||
total_difficulty: Some(total_difficulty),
|
total_difficulty: Some(total_difficulty),
|
||||||
seal_fields: view.seal().into_iter().map(Into::into).collect(),
|
seal_fields: view
|
||||||
|
.seal(eip1559_enabled)
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect(),
|
||||||
|
base_fee_per_gas: {
|
||||||
|
if eip1559_enabled {
|
||||||
|
Some(view.base_fee())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
uncles: block.uncle_hashes(),
|
uncles: block.uncle_hashes(),
|
||||||
transactions: match include_txs {
|
transactions: match include_txs {
|
||||||
true => BlockTransactions::Full(
|
true => BlockTransactions::Full(
|
||||||
@ -408,7 +420,8 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
let uncle = match client.uncle(uncle_id) {
|
let uncle = match client.uncle(uncle_id) {
|
||||||
Some(hdr) => match hdr.decode() {
|
Some(hdr) => match hdr.decode(self.client.engine().params().eip1559_transition)
|
||||||
|
{
|
||||||
Ok(h) => h,
|
Ok(h) => h,
|
||||||
Err(e) => return Err(errors::decode(e)),
|
Err(e) => return Err(errors::decode(e)),
|
||||||
},
|
},
|
||||||
@ -456,6 +469,7 @@ where
|
|||||||
receipts_root: *uncle.receipts_root(),
|
receipts_root: *uncle.receipts_root(),
|
||||||
extra_data: uncle.extra_data().clone().into(),
|
extra_data: uncle.extra_data().clone().into(),
|
||||||
seal_fields: uncle.seal().iter().cloned().map(Into::into).collect(),
|
seal_fields: uncle.seal().iter().cloned().map(Into::into).collect(),
|
||||||
|
base_fee_per_gas: uncle.base_fee(),
|
||||||
uncles: vec![],
|
uncles: vec![],
|
||||||
transactions: BlockTransactions::Hashes(vec![]),
|
transactions: BlockTransactions::Hashes(vec![]),
|
||||||
},
|
},
|
||||||
@ -1125,7 +1139,9 @@ where
|
|||||||
.client
|
.client
|
||||||
.block_header(id)
|
.block_header(id)
|
||||||
.ok_or_else(errors::state_pruned)
|
.ok_or_else(errors::state_pruned)
|
||||||
.and_then(|h| h.decode().map_err(errors::decode)));
|
.and_then(|h| h
|
||||||
|
.decode(self.client.engine().params().eip1559_transition)
|
||||||
|
.map_err(errors::decode)));
|
||||||
|
|
||||||
(state, header)
|
(state, header)
|
||||||
};
|
};
|
||||||
@ -1166,7 +1182,9 @@ where
|
|||||||
.client
|
.client
|
||||||
.block_header(id)
|
.block_header(id)
|
||||||
.ok_or_else(errors::state_pruned)
|
.ok_or_else(errors::state_pruned)
|
||||||
.and_then(|h| h.decode().map_err(errors::decode)));
|
.and_then(|h| h
|
||||||
|
.decode(self.client.engine().params().eip1559_transition)
|
||||||
|
.map_err(errors::decode)));
|
||||||
(state, header)
|
(state, header)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,10 +34,12 @@ use v1::{
|
|||||||
helpers::{errors, limit_logs, Subscribers},
|
helpers::{errors, limit_logs, Subscribers},
|
||||||
metadata::Metadata,
|
metadata::Metadata,
|
||||||
traits::EthPubSub,
|
traits::EthPubSub,
|
||||||
types::{pubsub, Log, RichHeader},
|
types::{pubsub, Header, Log, RichHeader},
|
||||||
};
|
};
|
||||||
|
|
||||||
use ethcore::client::{BlockChainClient, BlockId, ChainNotify, ChainRouteType, NewBlocks};
|
use ethcore::client::{
|
||||||
|
BlockChainClient, BlockId, ChainNotify, ChainRouteType, EngineInfo, NewBlocks,
|
||||||
|
};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use parity_runtime::Executor;
|
use parity_runtime::Executor;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
@ -100,7 +102,10 @@ pub struct ChainNotificationHandler<C> {
|
|||||||
transactions_subscribers: Arc<RwLock<Subscribers<Client>>>,
|
transactions_subscribers: Arc<RwLock<Subscribers<Client>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> ChainNotificationHandler<C> {
|
impl<C> ChainNotificationHandler<C>
|
||||||
|
where
|
||||||
|
C: EngineInfo,
|
||||||
|
{
|
||||||
fn notify(executor: &Executor, subscriber: &Client, result: pubsub::Result) {
|
fn notify(executor: &Executor, subscriber: &Client, result: pubsub::Result) {
|
||||||
executor.spawn(
|
executor.spawn(
|
||||||
subscriber
|
subscriber
|
||||||
@ -117,7 +122,10 @@ impl<C> ChainNotificationHandler<C> {
|
|||||||
&self.executor,
|
&self.executor,
|
||||||
subscriber,
|
subscriber,
|
||||||
pubsub::Result::Header(Box::new(RichHeader {
|
pubsub::Result::Header(Box::new(RichHeader {
|
||||||
inner: header.into(),
|
inner: Header::new(
|
||||||
|
header,
|
||||||
|
self.client.engine().params().eip1559_transition,
|
||||||
|
),
|
||||||
extra_info: extra_info.clone(),
|
extra_info: extra_info.clone(),
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
@ -174,7 +182,7 @@ impl<C> ChainNotificationHandler<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: BlockChainClient> ChainNotify for ChainNotificationHandler<C> {
|
impl<C: BlockChainClient + EngineInfo> ChainNotify for ChainNotificationHandler<C> {
|
||||||
// t_nb 11.3 RPC. Notify subscriber header/logs about new block
|
// t_nb 11.3 RPC. Notify subscriber header/logs about new block
|
||||||
fn new_blocks(&self, new_blocks: NewBlocks) {
|
fn new_blocks(&self, new_blocks: NewBlocks) {
|
||||||
if self.heads_subscribers.read().is_empty() && self.logs_subscribers.read().is_empty() {
|
if self.heads_subscribers.read().is_empty() && self.logs_subscribers.read().is_empty() {
|
||||||
|
@ -19,7 +19,7 @@ use std::{collections::BTreeMap, str::FromStr, sync::Arc};
|
|||||||
|
|
||||||
use crypto::{publickey::ecies, DEFAULT_MAC};
|
use crypto::{publickey::ecies, DEFAULT_MAC};
|
||||||
use ethcore::{
|
use ethcore::{
|
||||||
client::{BlockChainClient, Call, StateClient},
|
client::{BlockChainClient, Call, EngineInfo, StateClient},
|
||||||
miner::{self, MinerService, TransactionFilter},
|
miner::{self, MinerService, TransactionFilter},
|
||||||
snapshot::{RestorationStatus, SnapshotService},
|
snapshot::{RestorationStatus, SnapshotService},
|
||||||
state::StateInfo,
|
state::StateInfo,
|
||||||
@ -43,7 +43,7 @@ use v1::{
|
|||||||
metadata::Metadata,
|
metadata::Metadata,
|
||||||
traits::Parity,
|
traits::Parity,
|
||||||
types::{
|
types::{
|
||||||
block_number_to_id, BlockNumber, Bytes, CallRequest, ChainStatus, Histogram,
|
block_number_to_id, BlockNumber, Bytes, CallRequest, ChainStatus, Header, Histogram,
|
||||||
LocalTransactionStatus, Peers, Receipt, RecoveredAccount, RichHeader, RpcSettings,
|
LocalTransactionStatus, Peers, Receipt, RecoveredAccount, RichHeader, RpcSettings,
|
||||||
Transaction, TransactionStats,
|
Transaction, TransactionStats,
|
||||||
},
|
},
|
||||||
@ -69,7 +69,7 @@ where
|
|||||||
|
|
||||||
impl<C, M> ParityClient<C, M>
|
impl<C, M> ParityClient<C, M>
|
||||||
where
|
where
|
||||||
C: BlockChainClient + PrometheusMetrics,
|
C: BlockChainClient + PrometheusMetrics + EngineInfo,
|
||||||
{
|
{
|
||||||
/// Creates new `ParityClient`.
|
/// Creates new `ParityClient`.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@ -105,6 +105,7 @@ where
|
|||||||
+ PrometheusMetrics
|
+ PrometheusMetrics
|
||||||
+ StateClient<State = S>
|
+ StateClient<State = S>
|
||||||
+ Call<State = S>
|
+ Call<State = S>
|
||||||
|
+ EngineInfo
|
||||||
+ 'static,
|
+ 'static,
|
||||||
M: MinerService<State = S> + 'static,
|
M: MinerService<State = S> + 'static,
|
||||||
{
|
{
|
||||||
@ -386,7 +387,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
Box::new(future::ok(RichHeader {
|
Box::new(future::ok(RichHeader {
|
||||||
inner: header.into(),
|
inner: Header::new(&header, self.client.engine().params().eip1559_transition),
|
||||||
extra_info: extra.unwrap_or_default(),
|
extra_info: extra.unwrap_or_default(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -449,7 +450,7 @@ where
|
|||||||
.client
|
.client
|
||||||
.block_header(id)
|
.block_header(id)
|
||||||
.ok_or_else(errors::state_pruned)?
|
.ok_or_else(errors::state_pruned)?
|
||||||
.decode()
|
.decode(self.client.engine().params().eip1559_transition)
|
||||||
.map_err(errors::decode)?;
|
.map_err(errors::decode)?;
|
||||||
|
|
||||||
(state, header)
|
(state, header)
|
||||||
|
@ -124,8 +124,8 @@ impl<D: Dispatcher + 'static> SignerClient<D> {
|
|||||||
// Altering sender should always reset the nonce.
|
// Altering sender should always reset the nonce.
|
||||||
request.nonce = None;
|
request.nonce = None;
|
||||||
}
|
}
|
||||||
if let Some(gas_price) = modification.gas_price {
|
if modification.gas_price.is_some() {
|
||||||
request.gas_price = gas_price;
|
request.gas_price = modification.gas_price;
|
||||||
}
|
}
|
||||||
if let Some(gas) = modification.gas {
|
if let Some(gas) = modification.gas {
|
||||||
request.gas = gas;
|
request.gas = gas;
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ethcore::client::{
|
use ethcore::client::{
|
||||||
BlockChainClient, BlockId, Call, CallAnalytics, StateClient, StateInfo, TraceId, TransactionId,
|
BlockChainClient, BlockId, Call, CallAnalytics, EngineInfo, StateClient, StateInfo, TraceId,
|
||||||
|
TransactionId,
|
||||||
};
|
};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use types::transaction::{SignedTransaction, TypedTransaction};
|
use types::transaction::{SignedTransaction, TypedTransaction};
|
||||||
@ -60,7 +61,7 @@ impl<C> TracesClient<C> {
|
|||||||
impl<C, S> Traces for TracesClient<C>
|
impl<C, S> Traces for TracesClient<C>
|
||||||
where
|
where
|
||||||
S: StateInfo + 'static,
|
S: StateInfo + 'static,
|
||||||
C: BlockChainClient + StateClient<State = S> + Call<State = S> + 'static,
|
C: BlockChainClient + StateClient<State = S> + Call<State = S> + EngineInfo + 'static,
|
||||||
{
|
{
|
||||||
type Metadata = Metadata;
|
type Metadata = Metadata;
|
||||||
|
|
||||||
@ -135,7 +136,9 @@ where
|
|||||||
&signed,
|
&signed,
|
||||||
to_call_analytics(flags),
|
to_call_analytics(flags),
|
||||||
&mut state,
|
&mut state,
|
||||||
&header.decode().map_err(errors::decode)?,
|
&header
|
||||||
|
.decode(self.client.engine().params().eip1559_transition)
|
||||||
|
.map_err(errors::decode)?,
|
||||||
)
|
)
|
||||||
.map(TraceResults::from)
|
.map(TraceResults::from)
|
||||||
.map_err(errors::call)
|
.map_err(errors::call)
|
||||||
@ -181,7 +184,9 @@ where
|
|||||||
.call_many(
|
.call_many(
|
||||||
&requests,
|
&requests,
|
||||||
&mut state,
|
&mut state,
|
||||||
&header.decode().map_err(errors::decode)?,
|
&header
|
||||||
|
.decode(self.client.engine().params().eip1559_transition)
|
||||||
|
.map_err(errors::decode)?,
|
||||||
)
|
)
|
||||||
.map(|results| results.into_iter().map(TraceResults::from).collect())
|
.map(|results| results.into_iter().map(TraceResults::from).collect())
|
||||||
.map_err(errors::call)
|
.map_err(errors::call)
|
||||||
@ -224,7 +229,9 @@ where
|
|||||||
&signed,
|
&signed,
|
||||||
to_call_analytics(flags),
|
to_call_analytics(flags),
|
||||||
&mut state,
|
&mut state,
|
||||||
&header.decode().map_err(errors::decode)?,
|
&header
|
||||||
|
.decode(self.client.engine().params().eip1559_transition)
|
||||||
|
.map_err(errors::decode)?,
|
||||||
)
|
)
|
||||||
.map(TraceResults::from)
|
.map(TraceResults::from)
|
||||||
.map_err(errors::call)
|
.map_err(errors::call)
|
||||||
|
@ -97,7 +97,9 @@ impl EthTester {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for b in chain.blocks_rlp() {
|
for b in chain.blocks_rlp() {
|
||||||
if let Ok(block) = Unverified::from_rlp(b) {
|
if let Ok(block) =
|
||||||
|
Unverified::from_rlp(b, tester.client.engine().params().eip1559_transition)
|
||||||
|
{
|
||||||
let _ = tester.client.import_block(block);
|
let _ = tester.client.import_block(block);
|
||||||
tester.client.flush_queue();
|
tester.client.flush_queue();
|
||||||
tester.client.import_verified_blocks();
|
tester.client.import_verified_blocks();
|
||||||
@ -545,11 +547,9 @@ fn verify_transaction_counts(name: String, chain: BlockChain) {
|
|||||||
let tester = EthTester::from_chain(&chain);
|
let tester = EthTester::from_chain(&chain);
|
||||||
|
|
||||||
let mut id = 1;
|
let mut id = 1;
|
||||||
for b in chain
|
for b in chain.blocks_rlp().into_iter().filter_map(|b| {
|
||||||
.blocks_rlp()
|
Unverified::from_rlp(b, tester.client.engine().params().eip1559_transition).ok()
|
||||||
.into_iter()
|
}) {
|
||||||
.filter_map(|b| Unverified::from_rlp(b).ok())
|
|
||||||
{
|
|
||||||
let count = b.transactions.len();
|
let count = b.transactions.len();
|
||||||
|
|
||||||
let hash = b.header.hash();
|
let hash = b.header.hash();
|
||||||
|
@ -38,7 +38,6 @@ use miner::pool::{
|
|||||||
VerifiedTransaction,
|
VerifiedTransaction,
|
||||||
};
|
};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use txpool;
|
|
||||||
use types::{
|
use types::{
|
||||||
block::Block,
|
block::Block,
|
||||||
header::Header,
|
header::Header,
|
||||||
@ -335,6 +334,7 @@ impl MinerService for TestMinerService {
|
|||||||
block_gas_limit: 5_000_000.into(),
|
block_gas_limit: 5_000_000.into(),
|
||||||
tx_gas_limit: 5_000_000.into(),
|
tx_gas_limit: 5_000_000.into(),
|
||||||
no_early_reject: false,
|
no_early_reject: false,
|
||||||
|
block_base_fee: None,
|
||||||
},
|
},
|
||||||
status: txpool::LightStatus {
|
status: txpool::LightStatus {
|
||||||
mem_usage: 1_000,
|
mem_usage: 1_000,
|
||||||
|
@ -95,13 +95,15 @@ fn should_return_list_of_items_to_confirm() {
|
|||||||
from: Address::from_low_u64_be(1),
|
from: Address::from_low_u64_be(1),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: Some(U256::from(10_000)),
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
@ -142,13 +144,15 @@ fn should_reject_transaction_from_queue_without_dispatching() {
|
|||||||
from: Address::from_low_u64_be(1),
|
from: Address::from_low_u64_be(1),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: Some(U256::from(10_000)),
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
@ -180,13 +184,15 @@ fn should_not_remove_transaction_if_password_is_invalid() {
|
|||||||
from: Address::from_low_u64_be(1),
|
from: Address::from_low_u64_be(1),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: Some(U256::from(10_000)),
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
@ -246,13 +252,15 @@ fn should_confirm_transaction_and_dispatch() {
|
|||||||
from: address,
|
from: address,
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: Some(U256::from(10_000)),
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
@ -311,13 +319,15 @@ fn should_alter_the_sender_and_nonce() {
|
|||||||
from: Address::from_low_u64_be(0),
|
from: Address::from_low_u64_be(0),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: Some(U256::from(10_000)),
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: Some(10.into()),
|
nonce: Some(10.into()),
|
||||||
condition: None,
|
condition: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
@ -377,13 +387,15 @@ fn should_confirm_transaction_with_token() {
|
|||||||
from: address,
|
from: address,
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: Some(U256::from(10_000)),
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
@ -445,13 +457,15 @@ fn should_confirm_transaction_with_rlp() {
|
|||||||
from: address,
|
from: address,
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: Some(U256::from(10_000)),
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
@ -511,13 +525,15 @@ fn should_return_error_when_sender_does_not_match() {
|
|||||||
from: Address::default(),
|
from: Address::default(),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: Some(U256::from(10_000)),
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
@ -578,13 +594,15 @@ fn should_confirm_sign_transaction_with_rlp() {
|
|||||||
from: address,
|
from: address,
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: Some(U256::from(10_000)),
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
|
@ -18,7 +18,7 @@ use std::{collections::BTreeMap, ops::Deref};
|
|||||||
|
|
||||||
use ethereum_types::{Bloom as H2048, H160, H256, U256};
|
use ethereum_types::{Bloom as H2048, H160, H256, U256};
|
||||||
use serde::{ser::Error, Serialize, Serializer};
|
use serde::{ser::Error, Serialize, Serializer};
|
||||||
use types::encoded::Header as EthHeader;
|
use types::{encoded::Header as EthHeader, BlockNumber};
|
||||||
use v1::types::{Bytes, Transaction};
|
use v1::types::{Bytes, Transaction};
|
||||||
|
|
||||||
/// Block Transactions
|
/// Block Transactions
|
||||||
@ -81,6 +81,9 @@ pub struct Block {
|
|||||||
pub total_difficulty: Option<U256>,
|
pub total_difficulty: Option<U256>,
|
||||||
/// Seal fields
|
/// Seal fields
|
||||||
pub seal_fields: Vec<Bytes>,
|
pub seal_fields: Vec<Bytes>,
|
||||||
|
/// Base fee
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub base_fee_per_gas: Option<U256>,
|
||||||
/// Uncles' hashes
|
/// Uncles' hashes
|
||||||
pub uncles: Vec<H256>,
|
pub uncles: Vec<H256>,
|
||||||
/// Transactions
|
/// Transactions
|
||||||
@ -126,20 +129,18 @@ pub struct Header {
|
|||||||
pub difficulty: U256,
|
pub difficulty: U256,
|
||||||
/// Seal fields
|
/// Seal fields
|
||||||
pub seal_fields: Vec<Bytes>,
|
pub seal_fields: Vec<Bytes>,
|
||||||
|
/// Base fee
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub base_fee_per_gas: Option<U256>,
|
||||||
/// Size in bytes
|
/// Size in bytes
|
||||||
pub size: Option<U256>,
|
pub size: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EthHeader> for Header {
|
impl Header {
|
||||||
fn from(h: EthHeader) -> Self {
|
pub fn new(h: &EthHeader, eip1559_transition: BlockNumber) -> Self {
|
||||||
(&h).into()
|
let eip1559_enabled = h.number() >= eip1559_transition;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a EthHeader> for Header {
|
|
||||||
fn from(h: &'a EthHeader) -> Self {
|
|
||||||
Header {
|
Header {
|
||||||
hash: Some(h.hash()),
|
hash: Some(h.hash()),
|
||||||
size: Some(h.rlp().as_raw().len().into()),
|
size: Some(h.rlp().as_raw().len().into()),
|
||||||
parent_hash: h.parent_hash(),
|
parent_hash: h.parent_hash(),
|
||||||
uncles_hash: h.uncles_hash(),
|
uncles_hash: h.uncles_hash(),
|
||||||
@ -155,9 +156,16 @@ impl<'a> From<&'a EthHeader> for Header {
|
|||||||
timestamp: h.timestamp().into(),
|
timestamp: h.timestamp().into(),
|
||||||
difficulty: h.difficulty(),
|
difficulty: h.difficulty(),
|
||||||
extra_data: h.extra_data().into(),
|
extra_data: h.extra_data().into(),
|
||||||
seal_fields: h.view().decode_seal()
|
seal_fields: h.view().decode_seal(eip1559_enabled)
|
||||||
.expect("Client/Miner returns only valid headers. We only serialize headers from Client/Miner; qed")
|
.expect("Client/Miner returns only valid headers. We only serialize headers from Client/Miner; qed")
|
||||||
.into_iter().map(Into::into).collect(),
|
.into_iter().map(Into::into).collect(),
|
||||||
|
base_fee_per_gas: {
|
||||||
|
if eip1559_enabled {
|
||||||
|
Some(h.base_fee())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,7 +229,7 @@ mod tests {
|
|||||||
let serialized = serde_json::to_string(&t).unwrap();
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
serialized,
|
serialized,
|
||||||
r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"chainId":null,"v":"0x0","r":"0x0","s":"0x0","condition":null}]"#
|
r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"chainId":null,"v":"0x0","r":"0x0","s":"0x0","condition":null}]"#
|
||||||
);
|
);
|
||||||
|
|
||||||
let t = BlockTransactions::Hashes(vec![H256::default().into()]);
|
let t = BlockTransactions::Hashes(vec![H256::default().into()]);
|
||||||
@ -252,6 +260,7 @@ mod tests {
|
|||||||
difficulty: U256::default(),
|
difficulty: U256::default(),
|
||||||
total_difficulty: Some(U256::default()),
|
total_difficulty: Some(U256::default()),
|
||||||
seal_fields: vec![Bytes::default(), Bytes::default()],
|
seal_fields: vec![Bytes::default(), Bytes::default()],
|
||||||
|
base_fee_per_gas: None,
|
||||||
uncles: vec![],
|
uncles: vec![],
|
||||||
transactions: BlockTransactions::Hashes(vec![].into()),
|
transactions: BlockTransactions::Hashes(vec![].into()),
|
||||||
size: Some(69.into()),
|
size: Some(69.into()),
|
||||||
@ -296,6 +305,7 @@ mod tests {
|
|||||||
difficulty: U256::default(),
|
difficulty: U256::default(),
|
||||||
total_difficulty: Some(U256::default()),
|
total_difficulty: Some(U256::default()),
|
||||||
seal_fields: vec![Bytes::default(), Bytes::default()],
|
seal_fields: vec![Bytes::default(), Bytes::default()],
|
||||||
|
base_fee_per_gas: None,
|
||||||
uncles: vec![],
|
uncles: vec![],
|
||||||
transactions: BlockTransactions::Hashes(vec![].into()),
|
transactions: BlockTransactions::Hashes(vec![].into()),
|
||||||
size: None,
|
size: None,
|
||||||
@ -339,6 +349,7 @@ mod tests {
|
|||||||
timestamp: U256::default(),
|
timestamp: U256::default(),
|
||||||
difficulty: U256::default(),
|
difficulty: U256::default(),
|
||||||
seal_fields: vec![Bytes::default(), Bytes::default()],
|
seal_fields: vec![Bytes::default(), Bytes::default()],
|
||||||
|
base_fee_per_gas: None,
|
||||||
size: Some(69.into()),
|
size: Some(69.into()),
|
||||||
};
|
};
|
||||||
let serialized_header = serde_json::to_string(&header).unwrap();
|
let serialized_header = serde_json::to_string(&header).unwrap();
|
||||||
|
@ -33,7 +33,11 @@ pub struct CallRequest {
|
|||||||
/// To
|
/// To
|
||||||
pub to: Option<H160>,
|
pub to: Option<H160>,
|
||||||
/// Gas Price
|
/// Gas Price
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub gas_price: Option<U256>,
|
pub gas_price: Option<U256>,
|
||||||
|
/// Max fee per gas
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub max_fee_per_gas: Option<U256>,
|
||||||
/// Gas
|
/// Gas
|
||||||
pub gas: Option<U256>,
|
pub gas: Option<U256>,
|
||||||
/// Value
|
/// Value
|
||||||
@ -45,6 +49,9 @@ pub struct CallRequest {
|
|||||||
/// Access list
|
/// Access list
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub access_list: Option<AccessList>,
|
pub access_list: Option<AccessList>,
|
||||||
|
/// Miner bribe
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub max_priority_fee_per_gas: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Request> for CallRequest {
|
impl Into<Request> for CallRequest {
|
||||||
@ -54,11 +61,13 @@ impl Into<Request> for CallRequest {
|
|||||||
from: self.from.map(Into::into),
|
from: self.from.map(Into::into),
|
||||||
to: self.to.map(Into::into),
|
to: self.to.map(Into::into),
|
||||||
gas_price: self.gas_price.map(Into::into),
|
gas_price: self.gas_price.map(Into::into),
|
||||||
|
max_fee_per_gas: self.max_fee_per_gas,
|
||||||
gas: self.gas.map(Into::into),
|
gas: self.gas.map(Into::into),
|
||||||
value: self.value.map(Into::into),
|
value: self.value.map(Into::into),
|
||||||
data: self.data.map(Into::into),
|
data: self.data.map(Into::into),
|
||||||
nonce: self.nonce.map(Into::into),
|
nonce: self.nonce.map(Into::into),
|
||||||
access_list: self.access_list.map(Into::into),
|
access_list: self.access_list.map(Into::into),
|
||||||
|
max_priority_fee_per_gas: self.max_priority_fee_per_gas.map(Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,11 +100,13 @@ mod tests {
|
|||||||
from: Some(H160::from_low_u64_be(1)),
|
from: Some(H160::from_low_u64_be(1)),
|
||||||
to: Some(H160::from_low_u64_be(2)),
|
to: Some(H160::from_low_u64_be(2)),
|
||||||
gas_price: Some(U256::from(1)),
|
gas_price: Some(U256::from(1)),
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: Some(U256::from(2)),
|
gas: Some(U256::from(2)),
|
||||||
value: Some(U256::from(3)),
|
value: Some(U256::from(3)),
|
||||||
data: Some(vec![0x12, 0x34, 0x56].into()),
|
data: Some(vec![0x12, 0x34, 0x56].into()),
|
||||||
nonce: Some(U256::from(4)),
|
nonce: Some(U256::from(4)),
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -117,11 +128,13 @@ mod tests {
|
|||||||
from: Some(H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()),
|
from: Some(H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()),
|
||||||
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
gas_price: Some(U256::from_str("9184e72a000").unwrap()),
|
gas_price: Some(U256::from_str("9184e72a000").unwrap()),
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: Some(U256::from_str("76c0").unwrap()),
|
gas: Some(U256::from_str("76c0").unwrap()),
|
||||||
value: Some(U256::from_str("9184e72a").unwrap()),
|
value: Some(U256::from_str("9184e72a").unwrap()),
|
||||||
data: Some("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()),
|
data: Some("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()),
|
||||||
nonce: None,
|
nonce: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,11 +150,13 @@ mod tests {
|
|||||||
from: Some(H160::from_low_u64_be(1)),
|
from: Some(H160::from_low_u64_be(1)),
|
||||||
to: None,
|
to: None,
|
||||||
gas_price: None,
|
gas_price: None,
|
||||||
|
max_fee_per_gas: None,
|
||||||
gas: None,
|
gas: None,
|
||||||
value: None,
|
value: None,
|
||||||
data: None,
|
data: None,
|
||||||
nonce: None,
|
nonce: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -339,12 +339,14 @@ mod tests {
|
|||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: None,
|
to: None,
|
||||||
gas: 15_000.into(),
|
gas: 15_000.into(),
|
||||||
gas_price: 10_000.into(),
|
gas_price: Some(10_000.into()),
|
||||||
|
max_fee_per_gas: None,
|
||||||
value: 100_000.into(),
|
value: 100_000.into(),
|
||||||
data: vec![1, 2, 3],
|
data: vec![1, 2, 3],
|
||||||
nonce: Some(1.into()),
|
nonce: Some(1.into()),
|
||||||
condition: None,
|
condition: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
origin: Origin::Signer {
|
origin: Origin::Signer {
|
||||||
@ -372,12 +374,14 @@ mod tests {
|
|||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: None,
|
to: None,
|
||||||
gas: 15_000.into(),
|
gas: 15_000.into(),
|
||||||
gas_price: 10_000.into(),
|
gas_price: Some(10_000.into()),
|
||||||
|
max_fee_per_gas: None,
|
||||||
value: 100_000.into(),
|
value: 100_000.into(),
|
||||||
data: vec![1, 2, 3],
|
data: vec![1, 2, 3],
|
||||||
nonce: Some(1.into()),
|
nonce: Some(1.into()),
|
||||||
condition: None,
|
condition: None,
|
||||||
access_list: None,
|
access_list: None,
|
||||||
|
max_priority_fee_per_gas: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
origin: Origin::Unknown,
|
origin: Origin::Unknown,
|
||||||
|
@ -189,6 +189,7 @@ mod tests {
|
|||||||
timestamp: Default::default(),
|
timestamp: Default::default(),
|
||||||
difficulty: Default::default(),
|
difficulty: Default::default(),
|
||||||
seal_fields: vec![Default::default(), Default::default()],
|
seal_fields: vec![Default::default(), Default::default()],
|
||||||
|
base_fee_per_gas: None,
|
||||||
size: Some(69.into()),
|
size: Some(69.into()),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -118,7 +118,7 @@ impl From<RichReceipt> for Receipt {
|
|||||||
impl From<TypedReceipt> for Receipt {
|
impl From<TypedReceipt> for Receipt {
|
||||||
fn from(r: TypedReceipt) -> Self {
|
fn from(r: TypedReceipt) -> Self {
|
||||||
let transaction_type = r.tx_type().to_U64_option_id();
|
let transaction_type = r.tx_type().to_U64_option_id();
|
||||||
let r = r.receipt().clone();
|
let legacy_receipt = r.receipt().clone();
|
||||||
Receipt {
|
Receipt {
|
||||||
from: None,
|
from: None,
|
||||||
to: None,
|
to: None,
|
||||||
@ -127,13 +127,13 @@ impl From<TypedReceipt> for Receipt {
|
|||||||
transaction_index: None,
|
transaction_index: None,
|
||||||
block_hash: None,
|
block_hash: None,
|
||||||
block_number: None,
|
block_number: None,
|
||||||
cumulative_gas_used: r.gas_used,
|
cumulative_gas_used: legacy_receipt.gas_used,
|
||||||
gas_used: None,
|
gas_used: None,
|
||||||
contract_address: None,
|
contract_address: None,
|
||||||
logs: r.logs.into_iter().map(Into::into).collect(),
|
logs: legacy_receipt.logs.into_iter().map(Into::into).collect(),
|
||||||
status_code: Self::outcome_to_status_code(&r.outcome),
|
status_code: Self::outcome_to_status_code(&legacy_receipt.outcome),
|
||||||
state_root: Self::outcome_to_state_root(r.outcome),
|
state_root: Self::outcome_to_state_root(legacy_receipt.outcome),
|
||||||
logs_bloom: r.log_bloom,
|
logs_bloom: legacy_receipt.log_bloom,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,11 @@ pub struct Transaction {
|
|||||||
/// Transfered value
|
/// Transfered value
|
||||||
pub value: U256,
|
pub value: U256,
|
||||||
/// Gas Price
|
/// Gas Price
|
||||||
pub gas_price: U256,
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub gas_price: Option<U256>,
|
||||||
|
/// Max fee per gas
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub max_fee_per_gas: Option<U256>,
|
||||||
/// Gas
|
/// Gas
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
/// Data
|
/// Data
|
||||||
@ -77,6 +81,9 @@ pub struct Transaction {
|
|||||||
/// optional access list
|
/// optional access list
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub access_list: Option<AccessList>,
|
pub access_list: Option<AccessList>,
|
||||||
|
/// miner bribe
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub max_priority_fee_per_gas: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Local Transaction Status
|
/// Local Transaction Status
|
||||||
@ -187,12 +194,34 @@ impl Transaction {
|
|||||||
let signature = t.signature();
|
let signature = t.signature();
|
||||||
let scheme = CreateContractAddress::FromSenderAndNonce;
|
let scheme = CreateContractAddress::FromSenderAndNonce;
|
||||||
|
|
||||||
let access_list = if let TypedTransaction::AccessList(al) = t.as_unsigned() {
|
let access_list = match t.as_unsigned() {
|
||||||
Some(al.access_list.clone().into_iter().map(Into::into).collect())
|
TypedTransaction::AccessList(tx) => {
|
||||||
} else {
|
Some(tx.access_list.clone().into_iter().map(Into::into).collect())
|
||||||
None
|
}
|
||||||
|
TypedTransaction::EIP1559Transaction(tx) => Some(
|
||||||
|
tx.transaction
|
||||||
|
.access_list
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
TypedTransaction::Legacy(_) => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (gas_price, max_fee_per_gas) = match t.as_unsigned() {
|
||||||
|
TypedTransaction::Legacy(_) => (Some(t.tx().gas_price), None),
|
||||||
|
TypedTransaction::AccessList(_) => (Some(t.tx().gas_price), None),
|
||||||
|
TypedTransaction::EIP1559Transaction(_) => (None, Some(t.tx().gas_price)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let max_priority_fee_per_gas =
|
||||||
|
if let TypedTransaction::EIP1559Transaction(tx) = t.as_unsigned() {
|
||||||
|
Some(tx.max_priority_fee_per_gas)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let standard_v = if t.tx_type() == TypedTxId::Legacy {
|
let standard_v = if t.tx_type() == TypedTxId::Legacy {
|
||||||
Some(t.standard_v())
|
Some(t.standard_v())
|
||||||
} else {
|
} else {
|
||||||
@ -211,7 +240,8 @@ impl Transaction {
|
|||||||
Action::Call(ref address) => Some(*address),
|
Action::Call(ref address) => Some(*address),
|
||||||
},
|
},
|
||||||
value: t.tx().value,
|
value: t.tx().value,
|
||||||
gas_price: t.tx().gas_price,
|
gas_price,
|
||||||
|
max_fee_per_gas,
|
||||||
gas: t.tx().gas,
|
gas: t.tx().gas,
|
||||||
input: Bytes::new(t.tx().data.clone()),
|
input: Bytes::new(t.tx().data.clone()),
|
||||||
creates: match t.tx().action {
|
creates: match t.tx().action {
|
||||||
@ -230,6 +260,7 @@ impl Transaction {
|
|||||||
condition: None,
|
condition: None,
|
||||||
transaction_type: t.signed.tx_type().to_U64_option_id(),
|
transaction_type: t.signed.tx_type().to_U64_option_id(),
|
||||||
access_list,
|
access_list,
|
||||||
|
max_priority_fee_per_gas,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,11 +268,35 @@ impl Transaction {
|
|||||||
pub fn from_signed(t: SignedTransaction) -> Transaction {
|
pub fn from_signed(t: SignedTransaction) -> Transaction {
|
||||||
let signature = t.signature();
|
let signature = t.signature();
|
||||||
let scheme = CreateContractAddress::FromSenderAndNonce;
|
let scheme = CreateContractAddress::FromSenderAndNonce;
|
||||||
let access_list = if let TypedTransaction::AccessList(al) = t.as_unsigned() {
|
|
||||||
Some(al.access_list.clone().into_iter().map(Into::into).collect())
|
let access_list = match t.as_unsigned() {
|
||||||
} else {
|
TypedTransaction::AccessList(tx) => {
|
||||||
None
|
Some(tx.access_list.clone().into_iter().map(Into::into).collect())
|
||||||
|
}
|
||||||
|
TypedTransaction::EIP1559Transaction(tx) => Some(
|
||||||
|
tx.transaction
|
||||||
|
.access_list
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
TypedTransaction::Legacy(_) => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (gas_price, max_fee_per_gas) = match t.as_unsigned() {
|
||||||
|
TypedTransaction::Legacy(_) => (Some(t.tx().gas_price), None),
|
||||||
|
TypedTransaction::AccessList(_) => (Some(t.tx().gas_price), None),
|
||||||
|
TypedTransaction::EIP1559Transaction(_) => (None, Some(t.tx().gas_price)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let max_priority_fee_per_gas =
|
||||||
|
if let TypedTransaction::EIP1559Transaction(tx) = t.as_unsigned() {
|
||||||
|
Some(tx.max_priority_fee_per_gas)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let standard_v = if t.tx_type() == TypedTxId::Legacy {
|
let standard_v = if t.tx_type() == TypedTxId::Legacy {
|
||||||
Some(t.standard_v())
|
Some(t.standard_v())
|
||||||
} else {
|
} else {
|
||||||
@ -260,7 +315,8 @@ impl Transaction {
|
|||||||
Action::Call(ref address) => Some(*address),
|
Action::Call(ref address) => Some(*address),
|
||||||
},
|
},
|
||||||
value: t.tx().value,
|
value: t.tx().value,
|
||||||
gas_price: t.tx().gas_price,
|
gas_price,
|
||||||
|
max_fee_per_gas,
|
||||||
gas: t.tx().gas,
|
gas: t.tx().gas,
|
||||||
input: Bytes::new(t.tx().data.clone()),
|
input: Bytes::new(t.tx().data.clone()),
|
||||||
creates: match t.tx().action {
|
creates: match t.tx().action {
|
||||||
@ -279,6 +335,7 @@ impl Transaction {
|
|||||||
condition: None,
|
condition: None,
|
||||||
transaction_type: t.tx_type().to_U64_option_id(),
|
transaction_type: t.tx_type().to_U64_option_id(),
|
||||||
access_list,
|
access_list,
|
||||||
|
max_priority_fee_per_gas,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +387,7 @@ mod tests {
|
|||||||
let serialized = serde_json::to_string(&t).unwrap();
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
serialized,
|
serialized,
|
||||||
r#"{"type":"0x1","hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"chainId":null,"v":"0x0","r":"0x0","s":"0x0","condition":null,"accessList":[{"address":"0x0000000000000000000000000000000000000000","storageKeys":[]}]}"#
|
r#"{"type":"0x1","hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"chainId":null,"v":"0x0","r":"0x0","s":"0x0","condition":null,"accessList":[{"address":"0x0000000000000000000000000000000000000000","storageKeys":[]}]}"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user