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,
|
traits::Eth,
|
||||||
types::{
|
types::{
|
||||||
block_number_to_id, Block, BlockNumber, BlockTransactions, Bytes, CallRequest, EthAccount,
|
block_number_to_id, Block, BlockNumber, BlockTransactions, Bytes, CallRequest, EthAccount,
|
||||||
Filter, Index, Log, Receipt, RichBlock, StorageProof, SyncInfo, SyncStatus, Transaction,
|
EthFeeHistory, Filter, Index, Log, Receipt, RichBlock, StorageProof, SyncInfo, SyncStatus,
|
||||||
Work,
|
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>> {
|
fn accounts(&self) -> Result<Vec<H160>> {
|
||||||
self.deprecation_notice
|
self.deprecation_notice
|
||||||
.print("eth_accounts", deprecated::msgs::ACCOUNTS);
|
.print("eth_accounts", deprecated::msgs::ACCOUNTS);
|
||||||
|
@ -20,8 +20,8 @@ use jsonrpc_core::{BoxFuture, Result};
|
|||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
|
|
||||||
use v1::types::{
|
use v1::types::{
|
||||||
BlockNumber, Bytes, CallRequest, EthAccount, Filter, FilterChanges, Index, Log, Receipt,
|
BlockNumber, Bytes, CallRequest, EthAccount, EthFeeHistory, Filter, FilterChanges, Index, Log,
|
||||||
RichBlock, SyncStatus, Transaction, Work,
|
Receipt, RichBlock, SyncStatus, Transaction, Work,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Eth rpc interface.
|
/// Eth rpc interface.
|
||||||
@ -60,6 +60,11 @@ pub trait Eth {
|
|||||||
#[rpc(name = "eth_gasPrice")]
|
#[rpc(name = "eth_gasPrice")]
|
||||||
fn gas_price(&self) -> BoxFuture<U256>;
|
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.
|
/// Returns accounts list.
|
||||||
#[rpc(name = "eth_accounts")]
|
#[rpc(name = "eth_accounts")]
|
||||||
fn accounts(&self) -> Result<Vec<H160>>;
|
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},
|
derivation::{Derive, DeriveHash, DeriveHierarchical},
|
||||||
eip191::{EIP191Version, PresignedTransaction},
|
eip191::{EIP191Version, PresignedTransaction},
|
||||||
|
fee_history::EthFeeHistory,
|
||||||
filter::{Filter, FilterChanges},
|
filter::{Filter, FilterChanges},
|
||||||
histogram::Histogram,
|
histogram::Histogram,
|
||||||
index::Index,
|
index::Index,
|
||||||
@ -62,6 +63,7 @@ mod call_request;
|
|||||||
mod confirmations;
|
mod confirmations;
|
||||||
mod derivation;
|
mod derivation;
|
||||||
mod eip191;
|
mod eip191;
|
||||||
|
mod fee_history;
|
||||||
mod filter;
|
mod filter;
|
||||||
mod histogram;
|
mod histogram;
|
||||||
mod index;
|
mod index;
|
||||||
|
Loading…
Reference in New Issue
Block a user