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

33
ethcore/res/null.json Normal file
View File

@ -0,0 +1,33 @@
{
"name": "Morden",
"engine": {
"Null": null
},
"params": {
"accountStartNonce": "0x0",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x00006d6f7264656e",
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578"
}
},
"difficulty": "0x20000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2fefd8"
},
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "0", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "0", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "0", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "0", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "0" }
}
}

View File

@ -770,8 +770,7 @@ impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
author,
gas_floor_target,
extra_data,
).expect("OpenBlock::new only fails if parent state root invalid. State root of best block's header is never invalid. \
Therefore creating an OpenBlock with the best block's header will not fail.");
).expect("OpenBlock::new only fails if parent state root invalid; state root of best block's header is never invalid; qed");
// Add uncles
self.chain

View File

@ -34,6 +34,7 @@ pub use env_info::{LastHashes, EnvInfo};
use util::bytes::Bytes;
use util::hash::{Address, H256, H2048};
use util::numbers::U256;
use util::Itertools;
use blockchain::TreeRoute;
use block_queue::BlockQueueInfo;
use block::OpenBlock;
@ -41,6 +42,7 @@ use header::{BlockNumber, Header};
use transaction::{LocalizedTransaction, SignedTransaction};
use log_entry::LocalizedLogEntry;
use filter::Filter;
use views::BlockView;
use error::{ImportResult, ExecutionError};
use receipt::LocalizedReceipt;
use trace::LocalizedTrace;
@ -193,6 +195,32 @@ pub trait BlockChainClient : Sync + Send {
/// list all transactions
fn all_transactions(&self) -> Vec<SignedTransaction>;
/// Get the gas price distribution.
fn gas_price_statistics(&self, sample_size: usize, distribution_size: usize) -> Result<Vec<U256>, ()> {
let mut h = self.chain_info().best_block_hash;
let mut corpus = Vec::new();
for _ in 0..sample_size {
let block_bytes = self.block(BlockID::Hash(h)).expect("h is either the best_block_hash or an ancestor; qed");
let block = BlockView::new(&block_bytes);
let header = block.header_view();
if header.number() == 0 {
break;
}
block.transaction_views().iter().foreach(|t| corpus.push(t.gas_price()));
h = header.parent_hash().clone();
}
corpus.sort();
let n = corpus.len();
if n > 0 {
Ok((0..(distribution_size + 1))
.map(|i| corpus[i * (n - 1) / distribution_size])
.collect::<Vec<_>>()
)
} else {
Err(())
}
}
}
/// Extended client interface used for mining

View File

@ -244,6 +244,11 @@ impl Spec {
pub fn new_test() -> Spec {
Spec::load(include_bytes!("../../res/null_morden.json"))
}
/// Create a new Spec which is a NullEngine consensus with a premine of address whose secret is sha3('').
pub fn new_null() -> Spec {
Spec::load(include_bytes!("../../res/null.json"))
}
}
#[cfg(test)]

View File

