From 88b03580ff855749114ecbc42302016f5fc0763d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jun 2016 12:44:08 +0200 Subject: [PATCH] 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. --- ethcore/res/null.json | 33 +++++++++++ ethcore/src/client/client.rs | 3 +- ethcore/src/client/mod.rs | 28 +++++++++ ethcore/src/spec/spec.rs | 5 ++ ethcore/src/tests/client.rs | 12 ++++ ethcore/src/tests/helpers.rs | 75 +++++++++++++++++++----- ethcore/src/verification/verification.rs | 2 +- parity/rpc_apis.rs | 2 +- rpc/src/v1/impls/eth.rs | 14 ++++- rpc/src/v1/impls/ethcore.rs | 37 +++++++++--- rpc/src/v1/tests/mocked/ethcore.rs | 62 +++++++++++++------- rpc/src/v1/traits/ethcore.rs | 4 ++ 12 files changed, 225 insertions(+), 52 deletions(-) create mode 100644 ethcore/res/null.json diff --git a/ethcore/res/null.json b/ethcore/res/null.json new file mode 100644 index 000000000..b9b2b1260 --- /dev/null +++ b/ethcore/res/null.json @@ -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" } + } +} diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 75a60204f..85a3d693d 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -770,8 +770,7 @@ impl MiningBlockChainClient for Client 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 diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index dbd09ea4a..3fec68815 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -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; + + /// Get the gas price distribution. + fn gas_price_statistics(&self, sample_size: usize, distribution_size: usize) -> Result, ()> { + 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::>() + ) + } else { + Err(()) + } + } } /// Extended client interface used for mining diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 743f1bd9b..02b311b24 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -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)] diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index d87b41b62..a5459035e 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -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); diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 3b27ef4a4..151d53bba 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -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> { + 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> { + 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(get_test_spec: F, block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> GuardedTempResult> 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()); diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 6511a8ddd..c6b75416b 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -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); diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index d9085fc31..f4b2d067f 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -159,7 +159,7 @@ pub fn setup_rpc(server: T, deps: Arc, 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()) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 2d337e73c..80245708f 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -153,15 +153,23 @@ impl EthClient where } } + fn default_gas_price(&self) -> Result { + 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 { 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 Eth for EthClient where fn gas_price(&self, params: Params) -> Result { 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()) } } diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs index b3fe894c6..e77f46f5d 100644 --- a/rpc/src/v1/impls/ethcore.rs +++ b/rpc/src/v1/impls/ethcore.rs @@ -15,30 +15,34 @@ // along with Parity. If not, see . //! 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 where +pub struct EthcoreClient where + C: MiningBlockChainClient, M: MinerService { + client: Weak, miner: Weak, logger: Arc, settings: Arc, } -impl EthcoreClient where M: MinerService { +impl EthcoreClient where C: MiningBlockChainClient, M: MinerService { /// Creates new `EthcoreClient`. - pub fn new(miner: &Arc, logger: Arc, settings: Arc) -> Self { + pub fn new(client: &Arc, miner: &Arc, logger: Arc, settings: Arc) -> Self { EthcoreClient { + client: Arc::downgrade(client), miner: Arc::downgrade(miner), logger: logger, settings: settings, @@ -46,7 +50,7 @@ impl EthcoreClient where M: MinerService { } } -impl Ethcore for EthcoreClient where M: MinerService + 'static { +impl Ethcore for EthcoreClient where M: MinerService + 'static, C: MiningBlockChainClient + 'static { fn transactions_limit(&self, _: Params) -> Result { to_value(&take_weak!(self.miner).transactions_limit()) @@ -97,8 +101,23 @@ impl Ethcore for EthcoreClient where M: MinerService + 'static { Ok(Value::Object(map)) } - fn default_extra_data(&self, _params: Params) -> Result { - let version = version_data(); - to_value(&Bytes::new(version)) + fn default_extra_data(&self, params: Params) -> Result { + match params { + Params::None => to_value(&Bytes::new(version_data())), + _ => Err(Error::invalid_params()), + } + } + + fn gas_price_statistics(&self, params: Params) -> Result { + 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::>()), + _ => Err(Error::internal_error()), + }, + _ => Err(Error::invalid_params()), + } } } diff --git a/rpc/src/v1/tests/mocked/ethcore.rs b/rpc/src/v1/tests/mocked/ethcore.rs index 90103adef..68c33ecce 100644 --- a/rpc/src/v1/tests/mocked/ethcore.rs +++ b/rpc/src/v1/tests/mocked/ethcore.rs @@ -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 { Arc::new(TestMinerService::default()) } +fn client_service() -> Arc { + Arc::new(TestBlockChainClient::default()) +} + fn logger() -> Arc { Arc::new(RotatingLogger::new("rpc=trace".to_owned())) } @@ -45,19 +50,20 @@ fn settings() -> Arc { }) } -fn ethcore_client(miner: &Arc) -> EthcoreClient { - EthcoreClient::new(&miner, logger(), settings()) +fn ethcore_client(client: &Arc, miner: &Arc) -> EthcoreClient { + EthcoreClient::new(client, miner, logger(), settings()) } fn ethcore_set_client(miner: &Arc) -> EthcoreSetClient { - 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}"#; diff --git a/rpc/src/v1/traits/ethcore.rs b/rpc/src/v1/traits/ethcore.rs index 4ce3eca59..1dd00ff73 100644 --- a/rpc/src/v1/traits/ethcore.rs +++ b/rpc/src/v1/traits/ethcore.rs @@ -57,6 +57,9 @@ pub trait Ethcore: Sized + Send + Sync + 'static { /// Returns default extra data fn default_extra_data(&self, _: Params) -> Result; + /// Returns distribution of gas price in latest blocks. + fn gas_price_statistics(&self, _: Params) -> Result; + /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { 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 }