feeHistory implementation (#484)
* feeHistory implementation * code review fix
This commit is contained in:
parent
eb42f0c5d9
commit
87603926b5
@ -59,8 +59,8 @@ use v1::{
|
||||
traits::Eth,
|
||||
types::{
|
||||
block_number_to_id, Block, BlockNumber, BlockTransactions, Bytes, CallRequest, EthAccount,
|
||||
Filter, Index, Log, Receipt, RichBlock, StorageProof, SyncInfo, SyncStatus, Transaction,
|
||||
Work,
|
||||
EthFeeHistory, Filter, Index, Log, Receipt, RichBlock, StorageProof, SyncInfo, SyncStatus,
|
||||
Transaction, Work,
|
||||
},
|
||||
};
|
||||
|
||||
@ -696,6 +696,205 @@ where
|
||||
)))
|
||||
}
|
||||
|
||||
fn fee_history(
|
||||
&self,
|
||||
mut block_count: U256,
|
||||
newest_block: BlockNumber,
|
||||
reward_percentiles: Option<Vec<f64>>,
|
||||
) -> BoxFuture<EthFeeHistory> {
|
||||
let mut result = EthFeeHistory::default();
|
||||
|
||||
if block_count < 1.into() {
|
||||
return Box::new(future::done(Ok(result)));
|
||||
}
|
||||
|
||||
if block_count > 1024.into() {
|
||||
block_count = 1024.into();
|
||||
}
|
||||
|
||||
let latest_block = self.client.chain_info().best_block_number;
|
||||
let pending_block = self.client.chain_info().best_block_number + 1;
|
||||
|
||||
let last_block = match newest_block {
|
||||
BlockNumber::Hash {
|
||||
hash: _,
|
||||
require_canonical: _,
|
||||
} => 0,
|
||||
BlockNumber::Num(number) => {
|
||||
if number <= pending_block {
|
||||
number
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
BlockNumber::Latest => latest_block,
|
||||
BlockNumber::Earliest => 0,
|
||||
BlockNumber::Pending => pending_block,
|
||||
};
|
||||
|
||||
let first_block = if last_block >= block_count.as_u64() - 1 {
|
||||
last_block - (block_count.as_u64() - 1)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
result.oldest_block = BlockNumber::Num(first_block);
|
||||
|
||||
let get_block_header = |i| {
|
||||
self.client
|
||||
.block_header(BlockId::Number(i))
|
||||
.ok_or_else(errors::state_pruned)
|
||||
.and_then(|h| {
|
||||
h.decode(self.client.engine().params().eip1559_transition)
|
||||
.map_err(errors::decode)
|
||||
})
|
||||
};
|
||||
|
||||
let calculate_base_fee = |h| {
|
||||
self.client
|
||||
.engine()
|
||||
.calculate_base_fee(&h)
|
||||
.unwrap_or_default()
|
||||
};
|
||||
|
||||
let calculate_gas_used_ratio = |h: &Header| {
|
||||
let gas_used = match self.client.block_receipts(&h.hash()) {
|
||||
Some(receipts) => receipts
|
||||
.receipts
|
||||
.last()
|
||||
.map_or(U256::zero(), |r| r.gas_used),
|
||||
None => 0.into(),
|
||||
};
|
||||
|
||||
(gas_used.as_u64() as f64) / (h.gas_limit().as_u64() as f64)
|
||||
};
|
||||
|
||||
let get_block_transactions = |i| match self.client.block_body(BlockId::Number(i)) {
|
||||
Some(body) => Some(body.transactions()),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let reward_percentiles = reward_percentiles.unwrap_or_default();
|
||||
let mut reward_final = vec![];
|
||||
|
||||
for i in first_block..=last_block + 1 {
|
||||
let is_last = i == last_block + 1;
|
||||
|
||||
if i < pending_block {
|
||||
match get_block_header(i) {
|
||||
Ok(h) => {
|
||||
let base_fee = h.base_fee();
|
||||
|
||||
result.base_fee_per_gas.push(base_fee.unwrap_or_default());
|
||||
|
||||
if !is_last {
|
||||
result.gas_used_ratio.push(calculate_gas_used_ratio(&h));
|
||||
|
||||
if reward_percentiles.len() > 0 {
|
||||
let mut gas_and_reward: Vec<(U256, U256)> = vec![];
|
||||
if let Some(txs) = get_block_transactions(i) {
|
||||
if let Some(receipt) = self.client.block_receipts(&h.hash()) {
|
||||
if txs.len() == receipt.receipts.len() {
|
||||
for i in 0..txs.len() {
|
||||
let gas_used = if i == 0 {
|
||||
receipt.receipts[i].gas_used
|
||||
} else {
|
||||
receipt.receipts[i].gas_used
|
||||
- receipt.receipts[i - 1].gas_used
|
||||
};
|
||||
|
||||
gas_and_reward.push((
|
||||
gas_used,
|
||||
txs[i].effective_gas_price(base_fee)
|
||||
- base_fee.unwrap_or_default(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gas_and_reward.sort_by(|a, b| a.1.cmp(&b.1));
|
||||
|
||||
reward_final.push(
|
||||
reward_percentiles
|
||||
.iter()
|
||||
.map(|p| {
|
||||
let target_gas = U256::from(
|
||||
((h.gas_used().as_u64() as f64) * p / 100.0) as u64,
|
||||
);
|
||||
let mut sum_gas = U256::default();
|
||||
for pair in &gas_and_reward {
|
||||
sum_gas += pair.0;
|
||||
if target_gas <= sum_gas {
|
||||
return pair.1;
|
||||
}
|
||||
}
|
||||
0.into()
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => break, //reorg happened, skip rest of the blocks
|
||||
}
|
||||
} else if i == pending_block {
|
||||
match self.miner.pending_block_header(i - 1) {
|
||||
Some(h) => {
|
||||
result
|
||||
.base_fee_per_gas
|
||||
.push(h.base_fee().unwrap_or_default());
|
||||
|
||||
if !is_last {
|
||||
result.gas_used_ratio.push(calculate_gas_used_ratio(&h));
|
||||
|
||||
if reward_percentiles.len() > 0 {
|
||||
//zero values since can't be calculated for pending block
|
||||
reward_final.push(vec![0.into(); reward_percentiles.len()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
//calculate base fee based on the latest block
|
||||
match get_block_header(i - 1) {
|
||||
Ok(h) => {
|
||||
result.base_fee_per_gas.push(calculate_base_fee(h));
|
||||
|
||||
if !is_last {
|
||||
result.gas_used_ratio.push(0.into());
|
||||
|
||||
if reward_percentiles.len() > 0 {
|
||||
//zero values since can't be calculated for pending block
|
||||
reward_final.push(vec![0.into(); reward_percentiles.len()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => break, //reorg happened, skip rest of the blocks
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if i == pending_block + 1 {
|
||||
//calculate base fee based on the pending block, if exist
|
||||
match self.miner.pending_block_header(i - 1) {
|
||||
Some(h) => {
|
||||
result.base_fee_per_gas.push(calculate_base_fee(h));
|
||||
}
|
||||
None => {
|
||||
result.base_fee_per_gas.push(0.into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
}
|
||||
|
||||
if !reward_final.is_empty() {
|
||||
result.reward = Some(reward_final);
|
||||
}
|
||||
|
||||
Box::new(future::done(Ok(result)))
|
||||
}
|
||||
|
||||
fn accounts(&self) -> Result<Vec<H160>> {
|
||||
self.deprecation_notice
|
||||
.print("eth_accounts", deprecated::msgs::ACCOUNTS);
|
||||
|
@ -20,8 +20,8 @@ use jsonrpc_core::{BoxFuture, Result};
|
||||
use jsonrpc_derive::rpc;
|
||||
|
||||
use v1::types::{
|
||||
BlockNumber, Bytes, CallRequest, EthAccount, Filter, FilterChanges, Index, Log, Receipt,
|
||||
RichBlock, SyncStatus, Transaction, Work,
|
||||
BlockNumber, Bytes, CallRequest, EthAccount, EthFeeHistory, Filter, FilterChanges, Index, Log,
|
||||
Receipt, RichBlock, SyncStatus, Transaction, Work,
|
||||
};
|
||||
|
||||
/// Eth rpc interface.
|
||||
@ -60,6 +60,11 @@ pub trait Eth {
|
||||
#[rpc(name = "eth_gasPrice")]
|
||||
fn gas_price(&self) -> BoxFuture<U256>;
|
||||
|
||||
/// Returns transaction fee history.
|
||||
#[rpc(name = "eth_feeHistory")]
|
||||
fn fee_history(&self, _: U256, _: BlockNumber, _: Option<Vec<f64>>)
|
||||
-> BoxFuture<EthFeeHistory>;
|
||||
|
||||
/// Returns accounts list.
|
||||
#[rpc(name = "eth_accounts")]
|
||||
fn accounts(&self) -> Result<Vec<H160>>;
|
||||
|
30
crates/rpc/src/v1/types/fee_history.rs
Normal file
30
crates/rpc/src/v1/types/fee_history.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
||||
// This file is part of OpenEthereum.
|
||||
|
||||
// OpenEthereum 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.
|
||||
|
||||
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Return types for RPC calls
|
||||
|
||||
use ethereum_types::U256;
|
||||
use v1::types::BlockNumber;
|
||||
|
||||
/// Account information.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EthFeeHistory {
|
||||
pub oldest_block: BlockNumber,
|
||||
pub base_fee_per_gas: Vec<U256>,
|
||||
pub gas_used_ratio: Vec<f64>,
|
||||
pub reward: Option<Vec<Vec<U256>>>,
|
||||
}
|
@ -29,6 +29,7 @@ pub use self::{
|
||||
},
|
||||
derivation::{Derive, DeriveHash, DeriveHierarchical},
|
||||
eip191::{EIP191Version, PresignedTransaction},
|
||||
fee_history::EthFeeHistory,
|
||||
filter::{Filter, FilterChanges},
|
||||
histogram::Histogram,
|
||||
index::Index,
|
||||
@ -62,6 +63,7 @@ mod call_request;
|
||||
mod confirmations;
|
||||
mod derivation;
|
||||
mod eip191;
|
||||
mod fee_history;
|
||||
mod filter;
|
||||
mod histogram;
|
||||
mod index;
|
||||
|
Loading…
Reference in New Issue
Block a user