// Copyright 2015, 2016 Ethcore (UK) Ltd. // 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 . //! Test client. use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder}; use util::*; use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action}; use blockchain::TreeRoute; use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId, TraceId, TraceFilter, LastHashes}; use header::{Header as BlockHeader, BlockNumber}; use filter::Filter; use log_entry::LocalizedLogEntry; use receipt::{Receipt, LocalizedReceipt}; use extras::BlockReceipts; use error::{ImportResult}; use block_queue::BlockQueueInfo; use block::{SealedBlock, ClosedBlock, LockedBlock}; use executive::Executed; use error::Error; use engine::Engine; use trace::LocalizedTrace; /// Test client. pub struct TestBlockChainClient { /// Blocks. pub blocks: RwLock>, /// Mapping of numbers to hashes. pub numbers: RwLock>, /// Genesis block hash. pub genesis_hash: H256, /// Last block hash. pub last_hash: RwLock, /// Difficulty. pub difficulty: RwLock, /// Balances. pub balances: RwLock>, /// Nonces. pub nonces: RwLock>, /// Storage. pub storage: RwLock>, /// Code. pub code: RwLock>, /// Execution result. pub execution_result: RwLock>, /// Transaction receipts. pub receipts: RwLock>, /// Block queue size. pub queue_size: AtomicUsize, } #[derive(Clone)] /// Used for generating test client blocks. pub enum EachBlockWith { /// Plain block. Nothing, /// Block with an uncle. Uncle, /// Block with a transaction. Transaction, /// Block with an uncle and transaction. UncleAndTransaction } impl Default for TestBlockChainClient { fn default() -> Self { TestBlockChainClient::new() } } impl TestBlockChainClient { /// Creates new test client. pub fn new() -> Self { let mut client = TestBlockChainClient { blocks: RwLock::new(HashMap::new()), numbers: RwLock::new(HashMap::new()), genesis_hash: H256::new(), last_hash: RwLock::new(H256::new()), difficulty: RwLock::new(From::from(0)), balances: RwLock::new(HashMap::new()), nonces: RwLock::new(HashMap::new()), storage: RwLock::new(HashMap::new()), code: RwLock::new(HashMap::new()), execution_result: RwLock::new(None), receipts: RwLock::new(HashMap::new()), queue_size: AtomicUsize::new(0), }; client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); client } /// Set the transaction receipt result pub fn set_transaction_receipt(&self, id: TransactionId, receipt: LocalizedReceipt) { self.receipts.write().unwrap().insert(id, receipt); } /// Set the execution result. pub fn set_execution_result(&self, result: Executed) { *self.execution_result.write().unwrap() = Some(result); } /// Set the balance of account `address` to `balance`. pub fn set_balance(&self, address: Address, balance: U256) { self.balances.write().unwrap().insert(address, balance); } /// Set nonce of account `address` to `nonce`. pub fn set_nonce(&self, address: Address, nonce: U256) { self.nonces.write().unwrap().insert(address, nonce); } /// Set `code` at `address`. pub fn set_code(&self, address: Address, code: Bytes) { self.code.write().unwrap().insert(address, code); } /// Set storage `position` to `value` for account `address`. pub fn set_storage(&self, address: Address, position: H256, value: H256) { self.storage.write().unwrap().insert((address, position), value); } /// Set block queue size for testing pub fn set_queue_size(&self, size: usize) { self.queue_size.store(size, AtomicOrder::Relaxed); } /// Add blocks to test client. pub fn add_blocks(&self, count: usize, with: EachBlockWith) { let len = self.numbers.read().unwrap().len(); for n in len..(len + count) { let mut header = BlockHeader::new(); header.difficulty = From::from(n); header.parent_hash = self.last_hash.read().unwrap().clone(); header.number = n as BlockNumber; header.gas_limit = U256::from(1_000_000); let uncles = match with { EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => { let mut uncles = RlpStream::new_list(1); let mut uncle_header = BlockHeader::new(); uncle_header.difficulty = From::from(n); uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); uncle_header.number = n as BlockNumber; uncles.append(&uncle_header); header.uncles_hash = uncles.as_raw().sha3(); uncles }, _ => RlpStream::new_list(0) }; let txs = match with { EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => { let mut txs = RlpStream::new_list(1); let keypair = KeyPair::create().unwrap(); // Update nonces value self.nonces.write().unwrap().insert(keypair.address(), U256::one()); let tx = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::zero() }; let signed_tx = tx.sign(&keypair.secret()); txs.append(&signed_tx); txs.out() }, _ => rlp::NULL_RLP.to_vec() }; let mut rlp = RlpStream::new_list(3); rlp.append(&header); rlp.append_raw(&txs, 1); rlp.append_raw(uncles.as_raw(), 1); self.import_block(rlp.as_raw().to_vec()).unwrap(); } } /// TODO: pub fn corrupt_block(&mut self, n: BlockNumber) { let hash = self.block_hash(BlockId::Number(n)).unwrap(); let mut header: BlockHeader = decode(&self.block_header(BlockId::Number(n)).unwrap()); header.parent_hash = H256::new(); let mut rlp = RlpStream::new_list(3); rlp.append(&header); rlp.append_raw(&rlp::NULL_RLP, 1); rlp.append_raw(&rlp::NULL_RLP, 1); self.blocks.write().unwrap().insert(hash, rlp.out()); } /// TODO: pub fn block_hash_delta_minus(&mut self, delta: usize) -> H256 { let blocks_read = self.numbers.read().unwrap(); let index = blocks_read.len() - delta; blocks_read[&index].clone() } fn block_hash(&self, id: BlockId) -> Option { match id { BlockId::Hash(hash) => Some(hash), BlockId::Number(n) => self.numbers.read().unwrap().get(&(n as usize)).cloned(), BlockId::Earliest => self.numbers.read().unwrap().get(&0).cloned(), BlockId::Latest => self.numbers.read().unwrap().get(&(self.numbers.read().unwrap().len() - 1)).cloned() } } } impl BlockChainClient for TestBlockChainClient { fn call(&self, _t: &SignedTransaction) -> Result { Ok(self.execution_result.read().unwrap().clone().unwrap()) } fn block_total_difficulty(&self, _id: BlockId) -> Option { Some(U256::zero()) } fn block_hash(&self, _id: BlockId) -> Option { unimplemented!(); } fn nonce(&self, address: &Address) -> U256 { self.nonces.read().unwrap().get(address).cloned().unwrap_or_else(U256::zero) } fn code(&self, address: &Address) -> Option { self.code.read().unwrap().get(address).cloned() } fn balance(&self, address: &Address) -> U256 { self.balances.read().unwrap().get(address).cloned().unwrap_or_else(U256::zero) } fn storage_at(&self, address: &Address, position: &H256) -> H256 { self.storage.read().unwrap().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new) } fn transaction(&self, _id: TransactionId) -> Option { unimplemented!(); } fn uncle(&self, _id: UncleId) -> Option { unimplemented!(); } fn transaction_receipt(&self, id: TransactionId) -> Option { self.receipts.read().unwrap().get(&id).cloned() } fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option> { unimplemented!(); } fn logs(&self, _filter: Filter) -> Vec { unimplemented!(); } fn last_hashes(&self) -> LastHashes { unimplemented!(); } fn prepare_sealing(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes, _transactions: Vec) -> (Option, HashSet) { (None, HashSet::new()) } fn try_seal(&self, block: LockedBlock, _seal: Vec) -> Result { Err(block) } fn block_header(&self, id: BlockId) -> Option { self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) } fn block_body(&self, id: BlockId) -> Option { self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| { let mut stream = RlpStream::new_list(2); stream.append_raw(Rlp::new(&r).at(1).as_raw(), 1); stream.append_raw(Rlp::new(&r).at(2).as_raw(), 1); stream.out() })) } fn block(&self, id: BlockId) -> Option { self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).cloned()) } fn block_status(&self, id: BlockId) -> BlockStatus { match id { BlockId::Number(number) if (number as usize) < self.blocks.read().unwrap().len() => BlockStatus::InChain, BlockId::Hash(ref hash) if self.blocks.read().unwrap().get(hash).is_some() => BlockStatus::InChain, _ => BlockStatus::Unknown } } // works only if blocks are one after another 1 -> 2 -> 3 fn tree_route(&self, from: &H256, to: &H256) -> Option { Some(TreeRoute { ancestor: H256::new(), index: 0, blocks: { let numbers_read = self.numbers.read().unwrap(); let mut adding = false; let mut blocks = Vec::new(); for (_, hash) in numbers_read.iter().sort_by(|tuple1, tuple2| tuple1.0.cmp(tuple2.0)) { if hash == to { if adding { blocks.push(hash.clone()); } adding = false; break; } if hash == from { adding = true; } if adding { blocks.push(hash.clone()); } } if adding { Vec::new() } else { blocks } } }) } // TODO: returns just hashes instead of node state rlp(?) fn state_data(&self, hash: &H256) -> Option { // starts with 'f' ? if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { let mut rlp = RlpStream::new(); rlp.append(&hash.clone()); return Some(rlp.out()); } None } fn block_receipts(&self, hash: &H256) -> Option { // starts with 'f' ? if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { let receipt = BlockReceipts::new(vec![Receipt::new( H256::zero(), U256::zero(), vec![])]); let mut rlp = RlpStream::new(); rlp.append(&receipt); return Some(rlp.out()); } None } fn import_block(&self, b: Bytes) -> ImportResult { let header = Rlp::new(&b).val_at::(0); let h = header.hash(); let number: usize = header.number as usize; if number > self.blocks.read().unwrap().len() { panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().unwrap().len(), number); } if number > 0 { match self.blocks.read().unwrap().get(&header.parent_hash) { Some(parent) => { let parent = Rlp::new(parent).val_at::(0); if parent.number != (header.number - 1) { panic!("Unexpected block parent"); } }, None => { panic!("Unknown block parent {:?} for block {}", header.parent_hash, number); } } } let len = self.numbers.read().unwrap().len(); if number == len { { let mut difficulty = self.difficulty.write().unwrap(); *difficulty.deref_mut() = *difficulty.deref() + header.difficulty; } mem::replace(self.last_hash.write().unwrap().deref_mut(), h.clone()); self.blocks.write().unwrap().insert(h.clone(), b); self.numbers.write().unwrap().insert(number, h.clone()); let mut parent_hash = header.parent_hash; if number > 0 { let mut n = number - 1; while n > 0 && self.numbers.read().unwrap()[&n] != parent_hash { *self.numbers.write().unwrap().get_mut(&n).unwrap() = parent_hash.clone(); n -= 1; parent_hash = Rlp::new(&self.blocks.read().unwrap()[&parent_hash]).val_at::(0).parent_hash; } } } else { self.blocks.write().unwrap().insert(h.clone(), b.to_vec()); } Ok(h) } fn queue_info(&self) -> BlockQueueInfo { BlockQueueInfo { verified_queue_size: self.queue_size.load(AtomicOrder::Relaxed), unverified_queue_size: 0, verifying_queue_size: 0, max_queue_size: 0, max_mem_use: 0, mem_used: 0, } } fn clear_queue(&self) { } fn chain_info(&self) -> BlockChainInfo { BlockChainInfo { total_difficulty: *self.difficulty.read().unwrap(), pending_total_difficulty: *self.difficulty.read().unwrap(), genesis_hash: self.genesis_hash.clone(), best_block_hash: self.last_hash.read().unwrap().clone(), best_block_number: self.blocks.read().unwrap().len() as BlockNumber - 1, } } fn engine(&self) -> &Engine { unimplemented!(); } fn filter_traces(&self, _filter: TraceFilter) -> Option> { unimplemented!(); } fn trace(&self, _trace: TraceId) -> Option { unimplemented!(); } fn transaction_traces(&self, _trace: TransactionId) -> Option> { unimplemented!(); } fn block_traces(&self, _trace: BlockId) -> Option> { unimplemented!(); } }