// 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 . use std::sync::{atomic, Arc}; use ethereum_types::{Address, H256, U256}; use rlp::Rlp; use types::transaction::{ self, SignedTransaction, Transaction, TypedTransaction, UnverifiedTransaction, }; use pool::{self, client::AccountDetails}; const MAX_TRANSACTION_SIZE: usize = 15 * 1024; #[derive(Debug, Clone)] pub struct TestClient { verification_invoked: Arc, account_details: AccountDetails, gas_required: U256, is_service_transaction: bool, local_address: Address, max_transaction_size: usize, } impl Default for TestClient { fn default() -> Self { TestClient { verification_invoked: Default::default(), account_details: AccountDetails { nonce: 123.into(), balance: 63_100.into(), code_hash: None, is_local: false, }, gas_required: 21_000.into(), is_service_transaction: false, local_address: Default::default(), max_transaction_size: MAX_TRANSACTION_SIZE, } } } impl TestClient { pub fn new() -> Self { TestClient::default() } pub fn with_balance>(mut self, balance: T) -> Self { self.account_details.balance = balance.into(); self } pub fn with_nonce>(mut self, nonce: T) -> Self { self.account_details.nonce = nonce.into(); self } pub fn with_code_hash>(mut self, code_hash: T) -> Self { self.account_details.code_hash = Some(code_hash.into()); self } pub fn with_gas_required>(mut self, gas_required: T) -> Self { self.gas_required = gas_required.into(); self } pub fn with_local(mut self, address: &Address) -> Self { self.local_address = *address; self } pub fn with_service_transaction(mut self) -> Self { self.is_service_transaction = true; self } pub fn verify>( &self, tx: T, ) -> pool::VerifiedTransaction { let tx = tx.into(); pool::VerifiedTransaction { hash: tx.hash(), sender: tx.sender(), priority: pool::Priority::Regular, transaction: tx, insertion_id: 1, } } pub fn was_verification_triggered(&self) -> bool { self.verification_invoked.load(atomic::Ordering::SeqCst) } } impl pool::client::Client for TestClient { fn transaction_already_included(&self, _hash: &H256) -> bool { false } fn verify_transaction_basic( &self, _tx: &UnverifiedTransaction, ) -> Result<(), transaction::Error> { Ok(()) } fn verify_transaction( &self, tx: UnverifiedTransaction, ) -> Result { self.verification_invoked .store(true, atomic::Ordering::SeqCst); Ok(SignedTransaction::new(tx)?) } fn account_details(&self, address: &Address) -> AccountDetails { let mut details = self.account_details.clone(); if address == &self.local_address { details.is_local = true; } details } fn required_gas(&self, _tx: &Transaction) -> U256 { self.gas_required } fn transaction_type(&self, _tx: &SignedTransaction) -> pool::client::TransactionType { if self.is_service_transaction { pool::client::TransactionType::Service } else { pool::client::TransactionType::Regular } } fn decode_transaction( &self, transaction: &[u8], ) -> Result { let rlp = Rlp::new(&transaction); if rlp.as_raw().len() > self.max_transaction_size { return Err(transaction::Error::TooBig); } TypedTransaction::decode(transaction) .map_err(|e| transaction::Error::InvalidRlp(e.to_string())) } } impl pool::client::NonceClient for TestClient { fn account_nonce(&self, _address: &Address) -> U256 { self.account_details.nonce } }