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:
parent
1e9da1e0fa
commit
88b03580ff
33
ethcore/res/null.json
Normal file
33
ethcore/res/null.json
Normal 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" }
|
||||||
|
}
|
||||||
|
}
|
@ -770,8 +770,7 @@ impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
|
|||||||
author,
|
author,
|
||||||
gas_floor_target,
|
gas_floor_target,
|
||||||
extra_data,
|
extra_data,
|
||||||
).expect("OpenBlock::new only fails if parent state root invalid. State root of best block's header is never invalid. \
|
).expect("OpenBlock::new only fails if parent state root invalid; state root of best block's header is never invalid; qed");
|
||||||
Therefore creating an OpenBlock with the best block's header will not fail.");
|
|
||||||
|
|
||||||
// Add uncles
|
// Add uncles
|
||||||
self.chain
|
self.chain
|
||||||
|
@ -34,6 +34,7 @@ pub use env_info::{LastHashes, EnvInfo};
|
|||||||
use util::bytes::Bytes;
|
use util::bytes::Bytes;
|
||||||
use util::hash::{Address, H256, H2048};
|
use util::hash::{Address, H256, H2048};
|
||||||
use util::numbers::U256;
|
use util::numbers::U256;
|
||||||
|
use util::Itertools;
|
||||||
use blockchain::TreeRoute;
|
use blockchain::TreeRoute;
|
||||||
use block_queue::BlockQueueInfo;
|
use block_queue::BlockQueueInfo;
|
||||||
use block::OpenBlock;
|
use block::OpenBlock;
|
||||||
@ -41,6 +42,7 @@ use header::{BlockNumber, Header};
|
|||||||
use transaction::{LocalizedTransaction, SignedTransaction};
|
use transaction::{LocalizedTransaction, SignedTransaction};
|
||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
|
use views::BlockView;
|
||||||
use error::{ImportResult, ExecutionError};
|
use error::{ImportResult, ExecutionError};
|
||||||
use receipt::LocalizedReceipt;
|
use receipt::LocalizedReceipt;
|
||||||
use trace::LocalizedTrace;
|
use trace::LocalizedTrace;
|
||||||
@ -193,6 +195,32 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
|
|
||||||
/// list all transactions
|
/// list all transactions
|
||||||
fn all_transactions(&self) -> Vec<SignedTransaction>;
|
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
|
/// Extended client interface used for mining
|
||||||
|
@ -244,6 +244,11 @@ impl Spec {
|
|||||||
pub fn new_test() -> Spec {
|
pub fn new_test() -> Spec {
|
||||||
Spec::load(include_bytes!("../../res/null_morden.json"))
|
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)]
|
#[cfg(test)]
|
||||||
|
@ -112,6 +112,18 @@ fn can_collect_garbage() {
|
|||||||
assert!(client.blockchain_cache_info().blocks < 100 * 1024);
|
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]
|
#[test]
|
||||||
fn can_handle_long_fork() {
|
fn can_handle_long_fork() {
|
||||||
let client_result = generate_dummy_client(1200);
|
let client_result = generate_dummy_client(1200);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
use client::{BlockChainClient, Client, ClientConfig};
|
use client::{BlockChainClient, Client, ClientConfig};
|
||||||
use common::*;
|
use common::*;
|
||||||
use spec::*;
|
use spec::*;
|
||||||
|
use block::{OpenBlock};
|
||||||
use blockchain::{BlockChain, Config as BlockChainConfig};
|
use blockchain::{BlockChain, Config as BlockChainConfig};
|
||||||
use state::*;
|
use state::*;
|
||||||
use evm::Schedule;
|
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 {
|
pub fn get_test_spec() -> Spec {
|
||||||
Spec::new_test()
|
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))
|
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);
|
let mut rlp = RlpStream::new_list(3);
|
||||||
rlp.append(header);
|
rlp.append(header);
|
||||||
rlp.begin_list(transactions.len());
|
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>> {
|
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 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 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 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 db_result = get_temp_journal_db();
|
||||||
let mut rolling_block_number = 1;
|
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 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 {
|
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;
|
// forge block.
|
||||||
header.difficulty = U256::from(0x20000);
|
let mut b = OpenBlock::new(
|
||||||
header.timestamp = rolling_timestamp;
|
test_engine.deref(),
|
||||||
header.number = rolling_block_number;
|
&vm_factory,
|
||||||
header.parent_hash = rolling_hash;
|
false,
|
||||||
header.state_root = state_root.clone();
|
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();
|
// first block we don't have any balance, so can't send any transactions.
|
||||||
rolling_block_number = rolling_block_number + 1;
|
for _ in 0..txs_per_block {
|
||||||
rolling_timestamp = rolling_timestamp + 10;
|
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);
|
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.flush_queue();
|
||||||
client.import_verified_blocks(&IoChannel::disconnected());
|
client.import_verified_blocks(&IoChannel::disconnected());
|
||||||
|
@ -361,7 +361,7 @@ mod tests {
|
|||||||
nonce: U256::from(2)
|
nonce: U256::from(2)
|
||||||
}.sign(&keypair.secret());
|
}.sign(&keypair.secret());
|
||||||
|
|
||||||
let good_transactions = [ &tr1, &tr2 ];
|
let good_transactions = [ tr1.clone(), tr2.clone() ];
|
||||||
|
|
||||||
let diff_inc = U256::from(0x40);
|
let diff_inc = U256::from(0x40);
|
||||||
|
|
||||||
|
@ -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());
|
server.add_delegate(SignerClient::new(&deps.secret_store, &deps.client, &deps.miner, &deps.signer_queue).to_delegate());
|
||||||
},
|
},
|
||||||
Api::Ethcore => {
|
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 => {
|
Api::EthcoreSet => {
|
||||||
server.add_delegate(EthcoreSetClient::new(&deps.miner).to_delegate())
|
server.add_delegate(EthcoreSetClient::new(&deps.miner).to_delegate())
|
||||||
|
@ -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> {
|
fn sign_call(&self, request: CallRequest) -> Result<SignedTransaction, Error> {
|
||||||
let client = take_weak!(self.client);
|
let client = take_weak!(self.client);
|
||||||
let miner = take_weak!(self.miner);
|
|
||||||
let from = request.from.unwrap_or(Address::zero());
|
let from = request.from.unwrap_or(Address::zero());
|
||||||
Ok(EthTransaction {
|
Ok(EthTransaction {
|
||||||
nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)),
|
nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)),
|
||||||
action: request.to.map_or(Action::Create, Action::Call),
|
action: request.to.map_or(Action::Create, Action::Call),
|
||||||
gas: request.gas.unwrap_or(U256::from(50_000_000)),
|
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),
|
value: request.value.unwrap_or_else(U256::zero),
|
||||||
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
|
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
|
||||||
}.fake_sign(from))
|
}.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> {
|
fn gas_price(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
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())
|
_ => Err(Error::invalid_params())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,30 +15,34 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Ethcore-specific rpc implementation.
|
//! Ethcore-specific rpc implementation.
|
||||||
use util::RotatingLogger;
|
use util::{RotatingLogger};
|
||||||
use util::network_settings::NetworkSettings;
|
use util::network_settings::NetworkSettings;
|
||||||
use util::misc::version_data;
|
use util::misc::version_data;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::{BTreeMap};
|
||||||
|
use ethcore::client::{MiningBlockChainClient};
|
||||||
use jsonrpc_core::*;
|
use jsonrpc_core::*;
|
||||||
use ethcore::miner::MinerService;
|
use ethcore::miner::MinerService;
|
||||||
use v1::traits::Ethcore;
|
use v1::traits::Ethcore;
|
||||||
use v1::types::{Bytes};
|
use v1::types::{Bytes};
|
||||||
|
|
||||||
/// Ethcore implementation.
|
/// Ethcore implementation.
|
||||||
pub struct EthcoreClient<M> where
|
pub struct EthcoreClient<C, M> where
|
||||||
|
C: MiningBlockChainClient,
|
||||||
M: MinerService {
|
M: MinerService {
|
||||||
|
|
||||||
|
client: Weak<C>,
|
||||||
miner: Weak<M>,
|
miner: Weak<M>,
|
||||||
logger: Arc<RotatingLogger>,
|
logger: Arc<RotatingLogger>,
|
||||||
settings: Arc<NetworkSettings>,
|
settings: Arc<NetworkSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> EthcoreClient<M> where M: MinerService {
|
impl<C, M> EthcoreClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
||||||
/// Creates new `EthcoreClient`.
|
/// 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 {
|
EthcoreClient {
|
||||||
|
client: Arc::downgrade(client),
|
||||||
miner: Arc::downgrade(miner),
|
miner: Arc::downgrade(miner),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
settings: settings,
|
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> {
|
fn transactions_limit(&self, _: Params) -> Result<Value, Error> {
|
||||||
to_value(&take_weak!(self.miner).transactions_limit())
|
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))
|
Ok(Value::Object(map))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_extra_data(&self, _params: Params) -> Result<Value, Error> {
|
fn default_extra_data(&self, params: Params) -> Result<Value, Error> {
|
||||||
let version = version_data();
|
match params {
|
||||||
to_value(&Bytes::new(version))
|
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()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ use jsonrpc_core::IoHandler;
|
|||||||
use v1::{Ethcore, EthcoreClient, EthcoreSet, EthcoreSetClient};
|
use v1::{Ethcore, EthcoreClient, EthcoreSet, EthcoreSetClient};
|
||||||
use ethcore::miner::MinerService;
|
use ethcore::miner::MinerService;
|
||||||
use v1::tests::helpers::TestMinerService;
|
use v1::tests::helpers::TestMinerService;
|
||||||
|
use ethcore::client::{TestBlockChainClient};
|
||||||
use util::numbers::*;
|
use util::numbers::*;
|
||||||
use rustc_serialize::hex::FromHex;
|
use rustc_serialize::hex::FromHex;
|
||||||
use util::log::RotatingLogger;
|
use util::log::RotatingLogger;
|
||||||
@ -29,6 +30,10 @@ fn miner_service() -> Arc<TestMinerService> {
|
|||||||
Arc::new(TestMinerService::default())
|
Arc::new(TestMinerService::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn client_service() -> Arc<TestBlockChainClient> {
|
||||||
|
Arc::new(TestBlockChainClient::default())
|
||||||
|
}
|
||||||
|
|
||||||
fn logger() -> Arc<RotatingLogger> {
|
fn logger() -> Arc<RotatingLogger> {
|
||||||
Arc::new(RotatingLogger::new("rpc=trace".to_owned()))
|
Arc::new(RotatingLogger::new("rpc=trace".to_owned()))
|
||||||
}
|
}
|
||||||
@ -45,19 +50,20 @@ fn settings() -> Arc<NetworkSettings> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ethcore_client(miner: &Arc<TestMinerService>) -> EthcoreClient<TestMinerService> {
|
fn ethcore_client(client: &Arc<TestBlockChainClient>, miner: &Arc<TestMinerService>) -> EthcoreClient<TestBlockChainClient, TestMinerService> {
|
||||||
EthcoreClient::new(&miner, logger(), settings())
|
EthcoreClient::new(client, miner, logger(), settings())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ethcore_set_client(miner: &Arc<TestMinerService>) -> EthcoreSetClient<TestMinerService> {
|
fn ethcore_set_client(miner: &Arc<TestMinerService>) -> EthcoreSetClient<TestMinerService> {
|
||||||
EthcoreSetClient::new(&miner)
|
EthcoreSetClient::new(miner)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_extra_data() {
|
fn rpc_ethcore_extra_data() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_extraData", "params": [], "id": 1}"#;
|
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;
|
use util::ToPretty;
|
||||||
|
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_defaultExtraData", "params": [], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_defaultExtraData", "params": [], "id": 1}"#;
|
||||||
@ -85,8 +92,9 @@ fn rpc_ethcore_default_extra_data() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_gas_floor_target() {
|
fn rpc_ethcore_gas_floor_target() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_gasFloorTarget", "params": [], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_gasFloorTarget", "params": [], "id": 1}"#;
|
||||||
@ -98,8 +106,9 @@ fn rpc_ethcore_gas_floor_target() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_min_gas_price() {
|
fn rpc_ethcore_min_gas_price() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_minGasPrice", "params": [], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_minGasPrice", "params": [], "id": 1}"#;
|
||||||
@ -111,8 +120,9 @@ fn rpc_ethcore_min_gas_price() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_set_min_gas_price() {
|
fn rpc_ethcore_set_min_gas_price() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
|
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]
|
#[test]
|
||||||
fn rpc_ethcore_set_gas_floor_target() {
|
fn rpc_ethcore_set_gas_floor_target() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setGasFloorTarget", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
|
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]
|
#[test]
|
||||||
fn rpc_ethcore_set_extra_data() {
|
fn rpc_ethcore_set_extra_data() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setExtraData", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setExtraData", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
|
||||||
@ -153,8 +165,9 @@ fn rpc_ethcore_set_extra_data() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_set_author() {
|
fn rpc_ethcore_set_author() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setAuthor", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setAuthor", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
|
||||||
@ -167,10 +180,11 @@ fn rpc_ethcore_set_author() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_dev_logs() {
|
fn rpc_ethcore_dev_logs() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let logger = logger();
|
let logger = logger();
|
||||||
logger.append("a".to_owned());
|
logger.append("a".to_owned());
|
||||||
logger.append("b".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();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(ethcore);
|
io.add_delegate(ethcore);
|
||||||
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
@ -184,8 +198,9 @@ fn rpc_ethcore_dev_logs() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_dev_logs_levels() {
|
fn rpc_ethcore_dev_logs_levels() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_devLogsLevels", "params":[], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_devLogsLevels", "params":[], "id": 1}"#;
|
||||||
@ -196,8 +211,9 @@ fn rpc_ethcore_dev_logs_levels() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_set_transactions_limit() {
|
fn rpc_ethcore_set_transactions_limit() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setTransactionsLimit", "params":[10240240], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setTransactionsLimit", "params":[10240240], "id": 1}"#;
|
||||||
@ -210,8 +226,9 @@ fn rpc_ethcore_set_transactions_limit() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_transactions_limit() {
|
fn rpc_ethcore_transactions_limit() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_transactionsLimit", "params":[], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_transactionsLimit", "params":[], "id": 1}"#;
|
||||||
@ -223,8 +240,9 @@ fn rpc_ethcore_transactions_limit() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_net_chain() {
|
fn rpc_ethcore_net_chain() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netChain", "params":[], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netChain", "params":[], "id": 1}"#;
|
||||||
@ -236,8 +254,9 @@ fn rpc_ethcore_net_chain() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_net_max_peers() {
|
fn rpc_ethcore_net_max_peers() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netMaxPeers", "params":[], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netMaxPeers", "params":[], "id": 1}"#;
|
||||||
@ -249,8 +268,9 @@ fn rpc_ethcore_net_max_peers() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_net_port() {
|
fn rpc_ethcore_net_port() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPort", "params":[], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPort", "params":[], "id": 1}"#;
|
||||||
@ -262,8 +282,9 @@ fn rpc_ethcore_net_port() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_rpc_settings() {
|
fn rpc_ethcore_rpc_settings() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_rpcSettings", "params":[], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_rpcSettings", "params":[], "id": 1}"#;
|
||||||
@ -275,8 +296,9 @@ fn rpc_ethcore_rpc_settings() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_node_name() {
|
fn rpc_ethcore_node_name() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
let client = client_service();
|
||||||
let io = IoHandler::new();
|
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());
|
io.add_delegate(ethcore_set_client(&miner).to_delegate());
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_nodeName", "params":[], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_nodeName", "params":[], "id": 1}"#;
|
||||||
|
@ -57,6 +57,9 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
|
|||||||
/// Returns default extra data
|
/// Returns default extra data
|
||||||
fn default_extra_data(&self, _: Params) -> Result<Value, Error>;
|
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.
|
/// Should be used to convert object to io delegate.
|
||||||
fn to_delegate(self) -> IoDelegate<Self> {
|
fn to_delegate(self) -> IoDelegate<Self> {
|
||||||
let mut delegate = IoDelegate::new(Arc::new(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_rpcSettings", Ethcore::rpc_settings);
|
||||||
delegate.add_method("ethcore_nodeName", Ethcore::node_name);
|
delegate.add_method("ethcore_nodeName", Ethcore::node_name);
|
||||||
delegate.add_method("ethcore_defaultExtraData", Ethcore::default_extra_data);
|
delegate.add_method("ethcore_defaultExtraData", Ethcore::default_extra_data);
|
||||||
|
delegate.add_method("ethcore_gasPriceStatistics", Ethcore::gas_price_statistics);
|
||||||
|
|
||||||
delegate
|
delegate
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user