// Copyright 2015-2019 Parity Technologies (UK) Ltd. // This file is part of Parity Ethereum. // Parity Ethereum 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 Ethereum 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 Ethereum. If not, see . //! Test implementation of miner service. use std::sync::Arc; use std::collections::{BTreeMap, BTreeSet, HashMap}; use bytes::Bytes; use ethcore::block::{SealedBlock, IsBlock}; use ethcore::client::{Nonce, PrepareOpenBlock, StateClient, EngineInfo}; use ethcore::engines::{EthEngine, signer::EngineSigner}; use ethcore::error::Error; use ethcore::miner::{self, MinerService, AuthoringParams}; use ethereum_types::{H256, U256, Address}; use miner::pool::local_transactions::Status as LocalTransactionStatus; use miner::pool::{verifier, VerifiedTransaction, QueueStatus}; use parking_lot::{RwLock, Mutex}; use types::transaction::{self, UnverifiedTransaction, SignedTransaction, PendingTransaction}; use txpool; use types::BlockNumber; use types::block::Block; use types::header::Header; use types::ids::BlockId; use types::receipt::RichReceipt; /// Test miner service. pub struct TestMinerService { /// Imported transactions. pub imported_transactions: Mutex>, /// Pre-existed pending transactions pub pending_transactions: Mutex>, /// Pre-existed local transactions pub local_transactions: Mutex>, /// Pre-existed pending receipts pub pending_receipts: Mutex>, /// Next nonces. pub next_nonces: RwLock>, /// Signer (if any) pub signer: RwLock>>, authoring_params: RwLock, } impl Default for TestMinerService { fn default() -> TestMinerService { TestMinerService { imported_transactions: Default::default(), pending_transactions: Default::default(), local_transactions: Default::default(), pending_receipts: Default::default(), next_nonces: Default::default(), authoring_params: RwLock::new(AuthoringParams { author: Address::zero(), gas_range_target: (12345.into(), 54321.into()), extra_data: vec![1, 2, 3, 4], }), signer: RwLock::new(None), } } } impl TestMinerService { /// Increments nonce for given address. pub fn increment_nonce(&self, address: &Address) { let mut next_nonces = self.next_nonces.write(); let nonce = next_nonces.entry(*address).or_insert_with(|| 0.into()); *nonce = *nonce + 1; } } impl StateClient for TestMinerService { // State will not be used by test client anyway, since all methods that accept state are mocked type State = (); fn latest_state(&self) -> Self::State { () } fn state_at(&self, _id: BlockId) -> Option { Some(()) } } impl EngineInfo for TestMinerService { fn engine(&self) -> &EthEngine { unimplemented!() } } impl MinerService for TestMinerService { type State = (); fn pending_state(&self, _latest_block_number: BlockNumber) -> Option { None } fn pending_block_header(&self, _latest_block_number: BlockNumber) -> Option
{ None } fn pending_block(&self, _latest_block_number: BlockNumber) -> Option { None } fn authoring_params(&self) -> AuthoringParams { self.authoring_params.read().clone() } fn set_author(&self, author: miner::Author) { self.authoring_params.write().author = author.address(); if let miner::Author::Sealer(signer) = author { *self.signer.write() = Some(signer); } } fn set_extra_data(&self, extra_data: Bytes) { self.authoring_params.write().extra_data = extra_data; } fn set_gas_range_target(&self, target: (U256, U256)) { self.authoring_params.write().gas_range_target = target; } /// Imports transactions to transaction queue. fn import_external_transactions(&self, chain: &C, transactions: Vec) -> Vec> { // lets assume that all txs are valid let transactions: Vec<_> = transactions.into_iter().map(|tx| SignedTransaction::new(tx).unwrap()).collect(); self.imported_transactions.lock().extend_from_slice(&transactions); for sender in transactions.iter().map(|tx| tx.sender()) { let nonce = self.next_nonce(chain, &sender); self.next_nonces.write().insert(sender, nonce); } transactions .iter() .map(|_| Ok(())) .collect() } /// Imports transactions to transaction queue. fn import_own_transaction(&self, _chain: &C, _pending: PendingTransaction) -> Result<(), transaction::Error> { // this function is no longer called directly from RPC unimplemented!(); } /// Imports transactions to queue - treats as local based on trusted flag, config, and tx source fn import_claimed_local_transaction(&self, chain: &C, pending: PendingTransaction, _trusted: bool) -> Result<(), transaction::Error> { // keep the pending nonces up to date let sender = pending.transaction.sender(); let nonce = self.next_nonce(chain, &sender); self.next_nonces.write().insert(sender, nonce); // lets assume that all txs are valid self.imported_transactions.lock().push(pending.transaction); Ok(()) } /// Called when blocks are imported to chain, updates transactions queue. fn chain_new_blocks(&self, _chain: &C, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256], _is_internal: bool) { unimplemented!(); } /// New chain head event. Restart mining operation. fn update_sealing(&self, _chain: &C) { unimplemented!(); } fn work_package(&self, chain: &C) -> Option<(H256, BlockNumber, u64, U256)> { let params = self.authoring_params(); let open_block = chain.prepare_open_block(params.author, params.gas_range_target, params.extra_data).unwrap(); let closed = open_block.close().unwrap(); let header = closed.header(); Some((header.hash(), header.number(), header.timestamp(), *header.difficulty())) } fn transaction(&self, hash: &H256) -> Option> { self.pending_transactions.lock().get(hash).cloned().map(|tx| { Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)) }) } fn remove_transaction(&self, hash: &H256) -> Option> { self.pending_transactions.lock().remove(hash).map(|tx| { Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)) }) } fn pending_transactions(&self, _best_block: BlockNumber) -> Option> { Some(self.pending_transactions.lock().values().cloned().collect()) } fn local_transactions(&self) -> BTreeMap { self.local_transactions.lock().iter().map(|(hash, stats)| (*hash, stats.clone())).collect() } fn ready_transactions(&self, _chain: &C, _max_len: usize, _ordering: miner::PendingOrdering) -> Vec> { self.queued_transactions() } fn pending_transaction_hashes(&self, _chain: &C) -> BTreeSet { self.queued_transactions().into_iter().map(|tx| tx.signed().hash()).collect() } fn queued_transactions(&self) -> Vec> { self.pending_transactions.lock().values().cloned().map(|tx| { Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)) }).collect() } fn queued_transaction_hashes(&self) -> Vec { self.pending_transactions.lock().keys().cloned().map(|hash| hash).collect() } fn pending_receipts(&self, _best_block: BlockNumber) -> Option> { Some(self.pending_receipts.lock().clone()) } fn next_nonce(&self, _chain: &C, address: &Address) -> U256 { self.next_nonces.read().get(address).cloned().unwrap_or_default() } fn is_currently_sealing(&self) -> bool { false } fn queue_status(&self) -> QueueStatus { QueueStatus { options: verifier::Options { minimal_gas_price: 0x1312d00.into(), block_gas_limit: 5_000_000.into(), tx_gas_limit: 5_000_000.into(), no_early_reject: false, }, status: txpool::LightStatus { mem_usage: 1_000, transaction_count: 52, senders: 1, }, limits: txpool::Options { max_count: 1_024, max_per_sender: 16, max_mem_usage: 5_000, }, } } /// 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. fn submit_seal(&self, _pow_hash: H256, _seal: Vec) -> Result { unimplemented!(); } fn sensible_gas_price(&self) -> U256 { 20_000_000_000u64.into() } fn sensible_gas_limit(&self) -> U256 { 0x5208.into() } }