From 376ab81762f4dfcd071711b86be3048ed3a0f58f Mon Sep 17 00:00:00 2001 From: Gonza Montiel Date: Thu, 17 Oct 2024 14:12:50 -0300 Subject: [PATCH 1/2] Allow to specify integer as `block_count` for `eth_feeHistory` (#228) --- client/rpc-core/src/eth.rs | 2 +- client/rpc-core/src/types/block_count.rs | 134 +++++++++++++++++++++++ client/rpc-core/src/types/mod.rs | 2 + client/rpc/src/eth/fee.rs | 10 +- client/rpc/src/eth/mod.rs | 4 +- 5 files changed, 142 insertions(+), 10 deletions(-) create mode 100644 client/rpc-core/src/types/block_count.rs diff --git a/client/rpc-core/src/eth.rs b/client/rpc-core/src/eth.rs index 8a18c33086..a709a1e9b4 100644 --- a/client/rpc-core/src/eth.rs +++ b/client/rpc-core/src/eth.rs @@ -214,7 +214,7 @@ pub trait EthApi { #[method(name = "eth_feeHistory")] async fn fee_history( &self, - block_count: U256, + block_count: BlockCount, newest_block: BlockNumberOrHash, reward_percentiles: Option>, ) -> RpcResult; diff --git a/client/rpc-core/src/types/block_count.rs b/client/rpc-core/src/types/block_count.rs new file mode 100644 index 0000000000..2896f8371d --- /dev/null +++ b/client/rpc-core/src/types/block_count.rs @@ -0,0 +1,134 @@ +// This file is part of Frontier. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use std::convert::Into; +use std::{fmt, str::FromStr}; + +use ethereum_types::U256; +use serde::{ + de::{Error, Visitor}, + Deserialize, Deserializer, Serialize, Serializer, +}; + +/// Represents An RPC Api block count param, which can take the form of a number, an hex string, or a 32-bytes array +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum BlockCount { + /// U256 + U256(U256), + /// Number + Num(u64), +} + +impl<'a> Deserialize<'a> for BlockCount { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'a>, + { + deserializer.deserialize_any(BlockCountVisitor) + } +} + +impl Serialize for BlockCount { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + BlockCount::U256(ref x) => x.serialize(serializer), + BlockCount::Num(ref x) => serializer.serialize_str(&format!("0x{:x}", x)), + } + } +} + +struct BlockCountVisitor; + +impl Into for BlockCount { + fn into(self) -> U256 { + match self { + BlockCount::U256(n) => n, + BlockCount::Num(n) => U256::from(n), + } + } +} + +impl Into for BlockCount { + fn into(self) -> u64 { + match self { + BlockCount::U256(n) => n.as_u64(), + BlockCount::Num(n) => n, + } + } +} + +impl<'a> Visitor<'a> for BlockCountVisitor { + type Value = BlockCount; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "an intenger, a (both 0x-prefixed or not) hex string or byte array containing between (0; 32] bytes" + ) + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + let number = value.parse::(); + match number { + Ok(n) => Ok(BlockCount::Num(n)), + Err(_) => U256::from_str(value).map(BlockCount::U256).map_err(|_| { + Error::custom("Invalid block count: non-decimal or missing 0x prefix".to_string()) + }), + } + } + + fn visit_string(self, value: String) -> Result + where + E: Error, + { + self.visit_str(value.as_ref()) + } + + fn visit_u64(self, value: u64) -> Result + where + E: Error, + { + Ok(BlockCount::Num(value)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn match_block_number(block_count: BlockCount) -> Option { + match block_count { + BlockCount::Num(n) => Some(U256::from(n)), + BlockCount::U256(n) => Some(n), + } + } + + #[test] + fn block_number_deserialize() { + let bn_dec: BlockCount = serde_json::from_str(r#""42""#).unwrap(); + let bn_hex: BlockCount = serde_json::from_str(r#""0x45""#).unwrap(); + assert_eq!(match_block_number(bn_dec).unwrap(), U256::from(42)); + assert_eq!(match_block_number(bn_hex).unwrap(), U256::from("0x45")); + } +} diff --git a/client/rpc-core/src/types/mod.rs b/client/rpc-core/src/types/mod.rs index bdbce709b7..53635b00e7 100644 --- a/client/rpc-core/src/types/mod.rs +++ b/client/rpc-core/src/types/mod.rs @@ -20,6 +20,7 @@ mod account_info; mod block; +mod block_count; mod block_number; mod bytes; mod call_request; @@ -45,6 +46,7 @@ pub use self::txpool::{Summary, TransactionMap, TxPoolResult}; pub use self::{ account_info::{AccountInfo, EthAccount, ExtAccountInfo, RecoveredAccount, StorageProof}, block::{Block, BlockTransactions, Header, Rich, RichBlock, RichHeader}, + block_count::BlockCount, block_number::BlockNumberOrHash, bytes::Bytes, call_request::CallStateOverride, diff --git a/client/rpc/src/eth/fee.rs b/client/rpc/src/eth/fee.rs index df8a8c20a9..c53c174834 100644 --- a/client/rpc/src/eth/fee.rs +++ b/client/rpc/src/eth/fee.rs @@ -53,17 +53,13 @@ where pub async fn fee_history( &self, - block_count: U256, + block_count: u64, newest_block: BlockNumberOrHash, reward_percentiles: Option>, ) -> RpcResult { // The max supported range size is 1024 by spec. - let range_limit = U256::from(1024); - let block_count = if block_count > range_limit { - range_limit.as_u64() - } else { - block_count.as_u64() - }; + let range_limit: u64 = 1024; + let block_count: u64 = u64::min(block_count, range_limit); if let Some(id) = frontier_backend_client::native_block_id::( self.client.as_ref(), diff --git a/client/rpc/src/eth/mod.rs b/client/rpc/src/eth/mod.rs index d7d3e14fba..131bf5fd29 100644 --- a/client/rpc/src/eth/mod.rs +++ b/client/rpc/src/eth/mod.rs @@ -494,11 +494,11 @@ where async fn fee_history( &self, - block_count: U256, + block_count: BlockCount, newest_block: BlockNumberOrHash, reward_percentiles: Option>, ) -> RpcResult { - self.fee_history(block_count, newest_block, reward_percentiles) + self.fee_history(block_count.into(), newest_block, reward_percentiles) .await } From 3b3b2c2a222072b816b641991d6297a6c5d657b5 Mon Sep 17 00:00:00 2001 From: Tarek Mohamed Abdalla Date: Thu, 6 Feb 2025 16:32:36 +0200 Subject: [PATCH 2/2] style --- client/rpc-core/src/types/block_count.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/client/rpc-core/src/types/block_count.rs b/client/rpc-core/src/types/block_count.rs index 2896f8371d..db5f0ef417 100644 --- a/client/rpc-core/src/types/block_count.rs +++ b/client/rpc-core/src/types/block_count.rs @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::convert::Into; use std::{fmt, str::FromStr}; use ethereum_types::U256; @@ -57,20 +56,20 @@ impl Serialize for BlockCount { struct BlockCountVisitor; -impl Into for BlockCount { - fn into(self) -> U256 { - match self { - BlockCount::U256(n) => n, +impl From for U256 { + fn from(block_count: BlockCount) -> U256 { + match block_count { BlockCount::Num(n) => U256::from(n), + BlockCount::U256(n) => n, } } } -impl Into for BlockCount { - fn into(self) -> u64 { - match self { - BlockCount::U256(n) => n.as_u64(), +impl From for u64 { + fn from(block_count: BlockCount) -> u64 { + match block_count { BlockCount::Num(n) => n, + BlockCount::U256(n) => n.as_u64(), } } }