Gas price statistics. (#1291)

* Gas price statistics.

Affects eth_gasPrice.
Added ethcore_gasPriceStatistics.

Closes #1265

* Fix a bug in eth_gasPrice

* Fix tests.

* Revert minor alteration.

* Tests for gas_price_statistics.

- Tests;
- Additional infrastructure for generating test blocks with
transactions.
This commit is contained in:
Gav Wood
2016-06-16 12:44:08 +02:00
committed by arkpar
parent 6026dd3657
commit 335bce85e8
12 changed files with 225 additions and 52 deletions

View File

@@ -153,15 +153,23 @@ impl<C, S, A, M, EM> EthClient<C, S, A, M, EM> where
}
}
fn default_gas_price(&self) -> Result<U256, Error> {
let miner = take_weak!(self.miner);
Ok(take_weak!(self.client)
.gas_price_statistics(100, 8)
.map(|x| x[4])
.unwrap_or_else(|_| miner.sensible_gas_price())
)
}
fn sign_call(&self, request: CallRequest) -> Result<SignedTransaction, Error> {
let client = take_weak!(self.client);
let miner = take_weak!(self.miner);
let from = request.from.unwrap_or(Address::zero());
Ok(EthTransaction {
nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)),
action: request.to.map_or(Action::Create, Action::Call),
gas: request.gas.unwrap_or(U256::from(50_000_000)),
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
gas_price: request.gas_price.unwrap_or_else(|| self.default_gas_price().expect("call only fails if client or miner are unavailable; client and miner are both available to be here; qed")),
value: request.value.unwrap_or_else(U256::zero),
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
}.fake_sign(from))
@@ -293,7 +301,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM> where
fn gas_price(&self, params: Params) -> Result<Value, Error> {
match params {
Params::None => to_value(&take_weak!(self.miner).sensible_gas_price()),
Params::None => to_value(&try!(self.default_gas_price())),
_ => Err(Error::invalid_params())
}
}

View File

