386 lines
12 KiB
Rust
386 lines
12 KiB
Rust
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
|
// This file is part of OpenEthereum.
|
|
|
|
// OpenEthereum 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.
|
|
|
|
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
//! Test implementation of miner service.
|
|
|
|
use std::{
|
|
collections::{BTreeMap, BTreeSet, HashMap},
|
|
sync::Arc,
|
|
};
|
|
|
|
use bytes::Bytes;
|
|
use ethcore::{
|
|
block::SealedBlock,
|
|
client::{
|
|
test_client::TestState, traits::ForceUpdateSealing, EngineInfo, Nonce, PrepareOpenBlock,
|
|
StateClient,
|
|
},
|
|
engines::{signer::EngineSigner, EthEngine},
|
|
error::Error,
|
|
miner::{self, AuthoringParams, MinerService, TransactionFilter},
|
|
};
|
|
use ethereum_types::{Address, H256, U256};
|
|
use miner::pool::{
|
|
local_transactions::Status as LocalTransactionStatus, verifier, QueueStatus,
|
|
VerifiedTransaction,
|
|
};
|
|
use parking_lot::{Mutex, RwLock};
|
|
use types::{
|
|
block::Block,
|
|
header::Header,
|
|
ids::BlockId,
|
|
receipt::RichReceipt,
|
|
transaction::{self, PendingTransaction, SignedTransaction, UnverifiedTransaction},
|
|
BlockNumber,
|
|
};
|
|
|
|
/// Test miner service.
|
|
pub struct TestMinerService {
|
|
/// Imported transactions.
|
|
pub imported_transactions: Mutex<Vec<SignedTransaction>>,
|
|
/// Pre-existed pending transactions
|
|
pub pending_transactions: Mutex<HashMap<H256, SignedTransaction>>,
|
|
/// Pre-existed local transactions
|
|
pub local_transactions: Mutex<BTreeMap<H256, LocalTransactionStatus>>,
|
|
/// Pre-existed pending receipts
|
|
pub pending_receipts: Mutex<Vec<RichReceipt>>,
|
|
/// Next nonces.
|
|
pub next_nonces: RwLock<HashMap<Address, U256>>,
|
|
/// Minimum gas price
|
|
pub min_gas_price: RwLock<Option<U256>>,
|
|
/// Signer (if any)
|
|
pub signer: RwLock<Option<Box<dyn EngineSigner>>>,
|
|
|
|
authoring_params: RwLock<AuthoringParams>,
|
|
}
|
|
|
|
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(),
|
|
min_gas_price: RwLock::new(Some(0.into())),
|
|
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 = TestState;
|
|
|
|
fn latest_state_and_header(&self) -> (Self::State, Header) {
|
|
(TestState, Header::default())
|
|
}
|
|
|
|
fn state_at(&self, _id: BlockId) -> Option<Self::State> {
|
|
Some(TestState)
|
|
}
|
|
}
|
|
|
|
impl EngineInfo for TestMinerService {
|
|
fn engine(&self) -> &dyn EthEngine {
|
|
unimplemented!()
|
|
}
|
|
}
|
|
|
|
impl MinerService for TestMinerService {
|
|
type State = TestState;
|
|
|
|
fn pending_state(&self, _latest_block_number: BlockNumber) -> Option<Self::State> {
|
|
None
|
|
}
|
|
|
|
fn pending_block_header(&self, _latest_block_number: BlockNumber) -> Option<Header> {
|
|
None
|
|
}
|
|
|
|
fn pending_block(&self, _latest_block_number: BlockNumber) -> Option<Block> {
|
|
None
|
|
}
|
|
|
|
fn authoring_params(&self) -> AuthoringParams {
|
|
self.authoring_params.read().clone()
|
|
}
|
|
|
|
fn set_author<T: Into<Option<miner::Author>>>(&self, author: T) {
|
|
let author_opt = author.into();
|
|
self.authoring_params.write().author = author_opt
|
|
.as_ref()
|
|
.map(miner::Author::address)
|
|
.unwrap_or_default();
|
|
match author_opt {
|
|
Some(miner::Author::Sealer(signer)) => *self.signer.write() = Some(signer),
|
|
Some(miner::Author::External(_addr)) => (),
|
|
None => *self.signer.write() = None,
|
|
}
|
|
}
|
|
|
|
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<C: Nonce + Sync>(
|
|
&self,
|
|
chain: &C,
|
|
transactions: Vec<UnverifiedTransaction>,
|
|
) -> Vec<Result<(), transaction::Error>> {
|
|
// 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<C: Nonce + Sync>(
|
|
&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<C: Nonce + Sync>(
|
|
&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<C>(
|
|
&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<C>(&self, _chain: &C, _force: ForceUpdateSealing) {
|
|
unimplemented!();
|
|
}
|
|
|
|
fn work_package<C: PrepareOpenBlock>(
|
|
&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<Arc<VerifiedTransaction>> {
|
|
self.pending_transactions
|
|
.lock()
|
|
.get(hash)
|
|
.cloned()
|
|
.map(|tx| Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)))
|
|
}
|
|
|
|
fn remove_transaction(&self, hash: &H256) -> Option<Arc<VerifiedTransaction>> {
|
|
self.pending_transactions
|
|
.lock()
|
|
.remove(hash)
|
|
.map(|tx| Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)))
|
|
}
|
|
|
|
fn pending_transactions(&self, _best_block: BlockNumber) -> Option<Vec<SignedTransaction>> {
|
|
Some(self.pending_transactions.lock().values().cloned().collect())
|
|
}
|
|
|
|
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
|
|
self.local_transactions
|
|
.lock()
|
|
.iter()
|
|
.map(|(hash, stats)| (*hash, stats.clone()))
|
|
.collect()
|
|
}
|
|
|
|
fn ready_transactions_filtered<C>(
|
|
&self,
|
|
_chain: &C,
|
|
_max_len: usize,
|
|
filter: Option<TransactionFilter>,
|
|
_ordering: miner::PendingOrdering,
|
|
) -> Vec<Arc<VerifiedTransaction>> {
|
|
match filter {
|
|
Some(f) => self
|
|
.queued_transactions()
|
|
.into_iter()
|
|
.filter(|tx| f.matches(tx))
|
|
.collect(),
|
|
None => self.queued_transactions(),
|
|
}
|
|
}
|
|
|
|
fn pending_transaction_hashes<C>(&self, _chain: &C) -> BTreeSet<H256> {
|
|
self.queued_transactions()
|
|
.into_iter()
|
|
.map(|tx| tx.signed().hash())
|
|
.collect()
|
|
}
|
|
|
|
fn queued_transactions(&self) -> Vec<Arc<VerifiedTransaction>> {
|
|
self.pending_transactions
|
|
.lock()
|
|
.values()
|
|
.cloned()
|
|
.map(|tx| Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)))
|
|
.collect()
|
|
}
|
|
|
|
fn queued_transaction_hashes(&self) -> Vec<H256> {
|
|
self.pending_transactions
|
|
.lock()
|
|
.keys()
|
|
.cloned()
|
|
.map(|hash| hash)
|
|
.collect()
|
|
}
|
|
|
|
fn pending_receipts(&self, _best_block: BlockNumber) -> Option<Vec<RichReceipt>> {
|
|
Some(self.pending_receipts.lock().clone())
|
|
}
|
|
|
|
fn next_nonce<C: Nonce + Sync>(&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,
|
|
block_base_fee: None,
|
|
allow_non_eoa_sender: 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<Bytes>) -> Result<SealedBlock, Error> {
|
|
unimplemented!();
|
|
}
|
|
|
|
fn sensible_gas_price(&self) -> U256 {
|
|
20_000_000_000u64.into()
|
|
}
|
|
|
|
fn sensible_max_priority_fee(&self) -> U256 {
|
|
2_000_000_000u64.into()
|
|
}
|
|
|
|
fn sensible_gas_limit(&self) -> U256 {
|
|
0x5208.into()
|
|
}
|
|
|
|
fn set_minimal_gas_price(&self, gas_price: U256) -> Result<bool, &str> {
|
|
let mut new_price = self.min_gas_price.write();
|
|
match *new_price {
|
|
Some(ref mut v) => {
|
|
*v = gas_price;
|
|
Ok(true)
|
|
}
|
|
None => {
|
|
let error_msg =
|
|
"Can't update fixed gas price while automatic gas calibration is enabled.";
|
|
Err(error_msg)
|
|
}
|
|
}
|
|
}
|
|
}
|