From 3fcf87184bbf2c637882df8f500174fd0dcc32d5 Mon Sep 17 00:00:00 2001 From: Pana Date: Mon, 27 May 2024 18:08:49 +0800 Subject: [PATCH 01/14] update main crates rust-edition to 2021 --- bins/conflux/Cargo.toml | 2 +- crates/accounts/Cargo.toml | 2 +- crates/blockgen/Cargo.toml | 2 +- crates/cfx_utils/Cargo.toml | 2 +- crates/cfxcore/core/Cargo.toml | 2 +- crates/cfxcore/execute-helper/Cargo.toml | 2 +- crates/cfxcore/executor/Cargo.toml | 2 +- crates/cfxcore/internal_common/Cargo.toml | 2 +- crates/cfxcore/packing-pool/Cargo.toml | 2 +- crates/cfxcore/parameters/Cargo.toml | 2 +- crates/cfxcore/vm-interpreter/Cargo.toml | 2 +- crates/cfxcore/vm-types/Cargo.toml | 2 +- crates/client/Cargo.toml | 2 +- crates/dbs/db-errors/Cargo.toml | 2 +- crates/dbs/db/Cargo.toml | 2 +- crates/dbs/kvdb-rocksdb/Cargo.toml | 2 +- crates/dbs/statedb/Cargo.toml | 2 +- crates/dbs/storage/Cargo.toml | 2 +- crates/network/Cargo.toml | 2 +- crates/primitives/Cargo.toml | 2 +- crates/secret_store/Cargo.toml | 2 +- crates/stratum/Cargo.toml | 2 +- crates/transactiongen/Cargo.toml | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bins/conflux/Cargo.toml b/bins/conflux/Cargo.toml index ce3ba6da1d..daba982097 100644 --- a/bins/conflux/Cargo.toml +++ b/bins/conflux/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "conflux" build = "build.rs" -edition = "2018" +edition = "2021" version.workspace = true authors.workspace = true description.workspace = true diff --git a/crates/accounts/Cargo.toml b/crates/accounts/Cargo.toml index 484fa2e865..4667293273 100644 --- a/crates/accounts/Cargo.toml +++ b/crates/accounts/Cargo.toml @@ -5,7 +5,7 @@ license = "GPL-3.0" name = "cfxcore-accounts" version = "0.1.0" authors = ["Conflux Foundation"] -edition = "2018" +edition = "2021" [dependencies] cfxkey = { path = "../cfx_key" } diff --git a/crates/blockgen/Cargo.toml b/crates/blockgen/Cargo.toml index dcc8811a44..ff0dab5b3e 100644 --- a/crates/blockgen/Cargo.toml +++ b/crates/blockgen/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "blockgen" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] clap = "2" diff --git a/crates/cfx_utils/Cargo.toml b/crates/cfx_utils/Cargo.toml index 8df8343618..9a25935810 100644 --- a/crates/cfx_utils/Cargo.toml +++ b/crates/cfx_utils/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "cfx-utils" version = "0.6.0" -edition = "2018" +edition = "2021" [dependencies] log = "0.4" diff --git a/crates/cfxcore/core/Cargo.toml b/crates/cfxcore/core/Cargo.toml index c8870c7b46..3ed8aeb7ff 100644 --- a/crates/cfxcore/core/Cargo.toml +++ b/crates/cfxcore/core/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "cfxcore" version = "2.0.2" -edition = "2018" +edition = "2021" [dependencies] bit-set = "0.4" diff --git a/crates/cfxcore/execute-helper/Cargo.toml b/crates/cfxcore/execute-helper/Cargo.toml index b1e52aa643..49861b8c54 100644 --- a/crates/cfxcore/execute-helper/Cargo.toml +++ b/crates/cfxcore/execute-helper/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "cfx-execute-helper" version = "2.0.2" -edition = "2018" +edition = "2021" [dependencies] # substrate-bn = { git = "https://github.com/paritytech/bn", default-features = false, rev="63f8c587356a67b33c7396af98e065b66fca5dda" } diff --git a/crates/cfxcore/executor/Cargo.toml b/crates/cfxcore/executor/Cargo.toml index 096f05d41a..b4b4d5797c 100644 --- a/crates/cfxcore/executor/Cargo.toml +++ b/crates/cfxcore/executor/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "cfx-executor" version = "2.0.2" -edition = "2018" +edition = "2021" [dependencies] substrate-bn = { git = "https://github.com/paritytech/bn", default-features = false, rev="63f8c587356a67b33c7396af98e065b66fca5dda" } diff --git a/crates/cfxcore/internal_common/Cargo.toml b/crates/cfxcore/internal_common/Cargo.toml index c5c9ba6186..34d0a56875 100644 --- a/crates/cfxcore/internal_common/Cargo.toml +++ b/crates/cfxcore/internal_common/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "cfx-internal-common" version = "1.0.0" -edition = "2018" +edition = "2021" [dependencies] cfx-bytes = { path = "../../cfx_bytes" } diff --git a/crates/cfxcore/packing-pool/Cargo.toml b/crates/cfxcore/packing-pool/Cargo.toml index 812a810b0a..32efa04bf6 100644 --- a/crates/cfxcore/packing-pool/Cargo.toml +++ b/crates/cfxcore/packing-pool/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cfx-packing-pool" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/cfxcore/parameters/Cargo.toml b/crates/cfxcore/parameters/Cargo.toml index 69dac972b1..c92815550a 100644 --- a/crates/cfxcore/parameters/Cargo.toml +++ b/crates/cfxcore/parameters/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "cfx-parameters" version = "1.0.0" -edition = "2018" +edition = "2021" [dependencies] cfx-types = { path = "../../cfx_types" } diff --git a/crates/cfxcore/vm-interpreter/Cargo.toml b/crates/cfxcore/vm-interpreter/Cargo.toml index 07ab4e4b6b..a9758436cb 100644 --- a/crates/cfxcore/vm-interpreter/Cargo.toml +++ b/crates/cfxcore/vm-interpreter/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "cfx-vm-interpreter" version = "2.0.2" -edition = "2018" +edition = "2021" [dependencies] bit-set = "0.4" diff --git a/crates/cfxcore/vm-types/Cargo.toml b/crates/cfxcore/vm-types/Cargo.toml index 3d1d4b9c43..942c1e22fc 100644 --- a/crates/cfxcore/vm-types/Cargo.toml +++ b/crates/cfxcore/vm-types/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "cfx-vm-types" version = "2.0.2" -edition = "2018" +edition = "2021" [dependencies] cfx-bytes = { path = "../../cfx_bytes" } diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index c8949ce51d..a515724f10 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "client" version = "2.0.2" -edition = "2018" +edition = "2021" [dependencies] bigdecimal = "0.1.0" diff --git a/crates/dbs/db-errors/Cargo.toml b/crates/dbs/db-errors/Cargo.toml index eb3c3fdf25..8a5be605c1 100644 --- a/crates/dbs/db-errors/Cargo.toml +++ b/crates/dbs/db-errors/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "cfx-db-errors" version = "2.0.2" -edition = "2018" +edition = "2021" [dependencies] primitives = { path = "../../primitives" } diff --git a/crates/dbs/db/Cargo.toml b/crates/dbs/db/Cargo.toml index 741428a262..b44d9f2f8c 100644 --- a/crates/dbs/db/Cargo.toml +++ b/crates/dbs/db/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "db" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] log = "0.4" diff --git a/crates/dbs/kvdb-rocksdb/Cargo.toml b/crates/dbs/kvdb-rocksdb/Cargo.toml index fb2eb53475..32f843de8e 100644 --- a/crates/dbs/kvdb-rocksdb/Cargo.toml +++ b/crates/dbs/kvdb-rocksdb/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] repository = "https://github.com/paritytech/parity-common" description = "kvdb implementation backed by rocksDB" license = "GPL-3.0" -edition = "2018" +edition = "2021" [dependencies] cfx-types = { path = "../../cfx_types" } diff --git a/crates/dbs/statedb/Cargo.toml b/crates/dbs/statedb/Cargo.toml index 78e4a8ff48..d5024b8d8f 100644 --- a/crates/dbs/statedb/Cargo.toml +++ b/crates/dbs/statedb/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "cfx-statedb" version = "1.0.0" -edition = "2018" +edition = "2021" [dependencies] cfx-internal-common = { path = "../../cfxcore/internal_common" } diff --git a/crates/dbs/storage/Cargo.toml b/crates/dbs/storage/Cargo.toml index d533ff2c01..219092b067 100644 --- a/crates/dbs/storage/Cargo.toml +++ b/crates/dbs/storage/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "cfx-storage" version = "1.0.0" -edition = "2018" +edition = "2021" [dependencies] cfg-if = "0.1" diff --git a/crates/network/Cargo.toml b/crates/network/Cargo.toml index fcc5910fb7..682b073f01 100644 --- a/crates/network/Cargo.toml +++ b/crates/network/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "network" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] cfx-addr = { path = "../cfx_addr" } diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 330dad862d..9cc7a5497f 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "primitives" version = "0.2.0" -edition = "2018" +edition = "2021" [dependencies] byteorder = "1.2.7" diff --git a/crates/secret_store/Cargo.toml b/crates/secret_store/Cargo.toml index e2a510a31b..8e8b1ddf93 100644 --- a/crates/secret_store/Cargo.toml +++ b/crates/secret_store/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "secret-store" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] cfx-types = { path = "../cfx_types" } diff --git a/crates/stratum/Cargo.toml b/crates/stratum/Cargo.toml index dbdf1ab411..b19ebad8ca 100644 --- a/crates/stratum/Cargo.toml +++ b/crates/stratum/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" name = "cfx-stratum" version = "1.12.0" license = "GPL-3.0" -edition = "2018" +edition = "2021" [dependencies] cfx-types = { path = "../cfx_types" } diff --git a/crates/transactiongen/Cargo.toml b/crates/transactiongen/Cargo.toml index 42bc5e8439..f483931279 100644 --- a/crates/transactiongen/Cargo.toml +++ b/crates/transactiongen/Cargo.toml @@ -4,7 +4,7 @@ homepage = "https://www.confluxnetwork.org" license = "GPL-3.0" name = "txgen" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] clap = "2" From 16ab81da6eafb42ad8a6fe2ad4be207788497c73 Mon Sep 17 00:00:00 2001 From: Pana Date: Tue, 28 May 2024 10:04:46 +0800 Subject: [PATCH 02/14] update toolchain to 1.77.2 to mitigate issue CVE-2024-24576 on windows --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 79e15fd493..369f9966f6 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.77.0 +1.77.2 From f90530573b7e57db49791f69dc0990c5be6d2917 Mon Sep 17 00:00:00 2001 From: Chenxing Li Date: Wed, 29 May 2024 15:19:19 +0800 Subject: [PATCH 03/14] Fix packing issue for 1559 --- .../transaction_pool_inner.rs | 1 - tests/evm_space/eip1559_test.py | 85 +++++++++++++++---- 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs b/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs index b84ecc6172..be176bbc4a 100644 --- a/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs +++ b/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs @@ -1207,7 +1207,6 @@ impl TransactionPoolInner { tx_min_price, validity, ); - packed_transactions.extend_from_slice(&sampled_tx); // Recompute the base price, it should be <= estimated base price, // since the actual used gas is <= estimated limit diff --git a/tests/evm_space/eip1559_test.py b/tests/evm_space/eip1559_test.py index 4db1624bd9..6e52c5fece 100755 --- a/tests/evm_space/eip1559_test.py +++ b/tests/evm_space/eip1559_test.py @@ -10,6 +10,7 @@ from conflux.rpc import RpcClient from web3 import Web3 +BASE_PRICE = 20 * (10 ** 9) class Eip1559Test(Web3Base): def set_test_params(self): self.num_nodes = 2 @@ -34,30 +35,45 @@ def setup_network(self): def run_test(self): self.cfxPrivkey = default_config['GENESIS_PRI_KEY'] self.cfxAccount = self.rpc.GENESIS_ADDR - print(f'Using Conflux account {self.cfxAccount}') + self.log.info(f'Using Conflux account {self.cfxAccount}') + # initialize EVM account self.evmAccount = self.w3.eth.account.privateKeyToAccount(self.DEFAULT_TEST_ACCOUNT_KEY) - print(f'Using EVM account {self.evmAccount.address}') + self.log.info(f'Using EVM account {self.evmAccount.address}') self.cross_space_transfer(self.evmAccount.address, 100 * 10 ** 18) assert_equal(self.nodes[0].eth_getBalance(self.evmAccount.address), hex(100 * 10 ** 18)) - x = b32_address_to_hex("NET10:TYPE.USER:AAR8JZYBZV0FHZREAV49SYXNZUT8S0JT1ASMXX99XH") - y = b32_address_to_hex('NET10:TYPE.BUILTIN:AAEJUAAAAAAAAAAAAAAAAAAAAAAAAAAAA27GYVFYR7') + # x = b32_address_to_hex("NET10:TYPE.USER:AAR8JZYBZV0FHZREAV49SYXNZUT8S0JT1ASMXX99XH") + # y = b32_address_to_hex('NET10:TYPE.BUILTIN:AAEJUAAAAAAAAAAAAAAAAAAAAAAAAAAAA27GYVFYR7') ret = self.nodes[0].debug_getTransactionsByEpoch("0x1") assert_equal(len(ret), 1) - nonce = self.w3.eth.getTransactionCount(self.evmAccount.address) + self.nonce = self.w3.eth.getTransactionCount(self.evmAccount.address) + + tx, receipt = self.send_large_transaction() + self.check_node_sync(tx, receipt) + + tx, receipt = self.send_large_cheap_transactions() + self.check_node_sync(tx, receipt) + + tx, receipt = self.send_many_transactions_in_one_block() + self.check_node_sync(tx, receipt, tx_num = 10) + + self.check_fee_history() + + + def send_large_transaction(self): signed = self.evmAccount.signTransaction({ "type": "0x2", "to": self.evmAccount.address, "value": 1, "gas": 30000000, - 'maxFeePerGas': 200 * (10**9), + 'maxFeePerGas': 10 * BASE_PRICE, 'maxPriorityFeePerGas': 1, - "nonce": nonce, + "nonce": self.nonce, "chainId": 10, }) - self.log.info("Signed transaction %s", signed) + self.nonce += 1 return_tx_hash = self.w3.eth.sendRawTransaction(signed["rawTransaction"]) self.rpc.generate_block(1) @@ -70,18 +86,45 @@ def run_test(self): assert_equal(receipt["txExecErrorMsg"], None) tx = self.w3.eth.get_transaction(return_tx_hash) - self.log.info("Get transaction from node %s", tx) + + return tx, receipt + + def send_large_cheap_transactions(self): + for i in range(0, 5): + signed = self.evmAccount.signTransaction({ + "type": "0x2", + "to": self.evmAccount.address, + "value": 1, + "gas": 7_500_000, + 'maxFeePerGas': BASE_PRICE, + 'maxPriorityFeePerGas': 1, + "nonce": self.nonce + i, + "chainId": 10, + }) + return_tx_hash = self.w3.eth.sendRawTransaction(signed["rawTransaction"]) + + self.nonce += 5 + + self.rpc.generate_blocks(20, 5) + receipt = self.w3.eth.waitForTransactionReceipt(return_tx_hash) + assert_equal(receipt["status"], 1) + assert_equal(receipt["txExecErrorMsg"], None) + + tx = self.w3.eth.get_transaction(return_tx_hash) + return tx, receipt + + def check_node_sync(self, tx, receipt, tx_num = 1): # Check if another node can decode EIP1559 transactions sync_blocks(self.nodes) ret1 = self.nodes[0].debug_getTransactionsByEpoch(hex(receipt["blockNumber"])) ret2 = self.nodes[1].debug_getTransactionsByBlock(encode_hex_0x(tx["blockHash"])) - assert_equal(len(ret1), 1) - assert_equal(len(ret2), 1) + assert_equal(len(ret1), tx_num) + assert_equal(len(ret2), tx_num) assert_equal(ret1[0], ret2[0]) - + def check_fee_history(self): fee_history = self.nodes[0].eth_feeHistory("0x5", "latest", [21, 75]) assert_equal(len(fee_history['base_fee_per_gas']), 6) assert_equal(len(fee_history['gas_used_ratio']), 5) @@ -89,26 +132,32 @@ def run_test(self): assert_greater_than(int(self.nodes[0].cfx_getFeeBurnt(), 0), 0) - nonce = self.w3.eth.getTransactionCount(self.evmAccount.address) - for i in range(1, 10): + def send_many_transactions_in_one_block(self): + for i in range(0, 10): signed = self.evmAccount.signTransaction({ "type": "0x2", "to": self.evmAccount.address, "value": 1, "gas": 21000, - 'maxFeePerGas': 20* (10**9), + 'maxFeePerGas': BASE_PRICE, 'maxPriorityFeePerGas': 1, - "nonce": i, + "nonce": self.nonce + i, "chainId": 10, }) return_tx_hash = self.w3.eth.sendRawTransaction(signed["rawTransaction"]) + self.nonce += 10 + self.rpc.generate_block(10) - self.rpc.generate_blocks(20, 1) + self.rpc.generate_blocks(20, 0) receipt = self.w3.eth.waitForTransactionReceipt(return_tx_hash) - assert_equal(receipt["cumulativeGasUsed"], 21000 * 9) + assert_equal(receipt["cumulativeGasUsed"], 21000 * 10) assert_equal(receipt["gasUsed"], 21000) assert_equal(self.w3.eth.estimate_gas({"to": self.evmAccount.address}), 21000) + tx = self.w3.eth.get_transaction(return_tx_hash) + return tx, receipt + + if __name__ == "__main__": Eip1559Test().main() \ No newline at end of file From dfc5f27de85d943d5ac19731b4a904a47b3cfff2 Mon Sep 17 00:00:00 2001 From: Chenxing Li Date: Wed, 29 May 2024 11:37:01 +0800 Subject: [PATCH 04/14] Fix error in packing pool --- .../transaction_pool_inner.rs | 78 ++++++++++++++++--- crates/cfxcore/packing-pool/src/pool.rs | 19 +++++ crates/primitives/src/block_header.rs | 5 ++ 3 files changed, 92 insertions(+), 10 deletions(-) diff --git a/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs b/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs index be176bbc4a..28a274e0d2 100644 --- a/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs +++ b/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs @@ -111,7 +111,7 @@ impl DeferredPool { &self, space: Space, gas_target: U256, parent_base_price: U256, min_base_price: U256, ) -> (U256, U256) { - let packing_gas_limit = self + let estimated_gas_limit = self .packing_pool .in_space(space) .estimate_packing_gas_limit( @@ -119,6 +119,7 @@ impl DeferredPool { parent_base_price, min_base_price, ); + let packing_gas_limit = U256::min(gas_target * 2, estimated_gas_limit); let price_limit = compute_next_price( gas_target, packing_gas_limit, @@ -171,7 +172,6 @@ impl DeferredPool { { 'sender: for tx in sender_txs.iter() { if tx.gas_price() < &tx_min_price { - to_drop_txs.push(tx.clone()); break 'sender; } match validity(&*tx) { @@ -1132,6 +1132,11 @@ impl TransactionPoolInner { return (packed_transactions, parent_base_price); } + debug!( + "Packing transaction for 1559, parent base price {:?}", + parent_base_price + ); + let mut block_base_price = parent_base_price.clone(); let spec = machine.spec(best_block_number, best_epoch_height); @@ -1155,32 +1160,59 @@ impl TransactionPoolInner { let min_base_price = machine.params().min_base_price()[Space::Ethereum]; - let (packing_gas_limit, base_price) = + let (packing_gas_limit, tx_min_price) = self.deferred_pool.estimate_packing_gas_limit( Space::Ethereum, gas_target, parent_base_price, min_base_price, ); + debug!( + "Packing plan (espace): gas limit: {:?}, tx min price: {:?}", + packing_gas_limit, tx_min_price + ); let (sampled_tx, used_gas, used_size) = self.deferred_pool.packing_sampler( Space::Ethereum, packing_gas_limit, block_size_limit, num_txs, - base_price, + tx_min_price, validity, ); - packed_transactions.extend_from_slice(&sampled_tx); + // Recompute the base price, it should be <= estimated base price, // since the actual used gas is <= estimated limit - block_base_price[Space::Ethereum] = compute_next_price( + let base_price = compute_next_price( gas_target, used_gas, parent_base_price, min_base_price, ); - (sampled_tx.len(), used_size) + + if base_price <= tx_min_price { + debug!( + "Packing result (espace): gas used: {:?}, base price: {:?}", + used_gas, base_price + ); + block_base_price[Space::Ethereum] = base_price; + packed_transactions.extend_from_slice(&sampled_tx); + + (sampled_tx.len(), used_size) + } else { + // Should be unreachable + warn!( + "Inconsistent packing result (espace): gas used: {:?}, base price: {:?}", + used_gas, base_price + ); + block_base_price[Space::Ethereum] = compute_next_price( + gas_target, + U256::zero(), + parent_base_price, + min_base_price, + ); + (0, 0) + } } else { (0, 0) }; @@ -1191,7 +1223,7 @@ impl TransactionPoolInner { let min_base_price = machine.params().min_base_price()[Space::Native]; - let (packed_limit, tx_min_price) = + let (packing_gas_limit, tx_min_price) = self.deferred_pool.estimate_packing_gas_limit( Space::Native, gas_target, @@ -1199,9 +1231,14 @@ impl TransactionPoolInner { min_base_price, ); + debug!( + "Packing plan (core space): gas limit: {:?}, tx min price: {:?}", + packing_gas_limit, tx_min_price + ); + let (sampled_tx, used_gas, _) = self.deferred_pool.packing_sampler( Space::Native, - packed_limit, + packing_gas_limit, block_size_limit - evm_used_size, num_txs - evm_packed_tx_num, tx_min_price, @@ -1210,12 +1247,33 @@ impl TransactionPoolInner { // Recompute the base price, it should be <= estimated base price, // since the actual used gas is <= estimated limit - block_base_price[Space::Native] = compute_next_price( + let base_price = compute_next_price( gas_target, used_gas, parent_base_price, min_base_price, ); + + if base_price <= tx_min_price { + debug!( + "Packing result (core space): gas used: {:?}, base price: {:?}", + used_gas, base_price + ); + block_base_price[Space::Native] = base_price; + packed_transactions.extend_from_slice(&sampled_tx); + } else { + // Should be unreachable + warn!( + "Inconsistent packing result (core space): gas used: {:?}, base price: {:?}", + used_gas, base_price + ); + block_base_price[Space::Native] = compute_next_price( + gas_target, + U256::zero(), + parent_base_price, + min_base_price, + ); + } } if log::max_level() >= log::Level::Debug { diff --git a/crates/cfxcore/packing-pool/src/pool.rs b/crates/cfxcore/packing-pool/src/pool.rs index 7cca4e7515..5c9e7c6a18 100644 --- a/crates/cfxcore/packing-pool/src/pool.rs +++ b/crates/cfxcore/packing-pool/src/pool.rs @@ -352,6 +352,25 @@ mod pool_tests { } } + #[allow(dead_code)] + fn same_price_txs() -> PackingPool { + let config = PackingPoolConfig::new_for_test(); + let mut pool = PackingPool::new(config); + + static ID: AtomicUsize = AtomicUsize::new(0); + for i in 1000..2000 { + let (_, res) = pool.insert(MockTransaction { + sender: i, + nonce: 0, + gas_price: 20, + gas_limit: 1, + id: ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst), + }); + res.unwrap(); + } + pool + } + #[test] fn test_split_in_middle() { let mut pool = default_pool(5, 10); diff --git a/crates/primitives/src/block_header.rs b/crates/primitives/src/block_header.rs index ef71eb439a..6054884843 100644 --- a/crates/primitives/src/block_header.rs +++ b/crates/primitives/src/block_header.rs @@ -9,6 +9,7 @@ use crate::{ use cfx_types::{ Address, Bloom, Space, SpaceMap, H256, KECCAK_EMPTY_BLOOM, U256, }; +use log::warn; use malloc_size_of::{new_malloc_size_ops, MallocSizeOf, MallocSizeOfOps}; use once_cell::sync::OnceCell; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; @@ -692,6 +693,10 @@ pub fn compute_next_price( ) -> U256 { const DENOM: usize = BASE_PRICE_CHANGE_DENOMINATOR; + if gas_actual > gas_target * 2 { + warn!("gas target is larger than expected"); + } + let next_base_price = if gas_target.is_zero() || gas_target == gas_actual { last_base_price } else if gas_actual > gas_target { From 83c62995c8ed98755d5f7e2fc0c82152d075015d Mon Sep 17 00:00:00 2001 From: Chenxing Li Date: Wed, 29 May 2024 16:52:45 +0800 Subject: [PATCH 05/14] Add more tests --- .../cfxcore/core/src/transaction_pool/mod.rs | 16 +- .../transaction_pool_inner.rs | 209 +++++++++++++++--- 2 files changed, 194 insertions(+), 31 deletions(-) diff --git a/crates/cfxcore/core/src/transaction_pool/mod.rs b/crates/cfxcore/core/src/transaction_pool/mod.rs index e83ea75733..ef3878370f 100644 --- a/crates/cfxcore/core/src/transaction_pool/mod.rs +++ b/crates/cfxcore/core/src/transaction_pool/mod.rs @@ -745,15 +745,27 @@ impl TransactionPool { best_epoch_height += 1; // The best block number is not necessary an exact number. best_block_number += 1; + + let spec = self.machine.spec(best_block_number, best_epoch_height); + let transitions = &self.machine.params().transition_heights; + + let validity = |tx: &SignedTransaction| { + self.verification_config.fast_recheck( + tx, + best_epoch_height, + transitions, + &spec, + ) + }; + inner.pack_transactions_1559( num_txs, block_gas_limit, parent_base_price, block_size_limit, best_epoch_height, - best_block_number, - &self.verification_config, &self.machine, + validity, ) } diff --git a/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs b/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs index 28a274e0d2..628110ae65 100644 --- a/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs +++ b/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs @@ -592,6 +592,9 @@ impl TransactionPoolInner { } } + #[cfg(test)] + pub fn new_for_test() -> Self { Self::new(50_000, 3_000_000, 50, 4) } + pub fn clear(&mut self) { self.deferred_pool.clear(); self.ready_nonces_and_balances.clear(); @@ -793,6 +796,19 @@ impl TransactionPoolInner { pub fn capacity(&self) -> usize { self.capacity } + #[cfg(test)] + fn insert_transaction_for_test( + &mut self, transaction: Arc, sender_nonce: U256, + ) -> InsertResult { + self.insert_transaction_without_readiness_check( + transaction, + false, + true, + (sender_nonce, U256::from(u64::MAX)), + (0.into(), 0), + ) + } + // the new inserting will fail if tx_pool is full (even if `force` is true) fn insert_transaction_without_readiness_check( &mut self, transaction: Arc, packed: bool, @@ -1124,8 +1140,8 @@ impl TransactionPoolInner { pub fn pack_transactions_1559<'a>( &mut self, num_txs: usize, block_gas_limit: U256, parent_base_price: SpaceMap, block_size_limit: usize, - best_epoch_height: u64, best_block_number: u64, - verification_config: &VerificationConfig, machine: &Machine, + best_epoch_height: u64, machine: &Machine, + validity: impl Fn(&SignedTransaction) -> PackingCheckResult, ) -> (Vec>, SpaceMap) { let mut packed_transactions: Vec> = Vec::new(); if num_txs == 0 { @@ -1139,18 +1155,6 @@ impl TransactionPoolInner { let mut block_base_price = parent_base_price.clone(); - let spec = machine.spec(best_block_number, best_epoch_height); - let transitions = &machine.params().transition_heights; - - let validity = |tx: &SignedTransaction| { - verification_config.fast_recheck( - tx, - best_epoch_height, - transitions, - &spec, - ) - }; - let can_pack_evm = machine.params().can_pack_evm_transaction(best_epoch_height); @@ -1178,7 +1182,7 @@ impl TransactionPoolInner { block_size_limit, num_txs, tx_min_price, - validity, + &validity, ); // Recompute the base price, it should be <= estimated base price, @@ -1242,7 +1246,7 @@ impl TransactionPoolInner { block_size_limit - evm_used_size, num_txs - evm_packed_tx_num, tx_min_price, - validity, + &validity, ); // Recompute the base price, it should be <= estimated base price, @@ -1504,40 +1508,66 @@ impl TransactionPoolInner { } #[cfg(test)] -mod test_transaction_pool_inner { - use super::{DeferredPool, InsertResult, TxWithReadyInfo}; - use cfx_types::{Address, AddressSpaceUtil, U256}; +mod tests { + use crate::verification::PackingCheckResult; + + use super::{ + DeferredPool, InsertResult, TransactionPoolInner, TxWithReadyInfo, + }; + use cfx_executor::{ + machine::{new_machine, Machine, VmFactory}, + spec::CommonParams, + }; + use cfx_types::{Address, AddressSpaceUtil, Space, SpaceMap, U256}; + use itertools::Itertools; use keylib::{Generator, KeyPair, Random}; use primitives::{ - transaction::native_transaction::NativeTransaction, Action, - SignedTransaction, Transaction, + block_header::compute_next_price_tuple, + transaction::{ + native_transaction::NativeTransaction, Eip155Transaction, + }, + Action, SignedTransaction, Transaction, }; use std::sync::Arc; fn new_test_tx( - sender: &KeyPair, nonce: usize, gas_price: usize, value: usize, + sender: &KeyPair, nonce: usize, gas_price: usize, gas: usize, + value: usize, space: Space, ) -> Arc { - Arc::new( - Transaction::from(NativeTransaction { + let tx: Transaction = match space { + Space::Native => NativeTransaction { nonce: U256::from(nonce), gas_price: U256::from(gas_price), - gas: U256::from(50000), + gas: U256::from(gas), action: Action::Call(Address::random()), value: U256::from(value), storage_limit: 0, epoch_height: 0, chain_id: 1, data: Vec::new(), - }) - .sign(sender.secret()), - ) + } + .into(), + Space::Ethereum => Eip155Transaction { + nonce: U256::from(nonce), + gas_price: U256::from(gas_price), + gas: U256::from(gas), + action: Action::Call(Address::random()), + value: U256::from(value), + chain_id: Some(1), + data: Vec::new(), + } + .into(), + }; + Arc::new(tx.sign(sender.secret())) } fn new_test_tx_with_read_info( sender: &KeyPair, nonce: usize, gas_price: usize, value: usize, packed: bool, ) -> TxWithReadyInfo { - let transaction = new_test_tx(sender, nonce, gas_price, value); + let gas = 50000; + let transaction = + new_test_tx(sender, nonce, gas_price, gas, value, Space::Native); TxWithReadyInfo::new(transaction, packed, U256::from(0), 0) } @@ -1759,4 +1789,125 @@ mod test_transaction_pool_inner { None ); } + + fn pack_transactions_1559_checked( + pool: &mut TransactionPoolInner, machine: &Machine, + ) { + let parent_base_price = SpaceMap::new(100, 100).map_all(U256::from); + let block_gas_limit = U256::from(6000); + let best_epoch_height = 20; + + let (txs, base_price) = pool.pack_transactions_1559( + usize::MAX, + block_gas_limit, + parent_base_price, + usize::MAX, + best_epoch_height, + machine, + |_| PackingCheckResult::Pack, + ); + + let params = machine.params(); + + let core_gas_limit = block_gas_limit * 9 / 10; + let eth_gas_limit = + if params.can_pack_evm_transaction(best_epoch_height) { + block_gas_limit * 5 / 10 + } else { + U256::zero() + }; + + let gas_target = + SpaceMap::new(core_gas_limit, eth_gas_limit).map_all(|x| x / 2); + + let mut gas_used = SpaceMap::default(); + let mut min_gas_price = + SpaceMap::new(U256::max_value(), U256::max_value()); + + for tx in txs { + gas_used[tx.space()] += *tx.gas_limit(); + min_gas_price[tx.space()] = + min_gas_price[tx.space()].min(*tx.gas_limit()); + } + + let min_base_price = params.min_base_price(); + + let expected_base_price = SpaceMap::zip4( + gas_target, + gas_used, + parent_base_price, + min_base_price, + ) + .map_all(compute_next_price_tuple); + + assert_eq!(expected_base_price, base_price); + assert!(gas_used[Space::Native] <= core_gas_limit); + assert!(gas_used[Space::Ethereum] <= eth_gas_limit); + + for space in [Space::Native, Space::Ethereum] { + assert!(base_price[space] <= min_gas_price[space]); + } + } + + #[test] + fn test_eip1559_transactions() { + let mut pool = TransactionPoolInner::new_for_test(); + + let mut params = CommonParams::default(); + params.min_base_price = SpaceMap::new(100, 200).map_all(U256::from); + + let machine = Arc::new(new_machine(params, VmFactory::default())); + + let test_block_limit = SpaceMap::new(5400, 3000); + + let senders: Vec<_> = (0..20) + .into_iter() + .map(|_| Random.generate().unwrap()) + .collect(); + + let tasks = [1, 2, 3] + .into_iter() + .cartesian_product( + /* gas_price */ [50usize, 95, 100, 105, 150, 1000], + ) + .cartesian_product( + /* gas_limit_percent */ [5usize, 10, 40, 60, 100], + ) + .cartesian_product(/* price_increasing */ [0usize, 1]); + + for (((space_bits, gas_price), gas_limit_percent), price_inc) in tasks { + let tx_gas_limit = + test_block_limit.map_all(|x| x * gas_limit_percent / 100); + + for (idx, sender) in senders.iter().enumerate() { + let gas_price = gas_price + idx * price_inc; + + if space_bits & 0x1 != 0 { + let tx = new_test_tx( + sender, + 0, + gas_price, + tx_gas_limit[Space::Native], + 0, + Space::Native, + ); + pool.insert_transaction_for_test(tx, U256::zero()); + } + + if space_bits & 0x2 != 0 { + let tx = new_test_tx( + sender, + 0, + gas_price * 2, + tx_gas_limit[Space::Ethereum], + 0, + Space::Ethereum, + ); + pool.insert_transaction_for_test(tx, U256::zero()); + } + } + pack_transactions_1559_checked(&mut pool, &machine); + pool.clear(); + } + } } From e916dcf466ff1765f805091e99861f66988a3706 Mon Sep 17 00:00:00 2001 From: dayong Date: Wed, 29 May 2024 17:05:36 +0800 Subject: [PATCH 06/14] add params name for eth rpc methods --- crates/client/src/rpc/traits/eth_space/eth.rs | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/crates/client/src/rpc/traits/eth_space/eth.rs b/crates/client/src/rpc/traits/eth_space/eth.rs index 80fe7e50a0..10b7022a08 100644 --- a/crates/client/src/rpc/traits/eth_space/eth.rs +++ b/crates/client/src/rpc/traits/eth_space/eth.rs @@ -90,7 +90,7 @@ pub trait Eth { /// Returns balance of the given account. #[rpc(name = "eth_getBalance")] - fn balance(&self, _: H160, _: Option) -> Result; + fn balance(&self, address: H160, block: Option) -> Result; // /// Returns the account- and storage-values of the specified account // including the Merkle-proof #[rpc(name = "eth_getProof")] @@ -100,97 +100,97 @@ pub trait Eth { /// Returns content of the storage at given address. #[rpc(name = "eth_getStorageAt")] fn storage_at( - &self, _: H160, _: U256, _: Option, + &self, address: H160, storage_slot: U256, block: Option, ) -> jsonrpc_core::Result; /// Returns block with given hash. #[rpc(name = "eth_getBlockByHash")] - fn block_by_hash(&self, _: H256, _: bool) -> Result>; + fn block_by_hash(&self, block_hash: H256, hydrated_transactions: bool) -> Result>; /// Returns block with given number. #[rpc(name = "eth_getBlockByNumber")] - fn block_by_number(&self, _: BlockNumber, _: bool) + fn block_by_number(&self, block: BlockNumber, hydrated_transactions: bool) -> Result>; /// Returns the number of transactions sent from given address at given time /// (block number). #[rpc(name = "eth_getTransactionCount")] fn transaction_count( - &self, _: H160, _: Option, + &self, address: H160, block: Option, ) -> Result; /// Returns the number of transactions in a block with given hash. #[rpc(name = "eth_getBlockTransactionCountByHash")] - fn block_transaction_count_by_hash(&self, _: H256) -> Result>; + fn block_transaction_count_by_hash(&self, block_hash: H256) -> Result>; /// Returns the number of transactions in a block with given block number. #[rpc(name = "eth_getBlockTransactionCountByNumber")] fn block_transaction_count_by_number( - &self, _: BlockNumber, + &self, block: BlockNumber, ) -> Result>; /// Returns the number of uncles in a block with given hash. #[rpc(name = "eth_getUncleCountByBlockHash")] - fn block_uncles_count_by_hash(&self, _: H256) -> Result>; + fn block_uncles_count_by_hash(&self, block_hash: H256) -> Result>; /// Returns the number of uncles in a block with given block number. #[rpc(name = "eth_getUncleCountByBlockNumber")] fn block_uncles_count_by_number( - &self, _: BlockNumber, + &self, block: BlockNumber, ) -> Result>; /// Returns the code at given address at given time (block number). #[rpc(name = "eth_getCode")] - fn code_at(&self, _: H160, _: Option) -> Result; + fn code_at(&self, address: H160, block: Option) -> Result; /// Sends signed transaction, returning its hash. #[rpc(name = "eth_sendRawTransaction")] - fn send_raw_transaction(&self, _: Bytes) -> Result; + fn send_raw_transaction(&self, transaction: Bytes) -> Result; /// @alias of `eth_sendRawTransaction`. #[rpc(name = "eth_submitTransaction")] - fn submit_transaction(&self, _: Bytes) -> Result; + fn submit_transaction(&self, transaction: Bytes) -> Result; /// Call contract, returning the output data. #[rpc(name = "eth_call")] - fn call(&self, _: CallRequest, _: Option) -> Result; + fn call(&self, transaction: CallRequest, block: Option) -> Result; /// Estimate gas needed for execution of given contract. #[rpc(name = "eth_estimateGas")] fn estimate_gas( - &self, _: CallRequest, _: Option, + &self, transaction: CallRequest, block: Option, ) -> Result; /// Get transaction by its hash. #[rpc(name = "eth_getTransactionByHash")] - fn transaction_by_hash(&self, _: H256) -> Result>; + fn transaction_by_hash(&self, transaction_hash: H256) -> Result>; /// Returns transaction at given block hash and index. #[rpc(name = "eth_getTransactionByBlockHashAndIndex")] fn transaction_by_block_hash_and_index( - &self, _: H256, _: Index, + &self, block_hash: H256, transaction_index: Index, ) -> Result>; /// Returns transaction by given block number and index. #[rpc(name = "eth_getTransactionByBlockNumberAndIndex")] fn transaction_by_block_number_and_index( - &self, _: BlockNumber, _: Index, + &self, block: BlockNumber, transaction_index: Index, ) -> Result>; /// Returns transaction receipt by transaction hash. #[rpc(name = "eth_getTransactionReceipt")] - fn transaction_receipt(&self, _: H256) -> Result>; + fn transaction_receipt(&self, transaction_hash: H256) -> Result>; /// Returns an uncles at given block and index. #[rpc(name = "eth_getUncleByBlockHashAndIndex")] fn uncle_by_block_hash_and_index( - &self, _: H256, _: Index, + &self, block_hash: H256, _: Index, ) -> Result>; /// Returns an uncles at given block and index. #[rpc(name = "eth_getUncleByBlockNumberAndIndex")] fn uncle_by_block_number_and_index( - &self, _: BlockNumber, _: Index, + &self, block: BlockNumber, _: Index, ) -> Result>; // /// Returns available compilers. @@ -215,7 +215,7 @@ pub trait Eth { /// Returns logs matching given filter object. #[rpc(name = "eth_getLogs")] - fn logs(&self, _: EthRpcLogFilter) -> Result>; + fn logs(&self, filter: EthRpcLogFilter) -> Result>; // /// Returns the hash of the current block, the seedHash, and the boundary // condition to be met. #[rpc(name = "eth_getWork")] @@ -230,11 +230,11 @@ pub trait Eth { fn submit_hashrate(&self, _: U256, _: H256) -> Result; #[rpc(name = "parity_getBlockReceipts")] - fn block_receipts(&self, _: Option) -> Result>; + fn block_receipts(&self, block: Option) -> Result>; #[rpc(name = "eth_getAccountPendingTransactions")] fn account_pending_transactions( - &self, _: H160, maybe_start_nonce: Option, + &self, address: H160, maybe_start_nonce: Option, maybe_limit: Option, ) -> Result; } @@ -244,7 +244,7 @@ pub trait Eth { pub trait EthFilter { /// Returns id of new filter. #[rpc(name = "eth_newFilter")] - fn new_filter(&self, _: EthRpcLogFilter) -> Result; + fn new_filter(&self, filter: EthRpcLogFilter) -> Result; /// Returns id of new block filter. #[rpc(name = "eth_newBlockFilter")] @@ -256,13 +256,13 @@ pub trait EthFilter { /// Returns filter changes since last poll. #[rpc(name = "eth_getFilterChanges")] - fn filter_changes(&self, _: H128) -> Result; + fn filter_changes(&self, identifier: H128) -> Result; /// Returns all logs matching given filter (in a range 'from' - 'to'). #[rpc(name = "eth_getFilterLogs")] - fn filter_logs(&self, _: H128) -> Result>; + fn filter_logs(&self, identifier: H128) -> Result>; /// Uninstalls filter. #[rpc(name = "eth_uninstallFilter")] - fn uninstall_filter(&self, _: H128) -> Result; + fn uninstall_filter(&self, identifier: H128) -> Result; } From e73e199779ff304912256b1ebb4610e50f07868d Mon Sep 17 00:00:00 2001 From: dayong Date: Thu, 30 May 2024 10:48:30 +0800 Subject: [PATCH 07/14] fmt --- crates/client/src/rpc/traits/eth_space/eth.rs | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/crates/client/src/rpc/traits/eth_space/eth.rs b/crates/client/src/rpc/traits/eth_space/eth.rs index 10b7022a08..71b224bb75 100644 --- a/crates/client/src/rpc/traits/eth_space/eth.rs +++ b/crates/client/src/rpc/traits/eth_space/eth.rs @@ -90,7 +90,9 @@ pub trait Eth { /// Returns balance of the given account. #[rpc(name = "eth_getBalance")] - fn balance(&self, address: H160, block: Option) -> Result; + fn balance( + &self, address: H160, block: Option, + ) -> Result; // /// Returns the account- and storage-values of the specified account // including the Merkle-proof #[rpc(name = "eth_getProof")] @@ -105,12 +107,15 @@ pub trait Eth { /// Returns block with given hash. #[rpc(name = "eth_getBlockByHash")] - fn block_by_hash(&self, block_hash: H256, hydrated_transactions: bool) -> Result>; + fn block_by_hash( + &self, block_hash: H256, hydrated_transactions: bool, + ) -> Result>; /// Returns block with given number. #[rpc(name = "eth_getBlockByNumber")] - fn block_by_number(&self, block: BlockNumber, hydrated_transactions: bool) - -> Result>; + fn block_by_number( + &self, block: BlockNumber, hydrated_transactions: bool, + ) -> Result>; /// Returns the number of transactions sent from given address at given time /// (block number). @@ -121,7 +126,9 @@ pub trait Eth { /// Returns the number of transactions in a block with given hash. #[rpc(name = "eth_getBlockTransactionCountByHash")] - fn block_transaction_count_by_hash(&self, block_hash: H256) -> Result>; + fn block_transaction_count_by_hash( + &self, block_hash: H256, + ) -> Result>; /// Returns the number of transactions in a block with given block number. #[rpc(name = "eth_getBlockTransactionCountByNumber")] @@ -131,7 +138,9 @@ pub trait Eth { /// Returns the number of uncles in a block with given hash. #[rpc(name = "eth_getUncleCountByBlockHash")] - fn block_uncles_count_by_hash(&self, block_hash: H256) -> Result>; + fn block_uncles_count_by_hash( + &self, block_hash: H256, + ) -> Result>; /// Returns the number of uncles in a block with given block number. #[rpc(name = "eth_getUncleCountByBlockNumber")] @@ -141,7 +150,9 @@ pub trait Eth { /// Returns the code at given address at given time (block number). #[rpc(name = "eth_getCode")] - fn code_at(&self, address: H160, block: Option) -> Result; + fn code_at( + &self, address: H160, block: Option, + ) -> Result; /// Sends signed transaction, returning its hash. #[rpc(name = "eth_sendRawTransaction")] @@ -153,7 +164,9 @@ pub trait Eth { /// Call contract, returning the output data. #[rpc(name = "eth_call")] - fn call(&self, transaction: CallRequest, block: Option) -> Result; + fn call( + &self, transaction: CallRequest, block: Option, + ) -> Result; /// Estimate gas needed for execution of given contract. #[rpc(name = "eth_estimateGas")] @@ -163,7 +176,9 @@ pub trait Eth { /// Get transaction by its hash. #[rpc(name = "eth_getTransactionByHash")] - fn transaction_by_hash(&self, transaction_hash: H256) -> Result>; + fn transaction_by_hash( + &self, transaction_hash: H256, + ) -> Result>; /// Returns transaction at given block hash and index. #[rpc(name = "eth_getTransactionByBlockHashAndIndex")] @@ -179,7 +194,9 @@ pub trait Eth { /// Returns transaction receipt by transaction hash. #[rpc(name = "eth_getTransactionReceipt")] - fn transaction_receipt(&self, transaction_hash: H256) -> Result>; + fn transaction_receipt( + &self, transaction_hash: H256, + ) -> Result>; /// Returns an uncles at given block and index. #[rpc(name = "eth_getUncleByBlockHashAndIndex")] @@ -230,7 +247,9 @@ pub trait Eth { fn submit_hashrate(&self, _: U256, _: H256) -> Result; #[rpc(name = "parity_getBlockReceipts")] - fn block_receipts(&self, block: Option) -> Result>; + fn block_receipts( + &self, block: Option, + ) -> Result>; #[rpc(name = "eth_getAccountPendingTransactions")] fn account_pending_transactions( From 706558613bbecefe862a9724fff17d6ddd90e93a Mon Sep 17 00:00:00 2001 From: Pana Date: Wed, 29 May 2024 17:24:08 +0800 Subject: [PATCH 08/14] use const replace literal small op --- .../cfxcore/core/src/transaction_pool/mod.rs | 5 +- .../client/src/rpc/impls/cfx/cfx_handler.rs | 17 +-- .../client/src/rpc/impls/eth/eth_handler.rs | 25 ++-- crates/client/src/rpc/types/call_request.rs | 27 +++-- .../client/src/rpc/types/eth/call_request.rs | 109 ------------------ crates/primitives/src/transaction/mod.rs | 1 + 6 files changed, 36 insertions(+), 148 deletions(-) diff --git a/crates/cfxcore/core/src/transaction_pool/mod.rs b/crates/cfxcore/core/src/transaction_pool/mod.rs index e83ea75733..bdca618bb7 100644 --- a/crates/cfxcore/core/src/transaction_pool/mod.rs +++ b/crates/cfxcore/core/src/transaction_pool/mod.rs @@ -379,9 +379,6 @@ impl TransactionPool { let mut failure = HashMap::new(); let current_best_info = self.consensus_best_info.lock().clone(); - // filter out invalid transactions. - let mut index = 0; - let (chain_id, best_height, best_block_number) = { ( current_best_info.best_chain_id(), @@ -395,6 +392,8 @@ impl TransactionPool { let vm_spec = self.machine.spec(best_block_number, best_height); let transitions = &self.machine.params().transition_heights; + // filter out invalid transactions. + let mut index = 0; while let Some(tx) = transactions.get(index) { match self.verify_transaction_tx_pool( tx, diff --git a/crates/client/src/rpc/impls/cfx/cfx_handler.rs b/crates/client/src/rpc/impls/cfx/cfx_handler.rs index 4e1a0f6649..1028ad55cf 100644 --- a/crates/client/src/rpc/impls/cfx/cfx_handler.rs +++ b/crates/client/src/rpc/impls/cfx/cfx_handler.rs @@ -1359,18 +1359,13 @@ impl RpcImpl { }; let storage_collateralized = U64::from(estimation.estimated_storage_limit); - let estimated_gas_limit = estimation.estimated_gas_limit; + let estimated_gas_used = estimation.estimated_gas_limit; let response = EstimateGasAndCollateralResponse { - // We multiply the gas_used for 2 reasons: - // 1. In each EVM call, the gas passed is at most 63/64 of the - // remaining gas, so the gas_limit should be multiplied a factor so - // that the gas passed into the sub-call is sufficient. The 4 / 3 - // factor is sufficient for 18 level of calls. - // 2. In Conflux, we recommend setting the gas_limit to (gas_used * - // 4) / 3, because the extra gas will be refunded up to - // 1/4 of the gas limit. - gas_limit: estimation.estimated_gas_limit, - gas_used: estimated_gas_limit, + gas_limit: estimated_gas_used, /* gas_limit used to be 4/3 of + * gas_used due to inaccuracy, + * currently it's the same as gas + * used as it's more accurate */ + gas_used: estimated_gas_used, storage_collateralized, }; Ok(response) diff --git a/crates/client/src/rpc/impls/eth/eth_handler.rs b/crates/client/src/rpc/impls/eth/eth_handler.rs index 8f0d643583..f2188f05d5 100644 --- a/crates/client/src/rpc/impls/eth/eth_handler.rs +++ b/crates/client/src/rpc/impls/eth/eth_handler.rs @@ -41,8 +41,13 @@ use cfxcore::{ use clap::crate_version; use jsonrpc_core::{Error as RpcError, Result as RpcResult}; use primitives::{ - filter::LogFilter, receipt::EVM_SPACE_SUCCESS, Action, - BlockHashOrEpochNumber, EpochNumber, SignedTransaction, StorageKey, + filter::LogFilter, + receipt::EVM_SPACE_SUCCESS, + transaction::{ + Eip1559Transaction, Eip155Transaction, Eip2930Transaction, + EthereumTransaction::*, EIP1559_TYPE, EIP2930_TYPE, LEGACY_TX_TYPE, + }, + Action, BlockHashOrEpochNumber, EpochNumber, SignedTransaction, StorageKey, StorageValue, TransactionStatus, TransactionWithSignature, }; use rustc_hex::ToHex; @@ -79,8 +84,6 @@ impl EthHandler { pub fn sign_call( chain_id: u32, request: CallRequest, ) -> RpcResult { - use primitives::transaction::*; - use EthereumTransaction::*; let max_gas = U256::from(MAX_GAS_CALL_REQUEST); let gas = min(request.gas.unwrap_or(max_gas), max_gas); let nonce = request.nonce.unwrap_or_default(); @@ -90,11 +93,11 @@ pub fn sign_call( let default_type_id = if request.max_fee_per_gas.is_some() || request.max_priority_fee_per_gas.is_some() { - 2 + EIP1559_TYPE } else if request.access_list.is_some() { - 1 + EIP2930_TYPE } else { - 0 + LEGACY_TX_TYPE }; let transaction_type = request .transaction_type @@ -110,8 +113,8 @@ pub fn sign_call( let access_list = request.access_list.unwrap_or(vec![]); let data = request.data.unwrap_or_default().into_vec(); - let transaction = match transaction_type.as_usize() { - 0 => Eip155(Eip155Transaction { + let transaction = match transaction_type.as_usize() as u8 { + LEGACY_TX_TYPE => Eip155(Eip155Transaction { nonce, gas_price, gas, @@ -120,7 +123,7 @@ pub fn sign_call( chain_id: Some(chain_id), data, }), - 1 => Eip2930(Eip2930Transaction { + EIP2930_TYPE => Eip2930(Eip2930Transaction { chain_id, nonce, gas_price, @@ -130,7 +133,7 @@ pub fn sign_call( data, access_list, }), - 2 => Eip1559(Eip1559Transaction { + EIP1559_TYPE => Eip1559(Eip1559Transaction { chain_id, nonce, max_priority_fee_per_gas, diff --git a/crates/client/src/rpc/types/call_request.rs b/crates/client/src/rpc/types/call_request.rs index 65d3335d2e..57dcc199a1 100644 --- a/crates/client/src/rpc/types/call_request.rs +++ b/crates/client/src/rpc/types/call_request.rs @@ -19,16 +19,18 @@ use cfxkey::Password; use primitives::{ transaction::{ native_transaction::NativeTransaction as PrimitiveTransaction, Action, + Cip1559Transaction, Cip2930Transaction, NativeTransaction, + TypedNativeTransaction::*, CIP1559_TYPE, CIP2930_TYPE, LEGACY_TX_TYPE, }, AccessList, AccessListItem, SignedTransaction, Transaction, TransactionWithSignature, }; use std::{cmp::min, convert::Into, sync::Arc}; -// use serde_json::de::ParserNumber::U64; - -/// The MAX_GAS_CALL_REQUEST is one magnitude higher than block gas limit and -/// not too high that a call_virtual consumes too much resource. +/// The MAX_GAS_CALL_REQUEST is used as max value of cfx_call or cfx_estimate's +/// gas value to prevent call_virtual consumes too much resource. +/// The tx_pool will reject the tx if the gas is larger than half of the block +/// gas limit. which is 30_000_000 before 1559, and 60_000_000 after 1559. pub const MAX_GAS_CALL_REQUEST: u64 = 15_000_000; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -175,9 +177,6 @@ impl SendTxRequest { pub fn sign_call( epoch_height: u64, chain_id: u32, request: CallRequest, ) -> RpcResult { - use primitives::transaction::*; - use TypedNativeTransaction::*; - let max_gas = U256::from(MAX_GAS_CALL_REQUEST); let gas = min(request.gas.unwrap_or(max_gas), max_gas); @@ -196,11 +195,11 @@ pub fn sign_call( let default_type_id = if request.max_fee_per_gas.is_some() || request.max_priority_fee_per_gas.is_some() { - 2 + CIP1559_TYPE } else if request.access_list.is_some() { - 1 + CIP2930_TYPE } else { - 0 + LEGACY_TX_TYPE }; let transaction_type = request .transaction_type @@ -215,8 +214,8 @@ pub fn sign_call( request.max_priority_fee_per_gas.unwrap_or(U256::zero()); let access_list = request.access_list.unwrap_or(vec![]); - let transaction = match transaction_type.as_usize() { - 0 => Cip155(NativeTransaction { + let transaction = match transaction_type.as_usize() as u8 { + LEGACY_TX_TYPE => Cip155(NativeTransaction { nonce, action, gas, @@ -227,7 +226,7 @@ pub fn sign_call( chain_id, data, }), - 1 => Cip2930(Cip2930Transaction { + CIP2930_TYPE => Cip2930(Cip2930Transaction { nonce, gas_price, gas, @@ -239,7 +238,7 @@ pub fn sign_call( data, access_list: to_primitive_access_list(access_list), }), - 2 => Cip1559(Cip1559Transaction { + CIP1559_TYPE => Cip1559(Cip1559Transaction { nonce, action, gas, diff --git a/crates/client/src/rpc/types/eth/call_request.rs b/crates/client/src/rpc/types/eth/call_request.rs index ec3a52bf08..d9d7906cea 100644 --- a/crates/client/src/rpc/types/eth/call_request.rs +++ b/crates/client/src/rpc/types/eth/call_request.rs @@ -48,112 +48,3 @@ pub struct CallRequest { #[serde(rename = "type")] pub transaction_type: Option, } - -// impl Into for CallRequest { -// fn into(self) -> Request { -// Request { -// transaction_type: self.transaction_type, -// from: self.from.map(Into::into), -// to: self.to.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), -// value: self.value.map(Into::into), -// data: self.data.map(Into::into), -// nonce: self.nonce.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), } -// } -// } -// -// #[cfg(test)] -// mod tests { -// use super::CallRequest; -// use ethereum_types::{H160, U256}; -// use rustc_hex::FromHex; -// use serde_json; -// use std::str::FromStr; -// -// #[test] -// fn call_request_deserialize() { -// let s = r#"{ -// "from":"0x0000000000000000000000000000000000000001", -// "to":"0x0000000000000000000000000000000000000002", -// "gasPrice":"0x1", -// "gas":"0x2", -// "value":"0x3", -// "data":"0x123456", -// "nonce":"0x4" -// }"#; -// let deserialized: CallRequest = serde_json::from_str(s).unwrap(); -// -// assert_eq!( -// deserialized, -// CallRequest { -// transaction_type: Default::default(), -// from: Some(H160::from_low_u64_be(1)), -// to: Some(H160::from_low_u64_be(2)), -// gas_price: Some(U256::from(1)), -// max_fee_per_gas: None, -// gas: Some(U256::from(2)), -// value: Some(U256::from(3)), -// data: Some(vec![0x12, 0x34, 0x56].into()), -// nonce: Some(U256::from(4)), -// access_list: None, -// max_priority_fee_per_gas: None, -// } -// ); -// } -// -// #[test] -// fn call_request_deserialize2() { -// let s = r#"{ -// "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", -// "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", -// "gas": "0x76c0", -// "gasPrice": "0x9184e72a000", -// "value": "0x9184e72a", -// "data": -// "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" -// }"#; -// let deserialized: CallRequest = serde_json::from_str(s).unwrap(); -// -// assert_eq!(deserialized, CallRequest { -// transaction_type: Default::default(), -// from: Some(H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155"). -// unwrap()), to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567" -// ).unwrap()), gas_price: Some(U256::from_str("9184e72a000").unwrap()), -// max_fee_per_gas: None, -// gas: Some(U256::from_str("76c0").unwrap()), -// value: Some(U256::from_str("9184e72a").unwrap()), -// data: Some("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()), -// nonce: None, -// access_list: None, -// max_priority_fee_per_gas: None, -// }); -// } -// -// #[test] -// fn call_request_deserialize_empty() { -// let s = r#"{"from":"0x0000000000000000000000000000000000000001"}"#; -// let deserialized: CallRequest = serde_json::from_str(s).unwrap(); -// -// assert_eq!( -// deserialized, -// CallRequest { -// transaction_type: Default::default(), -// from: Some(H160::from_low_u64_be(1)), -// to: None, -// gas_price: None, -// max_fee_per_gas: None, -// gas: None, -// value: None, -// data: None, -// nonce: None, -// access_list: None, -// max_priority_fee_per_gas: None, -// } -// ); -// } -// } diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index f9f5a06e51..eb1528ace7 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -37,6 +37,7 @@ pub const UNSIGNED_SENDER: Address = H160([0xff; 20]); pub const TYPED_NATIVE_TX_PREFIX: &[u8; 3] = b"cfx"; pub const TYPED_NATIVE_TX_PREFIX_BYTE: u8 = TYPED_NATIVE_TX_PREFIX[0]; +pub const LEGACY_TX_TYPE: u8 = 0x00; pub const EIP2930_TYPE: u8 = 0x01; pub const EIP1559_TYPE: u8 = 0x02; pub const CIP2930_TYPE: u8 = 0x01; From 74d8d229e075c246a8f54dd7be8851da65961571 Mon Sep 17 00:00:00 2001 From: Pana Date: Thu, 30 May 2024 15:25:39 +0800 Subject: [PATCH 09/14] add camelCase attribute to FeeHistory fix feeHistory order and used_ratio issue update feehistory tests --- crates/client/src/rpc/impls/cfx/common.rs | 2 +- crates/client/src/rpc/impls/cfx/light.rs | 2 +- .../client/src/rpc/impls/eth/eth_handler.rs | 2 +- crates/client/src/rpc/types/fee_history.rs | 21 ++++++++++--------- tests/evm_space/eip1559_test.py | 4 ++-- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/crates/client/src/rpc/impls/cfx/common.rs b/crates/client/src/rpc/impls/cfx/common.rs index ae581ba4d1..c09f5a719c 100644 --- a/crates/client/src/rpc/impls/cfx/common.rs +++ b/crates/client/src/rpc/impls/cfx/common.rs @@ -585,7 +585,7 @@ impl RpcImpl { // Internal error happens only if the fetch header has inconsistent // block height fee_history - .push_back_block( + .push_front_block( Space::Native, &reward_percentiles, &block.block_header, diff --git a/crates/client/src/rpc/impls/cfx/light.rs b/crates/client/src/rpc/impls/cfx/light.rs index 8eed486234..8640bde85f 100644 --- a/crates/client/src/rpc/impls/cfx/light.rs +++ b/crates/client/src/rpc/impls/cfx/light.rs @@ -1135,7 +1135,7 @@ impl RpcImpl { // Internal error happens only if the fetch header has // inconsistent block height fee_history - .push_back_block( + .push_front_block( Space::Native, &reward_percentiles, &block.block_header, diff --git a/crates/client/src/rpc/impls/eth/eth_handler.rs b/crates/client/src/rpc/impls/eth/eth_handler.rs index f2188f05d5..44d7b145a7 100644 --- a/crates/client/src/rpc/impls/eth/eth_handler.rs +++ b/crates/client/src/rpc/impls/eth/eth_handler.rs @@ -955,7 +955,7 @@ impl Eth for EthHandler { // Internal error happens only if the fetch header has inconsistent // block height fee_history - .push_back_block( + .push_front_block( Space::Ethereum, &reward_percentiles, &block.pivot_header, diff --git a/crates/client/src/rpc/types/fee_history.rs b/crates/client/src/rpc/types/fee_history.rs index d706474220..69c6d0f345 100644 --- a/crates/client/src/rpc/types/fee_history.rs +++ b/crates/client/src/rpc/types/fee_history.rs @@ -4,6 +4,7 @@ use cfx_types::{Space, SpaceMap, U256}; use primitives::{transaction::SignedTransaction, BlockHeader}; #[derive(Serialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct FeeHistory { /// Oldest Block oldest_block: U256, @@ -23,7 +24,7 @@ impl FeeHistory { pub fn reward(&self) -> &VecDeque> { &self.reward } - pub fn push_back_block<'a, I>( + pub fn push_front_block<'a, I>( &mut self, space: Space, percentiles: &Vec, pivot_header: &BlockHeader, transactions: I, ) -> Result<(), String> @@ -33,13 +34,14 @@ impl FeeHistory { let base_price = if let Some(base_price) = pivot_header.base_price() { base_price[space] } else { - self.base_fee_per_gas.push_back(U256::zero()); - self.gas_used_ratio.push_back(0.0); - self.reward.push_back(vec![U256::zero(); percentiles.len()]); + self.base_fee_per_gas.push_front(U256::zero()); + self.gas_used_ratio.push_front(0.0); + self.reward + .push_front(vec![U256::zero(); percentiles.len()]); return Ok(()); }; - self.base_fee_per_gas.push_back( + self.base_fee_per_gas.push_front( pivot_header.base_price().map_or(U256::zero(), |x| x[space]), ); @@ -52,8 +54,7 @@ impl FeeHistory { .clone() .map(|x| *x.gas_limit()) .reduce(|x, y| x + y) - .unwrap_or_default() - / gas_limit; + .unwrap_or_default(); let gas_used_ratio = if gas_limit >= U256::from(u128::MAX) || gas_used >= U256::from(u128::MAX) @@ -64,10 +65,10 @@ impl FeeHistory { gas_used.as_u128() as f64 / gas_limit.as_u128() as f64 }; - self.gas_used_ratio.push_back(gas_used_ratio); + self.gas_used_ratio.push_front(gas_used_ratio); let reward = compute_reward(percentiles, transactions, base_price); - self.reward.push_back(reward); + self.reward.push_front(reward); Ok(()) } @@ -78,7 +79,7 @@ impl FeeHistory { ) { self.oldest_block = oldest_block.into(); self.base_fee_per_gas - .push_back(parent_base_price.map_or(U256::zero(), |x| x[space])); + .push_front(parent_base_price.map_or(U256::zero(), |x| x[space])); } } diff --git a/tests/evm_space/eip1559_test.py b/tests/evm_space/eip1559_test.py index 4db1624bd9..39f65e4d6a 100755 --- a/tests/evm_space/eip1559_test.py +++ b/tests/evm_space/eip1559_test.py @@ -83,8 +83,8 @@ def run_test(self): fee_history = self.nodes[0].eth_feeHistory("0x5", "latest", [21, 75]) - assert_equal(len(fee_history['base_fee_per_gas']), 6) - assert_equal(len(fee_history['gas_used_ratio']), 5) + assert_equal(len(fee_history['baseFeePerGas']), 6) + assert_equal(len(fee_history['gasUsedRatio']), 5) assert_equal(len(fee_history['reward']), 5) assert_greater_than(int(self.nodes[0].cfx_getFeeBurnt(), 0), 0) From ebb682fa6799025bcfcea7ce1264e6bfa0f2fd8e Mon Sep 17 00:00:00 2001 From: Pana Date: Thu, 30 May 2024 18:39:40 +0800 Subject: [PATCH 10/14] change toolchain file format --- rust-toolchain | 1 - rust-toolchain.toml | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 rust-toolchain create mode 100644 rust-toolchain.toml diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index 369f9966f6..0000000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -1.77.2 diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000000..fb0f94604f --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.77.2" \ No newline at end of file From 4b6642b42c53226c032361921f0e02178ee8d02c Mon Sep 17 00:00:00 2001 From: Pana Date: Fri, 31 May 2024 11:12:24 +0800 Subject: [PATCH 11/14] use custom de-hex U64 --- Cargo.lock | 1 + crates/client/Cargo.toml | 1 + .../client/src/rpc/impls/cfx/cfx_handler.rs | 4 +- crates/client/src/rpc/impls/cfx/common.rs | 8 +- crates/client/src/rpc/impls/cfx/light.rs | 7 +- .../client/src/rpc/impls/eth/eth_handler.rs | 13 +-- crates/client/src/rpc/traits/cfx_space/cfx.rs | 4 +- crates/client/src/rpc/traits/eth_space/eth.rs | 3 +- crates/client/src/rpc/types.rs | 2 + crates/client/src/rpc/types/fee_history.rs | 2 +- crates/client/src/rpc/types/variadic_u64.rs | 44 ++++++++++ crates/serde_utils/src/num.rs | 83 ++++++++++++++++++- 12 files changed, 151 insertions(+), 21 deletions(-) create mode 100644 crates/client/src/rpc/types/variadic_u64.rs diff --git a/Cargo.lock b/Cargo.lock index 09fdc8e77f..bf0ead7c0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1797,6 +1797,7 @@ dependencies = [ "rustc-hex", "secret-store", "serde", + "serde-utils", "serde_derive", "serde_json", "serial_test", diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index a515724f10..8d42f0551b 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -102,6 +102,7 @@ solidity-abi = {path= "../util/solidity-abi" } bls-signatures = {git = "https://github.com/Conflux-Chain/bls-signatures.git", rev = "fb52187df92d27c365642cb7e7b2aaf60437cf9c", default-features = false, features = ["multicore"]} alloy-rpc-types-trace = { workspace = true } geth-tracer = { path = "../cfxcore/geth-tracer" } +serde-utils = { path = "../serde_utils" } [dev-dependencies] criterion = "0.3" diff --git a/crates/client/src/rpc/impls/cfx/cfx_handler.rs b/crates/client/src/rpc/impls/cfx/cfx_handler.rs index 1028ad55cf..d49a200936 100644 --- a/crates/client/src/rpc/impls/cfx/cfx_handler.rs +++ b/crates/client/src/rpc/impls/cfx/cfx_handler.rs @@ -8,7 +8,7 @@ use crate::rpc::{ call_request::rpc_call_request_network, errors::check_rpc_address_network, pos::PoSEpochReward, FeeHistory, PoSEconomics, RpcAddress, SponsorInfo, StatOnGasLoad, TokenSupplyInfo, - VoteParamsInfo, WrapTransaction, + VoteParamsInfo, WrapTransaction, U64 as HexU64, }, }; use blockgen::BlockGenerator; @@ -2272,7 +2272,7 @@ impl Cfx for CfxHandler { fn account_pending_info(&self, addr: RpcAddress) -> BoxFuture>; fn account_pending_transactions(&self, address: RpcAddress, maybe_start_nonce: Option, maybe_limit: Option) -> BoxFuture; fn get_pos_reward_by_epoch(&self, epoch: EpochNumber) -> JsonRpcResult>; - fn fee_history(&self, block_count: U64, newest_block: EpochNumber, reward_percentiles: Vec) -> BoxFuture; + fn fee_history(&self, block_count: HexU64, newest_block: EpochNumber, reward_percentiles: Vec) -> BoxFuture; fn max_priority_fee_per_gas(&self) -> BoxFuture; } diff --git a/crates/client/src/rpc/impls/cfx/common.rs b/crates/client/src/rpc/impls/cfx/common.rs index c09f5a719c..b9ca7168d7 100644 --- a/crates/client/src/rpc/impls/cfx/common.rs +++ b/crates/client/src/rpc/impls/cfx/common.rs @@ -17,7 +17,7 @@ use crate::rpc::{ BlockHashOrEpochNumber, Bytes, CheckBalanceAgainstTransactionResponse, EpochNumber, FeeHistory, RpcAddress, Status as RpcStatus, Transaction as RpcTransaction, TxPoolPendingNonceRange, TxPoolStatus, - TxWithPoolInfo, + TxWithPoolInfo, U64 as HexU64, }, RpcErrorKind, RpcResult, }; @@ -530,7 +530,7 @@ impl RpcImpl { } pub fn fee_history( - &self, block_count: U64, newest_block: EpochNumber, + &self, block_count: HexU64, newest_block: EpochNumber, reward_percentiles: Vec, ) -> RpcResult { info!( @@ -538,7 +538,7 @@ impl RpcImpl { block_count, newest_block, reward_percentiles ); - if block_count == U64::zero() { + if block_count.as_u64() == 0 { return Ok(FeeHistory::new()); } // keep read lock to ensure consistent view @@ -615,7 +615,7 @@ impl RpcImpl { info!("RPC Request: max_priority_fee_per_gas",); let fee_history = self.fee_history( - U64::from(300), + HexU64::from(300), EpochNumber::LatestState, vec![50f64], )?; diff --git a/crates/client/src/rpc/impls/cfx/light.rs b/crates/client/src/rpc/impls/cfx/light.rs index 8640bde85f..1fb19b00e8 100644 --- a/crates/client/src/rpc/impls/cfx/light.rs +++ b/crates/client/src/rpc/impls/cfx/light.rs @@ -50,6 +50,7 @@ use crate::{ SponsorInfo, StatOnGasLoad, Status as RpcStatus, StorageCollateralInfo, SyncGraphStates, TokenSupplyInfo, Transaction as RpcTransaction, VoteParamsInfo, WrapTransaction, + U64 as HexU64, }, RpcBoxFuture, RpcResult, }, @@ -1091,7 +1092,7 @@ impl RpcImpl { } fn fee_history( - &self, block_count: U64, newest_block: EpochNumber, + &self, block_count: HexU64, newest_block: EpochNumber, reward_percentiles: Vec, ) -> RpcBoxFuture { info!( @@ -1099,7 +1100,7 @@ impl RpcImpl { block_count, newest_block, reward_percentiles ); - if block_count == U64::zero() { + if block_count.as_u64() == 0 { return Box::new(async { Ok(FeeHistory::new()) }.boxed().compat()); } @@ -1239,7 +1240,7 @@ impl Cfx for CfxHandler { fn transaction_by_hash(&self, hash: H256) -> BoxFuture>; fn transaction_receipt(&self, tx_hash: H256) -> BoxFuture>; fn vote_list(&self, address: RpcAddress, num: Option) -> BoxFuture>; - fn fee_history(&self, block_count: U64, newest_block: EpochNumber, reward_percentiles: Vec) -> BoxFuture; + fn fee_history(&self, block_count: HexU64, newest_block: EpochNumber, reward_percentiles: Vec) -> BoxFuture; } } diff --git a/crates/client/src/rpc/impls/eth/eth_handler.rs b/crates/client/src/rpc/impls/eth/eth_handler.rs index 44d7b145a7..36dad68811 100644 --- a/crates/client/src/rpc/impls/eth/eth_handler.rs +++ b/crates/client/src/rpc/impls/eth/eth_handler.rs @@ -15,7 +15,7 @@ use crate::rpc::{ CallRequest, EthRpcLogFilter, Log, Receipt, SyncInfo, SyncStatus, Transaction, }, - Bytes, FeeHistory, Index, MAX_GAS_CALL_REQUEST, + Bytes, FeeHistory, Index, MAX_GAS_CALL_REQUEST, U64 as HexU64, }, }; use cfx_execute_helper::estimation::{ @@ -476,8 +476,11 @@ impl Eth for EthHandler { self.tx_pool.machine().params().evm_transaction_block_ratio as usize; - let fee_history = - self.fee_history(U64::from(300), BlockNumber::Latest, vec![50f64])?; + let fee_history = self.fee_history( + HexU64::from(300), + BlockNumber::Latest, + vec![50f64], + )?; let total_reward: U256 = fee_history .reward() @@ -904,7 +907,7 @@ impl Eth for EthHandler { } fn fee_history( - &self, block_count: U64, newest_block: BlockNumber, + &self, block_count: HexU64, newest_block: BlockNumber, reward_percentiles: Vec, ) -> jsonrpc_core::Result { info!( @@ -912,7 +915,7 @@ impl Eth for EthHandler { block_count, newest_block, reward_percentiles ); - if block_count == U64::zero() { + if block_count.as_u64() == 0 { return Ok(FeeHistory::new()); } diff --git a/crates/client/src/rpc/traits/cfx_space/cfx.rs b/crates/client/src/rpc/traits/cfx_space/cfx.rs index bb96fd4687..95de945952 100644 --- a/crates/client/src/rpc/traits/cfx_space/cfx.rs +++ b/crates/client/src/rpc/traits/cfx_space/cfx.rs @@ -10,7 +10,7 @@ use crate::rpc::types::{ EstimateGasAndCollateralResponse, FeeHistory, Log as RpcLog, PoSEconomics, Receipt as RpcReceipt, RewardInfo as RpcRewardInfo, RpcAddress, SponsorInfo, Status as RpcStatus, StorageCollateralInfo, TokenSupplyInfo, - Transaction, VoteParamsInfo, + Transaction, VoteParamsInfo, U64 as HexU64, }; use cfx_types::{H128, H256, U256, U64}; use jsonrpc_core::{BoxFuture, Result as JsonRpcResult}; @@ -203,7 +203,7 @@ pub trait Cfx { #[rpc(name = "cfx_feeHistory")] fn fee_history( - &self, block_count: U64, newest_block: EpochNumber, + &self, block_count: HexU64, newest_block: EpochNumber, reward_percentiles: Vec, ) -> BoxFuture; diff --git a/crates/client/src/rpc/traits/eth_space/eth.rs b/crates/client/src/rpc/traits/eth_space/eth.rs index f3b0bbc06c..1df91b07d1 100644 --- a/crates/client/src/rpc/traits/eth_space/eth.rs +++ b/crates/client/src/rpc/traits/eth_space/eth.rs @@ -19,6 +19,7 @@ // along with OpenEthereum. If not, see . //! Eth rpc interface. +use crate::rpc::types::U64 as HexU64; use cfx_types::{H128, H160, H256, U256, U64}; use jsonrpc_core::Result; use jsonrpc_derive::rpc; @@ -76,7 +77,7 @@ pub trait Eth { #[rpc(name = "eth_feeHistory")] fn fee_history( - &self, block_count: U64, newest_block: BlockNumber, + &self, block_count: HexU64, newest_block: BlockNumber, reward_percentiles: Vec, ) -> Result; diff --git a/crates/client/src/rpc/types.rs b/crates/client/src/rpc/types.rs index 23b0141556..9746807d2f 100644 --- a/crates/client/src/rpc/types.rs +++ b/crates/client/src/rpc/types.rs @@ -32,6 +32,7 @@ mod trace; mod trace_filter; mod transaction; mod tx_pool; +mod variadic_u64; mod vote_params_info; pub use self::{ @@ -70,5 +71,6 @@ pub use self::{ AccountPendingInfo, AccountPendingTransactions, TxPoolPendingNonceRange, TxPoolStatus, TxWithPoolInfo, }, + variadic_u64::U64, vote_params_info::VoteParamsInfo, }; diff --git a/crates/client/src/rpc/types/fee_history.rs b/crates/client/src/rpc/types/fee_history.rs index 69c6d0f345..50a68f1344 100644 --- a/crates/client/src/rpc/types/fee_history.rs +++ b/crates/client/src/rpc/types/fee_history.rs @@ -106,7 +106,7 @@ where I: Iterator { percentiles .into_iter() .map(|per| { - let mut index = (*per) as usize * n / 100; + let mut index = ((*per) * (n as f64) / 100f64) as usize; if index >= n { index = n - 1; } diff --git a/crates/client/src/rpc/types/variadic_u64.rs b/crates/client/src/rpc/types/variadic_u64.rs new file mode 100644 index 0000000000..0f9011b21f --- /dev/null +++ b/crates/client/src/rpc/types/variadic_u64.rs @@ -0,0 +1,44 @@ +use serde::{Deserialize, Deserializer}; +use serde_utils::num::deserialize_u64_from_num_or_hex; +use std::fmt; + +// support both hex strings and number deserialization +#[derive(Debug)] +pub struct U64(u64); + +impl fmt::Display for U64 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From for U64 { + fn from(value: u64) -> Self { U64(value) } +} + +impl U64 { + pub fn as_u64(&self) -> u64 { self.0 } +} + +impl<'de> Deserialize<'de> for U64 { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> { + Ok(U64(deserialize_u64_from_num_or_hex(deserializer)?)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_deserialize_u64_or_hex() { + let json_data = r#""0x1a""#; + let my_struct: U64 = serde_json::from_str(json_data).unwrap(); + assert_eq!(my_struct.as_u64(), 26); + + let json_data = r#"26"#; + let my_struct: U64 = serde_json::from_str(json_data).unwrap(); + assert_eq!(my_struct.as_u64(), 26); + } +} diff --git a/crates/serde_utils/src/num.rs b/crates/serde_utils/src/num.rs index 10364c356b..d1f4b4d91f 100644 --- a/crates/serde_utils/src/num.rs +++ b/crates/serde_utils/src/num.rs @@ -1,6 +1,7 @@ -use cfx_types::U256; +use cfx_types::{U256, U64}; use core::str::FromStr; use serde::{de, Deserialize, Deserializer}; +use std::fmt; /// An enum that represents either a [serde_json::Number] integer, or a hex /// [U256]. @@ -28,14 +29,16 @@ impl NumberOrHexU256 { /// Deserializes the input into a U256, accepting both 0x-prefixed hex and /// decimal strings with arbitrary precision, defined by serde_json's /// [`Number`](serde_json::Number). -pub fn from_int_or_hex<'de, D>(deserializer: D) -> Result +pub fn from_int_or_hex_to_u256<'de, D>( + deserializer: D, +) -> Result where D: Deserializer<'de> { NumberOrHexU256::deserialize(deserializer)?.try_into_u256() } /// Deserializes the input into an `Option`, using [`from_int_or_hex`] to /// deserialize the inner value. -pub fn from_int_or_hex_opt<'de, D>( +pub fn from_int_or_hex_to_u256_opt<'de, D>( deserializer: D, ) -> Result, D::Error> where D: Deserializer<'de> { @@ -44,3 +47,77 @@ where D: Deserializer<'de> { None => Ok(None), } } + +/// An enum that represents either a [serde_json::Number] integer, or a hex +/// [U64]. +#[derive(Debug, Deserialize)] +#[serde(untagged)] +pub enum NumberOrHexU64 { + /// An integer + Int(serde_json::Number), + /// A hex U64 + Hex(U64), +} + +impl NumberOrHexU64 { + /// Tries to convert this into a [U64]]. + pub fn try_into_u64(self) -> Result { + match self { + NumberOrHexU64::Int(num) => { + U64::from_str(num.to_string().as_str()).map_err(E::custom) + } + NumberOrHexU64::Hex(val) => Ok(val), + } + } +} + +/// Deserializes the input into a U64, accepting both 0x-prefixed hex and +/// decimal strings with arbitrary precision, defined by serde_json's +/// [`Number`](serde_json::Number). +pub fn from_int_or_hex_to_u64<'de, D>( + deserializer: D, +) -> Result +where D: Deserializer<'de> { + NumberOrHexU64::deserialize(deserializer)?.try_into_u64() +} + +/// Deserializes the input into an `Option`, using +/// [`from_int_or_hex_to_u64`] to deserialize the inner value. +pub fn from_int_or_hex_to_u64_opt<'de, D>( + deserializer: D, +) -> Result, D::Error> +where D: Deserializer<'de> { + match Option::::deserialize(deserializer)? { + Some(val) => val.try_into_u64().map(Some), + None => Ok(None), + } +} + +pub fn deserialize_u64_from_num_or_hex<'de, D>( + deserializer: D, +) -> Result +where D: Deserializer<'de> { + struct U64OrHexVisitor; + + impl<'de> serde::de::Visitor<'de> for U64OrHexVisitor { + type Value = u64; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .write_str("a u64 integer or a hex string representing a u64") + } + + fn visit_u64(self, value: u64) -> Result { Ok(value) } + + fn visit_str(self, value: &str) -> Result + where E: serde::de::Error { + if let Some(stripped) = value.strip_prefix("0x") { + u64::from_str_radix(stripped, 16).map_err(E::custom) + } else { + Err(E::custom("expected hex string to start with '0x'")) + } + } + } + + deserializer.deserialize_any(U64OrHexVisitor) +} From dc398b4ea1e22862f7b4dbce3c4f18b4a35d0a98 Mon Sep 17 00:00:00 2001 From: Pana Date: Fri, 31 May 2024 17:25:32 +0800 Subject: [PATCH 12/14] core transaction.accessList address change to base32 format --- crates/client/src/rpc/types.rs | 4 +- crates/client/src/rpc/types/call_request.rs | 30 ++------------- .../client/src/rpc/types/cfx/access_list.rs | 38 +++++++++++++++++++ .../client/src/rpc/types/{ => cfx}/address.rs | 0 crates/client/src/rpc/types/cfx/mod.rs | 5 +++ crates/client/src/rpc/types/transaction.rs | 17 ++++++--- 6 files changed, 60 insertions(+), 34 deletions(-) create mode 100644 crates/client/src/rpc/types/cfx/access_list.rs rename crates/client/src/rpc/types/{ => cfx}/address.rs (100%) create mode 100644 crates/client/src/rpc/types/cfx/mod.rs diff --git a/crates/client/src/rpc/types.rs b/crates/client/src/rpc/types.rs index 23b0141556..90a6f50d70 100644 --- a/crates/client/src/rpc/types.rs +++ b/crates/client/src/rpc/types.rs @@ -3,11 +3,11 @@ // See http://www.gnu.org/licenses/ mod account; -pub mod address; mod blame_info; mod block; mod bytes; pub mod call_request; +pub mod cfx; mod consensus_graph_states; mod epoch_number; pub mod errors; @@ -36,7 +36,6 @@ mod vote_params_info; pub use self::{ account::Account, - address::RpcAddress, blame_info::BlameInfo, block::{Block, BlockTransactions, Header}, bytes::Bytes, @@ -44,6 +43,7 @@ pub use self::{ sign_call, CallRequest, CheckBalanceAgainstTransactionResponse, EstimateGasAndCollateralResponse, SendTxRequest, MAX_GAS_CALL_REQUEST, }, + cfx::{address, address::RpcAddress}, consensus_graph_states::ConsensusGraphStates, epoch_number::{BlockHashOrEpochNumber, EpochNumber}, fee_history::FeeHistory, diff --git a/crates/client/src/rpc/types/call_request.rs b/crates/client/src/rpc/types/call_request.rs index 65d3335d2e..0efa3a27ba 100644 --- a/crates/client/src/rpc/types/call_request.rs +++ b/crates/client/src/rpc/types/call_request.rs @@ -6,13 +6,14 @@ use crate::rpc::{ error_codes::invalid_params, types::{ address::RpcAddress, + cfx::{to_primitive_access_list, CfxAccessList}, errors::{check_rpc_address_network, RcpAddressNetworkInconsistent}, Bytes, }, RpcResult, }; use cfx_addr::Network; -use cfx_types::{Address, AddressSpaceUtil, H256, U256, U64}; +use cfx_types::{Address, AddressSpaceUtil, U256, U64}; use cfxcore::rpc_errors::invalid_params_check; use cfxcore_accounts::AccountProvider; use cfxkey::Password; @@ -20,8 +21,7 @@ use primitives::{ transaction::{ native_transaction::NativeTransaction as PrimitiveTransaction, Action, }, - AccessList, AccessListItem, SignedTransaction, Transaction, - TransactionWithSignature, + SignedTransaction, Transaction, TransactionWithSignature, }; use std::{cmp::min, convert::Into, sync::Arc}; @@ -31,28 +31,6 @@ use std::{cmp::min, convert::Into, sync::Arc}; /// not too high that a call_virtual consumes too much resource. pub const MAX_GAS_CALL_REQUEST: u64 = 15_000_000; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CoreAccessListItem { - pub address: RpcAddress, - pub storage_keys: Vec, -} - -impl Into for CoreAccessListItem { - fn into(self) -> AccessListItem { - AccessListItem { - address: self.address.hex_address, - storage_keys: self.storage_keys, - } - } -} - -pub type CoreAccessList = Vec; - -fn to_primitive_access_list(list: CoreAccessList) -> AccessList { - list.into_iter().map(|item| item.into()).collect() -} - #[derive(Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct CallRequest { @@ -73,7 +51,7 @@ pub struct CallRequest { /// StorageLimit pub storage_limit: Option, /// Access list in EIP-2930 - pub access_list: Option, + pub access_list: Option, pub max_fee_per_gas: Option, pub max_priority_fee_per_gas: Option, #[serde(rename = "type")] diff --git a/crates/client/src/rpc/types/cfx/access_list.rs b/crates/client/src/rpc/types/cfx/access_list.rs new file mode 100644 index 0000000000..1e0295669d --- /dev/null +++ b/crates/client/src/rpc/types/cfx/access_list.rs @@ -0,0 +1,38 @@ +use crate::rpc::types::address::RpcAddress; +use cfx_addr::Network; +use cfx_types::H256; +use primitives::{AccessList, AccessListItem}; +use std::convert::Into; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CfxAccessListItem { + pub address: RpcAddress, + pub storage_keys: Vec, +} + +impl Into for CfxAccessListItem { + fn into(self) -> AccessListItem { + AccessListItem { + address: self.address.hex_address, + storage_keys: self.storage_keys, + } + } +} + +pub type CfxAccessList = Vec; + +pub fn to_primitive_access_list(list: CfxAccessList) -> AccessList { + list.into_iter().map(|item| item.into()).collect() +} + +pub fn from_primitive_access_list( + list: AccessList, network: Network, +) -> CfxAccessList { + list.into_iter() + .map(|item| CfxAccessListItem { + address: RpcAddress::try_from_h160(item.address, network).unwrap(), + storage_keys: item.storage_keys, + }) + .collect() +} diff --git a/crates/client/src/rpc/types/address.rs b/crates/client/src/rpc/types/cfx/address.rs similarity index 100% rename from crates/client/src/rpc/types/address.rs rename to crates/client/src/rpc/types/cfx/address.rs diff --git a/crates/client/src/rpc/types/cfx/mod.rs b/crates/client/src/rpc/types/cfx/mod.rs new file mode 100644 index 0000000000..89d8fb6a46 --- /dev/null +++ b/crates/client/src/rpc/types/cfx/mod.rs @@ -0,0 +1,5 @@ +mod access_list; +pub mod address; + +pub use access_list::*; +pub use address::RpcAddress; diff --git a/crates/client/src/rpc/types/transaction.rs b/crates/client/src/rpc/types/transaction.rs index 50933efeb8..a5795a1aaa 100644 --- a/crates/client/src/rpc/types/transaction.rs +++ b/crates/client/src/rpc/types/transaction.rs @@ -3,7 +3,10 @@ // See http://www.gnu.org/licenses/ use crate::rpc::types::{ - eth::Transaction as ETHTransaction, receipt::Receipt, Bytes, RpcAddress, + cfx::{from_primitive_access_list, CfxAccessList}, + eth::Transaction as ETHTransaction, + receipt::Receipt, + Bytes, RpcAddress, }; use cfx_addr::Network; use cfx_types::{Space, H256, U256, U64}; @@ -13,9 +16,8 @@ use primitives::{ eth_transaction::Eip155Transaction, native_transaction::NativeTransaction, Action, }, - AccessList, SignedTransaction, Transaction as PrimitiveTransaction, - TransactionIndex, TransactionWithSignature, - TransactionWithSignatureSerializePart, + SignedTransaction, Transaction as PrimitiveTransaction, TransactionIndex, + TransactionWithSignature, TransactionWithSignatureSerializePart, }; #[derive(Debug, Clone, PartialEq, Serialize)] @@ -49,7 +51,7 @@ pub struct Transaction { pub status: Option, /// Optional access list #[serde(skip_serializing_if = "Option::is_none")] - pub access_list: Option, + pub access_list: Option, /// miner bribe #[serde(skip_serializing_if = "Option::is_none")] pub max_priority_fee_per_gas: Option, @@ -158,7 +160,10 @@ impl Transaction { storage_limit: storage_limit.into(), epoch_height: epoch_height.into(), chain_id: t.chain_id().map(|x| U256::from(x as u64)), - access_list: t.access_list().cloned(), + access_list: t + .access_list() + .cloned() + .map(|list| from_primitive_access_list(list, network)), max_fee_per_gas: t.after_1559().then_some(*t.gas_price()), max_priority_fee_per_gas: t .after_1559() From e32bd51fa3097998da1696ea12ab702d2fcfbfcb Mon Sep 17 00:00:00 2001 From: Chenxing Li Date: Fri, 31 May 2024 19:43:29 +0800 Subject: [PATCH 13/14] Update 1559 gas limit estimation & Fix issues in test --- Cargo.lock | 1 + .../transaction_pool_inner.rs | 13 +- crates/cfxcore/packing-pool/src/pool.rs | 36 +++- crates/primitives/Cargo.toml | 1 + crates/primitives/src/block_header.rs | 68 +----- .../primitives/src/block_header/base_price.rs | 201 ++++++++++++++++++ 6 files changed, 248 insertions(+), 72 deletions(-) create mode 100644 crates/primitives/src/block_header/base_price.rs diff --git a/Cargo.lock b/Cargo.lock index 09fdc8e77f..81ff5a725c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6162,6 +6162,7 @@ dependencies = [ "cfxkey", "criterion", "fixed-hash 0.5.2", + "itertools 0.10.5", "keccak-hash", "lazy_static", "log", diff --git a/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs b/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs index 628110ae65..612d1c3c60 100644 --- a/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs +++ b/crates/cfxcore/core/src/transaction_pool/transaction_pool_inner.rs @@ -800,13 +800,16 @@ impl TransactionPoolInner { fn insert_transaction_for_test( &mut self, transaction: Arc, sender_nonce: U256, ) -> InsertResult { - self.insert_transaction_without_readiness_check( + let sender = transaction.sender(); + let res = self.insert_transaction_without_readiness_check( transaction, false, true, (sender_nonce, U256::from(u64::MAX)), (0.into(), 0), - ) + ); + self.recalculate_readiness(&sender, sender_nonce, U256::from(u64::MAX)); + res } // the new inserting will fail if tx_pool is full (even if `force` is true) @@ -1793,7 +1796,7 @@ mod tests { fn pack_transactions_1559_checked( pool: &mut TransactionPoolInner, machine: &Machine, ) { - let parent_base_price = SpaceMap::new(100, 100).map_all(U256::from); + let parent_base_price = SpaceMap::new(100, 200).map_all(U256::from); let block_gas_limit = U256::from(6000); let best_epoch_height = 20; @@ -1827,7 +1830,7 @@ mod tests { for tx in txs { gas_used[tx.space()] += *tx.gas_limit(); min_gas_price[tx.space()] = - min_gas_price[tx.space()].min(*tx.gas_limit()); + min_gas_price[tx.space()].min(*tx.gas_price()); } let min_base_price = params.min_base_price(); @@ -1850,7 +1853,7 @@ mod tests { } #[test] - fn test_eip1559_transactions() { + fn test_pack_eip1559_transactions() { let mut pool = TransactionPoolInner::new_for_test(); let mut params = CommonParams::default(); diff --git a/crates/cfxcore/packing-pool/src/pool.rs b/crates/cfxcore/packing-pool/src/pool.rs index 5c9e7c6a18..ac0d0256f0 100644 --- a/crates/cfxcore/packing-pool/src/pool.rs +++ b/crates/cfxcore/packing-pool/src/pool.rs @@ -12,7 +12,9 @@ use super::{ }; use cfx_types::U256; use malloc_size_of::MallocSizeOf; -use primitives::block_header::estimate_gas_used; +use primitives::block_header::{ + compute_next_price, estimate_gas_used_boundary, estimate_max_possible_gas, +}; use rand::RngCore; use treap_map::{ ApplyOpOutcome, ConsoliableWeight, Node, SearchDirection, SearchResult, @@ -210,7 +212,24 @@ impl PackingPool { Some( SearchResult::Found { base_weight, .. } | SearchResult::RightMost(base_weight), - ) => base_weight.gas_limit, + ) => { + let gas_limit = estimate_max_possible_gas( + gas_target, + base_weight.min_gas_price, + parent_base_price, + ); + if cfg!(test) { + // Guarantee the searched result can be packed + let next_price = compute_next_price( + gas_target, + gas_limit, + parent_base_price, + min_base_price, + ); + assert!(base_weight.min_gas_price >= next_price); + } + gas_limit + } _ => U256::zero(), } } @@ -285,20 +304,23 @@ fn can_sample_within_1559( return false; } - let target_gas_used = - estimate_gas_used(gas_target, weight.min_gas_price, parent_base_price); + let max_target_gas_used = estimate_max_possible_gas( + gas_target, + weight.min_gas_price, + parent_base_price, + ); - if target_gas_used.is_zero() { + if max_target_gas_used.is_zero() { return false; } - if weight.gas_limit <= target_gas_used { + if weight.gas_limit <= max_target_gas_used { return true; } weight .max_loss_ratio - .saturating_mul(weight.gas_limit - target_gas_used) + .saturating_mul(weight.gas_limit - max_target_gas_used) < weight.weighted_loss_ratio } diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 9cc7a5497f..254d0a6981 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -25,6 +25,7 @@ once_cell = "1.17.1" [dev-dependencies] criterion = "0.3" serde_json = "1.0" +itertools = "0.10" [[bench]] name = "benchmark" diff --git a/crates/primitives/src/block_header.rs b/crates/primitives/src/block_header.rs index 6054884843..357555cc1b 100644 --- a/crates/primitives/src/block_header.rs +++ b/crates/primitives/src/block_header.rs @@ -2,6 +2,12 @@ // Conflux is free software and distributed under GNU General Public License. // See http://www.gnu.org/licenses/ +mod base_price; +pub use base_price::{ + compute_next_price, compute_next_price_tuple, estimate_gas_used_boundary, + estimate_max_possible_gas, +}; + use crate::{ block::BlockHeight, bytes::Bytes, hash::keccak, pos::PosBlockId, receipt::BlockReceipts, MERKLE_NULL_NODE, NULL_EPOCH, @@ -9,7 +15,6 @@ use crate::{ use cfx_types::{ Address, Bloom, Space, SpaceMap, H256, KECCAK_EMPTY_BLOOM, U256, }; -use log::warn; use malloc_size_of::{new_malloc_size_ops, MallocSizeOf, MallocSizeOfOps}; use once_cell::sync::OnceCell; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; @@ -25,6 +30,8 @@ const HEADER_LIST_MIN_LEN: usize = 13; /// field. pub static CIP112_TRANSITION_HEIGHT: OnceCell = OnceCell::new(); +const BASE_PRICE_CHANGE_DENOMINATOR: usize = 8; + #[derive(Clone, Debug, Eq)] pub struct BlockHeaderRlpPart { /// Parent hash. @@ -684,65 +691,6 @@ pub struct BasePrice { pub core_base_price: U256, pub espace_base_price: U256, } - -const BASE_PRICE_CHANGE_DENOMINATOR: usize = 8; - -pub fn compute_next_price( - gas_target: U256, gas_actual: U256, last_base_price: U256, - min_base_price: U256, -) -> U256 { - const DENOM: usize = BASE_PRICE_CHANGE_DENOMINATOR; - - if gas_actual > gas_target * 2 { - warn!("gas target is larger than expected"); - } - - let next_base_price = if gas_target.is_zero() || gas_target == gas_actual { - last_base_price - } else if gas_actual > gas_target { - let delta = gas_actual - gas_target; - let mut price_delta = last_base_price * delta / gas_target / DENOM; - if price_delta.is_zero() { - price_delta = U256::one(); - } - last_base_price + price_delta - } else { - let delta = gas_target - gas_actual; - let mut price_delta = last_base_price * delta / gas_target / DENOM; - if price_delta.is_zero() { - price_delta = U256::one(); - } - last_base_price - price_delta - }; - next_base_price.max(min_base_price) -} - -pub fn estimate_gas_used( - gas_target: U256, current_base_price: U256, last_base_price: U256, -) -> U256 { - // dbg!(gas_target, current_base_price, last_base_price); - const DENOM: usize = BASE_PRICE_CHANGE_DENOMINATOR; - - let delta = U256::max(U256::one(), last_base_price / DENOM); - - let upper_base_price = last_base_price + delta; - let lower_base_price = last_base_price - delta; - - if current_base_price > upper_base_price { - gas_target * 2 - } else if current_base_price < lower_base_price { - U256::zero() - } else { - gas_target * 2 * (current_base_price - lower_base_price) - / (upper_base_price - lower_base_price) - } -} - -/// A helper function for `compute_next_price` which takes a typle as input -pub fn compute_next_price_tuple(x: (U256, U256, U256, U256)) -> U256 { - compute_next_price(x.0, x.1, x.2, x.3) -} - #[cfg(test)] mod tests { use super::BlockHeaderBuilder; diff --git a/crates/primitives/src/block_header/base_price.rs b/crates/primitives/src/block_header/base_price.rs new file mode 100644 index 0000000000..02b9550c9b --- /dev/null +++ b/crates/primitives/src/block_header/base_price.rs @@ -0,0 +1,201 @@ +use super::BASE_PRICE_CHANGE_DENOMINATOR as DENOM; +use cfx_types::U256; +use log::warn; + +pub fn compute_next_price( + gas_target: U256, gas_actual: U256, last_base_price: U256, + min_base_price: U256, +) -> U256 { + let gas_actual = if gas_actual > gas_target * 2 { + warn!("gas target is larger than expected"); + gas_target * 2 + } else { + gas_actual + }; + + let next_base_price = if gas_target.is_zero() || gas_target == gas_actual { + last_base_price + } else { + let (gas_delta, delta_sign) = if gas_actual > gas_target { + (gas_actual - gas_target, true) + } else { + (gas_target - gas_actual, false) + }; + + assert!(gas_delta <= gas_target); + + let mut price_delta = gas_delta * last_base_price / gas_target / DENOM; + if price_delta.is_zero() { + price_delta = U256::one() + } + + if delta_sign { + last_base_price + price_delta + } else if !last_base_price.is_zero() { + last_base_price - price_delta + } else { + U256::zero() + } + }; + + next_base_price.max(min_base_price) +} + +pub fn estimate_max_possible_gas( + gas_target: U256, current_base_price: U256, last_base_price: U256, +) -> U256 { + let (_, upper_boundary) = estimate_gas_used_boundary( + gas_target, + current_base_price, + last_base_price, + ); + match upper_boundary { + None => gas_target * 2, + Some(U256([0, 0, 0, 0])) => U256::zero(), + Some(x) => x - 1, + } +} + +// Returns the outside boundary gas usage values that define the range +// +// The first item represents the maximum value that the next_price < +// current_base_price. +// +// The second item represents the minimum value that the +// next_price > current_base_price. +pub fn estimate_gas_used_boundary( + gas_target: U256, current_base_price: U256, last_base_price: U256, +) -> (Option, Option) { + if gas_target.is_zero() { + return (None, Some(1.into())); + } + + if last_base_price.is_zero() { + return if current_base_price == U256::zero() { + (None, Some(gas_target + 1)) + } else if current_base_price == U256::one() { + (Some(gas_target), Some(gas_target * 2 + 1)) + } else { + (Some(gas_target * 2), None) + }; + } + + let max_price_delta = U256::max(U256::one(), last_base_price / DENOM); + let upper_base_price = last_base_price + max_price_delta; + let lower_base_price = last_base_price - max_price_delta; + + if current_base_price > upper_base_price { + (Some(gas_target * 2), None) + } else if current_base_price < lower_base_price { + (None, Some(U256::zero())) + } else if current_base_price == last_base_price { + (Some(gas_target - 1), Some(gas_target + 1)) + } else { + let (price_delta, delta_sign) = if current_base_price > last_base_price + { + (current_base_price - last_base_price, true) + } else { + (last_base_price - current_base_price, false) + }; + + assert!(!price_delta.is_zero()); + + let lower_bound = if price_delta == U256::one() { + U256::zero() + } else { + (price_delta * gas_target * DENOM - 1) / last_base_price + }; + + let upper_bound = + ((price_delta + 1) * gas_target * DENOM + last_base_price - 1) + / last_base_price; + + if delta_sign { + ( + Some(gas_target + lower_bound), + Some(U256::min(gas_target + upper_bound, gas_target * 2 + 1)), + ) + } else { + ( + // Underflow could happen + gas_target.checked_sub(upper_bound), + Some(gas_target - lower_bound), + ) + } + } +} + +/// A helper function for `compute_next_price` which takes a typle as input +pub fn compute_next_price_tuple(x: (U256, U256, U256, U256)) -> U256 { + compute_next_price(x.0, x.1, x.2, x.3) +} + +#[cfg(test)] +mod tests { + use crate::block_header::compute_next_price; + + use super::{estimate_gas_used_boundary, DENOM, U256}; + use itertools::Itertools; + + fn test_boundary(gas_target: usize, last_base_price: usize) { + let max_price_delta = usize::max(1, last_base_price / DENOM); + + let start = last_base_price.saturating_sub(max_price_delta); + let end = last_base_price.saturating_add(max_price_delta); + + let mut next_start = 0usize; + + for price in start..=end { + // dbg!(gas_target, price, last_base_price); + let (lo, up) = estimate_gas_used_boundary( + gas_target.into(), + price.into(), + last_base_price.into(), + ); + let s = lo.map_or(0, |x| x.as_usize() + 1); + let e = up.unwrap().as_usize(); + assert_eq!(s, next_start); + next_start = e; + for gas_used in s..e { + let next_price = compute_next_price( + gas_target.into(), + gas_used.into(), + last_base_price.into(), + U256::zero(), + ) + .as_usize(); + assert_eq!(next_price, price); + } + } + assert_eq!(next_start, gas_target * 2 + 1); + + if start > 0 { + let res = estimate_gas_used_boundary( + gas_target.into(), + (start - 1).into(), + last_base_price.into(), + ); + assert_eq!(res, (None, Some(U256::zero()))) + } + + let res = estimate_gas_used_boundary( + gas_target.into(), + (end + 1).into(), + last_base_price.into(), + ); + assert_eq!(res, (Some((gas_target * 2).into()), None)); + } + + #[test] + fn test_gas_used_estimation() { + let tasks = [1, 2, 3, 4, 5, 8, 10, 991, 1000, 1019, 9949, 10000, 10067] + .into_iter() + .cartesian_product([ + 0, 1, 2, 3, 4, 5, 8, 10, 991, 1000, 1019, 9949, 10000, 10067, + ]); + + for (gas_target, last_base_price) in tasks.into_iter() { + test_boundary(gas_target, last_base_price); + } + } +} From d4f03bc18a9bc1bba28fbc7fe57d725ff1c02acf Mon Sep 17 00:00:00 2001 From: Chenxing Li Date: Mon, 3 Jun 2024 11:54:27 +0800 Subject: [PATCH 14/14] Cargo fmt --- crates/cfxcore/packing-pool/src/pool.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/cfxcore/packing-pool/src/pool.rs b/crates/cfxcore/packing-pool/src/pool.rs index ac0d0256f0..8268ad6c3f 100644 --- a/crates/cfxcore/packing-pool/src/pool.rs +++ b/crates/cfxcore/packing-pool/src/pool.rs @@ -12,9 +12,7 @@ use super::{ }; use cfx_types::U256; use malloc_size_of::MallocSizeOf; -use primitives::block_header::{ - compute_next_price, estimate_gas_used_boundary, estimate_max_possible_gas, -}; +use primitives::block_header::{compute_next_price, estimate_max_possible_gas}; use rand::RngCore; use treap_map::{ ApplyOpOutcome, ConsoliableWeight, Node, SearchDirection, SearchResult,