@@ -15,30 +15,34 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Ethcore-specific rpc implementation.
use util::RotatingLogger;
use util::{RotatingLogger};
use util::network_settings::NetworkSettings;
use util::misc::version_data;
use std::sync::{Arc, Weak};
use std::ops::Deref;
use std::collections::BTreeMap;
use std::collections::{BTreeMap};
use ethcore::client::{MiningBlockChainClient};
use jsonrpc_core::*;
use ethcore::miner::MinerService;
use v1::traits::Ethcore;
use v1::types::{Bytes};
/// Ethcore implementation.
pub struct EthcoreClient<M> where
pub struct EthcoreClient<C, M> where
C: MiningBlockChainClient,
M: MinerService {
client: Weak<C>,
miner: Weak<M>,
logger: Arc<RotatingLogger>,
settings: Arc<NetworkSettings>,
}
impl<M> EthcoreClient<M> where M: MinerService {
impl<C, M> EthcoreClient<C, M> where C: MiningBlockChainClient, M: MinerService {
/// Creates new `EthcoreClient`.
pub fn new(miner: &Arc<M>, logger: Arc<RotatingLogger>, settings: Arc<NetworkSettings>) -> Self {
pub fn new(client: &Arc<C>, miner: &Arc<M>, logger: Arc<RotatingLogger>, settings: Arc<NetworkSettings>) -> Self {
EthcoreClient {
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
logger: logger,
settings: settings,
@@ -46,7 +50,7 @@ impl<M> EthcoreClient<M> where M: MinerService {
}
}
impl<M> Ethcore for EthcoreClient<M> where M: MinerService + 'static {
impl<C, M> Ethcore for EthcoreClient<C, M> where M: MinerService + 'static, C: MiningBlockChainClient + 'static {
fn transactions_limit(&self, _: Params) -> Result<Value, Error> {
to_value(&take_weak!(self.miner).transactions_limit())
@@ -97,8 +101,23 @@ impl<M> Ethcore for EthcoreClient<M> where M: MinerService + 'static {
Ok(Value::Object(map))
}
fn default_extra_data(&self, _params: Params) -> Result<Value, Error> {
let version = version_data();
to_value(&Bytes::new(version))
fn default_extra_data(&self, params: Params) -> Result<Value, Error> {
match params {
Params::None => to_value(&Bytes::new(version_data())),
_ => Err(Error::invalid_params()),
}
}
fn gas_price_statistics(&self, params: Params) -> Result<Value, Error> {
match params {
Params::None => match take_weak!(self.client).gas_price_statistics(100, 8) {
Ok(stats) => to_value(&stats
.iter()
.map(|x| to_value(&x).expect("x must be U256; qed"))
.collect::<Vec<_>>()),
_ => Err(Error::internal_error()),
},
_ => Err(Error::invalid_params()),
}
}
}

View File

@@ -20,6 +20,7 @@ use jsonrpc_core::IoHandler;
use v1::{Ethcore, EthcoreClient, EthcoreSet, EthcoreSetClient};
use ethcore::miner::MinerService;
use v1::tests::helpers::TestMinerService;
use ethcore::client::{TestBlockChainClient};
use util::numbers::*;
use rustc_serialize::hex::FromHex;
use util::log::RotatingLogger;
@@ -29,6 +30,10 @@ fn miner_service() -> Arc<TestMinerService> {
Arc::new(TestMinerService::default())
}
fn client_service() -> Arc<TestBlockChainClient> {
Arc::new(TestBlockChainClient::default())
}
fn logger() -> Arc<RotatingLogger> {
Arc::new(RotatingLogger::new("rpc=trace".to_owned()))
}
@@ -45,19 +50,20 @@ fn settings() -> Arc<NetworkSettings> {
})
}
fn ethcore_client(miner: &Arc<TestMinerService>) -> EthcoreClient<TestMinerService> {
EthcoreClient::new(&miner, logger(), settings())
fn ethcore_client(client: &Arc<TestBlockChainClient>, miner: &Arc<TestMinerService>) -> EthcoreClient<TestBlockChainClient, TestMinerService> {
EthcoreClient::new(client, miner, logger(), settings())
}
fn ethcore_set_client(miner: &Arc<TestMinerService>) -> EthcoreSetClient<TestMinerService> {
EthcoreSetClient::new(&miner)
EthcoreSetClient::new(miner)
}
#[test]
fn rpc_ethcore_extra_data() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_extraData", "params": [], "id": 1}"#;
@@ -72,8 +78,9 @@ fn rpc_ethcore_default_extra_data() {
use util::ToPretty;
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_defaultExtraData", "params": [], "id": 1}"#;
@@ -85,8 +92,9 @@ fn rpc_ethcore_default_extra_data() {
#[test]
fn rpc_ethcore_gas_floor_target() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_gasFloorTarget", "params": [], "id": 1}"#;
@@ -98,8 +106,9 @@ fn rpc_ethcore_gas_floor_target() {
#[test]
fn rpc_ethcore_min_gas_price() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_minGasPrice", "params": [], "id": 1}"#;
@@ -111,8 +120,9 @@ fn rpc_ethcore_min_gas_price() {
#[test]
fn rpc_ethcore_set_min_gas_price() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
@@ -125,8 +135,9 @@ fn rpc_ethcore_set_min_gas_price() {
#[test]
fn rpc_ethcore_set_gas_floor_target() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setGasFloorTarget", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
@@ -139,8 +150,9 @@ fn rpc_ethcore_set_gas_floor_target() {
#[test]
fn rpc_ethcore_set_extra_data() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setExtraData", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
@@ -153,8 +165,9 @@ fn rpc_ethcore_set_extra_data() {
#[test]
fn rpc_ethcore_set_author() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setAuthor", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
@@ -167,10 +180,11 @@ fn rpc_ethcore_set_author() {
#[test]
fn rpc_ethcore_dev_logs() {
let miner = miner_service();
let client = client_service();
let logger = logger();
logger.append("a".to_owned());
logger.append("b".to_owned());
let ethcore = EthcoreClient::new(&miner, logger.clone(), settings()).to_delegate();
let ethcore = EthcoreClient::new(&client, &miner, logger.clone(), settings()).to_delegate();
let io = IoHandler::new();
io.add_delegate(ethcore);
io.add_delegate(ethcore_set_client(&miner).to_delegate());
@@ -184,8 +198,9 @@ fn rpc_ethcore_dev_logs() {
#[test]
fn rpc_ethcore_dev_logs_levels() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_devLogsLevels", "params":[], "id": 1}"#;
@@ -196,8 +211,9 @@ fn rpc_ethcore_dev_logs_levels() {
#[test]
fn rpc_ethcore_set_transactions_limit() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setTransactionsLimit", "params":[10240240], "id": 1}"#;
@@ -210,8 +226,9 @@ fn rpc_ethcore_set_transactions_limit() {
#[test]
fn rpc_ethcore_transactions_limit() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_transactionsLimit", "params":[], "id": 1}"#;
@@ -223,8 +240,9 @@ fn rpc_ethcore_transactions_limit() {
#[test]
fn rpc_ethcore_net_chain() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netChain", "params":[], "id": 1}"#;
@@ -236,8 +254,9 @@ fn rpc_ethcore_net_chain() {
#[test]
fn rpc_ethcore_net_max_peers() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netMaxPeers", "params":[], "id": 1}"#;
@@ -249,8 +268,9 @@ fn rpc_ethcore_net_max_peers() {
#[test]
fn rpc_ethcore_net_port() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPort", "params":[], "id": 1}"#;
@@ -262,8 +282,9 @@ fn rpc_ethcore_net_port() {
#[test]
fn rpc_ethcore_rpc_settings() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_rpcSettings", "params":[], "id": 1}"#;
@@ -275,8 +296,9 @@ fn rpc_ethcore_rpc_settings() {
#[test]
fn rpc_ethcore_node_name() {
let miner = miner_service();
let client = client_service();
let io = IoHandler::new();
io.add_delegate(ethcore_client(&miner).to_delegate());
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
io.add_delegate(ethcore_set_client(&miner).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_nodeName", "params":[], "id": 1}"#;

View File

@@ -57,6 +57,9 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
/// Returns default extra data
fn default_extra_data(&self, _: Params) -> Result<Value, Error>;
/// Returns distribution of gas price in latest blocks.
fn gas_price_statistics(&self, _: Params) -> Result<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {
let mut delegate = IoDelegate::new(Arc::new(self));
@@ -73,6 +76,7 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
delegate.add_method("ethcore_rpcSettings", Ethcore::rpc_settings);
delegate.add_method("ethcore_nodeName", Ethcore::node_name);
delegate.add_method("ethcore_defaultExtraData", Ethcore::default_extra_data);
delegate.add_method("ethcore_gasPriceStatistics", Ethcore::gas_price_statistics);
delegate
}