From 706558613bbecefe862a9724fff17d6ddd90e93a Mon Sep 17 00:00:00 2001 From: Pana Date: Wed, 29 May 2024 17:24:08 +0800 Subject: [PATCH 1/3] 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 2/3] 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 4b6642b42c53226c032361921f0e02178ee8d02c Mon Sep 17 00:00:00 2001 From: Pana Date: Fri, 31 May 2024 11:12:24 +0800 Subject: [PATCH 3/3] 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) +}