Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eth_feeHistory implementation #558

Merged
merged 8 commits into from
Oct 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 48 additions & 4 deletions src/api/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ use crate::{
api::Namespace,
helpers::{self, CallFuture},
types::{
Address, Block, BlockHeader, BlockId, BlockNumber, Bytes, CallRequest, Filter, Index, Log, SyncState,
Transaction, TransactionId, TransactionReceipt, TransactionRequest, Work, H256, H520, H64, U256, U64,
Address, Block, BlockHeader, BlockId, BlockNumber, Bytes, CallRequest, FeeHistory, Filter, Index, Log,
SyncState, Transaction, TransactionId, TransactionReceipt, TransactionRequest, Work, H256, H520, H64, U256,
U64,
},
Transport,
};
Expand Down Expand Up @@ -88,6 +89,24 @@ impl<T: Transport> Eth<T> {
CallFuture::new(self.transport.execute("eth_gasPrice", vec![]))
}

/// Returns a collection of historical gas information. This can be used for evaluating the max_fee_per_gas
/// and max_priority_fee_per_gas to send the future transactions.
pub fn fee_history(
&self,
block_count: U256,
newest_block: BlockNumber,
reward_percentiles: Option<Vec<f64>>,
) -> CallFuture<FeeHistory, T::Out> {
let block_count = helpers::serialize(&block_count);
let newest_block = helpers::serialize(&newest_block);
let reward_percentiles = helpers::serialize(&reward_percentiles);

CallFuture::new(
self.transport
.execute("eth_feeHistory", vec![block_count, newest_block, reward_percentiles]),
)
}

/// Get balance of given address
pub fn balance(&self, address: Address, block: Option<BlockNumber>) -> CallFuture<U256, T::Out> {
let address = helpers::serialize(&address);
Expand Down Expand Up @@ -356,8 +375,8 @@ mod tests {
api::Namespace,
rpc::Value,
types::{
Address, Block, BlockHeader, BlockId, BlockNumber, CallRequest, FilterBuilder, Log, SyncInfo, SyncState,
Transaction, TransactionId, TransactionReceipt, TransactionRequest, Work, H256, H520, H64,
Address, Block, BlockHeader, BlockId, BlockNumber, CallRequest, FeeHistory, FilterBuilder, Log, SyncInfo,
SyncState, Transaction, TransactionId, TransactionReceipt, TransactionRequest, Work, H256, H520, H64,
},
};
use hex_literal::hex;
Expand Down Expand Up @@ -473,6 +492,25 @@ mod tests {
"effectiveGasPrice": "0x100"
}"#;

const EXAMPLE_FEE_HISTORY: &str = r#"{
"baseFeePerGas": [
"0x15f794d04b",
"0x1730fe199f",
"0x176212b802",
"0x165bce08cb",
"0x16c6235c9d",
"0x1539ff7ccd"
],
"gasUsedRatio": [
0.722926465013414,
0.53306761204479,
0.32474768127264964,
0.574309529134573,
0.2282121795900929
],
"oldestBlock": "0xcd1df9"
}"#;

