2017-01-25 18:51:41 +01:00
|
|
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
2016-03-13 17:01:50 +01:00
|
|
|
// This file is part of Parity.
|
|
|
|
|
|
|
|
// Parity is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
|
|
|
// Parity is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2016-03-18 19:16:46 +01:00
|
|
|
//! Test implementation of miner service.
|
|
|
|
|
2016-07-13 19:59:59 +02:00
|
|
|
use util::{Address, H256, Bytes, U256, FixedHash, Uint};
|
2016-03-13 17:01:50 +01:00
|
|
|
use util::standard::*;
|
2016-08-04 18:17:21 +02:00
|
|
|
use ethcore::error::{Error, CallError};
|
2016-06-02 12:28:09 +02:00
|
|
|
use ethcore::client::{MiningBlockChainClient, Executed, CallAnalytics};
|
2016-04-28 21:47:44 +02:00
|
|
|
use ethcore::block::{ClosedBlock, IsBlock};
|
2016-10-07 12:13:15 +02:00
|
|
|
use ethcore::header::BlockNumber;
|
2017-01-13 09:51:36 +01:00
|
|
|
use ethcore::transaction::{UnverifiedTransaction, SignedTransaction, PendingTransaction};
|
2016-08-17 19:25:02 +02:00
|
|
|
use ethcore::receipt::{Receipt, RichReceipt};
|
2016-11-16 17:54:54 +01:00
|
|
|
use ethcore::miner::{MinerService, MinerStatus, TransactionImportResult, LocalTransactionStatus};
|
2016-12-05 18:08:16 +01:00
|
|
|
use ethcore::account_provider::Error as AccountError;
|
2016-03-13 17:01:50 +01:00
|
|
|
|
2016-03-18 19:16:46 +01:00
|
|
|
/// Test miner service.
|
2016-03-16 10:37:08 +01:00
|
|
|
pub struct TestMinerService {
|
2016-03-18 19:16:46 +01:00
|
|
|
/// Imported transactions.
|
2016-04-06 12:15:20 +02:00
|
|
|
pub imported_transactions: Mutex<Vec<SignedTransaction>>,
|
2016-03-18 19:16:46 +01:00
|
|
|
/// Latest closed block.
|
2016-03-16 10:37:08 +01:00
|
|
|
pub latest_closed_block: Mutex<Option<ClosedBlock>>,
|
2016-03-27 16:16:15 +02:00
|
|
|
/// Pre-existed pending transactions
|
|
|
|
pub pending_transactions: Mutex<HashMap<H256, SignedTransaction>>,
|
2016-11-16 17:54:54 +01:00
|
|
|
/// Pre-existed local transactions
|
|
|
|
pub local_transactions: Mutex<BTreeMap<H256, LocalTransactionStatus>>,
|
2016-05-24 21:56:32 +02:00
|
|
|
/// Pre-existed pending receipts
|
|
|
|
pub pending_receipts: Mutex<BTreeMap<H256, Receipt>>,
|
2016-04-06 12:15:20 +02:00
|
|
|
/// Last nonces.
|
|
|
|
pub last_nonces: RwLock<HashMap<Address, U256>>,
|
2016-12-05 18:08:16 +01:00
|
|
|
/// Password held by Engine.
|
|
|
|
pub password: RwLock<String>,
|
2016-04-13 00:04:40 +02:00
|
|
|
|
|
|
|
min_gas_price: RwLock<U256>,
|
2016-06-23 14:29:16 +02:00
|
|
|
gas_range_target: RwLock<(U256, U256)>,
|
2016-04-13 00:04:40 +02:00
|
|
|
author: RwLock<Address>,
|
|
|
|
extra_data: RwLock<Bytes>,
|
2016-04-18 23:13:38 +02:00
|
|
|
limit: RwLock<usize>,
|
2016-06-28 10:21:29 +02:00
|
|
|
tx_gas_limit: RwLock<U256>,
|
2016-03-16 10:37:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for TestMinerService {
|
|
|
|
fn default() -> TestMinerService {
|
|
|
|
TestMinerService {
|
2016-04-06 12:15:20 +02:00
|
|
|
imported_transactions: Mutex::new(Vec::new()),
|
2016-03-16 10:37:08 +01:00
|
|
|
latest_closed_block: Mutex::new(None),
|
2016-03-27 16:16:15 +02:00
|
|
|
pending_transactions: Mutex::new(HashMap::new()),
|
2016-11-16 17:54:54 +01:00
|
|
|
local_transactions: Mutex::new(BTreeMap::new()),
|
2016-05-24 21:56:32 +02:00
|
|
|
pending_receipts: Mutex::new(BTreeMap::new()),
|
2016-04-06 12:15:20 +02:00
|
|
|
last_nonces: RwLock::new(HashMap::new()),
|
2016-04-13 00:04:40 +02:00
|
|
|
min_gas_price: RwLock::new(U256::from(20_000_000)),
|
2016-06-23 14:29:16 +02:00
|
|
|
gas_range_target: RwLock::new((U256::from(12345), U256::from(54321))),
|
2016-04-13 00:04:40 +02:00
|
|
|
author: RwLock::new(Address::zero()),
|
2016-12-05 18:08:16 +01:00
|
|
|
password: RwLock::new(String::new()),
|
2016-04-13 00:04:40 +02:00
|
|
|
extra_data: RwLock::new(vec![1, 2, 3, 4]),
|
2016-04-18 23:13:38 +02:00
|
|
|
limit: RwLock::new(1024),
|
2016-06-28 10:21:29 +02:00
|
|
|
tx_gas_limit: RwLock::new(!U256::zero()),
|
2016-03-16 10:37:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-13 17:01:50 +01:00
|
|
|
|
|
|
|
impl MinerService for TestMinerService {
|
|
|
|
|
|
|
|
/// Returns miner's status.
|
2016-03-17 11:19:12 +01:00
|
|
|
fn status(&self) -> MinerStatus {
|
|
|
|
MinerStatus {
|
2016-03-17 11:19:12 +01:00
|
|
|
transactions_in_pending_queue: 0,
|
|
|
|
transactions_in_future_queue: 0,
|
|
|
|
transactions_in_pending_block: 1
|
2016-03-17 11:19:12 +01:00
|
|
|
}
|
|
|
|
}
|
2016-03-13 17:01:50 +01:00
|
|
|
|
2016-04-13 00:04:40 +02:00
|
|
|
fn set_author(&self, author: Address) {
|
2016-07-13 19:59:59 +02:00
|
|
|
*self.author.write() = author;
|
2016-04-13 00:04:40 +02:00
|
|
|
}
|
|
|
|
|
2016-12-05 22:31:38 +01:00
|
|
|
fn set_engine_signer(&self, address: Address, password: String) -> Result<(), AccountError> {
|
2016-12-05 18:08:16 +01:00
|
|
|
*self.author.write() = address;
|
|
|
|
*self.password.write() = password;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2016-04-13 00:04:40 +02:00
|
|
|
fn set_extra_data(&self, extra_data: Bytes) {
|
2016-07-13 19:59:59 +02:00
|
|
|
*self.extra_data.write() = extra_data;
|
2016-04-13 00:04:40 +02:00
|
|
|
}
|
|
|
|
|
2016-06-23 14:29:16 +02:00
|
|
|
/// Set the lower gas limit we wish to target when sealing a new block.
|
2016-04-13 00:04:40 +02:00
|
|
|
fn set_gas_floor_target(&self, target: U256) {
|
2016-07-13 19:59:59 +02:00
|
|
|
self.gas_range_target.write().0 = target;
|
2016-06-23 14:29:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the upper gas limit we wish to target when sealing a new block.
|
|
|
|
fn set_gas_ceil_target(&self, target: U256) {
|
2016-07-13 19:59:59 +02:00
|
|
|
self.gas_range_target.write().1 = target;
|
2016-04-13 00:04:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set_minimal_gas_price(&self, min_gas_price: U256) {
|
2016-07-13 19:59:59 +02:00
|
|
|
*self.min_gas_price.write() = min_gas_price;
|
2016-04-13 00:04:40 +02:00
|
|
|
}
|
|
|
|
|
2016-04-18 23:13:38 +02:00
|
|
|
fn set_transactions_limit(&self, limit: usize) {
|
2016-07-13 19:59:59 +02:00
|
|
|
*self.limit.write() = limit;
|
2016-04-18 23:13:38 +02:00
|
|
|
}
|
|
|
|
|
2016-06-28 10:21:29 +02:00
|
|
|
fn set_tx_gas_limit(&self, limit: U256) {
|
2016-07-13 19:59:59 +02:00
|
|
|
*self.tx_gas_limit.write() = limit;
|
2016-06-27 20:19:01 +02:00
|
|
|
}
|
|
|
|
|
2016-04-18 23:13:38 +02:00
|
|
|
fn transactions_limit(&self) -> usize {
|
2016-07-13 19:59:59 +02:00
|
|
|
*self.limit.read()
|
2016-04-18 23:13:38 +02:00
|
|
|
}
|
|
|
|
|
2016-04-13 00:04:40 +02:00
|
|
|
fn author(&self) -> Address {
|
2016-07-13 19:59:59 +02:00
|
|
|
*self.author.read()
|
2016-04-13 00:04:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn minimal_gas_price(&self) -> U256 {
|
2016-07-13 19:59:59 +02:00
|
|
|
*self.min_gas_price.read()
|
2016-04-13 00:04:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn extra_data(&self) -> Bytes {
|
2016-07-13 19:59:59 +02:00
|
|
|
self.extra_data.read().clone()
|
2016-04-13 00:04:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn gas_floor_target(&self) -> U256 {
|
2016-07-13 19:59:59 +02:00
|
|
|
self.gas_range_target.read().0
|
2016-06-23 14:29:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn gas_ceil_target(&self) -> U256 {
|
2016-07-13 19:59:59 +02:00
|
|
|
self.gas_range_target.read().1
|
2016-04-13 00:04:40 +02:00
|
|
|
}
|
|
|
|
|
2016-03-13 17:01:50 +01:00
|
|
|
/// Imports transactions to transaction queue.
|
2017-01-13 09:51:36 +01:00
|
|
|
fn import_external_transactions(&self, _chain: &MiningBlockChainClient, transactions: Vec<UnverifiedTransaction>) ->
|
2016-07-06 17:15:59 +02:00
|
|
|
Vec<Result<TransactionImportResult, Error>> {
|
2016-04-06 12:15:20 +02:00
|
|
|
// lets assume that all txs are valid
|
2017-01-13 09:51:36 +01:00
|
|
|
let transactions: Vec<_> = transactions.into_iter().map(|tx| SignedTransaction::new(tx).unwrap()).collect();
|
2016-07-13 19:59:59 +02:00
|
|
|
self.imported_transactions.lock().extend_from_slice(&transactions);
|
2016-04-06 12:15:20 +02:00
|
|
|
|
2017-01-13 09:51:36 +01:00
|
|
|
for sender in transactions.iter().map(|tx| tx.sender()) {
|
2016-07-06 17:15:59 +02:00
|
|
|
let nonce = self.last_nonce(&sender).expect("last_nonce must be populated in tests");
|
2016-07-13 19:59:59 +02:00
|
|
|
self.last_nonces.write().insert(sender, nonce + U256::from(1));
|
2016-05-25 13:22:17 +02:00
|
|
|
}
|
2016-04-06 12:15:20 +02:00
|
|
|
transactions
|
|
|
|
.iter()
|
2016-04-17 18:26:15 +02:00
|
|
|
.map(|_| Ok(TransactionImportResult::Current))
|
2016-04-06 12:15:20 +02:00
|
|
|
.collect()
|
|
|
|
}
|
2016-03-13 17:01:50 +01:00
|
|
|
|
2016-04-17 18:26:15 +02:00
|
|
|
/// Imports transactions to transaction queue.
|
2016-12-15 18:19:19 +01:00
|
|
|
fn import_own_transaction(&self, chain: &MiningBlockChainClient, pending: PendingTransaction) ->
|
2016-07-06 17:15:59 +02:00
|
|
|
Result<TransactionImportResult, Error> {
|
2016-05-25 13:22:17 +02:00
|
|
|
|
|
|
|
// keep the pending nonces up to date
|
2017-01-13 09:51:36 +01:00
|
|
|
let sender = pending.transaction.sender();
|
|
|
|
let nonce = self.last_nonce(&sender).unwrap_or(chain.latest_nonce(&sender));
|
|
|
|
self.last_nonces.write().insert(sender, nonce + U256::from(1));
|
2016-05-25 13:22:17 +02:00
|
|
|
|
2016-04-17 18:26:15 +02:00
|
|
|
// lets assume that all txs are valid
|
2016-12-15 18:19:19 +01:00
|
|
|
self.imported_transactions.lock().push(pending.transaction);
|
2016-04-17 18:26:15 +02:00
|
|
|
|
|
|
|
Ok(TransactionImportResult::Current)
|
|
|
|
}
|
|
|
|
|
2016-03-13 17:01:50 +01:00
|
|
|
/// Returns hashes of transactions currently in pending
|
2016-10-07 12:13:15 +02:00
|
|
|
fn pending_transactions_hashes(&self, _best_block: BlockNumber) -> Vec<H256> {
|
2016-04-06 12:15:20 +02:00
|
|
|
vec![]
|
|
|
|
}
|
2016-03-13 17:01:50 +01:00
|
|
|
|
|
|
|
/// Removes all transactions from the queue and restart mining operation.
|
2016-05-31 21:31:42 +02:00
|
|
|
fn clear_and_reset(&self, _chain: &MiningBlockChainClient) {
|
2016-04-06 12:15:20 +02:00
|
|
|
unimplemented!();
|
|
|
|
}
|
2016-03-13 17:01:50 +01:00
|
|
|
|
|
|
|
/// Called when blocks are imported to chain, updates transactions queue.
|
2016-05-31 21:31:42 +02:00
|
|
|
fn chain_new_blocks(&self, _chain: &MiningBlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) {
|
2016-04-06 12:15:20 +02:00
|
|
|
unimplemented!();
|
|
|
|
}
|
2016-03-13 17:01:50 +01:00
|
|
|
|
|
|
|
/// New chain head event. Restart mining operation.
|
2016-05-31 21:31:42 +02:00
|
|
|
fn update_sealing(&self, _chain: &MiningBlockChainClient) {
|
2016-04-06 12:15:20 +02:00
|
|
|
unimplemented!();
|
|
|
|
}
|
2016-03-13 17:01:50 +01:00
|
|
|
|
2016-08-03 15:31:00 +02:00
|
|
|
fn map_sealing_work<F, T>(&self, chain: &MiningBlockChainClient, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T {
|
|
|
|
let open_block = chain.prepare_open_block(self.author(), *self.gas_range_target.write(), self.extra_data());
|
|
|
|
Some(f(&open_block.close()))
|
2016-04-06 12:15:20 +02:00
|
|
|
}
|
2016-03-13 17:01:50 +01:00
|
|
|
|
2016-10-07 12:13:15 +02:00
|
|
|
fn transaction(&self, _best_block: BlockNumber, hash: &H256) -> Option<SignedTransaction> {
|
2016-07-13 19:59:59 +02:00
|
|
|
self.pending_transactions.lock().get(hash).cloned()
|
2016-04-06 12:15:20 +02:00
|
|
|
}
|
|
|
|
|
2016-12-16 14:54:26 +01:00
|
|
|
fn pending_transactions(&self) -> Vec<PendingTransaction> {
|
2016-12-15 18:19:19 +01:00
|
|
|
self.pending_transactions.lock().values().cloned().map(Into::into).collect()
|
2016-05-24 21:56:32 +02:00
|
|
|
}
|
|
|
|
|
2016-11-16 17:54:54 +01:00
|
|
|
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
|
|
|
|
self.local_transactions.lock().iter().map(|(hash, stats)| (*hash, stats.clone())).collect()
|
|
|
|
}
|
|
|
|
|
2016-12-16 14:54:26 +01:00
|
|
|
fn ready_transactions(&self, _best_block: BlockNumber) -> Vec<PendingTransaction> {
|
2016-12-15 18:19:19 +01:00
|
|
|
self.pending_transactions.lock().values().cloned().map(Into::into).collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn future_transactions(&self) -> Vec<PendingTransaction> {
|
|
|
|
vec![]
|
2016-04-06 23:03:07 +02:00
|
|
|
}
|
|
|
|
|
2016-10-07 12:13:15 +02:00
|
|
|
fn pending_receipt(&self, _best_block: BlockNumber, hash: &H256) -> Option<RichReceipt> {
|
2016-08-17 19:25:02 +02:00
|
|
|
// Not much point implementing this since the logic is complex and the only thing it relies on is pending_receipts, which is already tested.
|
2016-10-07 12:13:15 +02:00
|
|
|
self.pending_receipts(0).get(hash).map(|r|
|
2016-08-17 19:25:02 +02:00
|
|
|
RichReceipt {
|
|
|
|
transaction_hash: Default::default(),
|
|
|
|
transaction_index: Default::default(),
|
|
|
|
cumulative_gas_used: r.gas_used.clone(),
|
|
|
|
gas_used: r.gas_used.clone(),
|
|
|
|
contract_address: None,
|
|
|
|
logs: r.logs.clone(),
|
2016-11-04 12:33:13 +01:00
|
|
|
log_bloom: r.log_bloom,
|
|
|
|
state_root: r.state_root,
|
2016-08-17 19:25:02 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2016-10-07 12:13:15 +02:00
|
|
|
fn pending_receipts(&self, _best_block: BlockNumber) -> BTreeMap<H256, Receipt> {
|
2016-07-13 19:59:59 +02:00
|
|
|
self.pending_receipts.lock().clone()
|
2016-05-24 21:56:32 +02:00
|
|
|
}
|
|
|
|
|
2016-04-06 12:15:20 +02:00
|
|
|
fn last_nonce(&self, address: &Address) -> Option<U256> {
|
2016-07-13 19:59:59 +02:00
|
|
|
self.last_nonces.read().get(address).cloned()
|
2016-03-27 15:12:21 +02:00
|
|
|
}
|
|
|
|
|
2016-08-02 18:53:32 +02:00
|
|
|
fn is_sealing(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2016-03-13 17:01:50 +01:00
|
|
|
/// Submit `seal` as a valid solution for the header of `pow_hash`.
|
|
|
|
/// Will check the seal, but not actually insert the block into the chain.
|
2016-05-31 21:31:42 +02:00
|
|
|
fn submit_seal(&self, _chain: &MiningBlockChainClient, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> {
|
2016-04-06 12:15:20 +02:00
|
|
|
unimplemented!();
|
|
|
|
}
|
2016-04-28 21:47:44 +02:00
|
|
|
|
2016-05-31 21:31:42 +02:00
|
|
|
fn balance(&self, _chain: &MiningBlockChainClient, address: &Address) -> U256 {
|
2016-07-13 19:59:59 +02:00
|
|
|
self.latest_closed_block.lock().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.balance(address).clone())
|
2016-04-28 21:47:44 +02:00
|
|
|
}
|
|
|
|
|
2016-08-04 18:17:21 +02:00
|
|
|
fn call(&self, _chain: &MiningBlockChainClient, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, CallError> {
|
2016-04-28 21:47:44 +02:00
|
|
|
unimplemented!();
|
|
|
|
}
|
|
|
|
|
2016-05-31 21:31:42 +02:00
|
|
|
fn storage_at(&self, _chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256 {
|
2016-07-13 19:59:59 +02:00
|
|
|
self.latest_closed_block.lock().as_ref().map_or_else(H256::default, |b| b.block().fields().state.storage_at(address, position).clone())
|
2016-04-28 21:47:44 +02:00
|
|
|
}
|
|
|
|
|
2016-05-31 21:31:42 +02:00
|
|
|
fn nonce(&self, _chain: &MiningBlockChainClient, address: &Address) -> U256 {
|
2016-05-25 13:22:17 +02:00
|
|
|
// we assume all transactions are in a pending block, ignoring the
|
|
|
|
// reality of gas limits.
|
|
|
|
self.last_nonce(address).unwrap_or(U256::zero())
|
2016-04-28 21:47:44 +02:00
|
|
|
}
|
|
|
|
|
2016-05-31 21:31:42 +02:00
|
|
|
fn code(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> {
|
2016-10-02 18:45:36 +02:00
|
|
|
self.latest_closed_block.lock().as_ref().map_or(None, |b| b.block().fields().state.code(address).map(|c| (*c).clone()))
|
2016-04-28 21:47:44 +02:00
|
|
|
}
|
|
|
|
|
2016-10-31 12:57:48 +01:00
|
|
|
fn sensible_gas_price(&self) -> U256 {
|
|
|
|
20000000000u64.into()
|
|
|
|
}
|
2016-03-16 10:37:08 +01:00
|
|
|
}
|