@ -112,6 +112,18 @@ fn can_collect_garbage() {
assert!(client.blockchain_cache_info().blocks < 100 * 1024);
}
#[test]
fn can_generate_gas_price_statistics() {
let client_result = generate_dummy_client_with_data(16, 1, &vec_into![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
let client = client_result.reference();
let s = client.gas_price_statistics(8, 8).unwrap();
assert_eq!(s, vec_into![8, 8, 9, 10, 11, 12, 13, 14, 15]);
let s = client.gas_price_statistics(16, 8).unwrap();
assert_eq!(s, vec_into![0, 1, 3, 5, 7, 9, 11, 13, 15]);
let s = client.gas_price_statistics(32, 8).unwrap();
assert_eq!(s, vec_into![0, 1, 3, 5, 7, 9, 11, 13, 15]);
}
#[test]
fn can_handle_long_fork() {
let client_result = generate_dummy_client(1200);

View File

@ -17,6 +17,7 @@
use client::{BlockChainClient, Client, ClientConfig};
use common::*;
use spec::*;
use block::{OpenBlock};
use blockchain::{BlockChain, Config as BlockChainConfig};
use state::*;
use evm::Schedule;
@ -85,6 +86,7 @@ impl Engine for TestEngine {
}
}
// TODO: move everything over to get_null_spec.
pub fn get_test_spec() -> Spec {
Spec::new_test()
}
@ -126,7 +128,7 @@ fn create_unverifiable_block(order: u32, parent_hash: H256) -> Bytes {
create_test_block(&create_unverifiable_block_header(order, parent_hash))
}
pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTransaction], uncles: &[Header]) -> Bytes {
pub fn create_test_block_with_data(header: &Header, transactions: &[SignedTransaction], uncles: &[Header]) -> Bytes {
let mut rlp = RlpStream::new_list(3);
rlp.append(header);
rlp.begin_list(transactions.len());
@ -138,33 +140,74 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTrans
}
pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult<Arc<Client>> {
generate_dummy_client_with_spec_and_data(Spec::new_test, block_number, 0, &(vec![]))
}
pub fn generate_dummy_client_with_data(block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> GuardedTempResult<Arc<Client>> {
generate_dummy_client_with_spec_and_data(Spec::new_null, block_number, txs_per_block, tx_gas_prices)
}
pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> GuardedTempResult<Arc<Client>> where F: Fn()->Spec {
let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
let test_spec = get_test_spec();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
let test_engine = &test_spec.engine;
let state_root = test_spec.genesis_header().state_root;
let mut rolling_hash = test_spec.genesis_header().hash();
let mut rolling_block_number = 1;
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
test_spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default();
let genesis_header = test_spec.genesis_header();
let mut rolling_timestamp = 40;
let mut last_hashes = vec![];
let mut last_header = genesis_header.clone();
let kp = KeyPair::from_secret("".sha3()).unwrap() ;
let author = kp.address();
let mut n = 0;
for _ in 0..block_number {
let mut header = Header::new();
last_hashes.push(last_header.hash());
header.gas_limit = test_engine.params().min_gas_limit;
header.difficulty = U256::from(0x20000);
header.timestamp = rolling_timestamp;
header.number = rolling_block_number;
header.parent_hash = rolling_hash;
header.state_root = state_root.clone();
// forge block.
let mut b = OpenBlock::new(
test_engine.deref(),
&vm_factory,
false,
db,
&last_header,
last_hashes.clone(),
author.clone(),
3141562.into(),
vec![]
).unwrap();
b.set_difficulty(U256::from(0x20000));
rolling_timestamp += 10;
b.set_timestamp(rolling_timestamp);
rolling_hash = header.hash();
rolling_block_number = rolling_block_number + 1;
rolling_timestamp = rolling_timestamp + 10;
// first block we don't have any balance, so can't send any transactions.
for _ in 0..txs_per_block {
b.push_transaction(Transaction {
nonce: n.into(),
gas_price: tx_gas_prices[n % tx_gas_prices.len()],
gas: 100000.into(),
action: Action::Create,
data: vec![],
value: U256::zero(),
}.sign(kp.secret()), None).unwrap();
n += 1;
}
if let Err(e) = client.import_block(create_test_block(&header)) {
let b = b.close_and_lock().seal(test_engine.deref(), vec![]).unwrap();
if let Err(e) = client.import_block(b.rlp_bytes()) {
panic!("error importing block which is valid by definition: {:?}", e);
}
last_header = BlockView::new(&b.rlp_bytes()).header();
db = b.drain();
}
client.flush_queue();
client.import_verified_blocks(&IoChannel::disconnected());

View File

@ -361,7 +361,7 @@ mod tests {
nonce: U256::from(2)
}.sign(&keypair.secret());
let good_transactions = [ &tr1, &tr2 ];
let good_transactions = [ tr1.clone(), tr2.clone() ];
let diff_inc = U256::from(0x40);

View File

@ -159,7 +159,7 @@ pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet
server.add_delegate(SignerClient::new(&deps.secret_store, &deps.client, &deps.miner, &deps.signer_queue).to_delegate());
},
Api::Ethcore => {
server.add_delegate(EthcoreClient::new(&deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate())
server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate())
},
Api::EthcoreSet => {
server.add_delegate(EthcoreSetClient::new(&deps.miner).to_delegate())

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
}