rpc_test! (
Eth:accounts => "eth_accounts";
Value::Array(vec![Value::String("0x0000000000000000000000000000000000000123".into())]) => vec![Address::from_low_u64_be(0x123)]
Expand Down Expand Up @@ -560,6 +598,12 @@ mod tests {
Value::String("0x123".into()) => 0x123
);

rpc_test! (
Eth:fee_history, 0x3, BlockNumber::Latest, None => "eth_feeHistory", vec![r#""0x3""#, r#""latest""#, r#"null"#];
::serde_json::from_str(EXAMPLE_FEE_HISTORY).unwrap()
=> ::serde_json::from_str::<FeeHistory>(EXAMPLE_FEE_HISTORY).unwrap()
);

rpc_test! (
Eth:balance, Address::from_low_u64_be(0x123), None
=>
Expand Down
52 changes: 51 additions & 1 deletion src/types/block.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::types::{Bytes, H160, H2048, H256, H64, U256, U64};
use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};

/// The block header type returned from RPC calls.
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
Expand Down Expand Up @@ -158,6 +158,24 @@ impl Serialize for BlockNumber {
}
}

impl<'a> Deserialize<'a> for BlockNumber {
fn deserialize<D>(deserializer: D) -> Result<BlockNumber, D::Error>
where
D: Deserializer<'a>,
{
let value = String::deserialize(deserializer)?;
match value.as_str() {
"latest" => Ok(BlockNumber::Latest),
"earliest" => Ok(BlockNumber::Earliest),
"pending" => Ok(BlockNumber::Pending),
_ if value.starts_with("0x") => U64::from_str_radix(&value[2..], 16)
.map(BlockNumber::Number)
.map_err(|e| D::Error::custom(format!("invalid block number: {}", e))),
_ => Err(D::Error::custom("invalid block number: missing 0x prefix".to_string())),
}
}
}

sunce86 marked this conversation as resolved.
Show resolved Hide resolved
/// Block Identifier
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BlockId {
Expand Down Expand Up @@ -291,4 +309,36 @@ mod tests {
let block: Block<()> = serde_json::from_value(json.clone()).unwrap();
assert_eq!(block.base_fee_per_gas, Some(U256::from(7)));
}

#[test]
fn serialize_deserialize_block_number() {
// BlockNumber::Latest
let serialized = serde_json::to_value(BlockNumber::Latest).unwrap();
assert_eq!(serialized, "latest");
let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
assert_eq!(deserialized, BlockNumber::Latest);

// BlockNumber::Earliest
let serialized = serde_json::to_value(BlockNumber::Earliest).unwrap();
assert_eq!(serialized, "earliest");
let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
assert_eq!(deserialized, BlockNumber::Earliest);

// BlockNumber::Pending
let serialized = serde_json::to_value(BlockNumber::Pending).unwrap();
assert_eq!(serialized, "pending");
let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
assert_eq!(deserialized, BlockNumber::Pending);

// BlockNumber::Number
let serialized = serde_json::to_value(BlockNumber::Number(100.into())).unwrap();
assert_eq!(serialized, "0x64");
let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
assert_eq!(deserialized, BlockNumber::Number(100.into()));
let deserialized = serde_json::from_value::<BlockNumber>("64".into());
assert_eq!(
deserialized.unwrap_err().to_string(),
"invalid block number: missing 0x prefix"
);
}
}
37 changes: 37 additions & 0 deletions src/types/fee_history.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use crate::types::{BlockNumber, U256};
use serde::{Deserialize, Serialize};

/// The fee history type returned from `eth_feeHistory` call.
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FeeHistory {
/// Lowest number block of the returned range.
pub oldest_block: BlockNumber,
/// A vector of block base fees per gas. This includes the next block after the newest of the returned range, because this value can be derived from the newest block. Zeroes are returned for pre-EIP-1559 blocks.
pub base_fee_per_gas: Vec<U256>,
/// A vector of block gas used ratios. These are calculated as the ratio of gas used and gas limit.
pub gas_used_ratio: Vec<f64>,
/// A vector of effective priority fee per gas data points from a single block. All zeroes are returned if the block is empty. Returned only if requested.
pub reward: Option<Vec<Vec<U256>>>,
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn fee_history() {
let fee_history = FeeHistory {
oldest_block: BlockNumber::Number(123456.into()),
base_fee_per_gas: vec![100.into(), 110.into()],
gas_used_ratio: vec![1.0, 2.0, 3.0],
reward: None,
};

let serialized = serde_json::to_value(fee_history.clone()).unwrap();
assert_eq!(serialized.to_string(), "{\"baseFeePerGas\":[\"0x64\",\"0x6e\"],\"gasUsedRatio\":[1.0,2.0,3.0],\"oldestBlock\":\"0x1e240\",\"reward\":null}");

let deserialized = serde_json::from_value(serialized).unwrap();
assert_eq!(fee_history, deserialized);
sunce86 marked this conversation as resolved.
Show resolved Hide resolved
}
}
2 changes: 2 additions & 0 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
mod block;
mod bytes;
mod bytes_array;
mod fee_history;
mod log;
mod parity_peers;
mod parity_pending_transaction;
Expand All @@ -22,6 +23,7 @@ pub use self::{
block::{Block, BlockHeader, BlockId, BlockNumber},
bytes::Bytes,
bytes_array::BytesArray,
fee_history::FeeHistory,
log::{Filter, FilterBuilder, Log},
parity_peers::{
EthProtocolInfo, ParityPeerInfo, ParityPeerType, PeerNetworkInfo, PeerProtocolsInfo, PipProtocolInfo,
Expand Down