Client refactoring (#7038)
				
					
				
			* Improves `BestBlock` comment * Improves `TraceDB` comment * Improves `journaldb::Algorithm` comment. Probably the whole enum should be renamed to `Strategy` or something alike. * Comments some of the `Client`'s fields * Deglobs client imports * Fixes comments * Extracts `import_lock` to `Importer` struct * Extracts `verifier` to `Importer` struct * Extracts `block_queue` to `Importer` struct * Extracts `miner` to `Importer` struct * Extracts `ancient_verifier` to `Importer` struct * Extracts `rng` to `Importer` struct * Extracts `import_old_block` to `Importer` struct * Adds `Nonce` trait * Adds `Balance` trait * Adds `ChainInfo` trait * Fixes imports for tests using `chain_info` method * Adds `BlockInfo` trait * Adds more `ChainInfo` imports * Adds `BlockInfo` imports * Adds `ReopenBlock` trait * Adds `PrepareOpenBlock` trait * Fixes import in tests * Adds `CallContract` trait * Fixes imports in tests using `call_contract` method * Adds `TransactionInfo` trait * Adds `RegistryInfo` trait * Fixes imports in tests using `registry_address` method * Adds `ScheduleInfo` trait * Adds `ImportSealedBlock` trait * Fixes imports in test using `import_sealed_block` method * Adds `BroadcastProposalBlock` trait * Migrates `Miner` to static dispatch * Fixes tests * Moves `calculate_enacted_retracted` to `Importer` * Moves import-related methods to `Importer` * Removes redundant `import_old_block` wrapper * Extracts `import_block*` into separate trait * Fixes tests * Handles `Pending` in `LightFetch` * Handles `Pending` in filters * Handles `Pending` in `ParityClient` * Handles `Pending` in `EthClient` * Removes `BlockId::Pending`, partly refactors dependent code * Adds `StateInfo` trait * Exports `StateOrBlock` and `BlockChain` types from `client` module * Refactors `balance` RPC using generic API * Refactors `storage_at` RPC using generic API * Makes `MinerService::pending_state`'s return type dynamic * Adds `StateOrBlock` and `BlockChain` types * Adds impl of `client::BlockChain` for `Client` * Exports `StateInfo` trait from `client` module * Missing `self` use To be fixed up to "Adds impl of `client::BlockChain` for `Client`" * Adds `number_to_id` and refactors dependent RPC methods * Refactors `code_at` using generic API * Adds `StateClient` trait * Refactors RPC to use `StateClient` trait * Reverts `client::BlockChain` trait stuff, refactors methods to accept `StateOrBlock` * Refactors TestClient * Adds helper function `block_number_to_id` * Uses `block_number_to_id` instead of local function * Handles `Pending` in `list_accounts` and `list_storage_keys` * Attempt to use associated types for state instead of trait objects * Simplifies `state_at_beginning` * Extracts `call` and `call_many` into separate trait * Refactors `build_last_hashes` to accept reference * Exports `Call` type from the module * Refactors `call` and `call_many` to accept state and header * Exports `state_at` in `StateClient` * Exports `pending_block_header` from `MinerService` * Refactors RPC `call` method using new API * Adds missing parentheses * Refactors `parity::call` to use new call API * Update .gitlab-ci.yml fix gitlab lint * Fixes error handling * Refactors `traces::call` and `call_many` to use new call API * Refactors `call_contract` * Refactors `block_header` * Refactors internal RPC method `block` * Moves `estimate_gas` to `Call` trait, refactors parameters * Refactors `estimate_gas` in RPC * Refactors `uncle` * Refactors RPC `transaction` * Covers missing branches * Makes it all compile, fixes compiler grumbles * Adds casts in `blockchain` module * Fixes `PendingBlock` tests, work on `MinerService` * Adds test stubs for StateClient and EngineInfo * Makes `state_db` public * Adds missing impls for `TestBlockChainClient` * Adds trait documentation * Adds missing docs to the `state_db` module * Fixes trivial compilation errors * Moves `code_hash` method to a `BlockInfo` trait * Refactors `Verifier` to be generic over client * Refactors `TransactionFilter` to be generic over client * Refactors `Miner` and `Client` to reflect changes in verifier and txfilter API * Moves `ServiceTransactionChecker` back to `ethcore` * Fixes trait bounds in `Miner` API * Fixes `Client` * Fixes lifetime bound in `FullFamilyParams` * Adds comments to `FullFamilyParams` * Fixes imports in `ethcore` * Fixes BlockNumber handling in `code_at` and `replay_block_transactions` * fix compile issues * First step to redundant trait merge * Fixes compilation error in RPC tests * Adds mock `State` as a stub for `TestClient` * Handles `StateOrBlock::State` in `TestBlockChainClient::balance` * Fixes `transaction_count` RPC * Fixes `transaction_count` * Moves `service_transaction.json` to the `contracts` subfolder * Fixes compilation errors in tests * Refactors client to use `AccountData` * Refactors client to use `BlockChain` * Refactors miner to use aggregate traits * Adds `SealedBlockImporter` trait * Refactors miner to use `SealedBlockImporter` trait * Removes unused imports * Simplifies `RegistryInfo::registry_address` * Fixes indentation * Removes commented out trait bound
This commit is contained in:
		
							parent
							
								
									81b52c7336
								
							
						
					
					
						commit
						9d7d6f7108
					
				
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -2146,6 +2146,7 @@ dependencies = [ | ||||
|  "parity-updater 1.9.0", | ||||
|  "parity-version 1.10.0", | ||||
|  "parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "patricia-trie 0.1.0", | ||||
|  "pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rand 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rlp 0.2.1", | ||||
|  | ||||
| @ -497,7 +497,7 @@ impl HeaderChain { | ||||
| 				if self.best_block.read().number < num { return None } | ||||
| 				self.candidates.read().get(&num).map(|entry| entry.canonical_hash) | ||||
| 			} | ||||
| 			BlockId::Latest | BlockId::Pending => { | ||||
| 			BlockId::Latest => { | ||||
| 				Some(self.best_block.read().hash) | ||||
| 			} | ||||
| 		} | ||||
| @ -539,7 +539,7 @@ impl HeaderChain { | ||||
| 				self.candidates.read().get(&num).map(|entry| entry.canonical_hash) | ||||
| 					.and_then(load_from_db) | ||||
| 			} | ||||
| 			BlockId::Latest | BlockId::Pending => { | ||||
| 			BlockId::Latest => { | ||||
| 				// hold candidates hear to prevent deletion of the header
 | ||||
| 				// as we read it.
 | ||||
| 				let _candidates = self.candidates.read(); | ||||
| @ -575,7 +575,7 @@ impl HeaderChain { | ||||
| 				if self.best_block.read().number < num { return None } | ||||
| 				candidates.get(&num).map(|era| era.candidates[0].total_difficulty) | ||||
| 			} | ||||
| 			BlockId::Latest | BlockId::Pending => Some(self.best_block.read().total_difficulty) | ||||
| 			BlockId::Latest => Some(self.best_block.read().total_difficulty) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -866,7 +866,6 @@ mod tests { | ||||
| 
 | ||||
| 		assert!(chain.block_header(BlockId::Earliest).is_some()); | ||||
| 		assert!(chain.block_header(BlockId::Latest).is_some()); | ||||
| 		assert!(chain.block_header(BlockId::Pending).is_some()); | ||||
| 	} | ||||
| 
 | ||||
| 	#[test] | ||||
|  | ||||
| @ -574,6 +574,12 @@ impl<T: ChainDataFetcher> LightChainClient for Client<T> { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<T: ChainDataFetcher> ::ethcore::client::ChainInfo for Client<T> { | ||||
| 	fn chain_info(&self) -> BlockChainInfo { | ||||
| 		Client::chain_info(self) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<T: ChainDataFetcher> ::ethcore::client::EngineClient for Client<T> { | ||||
| 	fn update_sealing(&self) { } | ||||
| 	fn submit_seal(&self, _block_hash: H256, _seal: Vec<Vec<u8>>) { } | ||||
| @ -587,10 +593,6 @@ impl<T: ChainDataFetcher> ::ethcore::client::EngineClient for Client<T> { | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	fn chain_info(&self) -> BlockChainInfo { | ||||
| 		Client::chain_info(self) | ||||
| 	} | ||||
| 
 | ||||
| 	fn as_full_client(&self) -> Option<&::ethcore::client::BlockChainClient> { | ||||
| 		None | ||||
| 	} | ||||
|  | ||||
| @ -948,7 +948,7 @@ mod tests { | ||||
| 	use trie::recorder::Recorder; | ||||
| 	use hash::keccak; | ||||
| 
 | ||||
| 	use ethcore::client::{BlockChainClient, TestBlockChainClient, EachBlockWith}; | ||||
| 	use ethcore::client::{BlockChainClient, BlockInfo, TestBlockChainClient, EachBlockWith}; | ||||
| 	use ethcore::header::Header; | ||||
| 	use ethcore::encoded; | ||||
| 	use ethcore::receipt::{Receipt, TransactionOutcome}; | ||||
|  | ||||
| @ -20,9 +20,9 @@ | ||||
| use std::sync::Arc; | ||||
| 
 | ||||
| use ethcore::blockchain_info::BlockChainInfo; | ||||
| use ethcore::client::{BlockChainClient, ProvingBlockChainClient}; | ||||
| use ethcore::encoded; | ||||
| use ethcore::client::{BlockChainClient, ProvingBlockChainClient, ChainInfo, BlockInfo as ClientBlockInfo}; | ||||
| use ethcore::ids::BlockId; | ||||
| use ethcore::encoded; | ||||
| use ethereum_types::H256; | ||||
| use parking_lot::RwLock; | ||||
| use transaction::PendingTransaction; | ||||
| @ -138,7 +138,7 @@ pub trait Provider: Send + Sync { | ||||
| // Implementation of a light client data provider for a client.
 | ||||
| impl<T: ProvingBlockChainClient + ?Sized> Provider for T { | ||||
| 	fn chain_info(&self) -> BlockChainInfo { | ||||
| 		BlockChainClient::chain_info(self) | ||||
| 		ChainInfo::chain_info(self) | ||||
| 	} | ||||
| 
 | ||||
| 	fn reorg_depth(&self, a: &H256, b: &H256) -> Option<u64> { | ||||
| @ -150,7 +150,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T { | ||||
| 	} | ||||
| 
 | ||||
| 	fn block_header(&self, id: BlockId) -> Option<encoded::Header> { | ||||
| 		BlockChainClient::block_header(self, id) | ||||
| 		ClientBlockInfo::block_header(self, id) | ||||
| 	} | ||||
| 
 | ||||
| 	fn transaction_index(&self, req: request::CompleteTransactionIndexRequest) | ||||
|  | ||||
| @ -18,7 +18,12 @@ use ethereum_types::{H256, U256}; | ||||
| use bytes::Bytes; | ||||
| use header::BlockNumber; | ||||
| 
 | ||||
| /// Best block info.
 | ||||
| /// Contains information on a best block that is specific to the consensus engine.
 | ||||
| ///
 | ||||
| /// For GHOST fork-choice rule it would typically describe the block with highest
 | ||||
| /// combined difficulty (usually the block with the highest block number).
 | ||||
| ///
 | ||||
| /// Sometimes refered as 'latest block'.
 | ||||
| #[derive(Default)] | ||||
| pub struct BestBlock { | ||||
| 	/// Best block hash.
 | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -30,9 +30,12 @@ pub use self::error::Error; | ||||
| pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactResult}; | ||||
| pub use self::test_client::{TestBlockChainClient, EachBlockWith}; | ||||
| pub use self::chain_notify::ChainNotify; | ||||
| pub use self::traits::{BlockChainClient, MiningBlockChainClient, EngineClient}; | ||||
| 
 | ||||
| pub use self::traits::ProvingBlockChainClient; | ||||
| pub use self::traits::{ | ||||
|     Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, CallContract, TransactionInfo, RegistryInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, | ||||
|     StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter | ||||
| }; | ||||
| pub use state::StateInfo; | ||||
| pub use self::traits::{BlockChainClient, MiningBlockChainClient, EngineClient, ProvingBlockChainClient}; | ||||
| 
 | ||||
| pub use types::ids::*; | ||||
| pub use types::trace_filter::Filter as TraceFilter; | ||||
|  | ||||
| @ -34,9 +34,11 @@ use ethkey::{Generator, Random}; | ||||
| use transaction::{self, Transaction, LocalizedTransaction, PendingTransaction, SignedTransaction, Action}; | ||||
| use blockchain::{TreeRoute, BlockReceipts}; | ||||
| use client::{ | ||||
| 	BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId, | ||||
| 	Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, CallContract, TransactionInfo, RegistryInfo, | ||||
| 	PrepareOpenBlock, BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId, | ||||
| 	TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError, | ||||
| 	ProvingBlockChainClient, | ||||
| 	ProvingBlockChainClient, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock, | ||||
| 	Call, StateClient, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter | ||||
| }; | ||||
| use db::{NUM_COLUMNS, COL_STATE}; | ||||
| use header::{Header as BlockHeader, BlockNumber}; | ||||
| @ -59,7 +61,11 @@ use executive::Executed; | ||||
| use error::CallError; | ||||
| use trace::LocalizedTrace; | ||||
| use state_db::StateDB; | ||||
| use header::Header; | ||||
| use encoded; | ||||
| use engines::EthEngine; | ||||
| use trie; | ||||
| use state::StateInfo; | ||||
| 
 | ||||
| /// Test client.
 | ||||
| pub struct TestBlockChainClient { | ||||
| @ -316,7 +322,7 @@ impl TestBlockChainClient { | ||||
| 			BlockId::Hash(hash) => Some(hash), | ||||
| 			BlockId::Number(n) => self.numbers.read().get(&(n as usize)).cloned(), | ||||
| 			BlockId::Earliest => self.numbers.read().get(&0).cloned(), | ||||
| 			BlockId::Latest | BlockId::Pending => self.numbers.read().get(&(self.numbers.read().len() - 1)).cloned() | ||||
| 			BlockId::Latest => self.numbers.read().get(&(self.numbers.read().len() - 1)).cloned() | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -357,13 +363,13 @@ pub fn get_temp_state_db() -> StateDB { | ||||
| 	StateDB::new(journal_db, 1024 * 1024) | ||||
| } | ||||
| 
 | ||||
| impl MiningBlockChainClient for TestBlockChainClient { | ||||
| 	fn as_block_chain_client(&self) -> &BlockChainClient { self } | ||||
| 
 | ||||
| 	fn latest_schedule(&self) -> Schedule { | ||||
| 		Schedule::new_post_eip150(24576, true, true, true) | ||||
| impl ReopenBlock for TestBlockChainClient { | ||||
| 	fn reopen_block(&self, block: ClosedBlock) -> OpenBlock { | ||||
| 		block.reopen(&*self.spec.engine) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl PrepareOpenBlock for TestBlockChainClient { | ||||
| 	fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock { | ||||
| 		let engine = &*self.spec.engine; | ||||
| 		let genesis_header = self.spec.genesis_header(); | ||||
| @ -386,39 +392,221 @@ impl MiningBlockChainClient for TestBlockChainClient { | ||||
| 		open_block.set_timestamp(*self.latest_block_timestamp.read()); | ||||
| 		open_block | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 	fn reopen_block(&self, block: ClosedBlock) -> OpenBlock { | ||||
| 		block.reopen(&*self.spec.engine) | ||||
| 	} | ||||
| 
 | ||||
| 	fn vm_factory(&self) -> &VmFactory { | ||||
| 		&self.vm_factory | ||||
| impl ScheduleInfo for TestBlockChainClient { | ||||
| 	fn latest_schedule(&self) -> Schedule { | ||||
| 		Schedule::new_post_eip150(24576, true, true, true) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl ImportSealedBlock for TestBlockChainClient { | ||||
| 	fn import_sealed_block(&self, _block: SealedBlock) -> ImportResult { | ||||
| 		Ok(H256::default()) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl BlockProducer for TestBlockChainClient {} | ||||
| 
 | ||||
| impl BroadcastProposalBlock for TestBlockChainClient { | ||||
| 	fn broadcast_proposal_block(&self, _block: SealedBlock) {} | ||||
| } | ||||
| 
 | ||||
| impl BlockChainClient for TestBlockChainClient { | ||||
| 	fn call(&self, _t: &SignedTransaction, _analytics: CallAnalytics, _block: BlockId) -> Result<Executed, CallError> { | ||||
| impl SealedBlockImporter for TestBlockChainClient {} | ||||
| 
 | ||||
| impl MiningBlockChainClient for TestBlockChainClient { | ||||
| 	fn vm_factory(&self) -> &VmFactory { | ||||
| 		&self.vm_factory | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl Nonce for TestBlockChainClient { | ||||
| 	fn nonce(&self, address: &Address, id: BlockId) -> Option<U256> { | ||||
| 		match id { | ||||
| 			BlockId::Latest => Some(self.nonces.read().get(address).cloned().unwrap_or(self.spec.params().account_start_nonce)), | ||||
| 			_ => None, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn latest_nonce(&self, address: &Address) -> U256 { | ||||
| 		self.nonce(address, BlockId::Latest).unwrap() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl Balance for TestBlockChainClient { | ||||
| 	fn balance(&self, address: &Address, state: StateOrBlock) -> Option<U256> { | ||||
| 		match state { | ||||
| 			StateOrBlock::Block(BlockId::Latest) | StateOrBlock::State(_) => Some(self.balances.read().get(address).cloned().unwrap_or_else(U256::zero)), | ||||
| 			_ => None, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn latest_balance(&self, address: &Address) -> U256 { | ||||
| 		self.balance(address, BlockId::Latest.into()).unwrap() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl AccountData for TestBlockChainClient {} | ||||
| 
 | ||||
| impl ChainInfo for TestBlockChainClient { | ||||
| 	fn chain_info(&self) -> BlockChainInfo { | ||||
| 		let number = self.blocks.read().len() as BlockNumber - 1; | ||||
| 		BlockChainInfo { | ||||
| 			total_difficulty: *self.difficulty.read(), | ||||
| 			pending_total_difficulty: *self.difficulty.read(), | ||||
| 			genesis_hash: self.genesis_hash.clone(), | ||||
| 			best_block_hash: self.last_hash.read().clone(), | ||||
| 			best_block_number: number, | ||||
| 			best_block_timestamp: number, | ||||
| 			first_block_hash: self.first_block.read().as_ref().map(|x| x.0), | ||||
| 			first_block_number: self.first_block.read().as_ref().map(|x| x.1), | ||||
| 			ancient_block_hash: self.ancient_block.read().as_ref().map(|x| x.0), | ||||
| 			ancient_block_number: self.ancient_block.read().as_ref().map(|x| x.1) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl BlockInfo for TestBlockChainClient { | ||||
| 	fn block_header(&self, id: BlockId) -> Option<encoded::Header> { | ||||
| 		self.block_hash(id) | ||||
| 			.and_then(|hash| self.blocks.read().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) | ||||
| 			.map(encoded::Header::new) | ||||
| 	} | ||||
| 
 | ||||
| 	fn best_block_header(&self) -> encoded::Header { | ||||
| 		self.block_header(BlockId::Hash(self.chain_info().best_block_hash)) | ||||
| 			.expect("Best block always has header.") | ||||
| 	} | ||||
| 
 | ||||
| 	fn block(&self, id: BlockId) -> Option<encoded::Block> { | ||||
| 		self.block_hash(id) | ||||
| 			.and_then(|hash| self.blocks.read().get(&hash).cloned()) | ||||
| 			.map(encoded::Block::new) | ||||
| 	} | ||||
| 
 | ||||
| 	fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256> { | ||||
| 		match id { | ||||
| 			BlockId::Latest => self.code.read().get(address).map(|c| keccak(&c)), | ||||
| 			_ => None, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl CallContract for TestBlockChainClient { | ||||
| 	fn call_contract(&self, _id: BlockId, _address: Address, _data: Bytes) -> Result<Bytes, String> { Ok(vec![]) } | ||||
| } | ||||
| 
 | ||||
| impl TransactionInfo for TestBlockChainClient { | ||||
| 	fn transaction_block(&self, _id: TransactionId) -> Option<H256> { | ||||
| 		None	// Simple default.
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl BlockChain for TestBlockChainClient {} | ||||
| 
 | ||||
| impl RegistryInfo for TestBlockChainClient { | ||||
| 	fn registry_address(&self, _name: String, _block: BlockId) -> Option<Address> { None } | ||||
| } | ||||
| 
 | ||||
| impl ImportBlock for TestBlockChainClient { | ||||
| 	fn import_block(&self, b: Bytes) -> Result<H256, BlockImportError> { | ||||
| 		let header = Rlp::new(&b).val_at::<BlockHeader>(0); | ||||
| 		let h = header.hash(); | ||||
| 		let number: usize = header.number() as usize; | ||||
| 		if number > self.blocks.read().len() { | ||||
| 			panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().len(), number); | ||||
| 		} | ||||
| 		if number > 0 { | ||||
| 			match self.blocks.read().get(header.parent_hash()) { | ||||
| 				Some(parent) => { | ||||
| 					let parent = Rlp::new(parent).val_at::<BlockHeader>(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().len(); | ||||
| 		if number == len { | ||||
| 			{ | ||||
| 				let mut difficulty = self.difficulty.write(); | ||||
| 				*difficulty = *difficulty + header.difficulty().clone(); | ||||
| 			} | ||||
| 			mem::replace(&mut *self.last_hash.write(), h.clone()); | ||||
| 			self.blocks.write().insert(h.clone(), b); | ||||
| 			self.numbers.write().insert(number, h.clone()); | ||||
| 			let mut parent_hash = header.parent_hash().clone(); | ||||
| 			if number > 0 { | ||||
| 				let mut n = number - 1; | ||||
| 				while n > 0 && self.numbers.read()[&n] != parent_hash { | ||||
| 					*self.numbers.write().get_mut(&n).unwrap() = parent_hash.clone(); | ||||
| 					n -= 1; | ||||
| 					parent_hash = Rlp::new(&self.blocks.read()[&parent_hash]).val_at::<BlockHeader>(0).parent_hash().clone(); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			self.blocks.write().insert(h.clone(), b.to_vec()); | ||||
| 		} | ||||
| 		Ok(h) | ||||
| 	} | ||||
| 
 | ||||
| 	fn import_block_with_receipts(&self, b: Bytes, _r: Bytes) -> Result<H256, BlockImportError> { | ||||
| 		self.import_block(b) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl Call for TestBlockChainClient { | ||||
| 	// State will not be used by test client anyway, since all methods that accept state are mocked
 | ||||
| 	type State = (); | ||||
| 
 | ||||
| 	fn call(&self, _t: &SignedTransaction, _analytics: CallAnalytics, _state: &mut Self::State, _header: &Header) -> Result<Executed, CallError> { | ||||
| 		self.execution_result.read().clone().unwrap() | ||||
| 	} | ||||
| 
 | ||||
| 	fn call_many(&self, txs: &[(SignedTransaction, CallAnalytics)], block: BlockId) -> Result<Vec<Executed>, CallError> { | ||||
| 	fn call_many(&self, txs: &[(SignedTransaction, CallAnalytics)], state: &mut Self::State, header: &Header) -> Result<Vec<Executed>, CallError> { | ||||
| 		let mut res = Vec::with_capacity(txs.len()); | ||||
| 		for &(ref tx, analytics) in txs { | ||||
| 			res.push(self.call(tx, analytics, block)?); | ||||
| 			res.push(self.call(tx, analytics, state, header)?); | ||||
| 		} | ||||
| 		Ok(res) | ||||
| 	} | ||||
| 
 | ||||
| 	fn estimate_gas(&self, _t: &SignedTransaction, _block: BlockId) -> Result<U256, CallError> { | ||||
| 	fn estimate_gas(&self, _t: &SignedTransaction, _state: &Self::State, _header: &Header) -> Result<U256, CallError> { | ||||
| 		Ok(21000.into()) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl StateInfo for () { | ||||
| 	fn nonce(&self, _address: &Address) -> trie::Result<U256> { unimplemented!() } | ||||
| 	fn balance(&self, _address: &Address) -> trie::Result<U256> { unimplemented!() } | ||||
| 	fn storage_at(&self, _address: &Address, _key: &H256) -> trie::Result<H256> { unimplemented!() } | ||||
| 	fn code(&self, _address: &Address) -> trie::Result<Option<Arc<Bytes>>> { unimplemented!() } | ||||
| } | ||||
| 
 | ||||
| impl StateClient for TestBlockChainClient { | ||||
| 	// 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<Self::State> { | ||||
| 		Some(()) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl EngineInfo for TestBlockChainClient { | ||||
| 	fn engine(&self) -> &EthEngine { | ||||
| 		unimplemented!() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl BlockChainClient for TestBlockChainClient { | ||||
| 	fn replay(&self, _id: TransactionId, _analytics: CallAnalytics) -> Result<Executed, CallError> { | ||||
| 		self.execution_result.read().clone().unwrap() | ||||
| 	} | ||||
| @ -435,49 +623,20 @@ impl BlockChainClient for TestBlockChainClient { | ||||
| 		Self::block_hash(self, id) | ||||
| 	} | ||||
| 
 | ||||
| 	fn nonce(&self, address: &Address, id: BlockId) -> Option<U256> { | ||||
| 		match id { | ||||
| 			BlockId::Latest | BlockId::Pending => Some(self.nonces.read().get(address).cloned().unwrap_or(self.spec.params().account_start_nonce)), | ||||
| 			_ => None, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn storage_root(&self, _address: &Address, _id: BlockId) -> Option<H256> { | ||||
| 		None | ||||
| 	} | ||||
| 
 | ||||
| 	fn latest_nonce(&self, address: &Address) -> U256 { | ||||
| 		self.nonce(address, BlockId::Latest).unwrap() | ||||
| 	} | ||||
| 
 | ||||
| 	fn code(&self, address: &Address, id: BlockId) -> Option<Option<Bytes>> { | ||||
| 		match id { | ||||
| 			BlockId::Latest | BlockId::Pending => Some(self.code.read().get(address).cloned()), | ||||
| 	fn code(&self, address: &Address, state: StateOrBlock) -> Option<Option<Bytes>> { | ||||
| 		match state { | ||||
| 			StateOrBlock::Block(BlockId::Latest) => Some(self.code.read().get(address).cloned()), | ||||
| 			_ => None, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256> { | ||||
| 		match id { | ||||
| 			BlockId::Latest | BlockId::Pending => self.code.read().get(address).map(|c| keccak(&c)), | ||||
| 			_ => None, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn balance(&self, address: &Address, id: BlockId) -> Option<U256> { | ||||
| 		match id { | ||||
| 			BlockId::Latest | BlockId::Pending => Some(self.balances.read().get(address).cloned().unwrap_or_else(U256::zero)), | ||||
| 			_ => None, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn latest_balance(&self, address: &Address) -> U256 { | ||||
| 		self.balance(address, BlockId::Latest).unwrap() | ||||
| 	} | ||||
| 
 | ||||
| 	fn storage_at(&self, address: &Address, position: &H256, id: BlockId) -> Option<H256> { | ||||
| 		match id { | ||||
| 			BlockId::Latest | BlockId::Pending => Some(self.storage.read().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new)), | ||||
| 	fn storage_at(&self, address: &Address, position: &H256, state: StateOrBlock) -> Option<H256> { | ||||
| 		match state { | ||||
| 			StateOrBlock::Block(BlockId::Latest) => Some(self.storage.read().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new)), | ||||
| 			_ => None, | ||||
| 		} | ||||
| 	} | ||||
| @ -493,10 +652,6 @@ impl BlockChainClient for TestBlockChainClient { | ||||
| 		None	// Simple default.
 | ||||
| 	} | ||||
| 
 | ||||
| 	fn transaction_block(&self, _id: TransactionId) -> Option<H256> { | ||||
| 		None	// Simple default.
 | ||||
| 	} | ||||
| 
 | ||||
| 	fn uncle(&self, _id: UncleId) -> Option<encoded::Header> { | ||||
| 		None	// Simple default.
 | ||||
| 	} | ||||
| @ -522,17 +677,6 @@ impl BlockChainClient for TestBlockChainClient { | ||||
| 		unimplemented!(); | ||||
| 	} | ||||
| 
 | ||||
| 	fn best_block_header(&self) -> encoded::Header { | ||||
| 		self.block_header(BlockId::Hash(self.chain_info().best_block_hash)) | ||||
| 			.expect("Best block always has header.") | ||||
| 	} | ||||
| 
 | ||||
| 	fn block_header(&self, id: BlockId) -> Option<encoded::Header> { | ||||
| 		self.block_hash(id) | ||||
| 			.and_then(|hash| self.blocks.read().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) | ||||
| 			.map(encoded::Header::new) | ||||
| 	} | ||||
| 
 | ||||
| 	fn block_number(&self, _id: BlockId) -> Option<BlockNumber> { | ||||
| 		unimplemented!() | ||||
| 	} | ||||
| @ -546,12 +690,6 @@ impl BlockChainClient for TestBlockChainClient { | ||||
| 		})) | ||||
| 	} | ||||
| 
 | ||||
| 	fn block(&self, id: BlockId) -> Option<encoded::Block> { | ||||
| 		self.block_hash(id) | ||||
| 			.and_then(|hash| self.blocks.read().get(&hash).cloned()) | ||||
| 			.map(encoded::Block::new) | ||||
| 	} | ||||
| 
 | ||||
| 	fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> { | ||||
| 		self.block(id) | ||||
| 			.map(|block| block.view().header()) | ||||
| @ -564,7 +702,6 @@ impl BlockChainClient for TestBlockChainClient { | ||||
| 			BlockId::Number(number) if (number as usize) < self.blocks.read().len() => BlockStatus::InChain, | ||||
| 			BlockId::Hash(ref hash) if self.blocks.read().get(hash).is_some() => BlockStatus::InChain, | ||||
| 			BlockId::Latest | BlockId::Earliest => BlockStatus::InChain, | ||||
| 			BlockId::Pending => BlockStatus::Pending, | ||||
| 			_ => BlockStatus::Unknown, | ||||
| 		} | ||||
| 	} | ||||
| @ -628,55 +765,6 @@ impl BlockChainClient for TestBlockChainClient { | ||||
| 		None | ||||
| 	} | ||||
| 
 | ||||
| 	fn import_block(&self, b: Bytes) -> Result<H256, BlockImportError> { | ||||
| 		let header = Rlp::new(&b).val_at::<BlockHeader>(0); | ||||
| 		let h = header.hash(); | ||||
| 		let number: usize = header.number() as usize; | ||||
| 		if number > self.blocks.read().len() { | ||||
| 			panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().len(), number); | ||||
| 		} | ||||
| 		if number > 0 { | ||||
| 			match self.blocks.read().get(header.parent_hash()) { | ||||
| 				Some(parent) => { | ||||
| 					let parent = Rlp::new(parent).val_at::<BlockHeader>(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().len(); | ||||
| 		if number == len { | ||||
| 			{ | ||||
| 				let mut difficulty = self.difficulty.write(); | ||||
| 				*difficulty = *difficulty + header.difficulty().clone(); | ||||
| 			} | ||||
| 			mem::replace(&mut *self.last_hash.write(), h.clone()); | ||||
| 			self.blocks.write().insert(h.clone(), b); | ||||
| 			self.numbers.write().insert(number, h.clone()); | ||||
| 			let mut parent_hash = header.parent_hash().clone(); | ||||
| 			if number > 0 { | ||||
| 				let mut n = number - 1; | ||||
| 				while n > 0 && self.numbers.read()[&n] != parent_hash { | ||||
| 					*self.numbers.write().get_mut(&n).unwrap() = parent_hash.clone(); | ||||
| 					n -= 1; | ||||
| 					parent_hash = Rlp::new(&self.blocks.read()[&parent_hash]).val_at::<BlockHeader>(0).parent_hash().clone(); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			self.blocks.write().insert(h.clone(), b.to_vec()); | ||||
| 		} | ||||
| 		Ok(h) | ||||
| 	} | ||||
| 
 | ||||
| 	fn import_block_with_receipts(&self, b: Bytes, _r: Bytes) -> Result<H256, BlockImportError> { | ||||
| 		self.import_block(b) | ||||
| 	} | ||||
| 
 | ||||
| 	fn queue_info(&self) -> QueueInfo { | ||||
| 		QueueInfo { | ||||
| 			verified_queue_size: self.queue_size.load(AtomicOrder::Relaxed), | ||||
| @ -695,22 +783,6 @@ impl BlockChainClient for TestBlockChainClient { | ||||
| 		Default::default() | ||||
| 	} | ||||
| 
 | ||||
| 	fn chain_info(&self) -> BlockChainInfo { | ||||
| 		let number = self.blocks.read().len() as BlockNumber - 1; | ||||
| 		BlockChainInfo { | ||||
| 			total_difficulty: *self.difficulty.read(), | ||||
| 			pending_total_difficulty: *self.difficulty.read(), | ||||
| 			genesis_hash: self.genesis_hash.clone(), | ||||
| 			best_block_hash: self.last_hash.read().clone(), | ||||
| 			best_block_number: number, | ||||
| 			best_block_timestamp: number, | ||||
| 			first_block_hash: self.first_block.read().as_ref().map(|x| x.0), | ||||
| 			first_block_number: self.first_block.read().as_ref().map(|x| x.1), | ||||
| 			ancient_block_hash: self.ancient_block.read().as_ref().map(|x| x.0), | ||||
| 			ancient_block_number: self.ancient_block.read().as_ref().map(|x| x.1) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn filter_traces(&self, _filter: TraceFilter) -> Option<Vec<LocalizedTrace>> { | ||||
| 		self.traces.read().clone() | ||||
| 	} | ||||
| @ -762,8 +834,6 @@ impl BlockChainClient for TestBlockChainClient { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn call_contract(&self, _id: BlockId, _address: Address, _data: Bytes) -> Result<Bytes, String> { Ok(vec![]) } | ||||
| 
 | ||||
| 	fn transact_contract(&self, address: Address, data: Bytes) -> Result<transaction::ImportResult, EthcoreError> { | ||||
| 		let transaction = Transaction { | ||||
| 			nonce: self.latest_nonce(&self.miner.author()), | ||||
| @ -781,8 +851,6 @@ impl BlockChainClient for TestBlockChainClient { | ||||
| 
 | ||||
| 	fn registrar_address(&self) -> Option<Address> { None } | ||||
| 
 | ||||
| 	fn registry_address(&self, _name: String, _block: BlockId) -> Option<Address> { None } | ||||
| 
 | ||||
| 	fn eip86_transition(&self) -> u64 { u64::max_value() } | ||||
| } | ||||
| 
 | ||||
| @ -821,10 +889,6 @@ impl super::traits::EngineClient for TestBlockChainClient { | ||||
| 		None | ||||
| 	} | ||||
| 
 | ||||
| 	fn chain_info(&self) -> BlockChainInfo { | ||||
| 		BlockChainClient::chain_info(self) | ||||
| 	} | ||||
| 
 | ||||
| 	fn as_full_client(&self) -> Option<&BlockChainClient> { Some(self) } | ||||
| 
 | ||||
| 	fn block_number(&self, id: BlockId) -> Option<BlockNumber> { | ||||
|  | ||||
| @ -32,6 +32,9 @@ use receipt::LocalizedReceipt; | ||||
| use trace::LocalizedTrace; | ||||
| use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction, ImportResult as TransactionImportResult}; | ||||
| use verification::queue::QueueInfo as BlockQueueInfo; | ||||
| use state::StateInfo; | ||||
| use header::Header; | ||||
| use engines::EthEngine; | ||||
| 
 | ||||
| use ethereum_types::{H256, U256, Address}; | ||||
| use bytes::Bytes; | ||||
| @ -46,80 +49,198 @@ use types::block_status::BlockStatus; | ||||
| use types::mode::Mode; | ||||
| use types::pruning_info::PruningInfo; | ||||
| 
 | ||||
| /// Blockchain database client. Owns and manages a blockchain and a block queue.
 | ||||
| pub trait BlockChainClient : Sync + Send { | ||||
| /// State information to be used during client query
 | ||||
| pub enum StateOrBlock { | ||||
| 	/// State to be used, may be pending
 | ||||
| 	State(Box<StateInfo>), | ||||
| 
 | ||||
| 	/// Get raw block header data by block id.
 | ||||
| 	fn block_header(&self, id: BlockId) -> Option<encoded::Header>; | ||||
| 	/// Id of an existing block from a chain to get state from
 | ||||
| 	Block(BlockId) | ||||
| } | ||||
| 
 | ||||
| 	/// Look up the block number for the given block ID.
 | ||||
| 	fn block_number(&self, id: BlockId) -> Option<BlockNumber>; | ||||
| impl<S: StateInfo + 'static> From<S> for StateOrBlock { | ||||
| 	fn from(info: S) -> StateOrBlock { | ||||
| 		StateOrBlock::State(Box::new(info) as Box<_>) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 	/// Get raw block body data by block id.
 | ||||
| 	/// Block body is an RLP list of two items: uncles and transactions.
 | ||||
| 	fn block_body(&self, id: BlockId) -> Option<encoded::Body>; | ||||
| impl From<Box<StateInfo>> for StateOrBlock { | ||||
| 	fn from(info: Box<StateInfo>) -> StateOrBlock { | ||||
| 		StateOrBlock::State(info) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 	/// Get raw block data by block header hash.
 | ||||
| 	fn block(&self, id: BlockId) -> Option<encoded::Block>; | ||||
| 
 | ||||
| 	/// Get block status by block header hash.
 | ||||
| 	fn block_status(&self, id: BlockId) -> BlockStatus; | ||||
| 
 | ||||
| 	/// Get block total difficulty.
 | ||||
| 	fn block_total_difficulty(&self, id: BlockId) -> Option<U256>; | ||||
| impl From<BlockId> for StateOrBlock { | ||||
| 	fn from(id: BlockId) -> StateOrBlock { | ||||
| 		StateOrBlock::Block(id) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// Provides `nonce` and `latest_nonce` methods
 | ||||
| pub trait Nonce { | ||||
| 	/// Attempt to get address nonce at given block.
 | ||||
| 	/// May not fail on BlockId::Latest.
 | ||||
| 	fn nonce(&self, address: &Address, id: BlockId) -> Option<U256>; | ||||
| 
 | ||||
| 	/// Attempt to get address storage root at given block.
 | ||||
| 	/// May not fail on BlockId::Latest.
 | ||||
| 	fn storage_root(&self, address: &Address, id: BlockId) -> Option<H256>; | ||||
| 
 | ||||
| 	/// Get address nonce at the latest block's state.
 | ||||
| 	fn latest_nonce(&self, address: &Address) -> U256 { | ||||
| 		self.nonce(address, BlockId::Latest) | ||||
| 			.expect("nonce will return Some when given BlockId::Latest. nonce was given BlockId::Latest. \ | ||||
| 			Therefore nonce has returned Some; qed")
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// Provides `balance` and `latest_balance` methods
 | ||||
| pub trait Balance { | ||||
| 	/// Get address balance at the given block's state.
 | ||||
| 	///
 | ||||
| 	/// May not return None if given BlockId::Latest.
 | ||||
| 	/// Returns None if and only if the block's root hash has been pruned from the DB.
 | ||||
| 	fn balance(&self, address: &Address, state: StateOrBlock) -> Option<U256>; | ||||
| 
 | ||||
| 	/// Get address balance at the latest block's state.
 | ||||
| 	fn latest_balance(&self, address: &Address) -> U256 { | ||||
| 		self.balance(address, BlockId::Latest.into()) | ||||
| 			.expect("balance will return Some if given BlockId::Latest. balance was given BlockId::Latest \ | ||||
| 			Therefore balance has returned Some; qed")
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// Provides methods to access account info
 | ||||
| pub trait AccountData: Nonce + Balance {} | ||||
| 
 | ||||
| /// Provides `chain_info` method
 | ||||
| pub trait ChainInfo { | ||||
| 	/// Get blockchain information.
 | ||||
| 	fn chain_info(&self) -> BlockChainInfo; | ||||
| } | ||||
| 
 | ||||
| /// Provides various information on a block by it's ID
 | ||||
| pub trait BlockInfo { | ||||
| 	/// Get raw block header data by block id.
 | ||||
| 	fn block_header(&self, id: BlockId) -> Option<encoded::Header>; | ||||
| 
 | ||||
| 	/// Get the best block header.
 | ||||
| 	fn best_block_header(&self) -> encoded::Header; | ||||
| 
 | ||||
| 	/// Get raw block data by block header hash.
 | ||||
| 	fn block(&self, id: BlockId) -> Option<encoded::Block>; | ||||
| 
 | ||||
| 	/// Get address code hash at given block's state.
 | ||||
| 	fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256>; | ||||
| } | ||||
| 
 | ||||
| /// Provides various information on a transaction by it's ID
 | ||||
| pub trait TransactionInfo { | ||||
| 	/// Get the hash of block that contains the transaction, if any.
 | ||||
| 	fn transaction_block(&self, id: TransactionId) -> Option<H256>; | ||||
| } | ||||
| 
 | ||||
| /// Provides methods to access chain state
 | ||||
| pub trait StateClient { | ||||
| 	/// Type representing chain state
 | ||||
| 	type State: StateInfo; | ||||
| 
 | ||||
| 	/// Get a copy of the best block's state.
 | ||||
| 	fn latest_state(&self) -> Self::State; | ||||
| 
 | ||||
| 	/// Attempt to get a copy of a specific block's final state.
 | ||||
| 	///
 | ||||
| 	/// This will not fail if given BlockId::Latest.
 | ||||
| 	/// Otherwise, this can fail (but may not) if the DB prunes state or the block
 | ||||
| 	/// is unknown.
 | ||||
| 	fn state_at(&self, id: BlockId) -> Option<Self::State>; | ||||
| } | ||||
| 
 | ||||
| /// Provides various blockchain information, like block header, chain state etc.
 | ||||
| pub trait BlockChain: ChainInfo + BlockInfo + TransactionInfo {} | ||||
| 
 | ||||
| /// Provides information on a blockchain service and it's registry
 | ||||
| pub trait RegistryInfo { | ||||
| 	/// Get the address of a particular blockchain service, if available.
 | ||||
| 	fn registry_address(&self, name: String, block: BlockId) -> Option<Address>; | ||||
| } | ||||
| 
 | ||||
| // FIXME Why these methods belong to BlockChainClient and not MiningBlockChainClient?
 | ||||
| /// Provides methods to import block into blockchain
 | ||||
| pub trait ImportBlock { | ||||
| 	/// Import a block into the blockchain.
 | ||||
| 	fn import_block(&self, bytes: Bytes) -> Result<H256, BlockImportError>; | ||||
| 
 | ||||
| 	/// Import a block with transaction receipts. Does no sealing and transaction validation.
 | ||||
| 	fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result<H256, BlockImportError>; | ||||
| } | ||||
| 
 | ||||
| /// Provides `call_contract` method
 | ||||
| pub trait CallContract { | ||||
| 	/// Like `call`, but with various defaults. Designed to be used for calling contracts.
 | ||||
| 	fn call_contract(&self, id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String>; | ||||
| } | ||||
| 
 | ||||
| /// Provides `call` and `call_many` methods
 | ||||
| pub trait Call { | ||||
| 	/// Type representing chain state
 | ||||
| 	type State: StateInfo; | ||||
| 
 | ||||
| 	/// Makes a non-persistent transaction call.
 | ||||
| 	fn call(&self, tx: &SignedTransaction, analytics: CallAnalytics, state: &mut Self::State, header: &Header) -> Result<Executed, CallError>; | ||||
| 
 | ||||
| 	/// Makes multiple non-persistent but dependent transaction calls.
 | ||||
| 	/// Returns a vector of successes or a failure if any of the transaction fails.
 | ||||
| 	fn call_many(&self, txs: &[(SignedTransaction, CallAnalytics)], state: &mut Self::State, header: &Header) -> Result<Vec<Executed>, CallError>; | ||||
| 
 | ||||
| 	/// Estimates how much gas will be necessary for a call.
 | ||||
| 	fn estimate_gas(&self, t: &SignedTransaction, state: &Self::State, header: &Header) -> Result<U256, CallError>; | ||||
| } | ||||
| 
 | ||||
| /// Provides `engine` method
 | ||||
| pub trait EngineInfo { | ||||
| 	/// Get underlying engine object
 | ||||
| 	fn engine(&self) -> &EthEngine; | ||||
| } | ||||
| 
 | ||||
| /// Blockchain database client. Owns and manages a blockchain and a block queue.
 | ||||
| pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContract + RegistryInfo + ImportBlock { | ||||
| 	/// Look up the block number for the given block ID.
 | ||||
| 	fn block_number(&self, id: BlockId) -> Option<BlockNumber>; | ||||
| 
 | ||||
| 	/// Get raw block body data by block id.
 | ||||
| 	/// Block body is an RLP list of two items: uncles and transactions.
 | ||||
| 	fn block_body(&self, id: BlockId) -> Option<encoded::Body>; | ||||
| 
 | ||||
| 	/// Get block status by block header hash.
 | ||||
| 	fn block_status(&self, id: BlockId) -> BlockStatus; | ||||
| 
 | ||||
| 	/// Get block total difficulty.
 | ||||
| 	fn block_total_difficulty(&self, id: BlockId) -> Option<U256>; | ||||
| 
 | ||||
| 	/// Attempt to get address storage root at given block.
 | ||||
| 	/// May not fail on BlockId::Latest.
 | ||||
| 	fn storage_root(&self, address: &Address, id: BlockId) -> Option<H256>; | ||||
| 
 | ||||
| 	/// Get block hash.
 | ||||
| 	fn block_hash(&self, id: BlockId) -> Option<H256>; | ||||
| 
 | ||||
| 	/// Get address code at given block's state.
 | ||||
| 	fn code(&self, address: &Address, id: BlockId) -> Option<Option<Bytes>>; | ||||
| 	fn code(&self, address: &Address, state: StateOrBlock) -> Option<Option<Bytes>>; | ||||
| 
 | ||||
| 	/// Get address code at the latest block's state.
 | ||||
| 	fn latest_code(&self, address: &Address) -> Option<Bytes> { | ||||
| 		self.code(address, BlockId::Latest) | ||||
| 		self.code(address, BlockId::Latest.into()) | ||||
| 			.expect("code will return Some if given BlockId::Latest; qed") | ||||
| 	} | ||||
| 
 | ||||
| 	/// Get address code hash at given block's state.
 | ||||
| 	fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256>; | ||||
| 
 | ||||
| 	/// Get address balance at the given block's state.
 | ||||
| 	///
 | ||||
| 	/// May not return None if given BlockId::Latest.
 | ||||
| 	/// Returns None if and only if the block's root hash has been pruned from the DB.
 | ||||
| 	fn balance(&self, address: &Address, id: BlockId) -> Option<U256>; | ||||
| 
 | ||||
| 	/// Get address balance at the latest block's state.
 | ||||
| 	fn latest_balance(&self, address: &Address) -> U256 { | ||||
| 		self.balance(address, BlockId::Latest) | ||||
| 			.expect("balance will return Some if given BlockId::Latest. balance was given BlockId::Latest \ | ||||
| 			Therefore balance has returned Some; qed")
 | ||||
| 	} | ||||
| 
 | ||||
| 	/// Get value of the storage at given position at the given block's state.
 | ||||
| 	///
 | ||||
| 	/// May not return None if given BlockId::Latest.
 | ||||
| 	/// Returns None if and only if the block's root hash has been pruned from the DB.
 | ||||
| 	fn storage_at(&self, address: &Address, position: &H256, id: BlockId) -> Option<H256>; | ||||
| 	fn storage_at(&self, address: &Address, position: &H256, state: StateOrBlock) -> Option<H256>; | ||||
| 
 | ||||
| 	/// Get value of the storage at given position at the latest block's state.
 | ||||
| 	fn latest_storage_at(&self, address: &Address, position: &H256) -> H256 { | ||||
| 		self.storage_at(address, position, BlockId::Latest) | ||||
| 		self.storage_at(address, position, BlockId::Latest.into()) | ||||
| 			.expect("storage_at will return Some if given BlockId::Latest. storage_at was given BlockId::Latest. \ | ||||
| 			Therefore storage_at has returned Some; qed")
 | ||||
| 	} | ||||
| @ -135,9 +256,6 @@ pub trait BlockChainClient : Sync + Send { | ||||
| 	/// Get transaction with given hash.
 | ||||
| 	fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction>; | ||||
| 
 | ||||
| 	/// Get the hash of block that contains the transaction, if any.
 | ||||
| 	fn transaction_block(&self, id: TransactionId) -> Option<H256>; | ||||
| 
 | ||||
| 	/// Get uncle with given id.
 | ||||
| 	fn uncle(&self, id: UncleId) -> Option<encoded::Header>; | ||||
| 
 | ||||
| @ -157,40 +275,18 @@ pub trait BlockChainClient : Sync + Send { | ||||
| 	/// Get raw block receipts data by block header hash.
 | ||||
| 	fn block_receipts(&self, hash: &H256) -> Option<Bytes>; | ||||
| 
 | ||||
| 	/// Import a block into the blockchain.
 | ||||
| 	fn import_block(&self, bytes: Bytes) -> Result<H256, BlockImportError>; | ||||
| 
 | ||||
| 	/// Import a block with transaction receipts. Does no sealing and transaction validation.
 | ||||
| 	fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result<H256, BlockImportError>; | ||||
| 
 | ||||
| 	/// Get block queue information.
 | ||||
| 	fn queue_info(&self) -> BlockQueueInfo; | ||||
| 
 | ||||
| 	/// Clear block queue and abort all import activity.
 | ||||
| 	fn clear_queue(&self); | ||||
| 
 | ||||
| 	/// Get blockchain information.
 | ||||
| 	fn chain_info(&self) -> BlockChainInfo; | ||||
| 
 | ||||
| 	/// Get the registrar address, if it exists.
 | ||||
| 	fn additional_params(&self) -> BTreeMap<String, String>; | ||||
| 
 | ||||
| 	/// Get the best block header.
 | ||||
| 	fn best_block_header(&self) -> encoded::Header; | ||||
| 
 | ||||
| 	/// Returns logs matching given filter.
 | ||||
| 	fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry>; | ||||
| 
 | ||||
| 	/// Makes a non-persistent transaction call.
 | ||||
| 	fn call(&self, tx: &SignedTransaction, analytics: CallAnalytics, block: BlockId) -> Result<Executed, CallError>; | ||||
| 
 | ||||
| 	/// Makes multiple non-persistent but dependent transaction calls.
 | ||||
| 	/// Returns a vector of successes or a failure if any of the transaction fails.
 | ||||
| 	fn call_many(&self, txs: &[(SignedTransaction, CallAnalytics)], block: BlockId) -> Result<Vec<Executed>, CallError>; | ||||
| 
 | ||||
| 	/// Estimates how much gas will be necessary for a call.
 | ||||
| 	fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result<U256, CallError>; | ||||
| 
 | ||||
| 	/// Replays a given transaction for inspection.
 | ||||
| 	fn replay(&self, t: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError>; | ||||
| 
 | ||||
| @ -270,52 +366,64 @@ pub trait BlockChainClient : Sync + Send { | ||||
| 	/// Returns information about pruning/data availability.
 | ||||
| 	fn pruning_info(&self) -> PruningInfo; | ||||
| 
 | ||||
| 	/// Like `call`, but with various defaults. Designed to be used for calling contracts.
 | ||||
| 	fn call_contract(&self, id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String>; | ||||
| 
 | ||||
| 	/// Import a transaction: used for misbehaviour reporting.
 | ||||
| 	fn transact_contract(&self, address: Address, data: Bytes) -> Result<TransactionImportResult, EthcoreError>; | ||||
| 
 | ||||
| 	/// Get the address of the registry itself.
 | ||||
| 	fn registrar_address(&self) -> Option<Address>; | ||||
| 
 | ||||
| 	/// Get the address of a particular blockchain service, if available.
 | ||||
| 	fn registry_address(&self, name: String, block: BlockId) -> Option<Address>; | ||||
| 
 | ||||
| 	/// Get the EIP-86 transition block number.
 | ||||
| 	fn eip86_transition(&self) -> u64; | ||||
| } | ||||
| 
 | ||||
| /// Extended client interface used for mining
 | ||||
| pub trait MiningBlockChainClient: BlockChainClient { | ||||
| /// Provides `reopen_block` method
 | ||||
| pub trait ReopenBlock { | ||||
| 	/// Reopens an OpenBlock and updates uncles.
 | ||||
| 	fn reopen_block(&self, block: ClosedBlock) -> OpenBlock; | ||||
| } | ||||
| 
 | ||||
| /// Provides `prepare_open_block` method
 | ||||
| pub trait PrepareOpenBlock { | ||||
| 	/// Returns OpenBlock prepared for closing.
 | ||||
| 	fn prepare_open_block(&self, | ||||
| 		author: Address, | ||||
| 		gas_range_target: (U256, U256), | ||||
| 		extra_data: Bytes | ||||
| 	) -> OpenBlock; | ||||
| } | ||||
| 
 | ||||
| 	/// Reopens an OpenBlock and updates uncles.
 | ||||
| 	fn reopen_block(&self, block: ClosedBlock) -> OpenBlock; | ||||
| 
 | ||||
| 	/// Returns EvmFactory.
 | ||||
| 	fn vm_factory(&self) -> &VmFactory; | ||||
| 
 | ||||
| 	/// Broadcast a block proposal.
 | ||||
| 	fn broadcast_proposal_block(&self, block: SealedBlock); | ||||
| 
 | ||||
| 	/// Import sealed block. Skips all verifications.
 | ||||
| 	fn import_sealed_block(&self, block: SealedBlock) -> ImportResult; | ||||
| /// Provides methods used for sealing new state
 | ||||
| pub trait BlockProducer: PrepareOpenBlock + ReopenBlock {} | ||||
| 
 | ||||
| /// Provides `latest_schedule` method
 | ||||
| pub trait ScheduleInfo { | ||||
| 	/// Returns latest schedule.
 | ||||
| 	fn latest_schedule(&self) -> Schedule; | ||||
| } | ||||
| 
 | ||||
| 	/// Returns base of this trait
 | ||||
| 	fn as_block_chain_client(&self) -> &BlockChainClient; | ||||
| ///Provides `import_sealed_block` method
 | ||||
| pub trait ImportSealedBlock { | ||||
| 	/// Import sealed block. Skips all verifications.
 | ||||
| 	fn import_sealed_block(&self, block: SealedBlock) -> ImportResult; | ||||
| } | ||||
| 
 | ||||
| /// Provides `broadcast_proposal_block` method
 | ||||
| pub trait BroadcastProposalBlock { | ||||
| 	/// Broadcast a block proposal.
 | ||||
| 	fn broadcast_proposal_block(&self, block: SealedBlock); | ||||
| } | ||||
| 
 | ||||
| /// Provides methods to import sealed block and broadcast a block proposal
 | ||||
| pub trait SealedBlockImporter: ImportSealedBlock + BroadcastProposalBlock {} | ||||
| 
 | ||||
| /// Extended client interface used for mining
 | ||||
| pub trait MiningBlockChainClient: BlockChainClient + BlockProducer + ScheduleInfo + SealedBlockImporter { | ||||
| 	/// Returns EvmFactory.
 | ||||
| 	fn vm_factory(&self) -> &VmFactory; | ||||
| } | ||||
| 
 | ||||
| /// Client facilities used by internally sealing Engines.
 | ||||
| pub trait EngineClient: Sync + Send { | ||||
| pub trait EngineClient: Sync + Send + ChainInfo { | ||||
| 	/// Make a new block and seal it.
 | ||||
| 	fn update_sealing(&self); | ||||
| 
 | ||||
| @ -332,9 +440,6 @@ pub trait EngineClient: Sync + Send { | ||||
| 	/// The block corresponding the the parent hash must be stored already.
 | ||||
| 	fn epoch_transition_for(&self, parent_hash: H256) -> Option<::engines::EpochTransition>; | ||||
| 
 | ||||
| 	/// Get block chain info.
 | ||||
| 	fn chain_info(&self) -> BlockChainInfo; | ||||
| 
 | ||||
| 	/// Attempt to cast the engine client to a full client.
 | ||||
| 	fn as_full_client(&self) -> Option<&BlockChainClient>; | ||||
| 
 | ||||
|  | ||||
| @ -781,6 +781,7 @@ mod tests { | ||||
| 	use block::*; | ||||
| 	use error::{Error, BlockError}; | ||||
| 	use header::Header; | ||||
| 	use client::ChainInfo; | ||||
| 	use miner::MinerService; | ||||
| 	use tests::helpers::*; | ||||
| 	use account_provider::AccountProvider; | ||||
|  | ||||
| @ -145,7 +145,7 @@ mod tests { | ||||
| 	use account_provider::AccountProvider; | ||||
| 	use miner::MinerService; | ||||
| 	use types::ids::BlockId; | ||||
| 	use client::BlockChainClient; | ||||
| 	use client::{BlockChainClient, ChainInfo, BlockInfo, CallContract}; | ||||
| 	use tests::helpers::generate_dummy_client_with_spec_and_accounts; | ||||
| 	use super::super::ValidatorSet; | ||||
| 	use super::ValidatorContract; | ||||
|  | ||||
| @ -148,7 +148,7 @@ mod tests { | ||||
| 	use std::collections::BTreeMap; | ||||
| 	use hash::keccak; | ||||
| 	use account_provider::AccountProvider; | ||||
| 	use client::BlockChainClient; | ||||
| 	use client::{BlockChainClient, ChainInfo, BlockInfo, ImportBlock}; | ||||
| 	use engines::EpochChange; | ||||
| 	use engines::validator_set::ValidatorSet; | ||||
| 	use ethkey::Secret; | ||||
|  | ||||
| @ -456,7 +456,7 @@ mod tests { | ||||
| 	use spec::Spec; | ||||
| 	use account_provider::AccountProvider; | ||||
| 	use transaction::{Transaction, Action}; | ||||
| 	use client::BlockChainClient; | ||||
| 	use client::{ChainInfo, BlockInfo, ImportBlock}; | ||||
| 	use ethkey::Secret; | ||||
| 	use miner::MinerService; | ||||
| 	use tests::helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data}; | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| use std::sync::Arc; | ||||
| use client::{EvmTestClient, BlockChainClient, Client, ClientConfig}; | ||||
| use client::{EvmTestClient, Client, ClientConfig, ChainInfo, ImportBlock}; | ||||
| use block::Block; | ||||
| use spec::Genesis; | ||||
| use ethjson; | ||||
|  | ||||
| @ -22,7 +22,7 @@ use std::sync::Arc; | ||||
| 
 | ||||
| use block::{ExecutedBlock, IsBlock}; | ||||
| use builtin::Builtin; | ||||
| use client::BlockChainClient; | ||||
| use client::{BlockInfo, CallContract}; | ||||
| use error::Error; | ||||
| use executive::Executive; | ||||
| use header::{BlockNumber, Header}; | ||||
| @ -366,7 +366,7 @@ impl EthereumMachine { | ||||
| 	/// Does verification of the transaction against the parent state.
 | ||||
| 	// TODO: refine the bound here to be a "state provider" or similar as opposed
 | ||||
| 	// to full client functionality.
 | ||||
| 	pub fn verify_transaction(&self, t: &SignedTransaction, header: &Header, client: &BlockChainClient) -> Result<(), Error> { | ||||
| 	pub fn verify_transaction<C: BlockInfo + CallContract>(&self, t: &SignedTransaction, header: &Header, client: &C) -> Result<(), Error> { | ||||
| 		if let Some(ref filter) = self.tx_filter.as_ref() { | ||||
| 			if !filter.transaction_allowed(header.parent_hash(), t, client) { | ||||
| 				return Err(transaction::Error::NotAllowed.into()) | ||||
|  | ||||
| @ -36,7 +36,7 @@ use ethcore_miner::transaction_queue::{ | ||||
| 	TransactionOrigin, | ||||
| }; | ||||
| use ethcore_miner::work_notify::{WorkPoster, NotifyWork}; | ||||
| use ethcore_miner::service_transaction_checker::ServiceTransactionChecker; | ||||
| use miner::service_transaction_checker::ServiceTransactionChecker; | ||||
| use miner::{MinerService, MinerStatus}; | ||||
| use price_info::fetch::Client as FetchClient; | ||||
| use price_info::{Client as PriceInfoClient, PriceInfo}; | ||||
| @ -50,9 +50,11 @@ use transaction::{ | ||||
| 	Error as TransactionError, | ||||
| }; | ||||
| use using_queue::{UsingQueue, GetAction}; | ||||
| 
 | ||||
| use block::{ClosedBlock, IsBlock, Block}; | ||||
| use client::{MiningBlockChainClient, BlockId, TransactionId}; | ||||
| use client::{ | ||||
| 	AccountData, BlockChain, RegistryInfo, ScheduleInfo, CallContract, BlockProducer, SealedBlockImporter | ||||
| }; | ||||
| use client::{BlockId, TransactionId, MiningBlockChainClient}; | ||||
| use executive::contract_address; | ||||
| use header::{Header, BlockNumber}; | ||||
| use receipt::{Receipt, RichReceipt}; | ||||
| @ -386,7 +388,7 @@ impl Miner { | ||||
| 	} | ||||
| 
 | ||||
| 	/// Prepares new block for sealing including top transactions from queue.
 | ||||
| 	fn prepare_block(&self, chain: &MiningBlockChainClient) -> (ClosedBlock, Option<H256>) { | ||||
| 	fn prepare_block<C: AccountData + BlockChain + BlockProducer + CallContract>(&self, chain: &C) -> (ClosedBlock, Option<H256>) { | ||||
| 		trace_time!("prepare_block"); | ||||
| 		let chain_info = chain.chain_info(); | ||||
| 		let (transactions, mut open_block, original_work_hash) = { | ||||
| @ -439,7 +441,7 @@ impl Miner { | ||||
| 			let hash = tx.hash(); | ||||
| 			let start = Instant::now(); | ||||
| 			// Check whether transaction type is allowed for sender
 | ||||
| 			let result = match self.engine.machine().verify_transaction(&tx, open_block.header(), chain.as_block_chain_client()) { | ||||
| 			let result = match self.engine.machine().verify_transaction(&tx, open_block.header(), chain) { | ||||
| 				Err(Error::Transaction(TransactionError::NotAllowed)) => { | ||||
| 					Err(TransactionError::NotAllowed.into()) | ||||
| 				} | ||||
| @ -567,7 +569,9 @@ impl Miner { | ||||
| 	} | ||||
| 
 | ||||
| 	/// Attempts to perform internal sealing (one that does not require work) and handles the result depending on the type of Seal.
 | ||||
| 	fn seal_and_import_block_internally(&self, chain: &MiningBlockChainClient, block: ClosedBlock) -> bool { | ||||
| 	fn seal_and_import_block_internally<C>(&self, chain: &C, block: ClosedBlock) -> bool | ||||
| 		where C: BlockChain + SealedBlockImporter | ||||
| 	{ | ||||
| 		if !block.transactions().is_empty() || self.forced_sealing() || Instant::now() > *self.next_mandatory_reseal.read() { | ||||
| 			trace!(target: "miner", "seal_block_internally: attempting internal seal."); | ||||
| 
 | ||||
| @ -647,7 +651,7 @@ impl Miner { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn update_gas_limit(&self, client: &MiningBlockChainClient) { | ||||
| 	fn update_gas_limit<C: BlockChain>(&self, client: &C) { | ||||
| 		let gas_limit = client.best_block_header().gas_limit(); | ||||
| 		let mut queue = self.transaction_queue.write(); | ||||
| 		queue.set_gas_limit(gas_limit); | ||||
| @ -658,7 +662,7 @@ impl Miner { | ||||
| 	} | ||||
| 
 | ||||
| 	/// Returns true if we had to prepare new pending block.
 | ||||
| 	fn prepare_work_sealing(&self, client: &MiningBlockChainClient) -> bool { | ||||
| 	fn prepare_work_sealing<C: AccountData + BlockChain + BlockProducer + CallContract>(&self, client: &C) -> bool { | ||||
| 		trace!(target: "miner", "prepare_work_sealing: entering"); | ||||
| 		let prepare_new = { | ||||
| 			let mut sealing_work = self.sealing_work.lock(); | ||||
| @ -690,9 +694,9 @@ impl Miner { | ||||
| 		prepare_new | ||||
| 	} | ||||
| 
 | ||||
| 	fn add_transactions_to_queue( | ||||
| 	fn add_transactions_to_queue<C: AccountData + BlockChain + CallContract + RegistryInfo + ScheduleInfo>( | ||||
| 		&self, | ||||
| 		client: &MiningBlockChainClient, | ||||
| 		client: &C, | ||||
| 		transactions: Vec<UnverifiedTransaction>, | ||||
| 		default_origin: TransactionOrigin, | ||||
| 		condition: Option<TransactionCondition>, | ||||
| @ -718,7 +722,7 @@ impl Miner { | ||||
| 					}, | ||||
| 					Ok(transaction) => { | ||||
| 						// This check goes here because verify_transaction takes SignedTransaction parameter
 | ||||
| 						self.engine.machine().verify_transaction(&transaction, &best_block_header, client.as_block_chain_client())?; | ||||
| 						self.engine.machine().verify_transaction(&transaction, &best_block_header, client)?; | ||||
| 
 | ||||
| 						let origin = self.accounts.as_ref().and_then(|accounts| { | ||||
| 							match accounts.has_account(transaction.sender()).unwrap_or(false) { | ||||
| @ -774,8 +778,9 @@ impl Miner { | ||||
| const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5; | ||||
| 
 | ||||
| impl MinerService for Miner { | ||||
| 	type State = State<::state_db::StateDB>; | ||||
| 
 | ||||
| 	fn clear_and_reset(&self, chain: &MiningBlockChainClient) { | ||||
| 	fn clear_and_reset<C: MiningBlockChainClient>(&self, chain: &C) { | ||||
| 		self.transaction_queue.write().clear(); | ||||
| 		// --------------------------------------------------------------------------
 | ||||
| 		// | NOTE Code below requires transaction_queue and sealing_work locks.     |
 | ||||
| @ -891,16 +896,16 @@ impl MinerService for Miner { | ||||
| 		self.gas_range_target.read().1 | ||||
| 	} | ||||
| 
 | ||||
| 	fn import_external_transactions( | ||||
| 	fn import_external_transactions<C: MiningBlockChainClient>( | ||||
| 		&self, | ||||
| 		chain: &MiningBlockChainClient, | ||||
| 		client: &C, | ||||
| 		transactions: Vec<UnverifiedTransaction> | ||||
| 	) -> Vec<Result<TransactionImportResult, Error>> { | ||||
| 		trace!(target: "external_tx", "Importing external transactions"); | ||||
| 		let results = { | ||||
| 			let mut transaction_queue = self.transaction_queue.write(); | ||||
| 			self.add_transactions_to_queue( | ||||
| 				chain, transactions, TransactionOrigin::External, None, &mut transaction_queue | ||||
| 				client, transactions, TransactionOrigin::External, None, &mut transaction_queue | ||||
| 			) | ||||
| 		}; | ||||
| 
 | ||||
| @ -909,14 +914,14 @@ impl MinerService for Miner { | ||||
| 			// | NOTE Code below requires transaction_queue and sealing_work locks.     |
 | ||||
| 			// | Make sure to release the locks before calling that method.             |
 | ||||
| 			// --------------------------------------------------------------------------
 | ||||
| 			self.update_sealing(chain); | ||||
| 			self.update_sealing(client); | ||||
| 		} | ||||
| 		results | ||||
| 	} | ||||
| 
 | ||||
| 	fn import_own_transaction( | ||||
| 	fn import_own_transaction<C: MiningBlockChainClient>( | ||||
| 		&self, | ||||
| 		chain: &MiningBlockChainClient, | ||||
| 		chain: &C, | ||||
| 		pending: PendingTransaction, | ||||
| 	) -> Result<TransactionImportResult, Error> { | ||||
| 
 | ||||
| @ -1040,7 +1045,7 @@ impl MinerService for Miner { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn remove_pending_transaction(&self, chain: &MiningBlockChainClient, hash: &H256) -> Option<PendingTransaction> { | ||||
| 	fn remove_pending_transaction<C: AccountData>(&self, chain: &C, hash: &H256) -> Option<PendingTransaction> { | ||||
| 		let mut queue = self.transaction_queue.write(); | ||||
| 		let tx = queue.find(hash); | ||||
| 		if tx.is_some() { | ||||
| @ -1110,7 +1115,10 @@ impl MinerService for Miner { | ||||
| 
 | ||||
| 	/// Update sealing if required.
 | ||||
| 	/// Prepare the block and work if the Engine does not seal internally.
 | ||||
| 	fn update_sealing(&self, chain: &MiningBlockChainClient) { | ||||
| 	fn update_sealing<C>(&self, chain: &C) | ||||
| 		where C: AccountData + BlockChain + RegistryInfo | ||||
| 		         + CallContract + BlockProducer + SealedBlockImporter | ||||
| 	{ | ||||
| 		trace!(target: "miner", "update_sealing"); | ||||
| 		const NO_NEW_CHAIN_WITH_FORKS: &str = "Your chain specification contains one or more hard forks which are required to be \ | ||||
| 			on by default. Please remove these forks and start your chain again.";
 | ||||
| @ -1150,9 +1158,12 @@ impl MinerService for Miner { | ||||
| 		self.sealing_work.lock().queue.is_in_use() | ||||
| 	} | ||||
| 
 | ||||
| 	fn map_sealing_work<F, T>(&self, chain: &MiningBlockChainClient, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T { | ||||
| 	fn map_sealing_work<C, F, T>(&self, client: &C, f: F) -> Option<T> | ||||
| 		where C: AccountData + BlockChain + BlockProducer + CallContract, | ||||
| 		      F: FnOnce(&ClosedBlock) -> T | ||||
| 	{ | ||||
| 		trace!(target: "miner", "map_sealing_work: entering"); | ||||
| 		self.prepare_work_sealing(chain); | ||||
| 		self.prepare_work_sealing(client); | ||||
| 		trace!(target: "miner", "map_sealing_work: sealing prepared"); | ||||
| 		let mut sealing_work = self.sealing_work.lock(); | ||||
| 		let ret = sealing_work.queue.use_last_ref(); | ||||
| @ -1160,7 +1171,7 @@ impl MinerService for Miner { | ||||
| 		ret.map(f) | ||||
| 	} | ||||
| 
 | ||||
| 	fn submit_seal(&self, chain: &MiningBlockChainClient, block_hash: H256, seal: Vec<Bytes>) -> Result<(), Error> { | ||||
| 	fn submit_seal<C: SealedBlockImporter>(&self, chain: &C, block_hash: H256, seal: Vec<Bytes>) -> Result<(), Error> { | ||||
| 		let result = | ||||
| 			if let Some(b) = self.sealing_work.lock().queue.get_used_if( | ||||
| 				if self.options.enable_resubmission { | ||||
| @ -1188,7 +1199,10 @@ impl MinerService for Miner { | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	fn chain_new_blocks(&self, chain: &MiningBlockChainClient, imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) { | ||||
| 	fn chain_new_blocks<C>(&self, chain: &C, imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) | ||||
| 		where C: AccountData + BlockChain + CallContract + RegistryInfo | ||||
| 		         + BlockProducer + ScheduleInfo + SealedBlockImporter | ||||
| 	{ | ||||
| 		trace!(target: "miner", "chain_new_blocks"); | ||||
| 
 | ||||
| 		// 1. We ignore blocks that were `imported` unless resealing on new uncles is enabled.
 | ||||
| @ -1234,6 +1248,18 @@ impl MinerService for Miner { | ||||
| 			self.update_sealing(chain); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn pending_state(&self, latest_block_number: BlockNumber) -> Option<Self::State> { | ||||
| 		Miner::pending_state(self, latest_block_number) | ||||
| 	} | ||||
| 
 | ||||
| 	fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option<Header> { | ||||
| 		Miner::pending_block_header(self, latest_block_number) | ||||
| 	} | ||||
| 
 | ||||
| 	fn pending_block(&self, latest_block_number: BlockNumber) -> Option<Block> { | ||||
| 		Miner::pending_block(self, latest_block_number) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// Action when service transaction is received
 | ||||
| @ -1245,31 +1271,22 @@ enum ServiceTransactionAction { | ||||
| } | ||||
| 
 | ||||
| impl ServiceTransactionAction { | ||||
| 	pub fn check(&self, client: &MiningBlockChainClient, tx: &SignedTransaction) -> Result<bool, String> { | ||||
| 	pub fn check<C: CallContract + RegistryInfo>(&self, client: &C, tx: &SignedTransaction) -> Result<bool, String> | ||||
| 	{ | ||||
| 		match *self { | ||||
| 			ServiceTransactionAction::Refuse => Err("configured to refuse service transactions".to_owned()), | ||||
| 			ServiceTransactionAction::Check(ref checker) => checker.check(&client, tx), | ||||
| 			ServiceTransactionAction::Check(ref checker) => checker.check(client, tx), | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<'a> ::ethcore_miner::service_transaction_checker::ContractCaller for &'a MiningBlockChainClient { | ||||
| 	fn registry_address(&self, name: &str) -> Option<Address> { | ||||
| 		MiningBlockChainClient::registry_address(*self, name.into(), BlockId::Latest) | ||||
| 	} | ||||
| 
 | ||||
| 	fn call_contract(&self, block: BlockId, address: Address, data: Vec<u8>) -> Result<Vec<u8>, String> { | ||||
| 		MiningBlockChainClient::call_contract(*self, block, address, data) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct TransactionDetailsProvider<'a> { | ||||
| 	client: &'a MiningBlockChainClient, | ||||
| struct TransactionDetailsProvider<'a, C: 'a> { | ||||
| 	client: &'a C, | ||||
| 	service_transaction_action: &'a ServiceTransactionAction, | ||||
| } | ||||
| 
 | ||||
| impl<'a> TransactionDetailsProvider<'a> { | ||||
| 	pub fn new(client: &'a MiningBlockChainClient, service_transaction_action: &'a ServiceTransactionAction) -> Self { | ||||
| impl<'a, C> TransactionDetailsProvider<'a, C> { | ||||
| 	pub fn new(client: &'a C, service_transaction_action: &'a ServiceTransactionAction) -> Self { | ||||
| 		TransactionDetailsProvider { | ||||
| 			client: client, | ||||
| 			service_transaction_action: service_transaction_action, | ||||
| @ -1277,7 +1294,9 @@ impl<'a> TransactionDetailsProvider<'a> { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<'a> TransactionQueueDetailsProvider for TransactionDetailsProvider<'a> { | ||||
| impl<'a, C> TransactionQueueDetailsProvider for TransactionDetailsProvider<'a, C> | ||||
| 	where C: AccountData + CallContract + RegistryInfo + ScheduleInfo | ||||
| { | ||||
| 	fn fetch_account(&self, address: &Address) -> AccountDetails { | ||||
| 		AccountDetails { | ||||
| 			nonce: self.client.latest_nonce(address), | ||||
| @ -1300,12 +1319,14 @@ mod tests { | ||||
| 	use ethcore_miner::transaction_queue::PrioritizationStrategy; | ||||
| 	use ethereum_types::U256; | ||||
| 	use ethkey::{Generator, Random}; | ||||
| 	use client::{TestBlockChainClient, EachBlockWith, ChainInfo}; | ||||
| 	use hash::keccak; | ||||
| 	use header::BlockNumber; | ||||
| 	use rustc_hex::FromHex; | ||||
| 	use transaction::Transaction; | ||||
| 
 | ||||
| 	use client::{BlockChainClient, TestBlockChainClient, EachBlockWith}; | ||||
| 	use spec::Spec; | ||||
| 	use transaction::{SignedTransaction, Transaction, PendingTransaction, Action}; | ||||
| 	use miner::MinerService; | ||||
| 
 | ||||
| 	use tests::helpers::{generate_dummy_client, generate_dummy_client_with_spec_and_accounts}; | ||||
| 
 | ||||
| 	#[test] | ||||
|  | ||||
| @ -40,6 +40,7 @@ | ||||
| 
 | ||||
| mod miner; | ||||
| mod stratum; | ||||
| mod service_transaction_checker; | ||||
| 
 | ||||
| pub use self::miner::{Miner, MinerOptions, Banning, PendingSet, GasPricer, GasPriceCalibratorOptions, GasLimit}; | ||||
| pub use self::stratum::{Stratum, Error as StratumError, Options as StratumOptions}; | ||||
| @ -47,18 +48,24 @@ pub use self::stratum::{Stratum, Error as StratumError, Options as StratumOption | ||||
| pub use ethcore_miner::local_transactions::Status as LocalTransactionStatus; | ||||
| 
 | ||||
| use std::collections::BTreeMap; | ||||
| use ethereum_types::{H256, U256, Address}; | ||||
| use bytes::Bytes; | ||||
| 
 | ||||
| use block::ClosedBlock; | ||||
| use client::{MiningBlockChainClient}; | ||||
| use block::{ClosedBlock, Block}; | ||||
| use bytes::Bytes; | ||||
| use client::{ | ||||
| 	MiningBlockChainClient, CallContract, RegistryInfo, ScheduleInfo, | ||||
| 	BlockChain, AccountData, BlockProducer, SealedBlockImporter | ||||
| }; | ||||
| use error::{Error}; | ||||
| use header::BlockNumber; | ||||
| use ethereum_types::{H256, U256, Address}; | ||||
| use header::{BlockNumber, Header}; | ||||
| use receipt::{RichReceipt, Receipt}; | ||||
| use transaction::{UnverifiedTransaction, PendingTransaction, ImportResult as TransactionImportResult}; | ||||
| use state::StateInfo; | ||||
| 
 | ||||
| /// Miner client API
 | ||||
| pub trait MinerService : Send + Sync { | ||||
| 	/// Type representing chain state
 | ||||
| 	type State: StateInfo + 'static; | ||||
| 
 | ||||
| 	/// Returns miner's status.
 | ||||
| 	fn status(&self) -> MinerStatus; | ||||
| @ -107,42 +114,46 @@ pub trait MinerService : Send + Sync { | ||||
| 	fn set_tx_gas_limit(&self, limit: U256); | ||||
| 
 | ||||
| 	/// Imports transactions to transaction queue.
 | ||||
| 	fn import_external_transactions(&self, chain: &MiningBlockChainClient, transactions: Vec<UnverifiedTransaction>) -> | ||||
| 	fn import_external_transactions<C: MiningBlockChainClient>(&self, client: &C, transactions: Vec<UnverifiedTransaction>) -> | ||||
| 		Vec<Result<TransactionImportResult, Error>>; | ||||
| 
 | ||||
| 	/// Imports own (node owner) transaction to queue.
 | ||||
| 	fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: PendingTransaction) -> | ||||
| 	fn import_own_transaction<C: MiningBlockChainClient>(&self, chain: &C, transaction: PendingTransaction) -> | ||||
| 		Result<TransactionImportResult, Error>; | ||||
| 
 | ||||
| 	/// Returns hashes of transactions currently in pending
 | ||||
| 	fn pending_transactions_hashes(&self, best_block: BlockNumber) -> Vec<H256>; | ||||
| 
 | ||||
| 	/// Removes all transactions from the queue and restart mining operation.
 | ||||
| 	fn clear_and_reset(&self, chain: &MiningBlockChainClient); | ||||
| 	fn clear_and_reset<C: MiningBlockChainClient>(&self, chain: &C); | ||||
| 
 | ||||
| 	/// Called when blocks are imported to chain, updates transactions queue.
 | ||||
| 	fn chain_new_blocks(&self, chain: &MiningBlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]); | ||||
| 	fn chain_new_blocks<C>(&self, chain: &C, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) | ||||
| 		where C: AccountData + BlockChain + CallContract + RegistryInfo + BlockProducer + ScheduleInfo + SealedBlockImporter; | ||||
| 
 | ||||
| 	/// PoW chain - can produce work package
 | ||||
| 	fn can_produce_work_package(&self) -> bool; | ||||
| 
 | ||||
| 	/// New chain head event. Restart mining operation.
 | ||||
| 	fn update_sealing(&self, chain: &MiningBlockChainClient); | ||||
| 	fn update_sealing<C>(&self, chain: &C) | ||||
| 		where C: AccountData + BlockChain + RegistryInfo + CallContract + BlockProducer + SealedBlockImporter; | ||||
| 
 | ||||
| 	/// 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, chain: &MiningBlockChainClient, pow_hash: H256, seal: Vec<Bytes>) -> Result<(), Error>; | ||||
| 	fn submit_seal<C: SealedBlockImporter>(&self, chain: &C, pow_hash: H256, seal: Vec<Bytes>) -> Result<(), Error>; | ||||
| 
 | ||||
| 	/// Get the sealing work package and if `Some`, apply some transform.
 | ||||
| 	fn map_sealing_work<F, T>(&self, chain: &MiningBlockChainClient, f: F) -> Option<T> | ||||
| 		where F: FnOnce(&ClosedBlock) -> T, Self: Sized; | ||||
| 	fn map_sealing_work<C, F, T>(&self, client: &C, f: F) -> Option<T> | ||||
| 		where C: AccountData + BlockChain + BlockProducer + CallContract, | ||||
| 		      F: FnOnce(&ClosedBlock) -> T, | ||||
| 		      Self: Sized; | ||||
| 
 | ||||
| 	/// Query pending transactions for hash.
 | ||||
| 	fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option<PendingTransaction>; | ||||
| 
 | ||||
| 	/// Removes transaction from the queue.
 | ||||
| 	/// NOTE: The transaction is not removed from pending block if mining.
 | ||||
| 	fn remove_pending_transaction(&self, chain: &MiningBlockChainClient, hash: &H256) -> Option<PendingTransaction>; | ||||
| 	fn remove_pending_transaction<C: AccountData>(&self, chain: &C, hash: &H256) -> Option<PendingTransaction>; | ||||
| 
 | ||||
| 	/// Get a list of all pending transactions in the queue.
 | ||||
| 	fn pending_transactions(&self) -> Vec<PendingTransaction>; | ||||
| @ -173,6 +184,15 @@ pub trait MinerService : Send + Sync { | ||||
| 
 | ||||
| 	/// Suggested gas limit.
 | ||||
| 	fn sensible_gas_limit(&self) -> U256 { 21000.into() } | ||||
| 
 | ||||
| 	/// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing.
 | ||||
| 	fn pending_state(&self, latest_block_number: BlockNumber) -> Option<Self::State>; | ||||
| 
 | ||||
| 	/// Get `Some` `clone()` of the current pending block header or `None` if we're not sealing.
 | ||||
| 	fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option<Header>; | ||||
| 
 | ||||
| 	/// Get `Some` `clone()` of the current pending block or `None` if we're not sealing.
 | ||||
| 	fn pending_block(&self, latest_block_number: BlockNumber) -> Option<Block>; | ||||
| } | ||||
| 
 | ||||
| /// Mining status
 | ||||
|  | ||||
| @ -16,23 +16,14 @@ | ||||
| 
 | ||||
| //! A service transactions contract checker.
 | ||||
| 
 | ||||
| use ethereum_types::Address; | ||||
| use client::{RegistryInfo, CallContract}; | ||||
| use transaction::SignedTransaction; | ||||
| use types::ids::BlockId; | ||||
| 
 | ||||
| use_contract!(service_transaction, "ServiceTransaction", "res/service_transaction.json"); | ||||
| use_contract!(service_transaction, "ServiceTransaction", "res/contracts/service_transaction.json"); | ||||
| 
 | ||||
| const SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME: &'static str = "service_transaction_checker"; | ||||
| 
 | ||||
| /// A contract calling interface.
 | ||||
| pub trait ContractCaller { | ||||
| 	/// Returns address of contract from the registry, given it's name
 | ||||
| 	fn registry_address(&self, name: &str) -> Option<Address>; | ||||
| 
 | ||||
| 	/// Executes a contract call at given block.
 | ||||
| 	fn call_contract(&self, BlockId, Address, Vec<u8>) -> Result<Vec<u8>, String>; | ||||
| } | ||||
| 
 | ||||
| /// Service transactions checker.
 | ||||
| #[derive(Default)] | ||||
| pub struct ServiceTransactionChecker { | ||||
| @ -41,10 +32,10 @@ pub struct ServiceTransactionChecker { | ||||
| 
 | ||||
| impl ServiceTransactionChecker { | ||||
| 	/// Checks if service transaction can be appended to the transaction queue.
 | ||||
| 	pub fn check(&self, client: &ContractCaller, tx: &SignedTransaction) -> Result<bool, String> { | ||||
| 	pub fn check<C: CallContract + RegistryInfo>(&self, client: &C, tx: &SignedTransaction) -> Result<bool, String> { | ||||
| 		assert!(tx.gas_price.is_zero()); | ||||
| 
 | ||||
| 		let address = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME) | ||||
| 		let address = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest) | ||||
| 			.ok_or_else(|| "contract is not configured")?; | ||||
| 
 | ||||
| 		trace!(target: "txqueue", "Checking service transaction checker contract from {}", address); | ||||
| @ -27,7 +27,7 @@ use super::{ManifestData, StateRebuilder, Rebuilder, RestorationStatus, Snapshot | ||||
| use super::io::{SnapshotReader, LooseReader, SnapshotWriter, LooseWriter}; | ||||
| 
 | ||||
| use blockchain::BlockChain; | ||||
| use client::{BlockChainClient, Client}; | ||||
| use client::{Client, ChainInfo}; | ||||
| use engines::EthEngine; | ||||
| use error::Error; | ||||
| use ids::BlockId; | ||||
|  | ||||
| @ -25,7 +25,7 @@ use hash::{KECCAK_NULL_RLP}; | ||||
| use account_db::AccountDBMut; | ||||
| use basic_account::BasicAccount; | ||||
| use blockchain::BlockChain; | ||||
| use client::{BlockChainClient, Client}; | ||||
| use client::{Client, ChainInfo}; | ||||
| use engines::EthEngine; | ||||
| use snapshot::{StateRebuilder}; | ||||
| use snapshot::io::{SnapshotReader, PackedWriter, PackedReader}; | ||||
|  | ||||
| @ -21,7 +21,7 @@ use std::sync::Arc; | ||||
| use std::str::FromStr; | ||||
| 
 | ||||
| use account_provider::AccountProvider; | ||||
| use client::{Client, BlockChainClient}; | ||||
| use client::{Client, BlockChainClient, ChainInfo}; | ||||
| use ethkey::Secret; | ||||
| use snapshot::tests::helpers as snapshot_helpers; | ||||
| use spec::Spec; | ||||
|  | ||||
| @ -19,7 +19,7 @@ | ||||
| use std::sync::Arc; | ||||
| 
 | ||||
| use tempdir::TempDir; | ||||
| use client::{BlockChainClient, Client}; | ||||
| use client::{Client, BlockInfo}; | ||||
| use ids::BlockId; | ||||
| use snapshot::service::{Service, ServiceParams}; | ||||
| use snapshot::{self, ManifestData, SnapshotService}; | ||||
|  | ||||
| @ -17,7 +17,7 @@ | ||||
| //! Watcher for snapshot-related chain events.
 | ||||
| 
 | ||||
| use parking_lot::Mutex; | ||||
| use client::{BlockChainClient, Client, ChainNotify}; | ||||
| use client::{BlockInfo, Client, ChainNotify}; | ||||
| use ids::BlockId; | ||||
| use service::ClientIoMessage; | ||||
| 
 | ||||
|  | ||||
| @ -334,6 +334,28 @@ pub enum CleanupMode<'a> { | ||||
| 	TrackTouched(&'a mut HashSet<Address>), | ||||
| } | ||||
| 
 | ||||
| /// Provides subset of `State` methods to query state information
 | ||||
| pub trait StateInfo { | ||||
| 	/// Get the nonce of account `a`.
 | ||||
| 	fn nonce(&self, a: &Address) -> trie::Result<U256>; | ||||
| 
 | ||||
| 	/// Get the balance of account `a`.
 | ||||
| 	fn balance(&self, a: &Address) -> trie::Result<U256>; | ||||
| 
 | ||||
| 	/// Mutate storage of account `address` so that it is `value` for `key`.
 | ||||
| 	fn storage_at(&self, address: &Address, key: &H256) -> trie::Result<H256>; | ||||
| 
 | ||||
| 	/// Get accounts' code.
 | ||||
| 	fn code(&self, a: &Address) -> trie::Result<Option<Arc<Bytes>>>; | ||||
| } | ||||
| 
 | ||||
| impl<B: Backend> StateInfo for State<B> { | ||||
| 	fn nonce(&self, a: &Address) -> trie::Result<U256> { State::nonce(self, a) } | ||||
| 	fn balance(&self, a: &Address) -> trie::Result<U256> { State::balance(self, a) } | ||||
| 	fn storage_at(&self, address: &Address, key: &H256) -> trie::Result<H256> { State::storage_at(self, address, key) } | ||||
| 	fn code(&self, address: &Address) -> trie::Result<Option<Arc<Bytes>>> { State::code(self, address) } | ||||
| } | ||||
| 
 | ||||
| const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \ | ||||
| 			 Therefore creating a SecTrieDB with this state's root will not fail.";
 | ||||
| 
 | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| //! State database abstraction.
 | ||||
| //! State database abstraction. For more info, see the doc for `StateDB`
 | ||||
| 
 | ||||
| use std::collections::{VecDeque, HashSet}; | ||||
| use std::sync::Arc; | ||||
| @ -33,13 +33,17 @@ use bloom_journal::{Bloom, BloomJournal}; | ||||
| use db::COL_ACCOUNT_BLOOM; | ||||
| use byteorder::{LittleEndian, ByteOrder}; | ||||
| 
 | ||||
| /// Number of bytes allocated in the memory for accounts bloom.
 | ||||
| /// Value used to initialize bloom bitmap size.
 | ||||
| ///
 | ||||
| /// Bitmap size is the size in bytes (not bits) that will be allocated in memory.
 | ||||
| pub const ACCOUNT_BLOOM_SPACE: usize = 1048576; | ||||
| 
 | ||||
| /// Estimated maximum number of accounts in memory bloom.
 | ||||
| /// Value used to initialize bloom items count.
 | ||||
| ///
 | ||||
| /// Items count is an estimation of the maximum number of items to store.
 | ||||
| pub const DEFAULT_ACCOUNT_PRESET: usize = 1000000; | ||||
| 
 | ||||
| /// Database key represening number of account hashes.
 | ||||
| /// Key for a value storing amount of hashes
 | ||||
| pub const ACCOUNT_BLOOM_HASHCOUNT_KEY: &'static [u8] = b"account_hash_count"; | ||||
| 
 | ||||
| const STATE_CACHE_BLOCKS: usize = 12; | ||||
| @ -175,7 +179,7 @@ impl StateDB { | ||||
| 		bloom | ||||
| 	} | ||||
| 
 | ||||
| 	/// Commit bloom to a database transaction
 | ||||
| 	/// Commit blooms journal to the database transaction
 | ||||
| 	pub fn commit_bloom(batch: &mut DBTransaction, journal: BloomJournal) -> Result<(), UtilError> { | ||||
| 		assert!(journal.hash_functions <= 255); | ||||
| 		batch.put(COL_ACCOUNT_BLOOM, ACCOUNT_BLOOM_HASHCOUNT_KEY, &[journal.hash_functions as u8]); | ||||
| @ -305,12 +309,12 @@ impl StateDB { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/// Returns immutable reference to underlying hashdb.
 | ||||
| 	/// Conversion method to interpret self as `HashDB` reference
 | ||||
| 	pub fn as_hashdb(&self) -> &HashDB { | ||||
| 		self.db.as_hashdb() | ||||
| 	} | ||||
| 
 | ||||
| 	/// Returns mutable reference to underlying hashdb.
 | ||||
| 	/// Conversion method to interpret self as mutable `HashDB` reference
 | ||||
| 	pub fn as_hashdb_mut(&mut self) -> &mut HashDB { | ||||
| 		self.db.as_hashdb_mut() | ||||
| 	} | ||||
|  | ||||
| @ -18,7 +18,7 @@ use std::str::FromStr; | ||||
| use std::sync::Arc; | ||||
| use hash::keccak; | ||||
| use io::IoChannel; | ||||
| use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockId}; | ||||
| use client::{BlockChainClient, Client, ClientConfig, BlockId, ChainInfo, BlockInfo, PrepareOpenBlock, ImportSealedBlock, ImportBlock}; | ||||
| use state::{self, State, CleanupMode}; | ||||
| use executive::{Executive, TransactOptions}; | ||||
| use ethereum; | ||||
|  | ||||
| @ -19,7 +19,7 @@ use ethereum_types::{H256, U256}; | ||||
| use block::{OpenBlock, Drain}; | ||||
| use blockchain::{BlockChain, Config as BlockChainConfig}; | ||||
| use bytes::Bytes; | ||||
| use client::{BlockChainClient, ChainNotify, Client, ClientConfig}; | ||||
| use client::{Client, ClientConfig, ChainInfo, ImportBlock, ChainNotify}; | ||||
| use ethereum::ethash::EthashParams; | ||||
| use ethkey::KeyPair; | ||||
| use evm::Factory as EvmFactory; | ||||
|  | ||||
| @ -65,7 +65,12 @@ enum CacheId { | ||||
| 	Bloom(H256), | ||||
| } | ||||
| 
 | ||||
| /// Trace database.
 | ||||
| /// Database to store transaction execution trace.
 | ||||
| ///
 | ||||
| /// Whenever a transaction is executed by EVM it's execution trace is stored
 | ||||
| /// in trace database. Each trace has information, which contracts have been
 | ||||
| /// touched, which have been created during the execution of transaction, and
 | ||||
| /// which calls failed.
 | ||||
| pub struct TraceDB<T> where T: DatabaseExtras { | ||||
| 	// cache
 | ||||
| 	traces: RwLock<HashMap<H256, FlatBlockTraces>>, | ||||
|  | ||||
| @ -19,7 +19,7 @@ | ||||
| use std::collections::HashMap; | ||||
| use std::collections::hash_map::Entry; | ||||
| use ethereum_types::{H256, Address}; | ||||
| use client::{BlockChainClient, BlockId, ChainNotify}; | ||||
| use client::{BlockInfo, CallContract, BlockId, ChainNotify}; | ||||
| use bytes::Bytes; | ||||
| use parking_lot::Mutex; | ||||
| use spec::CommonParams; | ||||
| @ -64,7 +64,7 @@ impl TransactionFilter { | ||||
| 	} | ||||
| 
 | ||||
| 	/// Check if transaction is allowed at given block.
 | ||||
| 	pub fn transaction_allowed(&self, parent_hash: &H256, transaction: &SignedTransaction, client: &BlockChainClient) -> bool { | ||||
| 	pub fn transaction_allowed<C: BlockInfo + CallContract>(&self, parent_hash: &H256, transaction: &SignedTransaction, client: &C) -> bool { | ||||
| 		let mut cache = self.permission_cache.lock(); let len = cache.len(); | ||||
| 
 | ||||
| 		let tx_type = match transaction.action { | ||||
|  | ||||
| @ -16,6 +16,7 @@ | ||||
| 
 | ||||
| //! Canonical verifier.
 | ||||
| 
 | ||||
| use client::{BlockInfo, CallContract}; | ||||
| use engines::EthEngine; | ||||
| use error::Error; | ||||
| use header::Header; | ||||
| @ -25,13 +26,13 @@ use super::verification; | ||||
| /// A canonial verifier -- this does full verification.
 | ||||
| pub struct CanonVerifier; | ||||
| 
 | ||||
| impl Verifier for CanonVerifier { | ||||
| impl<C: BlockInfo + CallContract> Verifier<C> for CanonVerifier { | ||||
| 	fn verify_block_family( | ||||
| 		&self, | ||||
| 		header: &Header, | ||||
| 		parent: &Header, | ||||
| 		engine: &EthEngine, | ||||
| 		do_full: Option<verification::FullFamilyParams>, | ||||
| 		do_full: Option<verification::FullFamilyParams<C>>, | ||||
| 	) -> Result<(), Error> { | ||||
| 		verification::verify_block_family(header, parent, engine, do_full) | ||||
| 	} | ||||
|  | ||||
| @ -28,6 +28,8 @@ pub use self::canon_verifier::CanonVerifier; | ||||
| pub use self::noop_verifier::NoopVerifier; | ||||
| pub use self::queue::{BlockQueue, Config as QueueConfig, VerificationQueue, QueueInfo}; | ||||
| 
 | ||||
| use client::{BlockInfo, CallContract}; | ||||
| 
 | ||||
| /// Verifier type.
 | ||||
| #[derive(Debug, PartialEq, Clone)] | ||||
| pub enum VerifierType { | ||||
| @ -47,7 +49,7 @@ impl Default for VerifierType { | ||||
| } | ||||
| 
 | ||||
| /// Create a new verifier based on type.
 | ||||
| pub fn new(v: VerifierType) -> Box<Verifier> { | ||||
| pub fn new<C: BlockInfo + CallContract>(v: VerifierType) -> Box<Verifier<C>> { | ||||
| 	match v { | ||||
| 		VerifierType::Canon | VerifierType::CanonNoSeal => Box::new(CanonVerifier), | ||||
| 		VerifierType::Noop => Box::new(NoopVerifier), | ||||
|  | ||||
| @ -16,6 +16,7 @@ | ||||
| 
 | ||||
| //! No-op verifier.
 | ||||
| 
 | ||||
| use client::{BlockInfo, CallContract}; | ||||
| use engines::EthEngine; | ||||
| use error::Error; | ||||
| use header::Header; | ||||
| @ -25,13 +26,13 @@ use super::{verification, Verifier}; | ||||
| #[allow(dead_code)] | ||||
| pub struct NoopVerifier; | ||||
| 
 | ||||
| impl Verifier for NoopVerifier { | ||||
| impl<C: BlockInfo + CallContract> Verifier<C> for NoopVerifier { | ||||
| 	fn verify_block_family( | ||||
| 		&self, | ||||
| 		_: &Header, | ||||
| 		_t: &Header, | ||||
| 		_: &EthEngine, | ||||
| 		_: Option<verification::FullFamilyParams> | ||||
| 		_: Option<verification::FullFamilyParams<C>> | ||||
| 	) -> Result<(), Error> { | ||||
| 		Ok(()) | ||||
| 	} | ||||
|  | ||||
| @ -33,7 +33,7 @@ use triehash::ordered_trie_root; | ||||
| use unexpected::{Mismatch, OutOfBounds}; | ||||
| 
 | ||||
| use blockchain::*; | ||||
| use client::BlockChainClient; | ||||
| use client::{BlockInfo, CallContract}; | ||||
| use engines::EthEngine; | ||||
| use error::{BlockError, Error}; | ||||
| use header::{BlockNumber, Header}; | ||||
| @ -109,24 +109,36 @@ pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &EthEngine, | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| /// Parameters for full verification of block family: block bytes, transactions, blockchain, and state access.
 | ||||
| pub type FullFamilyParams<'a> = (&'a [u8], &'a [SignedTransaction], &'a BlockProvider, &'a BlockChainClient); | ||||
| /// Parameters for full verification of block family
 | ||||
| pub struct FullFamilyParams<'a, C: BlockInfo + CallContract + 'a> { | ||||
| 	/// Serialized block bytes
 | ||||
| 	pub block_bytes: &'a [u8], | ||||
| 
 | ||||
| 	/// Signed transactions
 | ||||
| 	pub transactions: &'a [SignedTransaction], | ||||
| 
 | ||||
| 	/// Block provider to use during verification
 | ||||
| 	pub block_provider: &'a BlockProvider, | ||||
| 
 | ||||
| 	/// Engine client to use during verification
 | ||||
| 	pub client: &'a C, | ||||
| } | ||||
| 
 | ||||
| /// Phase 3 verification. Check block information against parent and uncles.
 | ||||
| pub fn verify_block_family(header: &Header, parent: &Header, engine: &EthEngine, do_full: Option<FullFamilyParams>) -> Result<(), Error> { | ||||
| pub fn verify_block_family<C: BlockInfo + CallContract>(header: &Header, parent: &Header, engine: &EthEngine, do_full: Option<FullFamilyParams<C>>) -> Result<(), Error> { | ||||
| 	// TODO: verify timestamp
 | ||||
| 	verify_parent(&header, &parent, engine.params().gas_limit_bound_divisor)?; | ||||
| 	engine.verify_block_family(&header, &parent)?; | ||||
| 
 | ||||
| 	let (bytes, txs, bc, client) = match do_full { | ||||
| 	let params = match do_full { | ||||
| 		Some(x) => x, | ||||
| 		None => return Ok(()), | ||||
| 	}; | ||||
| 
 | ||||
| 	verify_uncles(header, bytes, bc, engine)?; | ||||
| 	verify_uncles(header, params.block_bytes, params.block_provider, engine)?; | ||||
| 
 | ||||
| 	for transaction in txs { | ||||
| 		engine.machine().verify_transaction(transaction, header, client)?; | ||||
| 	for transaction in params.transactions { | ||||
| 		engine.machine().verify_transaction(transaction, header, params.client)?; | ||||
| 	} | ||||
| 
 | ||||
| 	Ok(()) | ||||
| @ -486,12 +498,12 @@ mod tests { | ||||
| 		let parent = bc.block_header(header.parent_hash()) | ||||
| 			.ok_or(BlockError::UnknownParent(header.parent_hash().clone()))?; | ||||
| 
 | ||||
| 		let full_params: FullFamilyParams = ( | ||||
| 			bytes, | ||||
| 			&transactions[..], | ||||
| 			bc as &BlockProvider, | ||||
| 			&client as &::client::BlockChainClient | ||||
| 		); | ||||
| 		let full_params = FullFamilyParams { | ||||
| 			block_bytes: bytes, | ||||
| 			transactions: &transactions[..], | ||||
| 			block_provider: bc as &BlockProvider, | ||||
| 			client: &client, | ||||
| 		}; | ||||
| 		verify_block_family(&header, &parent, engine, Some(full_params)) | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -16,20 +16,23 @@ | ||||
| 
 | ||||
| //! A generic verifier trait.
 | ||||
| 
 | ||||
| use client::{BlockInfo, CallContract}; | ||||
| use engines::EthEngine; | ||||
| use error::Error; | ||||
| use header::Header; | ||||
| use super::verification; | ||||
| 
 | ||||
| /// Should be used to verify blocks.
 | ||||
| pub trait Verifier: Send + Sync { | ||||
| pub trait Verifier<C>: Send + Sync | ||||
| 	where C: BlockInfo + CallContract | ||||
| { | ||||
| 	/// Verify a block relative to its parent and uncles.
 | ||||
|     fn verify_block_family( | ||||
| 	fn verify_block_family( | ||||
| 		&self, | ||||
| 		header: &Header, | ||||
| 		parent: &Header, | ||||
| 		engine: &EthEngine, | ||||
| 		do_full: Option<verification::FullFamilyParams> | ||||
| 		do_full: Option<verification::FullFamilyParams<C>> | ||||
| 	) -> Result<(), Error>; | ||||
| 
 | ||||
| 	/// Do a final verification check for an enacted header vs its expected counterpart.
 | ||||
|  | ||||
| @ -31,8 +31,6 @@ pub enum BlockId { | ||||
| 	Earliest, | ||||
| 	/// Latest mined block.
 | ||||
| 	Latest, | ||||
| 	/// Pending block.
 | ||||
| 	Pending, | ||||
| } | ||||
| 
 | ||||
| /// Uniquely identifies transaction.
 | ||||
|  | ||||
| @ -31,10 +31,6 @@ extern crate parking_lot; | ||||
| extern crate table; | ||||
| extern crate transient_hashmap; | ||||
| 
 | ||||
| #[macro_use] | ||||
| extern crate ethabi_derive; | ||||
| #[macro_use] | ||||
| extern crate ethabi_contract; | ||||
| #[cfg(test)] | ||||
| extern crate ethkey; | ||||
| #[macro_use] | ||||
| @ -45,6 +41,5 @@ extern crate rustc_hex; | ||||
| pub mod banning_queue; | ||||
| pub mod external; | ||||
| pub mod local_transactions; | ||||
| pub mod service_transaction_checker; | ||||
| pub mod transaction_queue; | ||||
| pub mod work_notify; | ||||
|  | ||||
| @ -26,7 +26,7 @@ use ethereum_types::{U256, H256, Address}; | ||||
| use bytes::ToPretty; | ||||
| use rlp::PayloadInfo; | ||||
| use ethcore::service::ClientService; | ||||
| use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockImportError, BlockChainClient, BlockId}; | ||||
| use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockImportError, Nonce, Balance, BlockChainClient, BlockId, BlockInfo, ImportBlock}; | ||||
| use ethcore::db::NUM_COLUMNS; | ||||
| use ethcore::error::ImportError; | ||||
| use ethcore::miner::Miner; | ||||
| @ -650,7 +650,7 @@ fn execute_export_state(cmd: ExportState) -> Result<(), String> { | ||||
| 		} | ||||
| 
 | ||||
| 		for account in accounts.into_iter() { | ||||
| 			let balance = client.balance(&account, at).unwrap_or_else(U256::zero); | ||||
| 			let balance = client.balance(&account, at.into()).unwrap_or_else(U256::zero); | ||||
| 			if cmd.min_balance.map_or(false, |m| balance < m) || cmd.max_balance.map_or(false, |m| balance > m) { | ||||
| 				last = Some(account); | ||||
| 				continue; //filtered out
 | ||||
| @ -660,7 +660,7 @@ fn execute_export_state(cmd: ExportState) -> Result<(), String> { | ||||
| 				out.write(b",").expect("Write error"); | ||||
| 			} | ||||
| 			out.write_fmt(format_args!("\n\"0x{:x}\": {{\"balance\": \"{:x}\", \"nonce\": \"{:x}\"", account, balance, client.nonce(&account, at).unwrap_or_else(U256::zero))).expect("Write error"); | ||||
| 			let code = client.code(&account, at).unwrap_or(None).unwrap_or_else(Vec::new); | ||||
| 			let code = client.code(&account, at.into()).unwrap_or(None).unwrap_or_else(Vec::new); | ||||
| 			if !code.is_empty() { | ||||
| 				out.write_fmt(format_args!(", \"code_hash\": \"0x{:x}\"", keccak(&code))).expect("Write error"); | ||||
| 				if cmd.code { | ||||
| @ -683,7 +683,7 @@ fn execute_export_state(cmd: ExportState) -> Result<(), String> { | ||||
| 							if last_storage.is_some() { | ||||
| 								out.write(b",").expect("Write error"); | ||||
| 							} | ||||
| 							out.write_fmt(format_args!("\n\t\"0x{:x}\": \"0x{:x}\"", key, client.storage_at(&account, &key, at).unwrap_or_else(Default::default))).expect("Write error"); | ||||
| 							out.write_fmt(format_args!("\n\t\"0x{:x}\": \"0x{:x}\"", key, client.storage_at(&account, &key, at.into()).unwrap_or_else(Default::default))).expect("Write error"); | ||||
| 							last_storage = Some(key); | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| @ -20,7 +20,7 @@ use std::sync::Arc; | ||||
| use bytes::Bytes; | ||||
| use dir::default_data_path; | ||||
| use dir::helpers::replace_home; | ||||
| use ethcore::client::{Client, BlockChainClient, BlockId}; | ||||
| use ethcore::client::{Client, BlockChainClient, BlockId, CallContract}; | ||||
| use ethsync::LightSync; | ||||
| use futures::{Future, future, IntoFuture}; | ||||
| use hash_fetch::fetch::Client as FetchClient; | ||||
|  | ||||
| @ -22,7 +22,7 @@ use std::sync::{Arc}; | ||||
| use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; | ||||
| use std::time::{Instant, Duration}; | ||||
| 
 | ||||
| use ethcore::client::{BlockId, BlockChainClient, BlockChainInfo, BlockQueueInfo, ChainNotify, ClientReport, Client}; | ||||
| use ethcore::client::{BlockId, BlockChainClient, ChainInfo, BlockInfo, BlockChainInfo, BlockQueueInfo, ChainNotify, ClientReport, Client}; | ||||
| use ethcore::header::BlockNumber; | ||||
| use ethcore::service::ClientIoMessage; | ||||
| use ethcore::snapshot::{RestorationStatus, SnapshotService as SS}; | ||||
|  | ||||
| @ -60,6 +60,7 @@ node-health = { path = "../dapps/node-health" } | ||||
| parity-reactor = { path = "../util/reactor" } | ||||
| parity-updater = { path = "../updater" } | ||||
| parity-version = { path = "../util/version" } | ||||
| patricia-trie = { path = "../util/patricia_trie" } | ||||
| rlp = { path = "../util/rlp" } | ||||
| stats = { path = "../util/stats" } | ||||
| vm = { path = "../ethcore/vm" } | ||||
|  | ||||
| @ -68,6 +68,7 @@ extern crate rlp; | ||||
| extern crate stats; | ||||
| extern crate keccak_hash as hash; | ||||
| extern crate hardware_wallet; | ||||
| extern crate patricia_trie as trie; | ||||
| 
 | ||||
| #[macro_use] | ||||
| extern crate log; | ||||
|  | ||||
| @ -197,7 +197,19 @@ impl LightFetch { | ||||
| 
 | ||||
| 		let (sync, on_demand, client) = (self.sync.clone(), self.on_demand.clone(), self.client.clone()); | ||||
| 		let req: CallRequestHelper = req.into(); | ||||
| 		let id = num.unwrap_or_default().into(); | ||||
| 
 | ||||
| 		// Note: Here we treat `Pending` as `Latest`.
 | ||||
| 		//       Since light clients don't produce pending blocks
 | ||||
| 		//       (they don't have state) we can safely fallback to `Latest`.
 | ||||
| 		let id = match num.unwrap_or_default() { | ||||
| 			BlockNumber::Num(n) => BlockId::Number(n), | ||||
| 			BlockNumber::Earliest => BlockId::Earliest, | ||||
| 			BlockNumber::Latest => BlockId::Latest, | ||||
| 			BlockNumber::Pending => { | ||||
| 				warn!("`Pending` is deprecated and may be removed in future versions. Falling back to `Latest`"); | ||||
| 				BlockId::Latest | ||||
| 			} | ||||
| 		}; | ||||
| 
 | ||||
| 		let from = req.from.unwrap_or(Address::zero()); | ||||
| 		let nonce_fut = match req.nonce { | ||||
| @ -308,7 +320,7 @@ impl LightFetch { | ||||
| 		let best_number = self.client.chain_info().best_block_number; | ||||
| 		let block_number = |id| match id { | ||||
| 			BlockId::Earliest => Some(0), | ||||
| 			BlockId::Latest | BlockId::Pending => Some(best_number), | ||||
| 			BlockId::Latest => Some(best_number), | ||||
| 			BlockId::Hash(h) => self.client.block_header(BlockId::Hash(h)).map(|hdr| hdr.number()), | ||||
| 			BlockId::Number(x) => Some(x), | ||||
| 		}; | ||||
|  | ||||
| @ -28,16 +28,17 @@ use parking_lot::Mutex; | ||||
| use ethash::SeedHashCompute; | ||||
| use ethcore::account_provider::{AccountProvider, DappId}; | ||||
| use ethcore::block::IsBlock; | ||||
| use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId}; | ||||
| use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo}; | ||||
| use ethcore::ethereum::Ethash; | ||||
| use ethcore::filter::Filter as EthcoreFilter; | ||||
| use ethcore::header::{Header as BlockHeader, BlockNumber as EthBlockNumber}; | ||||
| use ethcore::header::{BlockNumber as EthBlockNumber, Seal}; | ||||
| use ethcore::log_entry::LogEntry; | ||||
| use ethcore::miner::MinerService; | ||||
| use ethcore::snapshot::SnapshotService; | ||||
| use ethcore::encoded; | ||||
| use ethsync::{SyncProvider}; | ||||
| use miner::external::ExternalMinerService; | ||||
| use transaction::SignedTransaction; | ||||
| use transaction::{SignedTransaction, LocalizedTransaction}; | ||||
| 
 | ||||
| use jsonrpc_core::{BoxFuture, Result}; | ||||
| use jsonrpc_core::futures::future; | ||||
| @ -51,11 +52,11 @@ use v1::traits::Eth; | ||||
| use v1::types::{ | ||||
| 	RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, | ||||
| 	Transaction, CallRequest, Index, Filter, Log, Receipt, Work, | ||||
| 	H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256, | ||||
| 	H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256, block_number_to_id, | ||||
| }; | ||||
| use v1::metadata::Metadata; | ||||
| 
 | ||||
| const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched earlier), extra_info is always available if object exists; qed"; | ||||
| const EXTRA_INFO_PROOF: &'static str = "Object exists in blockchain (fetched earlier), extra_info is always available if object exists; qed"; | ||||
| 
 | ||||
| /// Eth RPC options
 | ||||
| pub struct EthClientOptions { | ||||
| @ -109,11 +110,43 @@ pub struct EthClient<C, SN: ?Sized, S: ?Sized, M, EM> where | ||||
| 	eip86_transition: u64, | ||||
| } | ||||
| 
 | ||||
| impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where | ||||
| 	C: MiningBlockChainClient, | ||||
| enum BlockNumberOrId { | ||||
| 	Number(BlockNumber), | ||||
| 	Id(BlockId), | ||||
| } | ||||
| 
 | ||||
| impl From<BlockId> for BlockNumberOrId { | ||||
| 	fn from(value: BlockId) -> BlockNumberOrId { | ||||
| 		BlockNumberOrId::Id(value) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl From<BlockNumber> for BlockNumberOrId { | ||||
| 	fn from(value: BlockNumber) -> BlockNumberOrId { | ||||
| 		BlockNumberOrId::Number(value) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| enum PendingOrBlock { | ||||
| 	Block(BlockId), | ||||
| 	Pending, | ||||
| } | ||||
| 
 | ||||
| struct PendingUncleId { | ||||
| 	id: PendingOrBlock, | ||||
| 	position: usize, | ||||
| } | ||||
| 
 | ||||
| enum PendingTransactionId { | ||||
| 	Hash(H256), | ||||
| 	Location(PendingOrBlock, usize) | ||||
| } | ||||
| 
 | ||||
| impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S, M, EM> where | ||||
| 	C: MiningBlockChainClient + StateClient<State=T> + Call<State=T> + EngineInfo, | ||||
| 	SN: SnapshotService, | ||||
| 	S: SyncProvider, | ||||
| 	M: MinerService, | ||||
| 	M: MinerService<State=T>, | ||||
| 	EM: ExternalMinerService { | ||||
| 
 | ||||
| 	/// Creates new EthClient.
 | ||||
| @ -145,9 +178,46 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where | ||||
| 		unwrap_provider(&self.accounts) | ||||
| 	} | ||||
| 
 | ||||
| 	fn block(&self, id: BlockId, include_txs: bool) -> Result<Option<RichBlock>> { | ||||
| 	fn rich_block(&self, id: BlockNumberOrId, include_txs: bool) -> Result<Option<RichBlock>> { | ||||
| 		let client = &self.client; | ||||
| 		match (client.block(id.clone()), client.block_total_difficulty(id)) { | ||||
| 
 | ||||
| 		let client_query = |id| (client.block(id), client.block_total_difficulty(id), client.block_extra_info(id)); | ||||
| 
 | ||||
| 		let (block, difficulty, extra) = match id { | ||||
| 			BlockNumberOrId::Number(BlockNumber::Pending) => { | ||||
| 				let info = self.client.chain_info(); | ||||
| 				let pending_block = self.miner.pending_block(info.best_block_number); | ||||
| 				let difficulty = { | ||||
| 					let latest_difficulty = self.client.block_total_difficulty(BlockId::Latest).expect("blocks in chain have details; qed"); | ||||
| 					let pending_difficulty = self.miner.pending_block_header(info.best_block_number).map(|header| *header.difficulty()); | ||||
| 
 | ||||
| 				 	if let Some(difficulty) = pending_difficulty { | ||||
| 						difficulty + latest_difficulty | ||||
| 					} else { | ||||
| 						latest_difficulty | ||||
| 					} | ||||
| 				}; | ||||
| 
 | ||||
| 				let extra = pending_block.as_ref().map(|b| self.client.engine().extra_info(&b.header)); | ||||
| 
 | ||||
| 				(pending_block.map(|b| encoded::Block::new(b.rlp_bytes(Seal::Without))), Some(difficulty), extra) | ||||
| 			}, | ||||
| 
 | ||||
| 			BlockNumberOrId::Number(num) => { | ||||
| 				let id = match num { | ||||
| 					BlockNumber::Latest => BlockId::Latest, | ||||
| 					BlockNumber::Earliest => BlockId::Earliest, | ||||
| 					BlockNumber::Num(n) => BlockId::Number(n), | ||||
| 					BlockNumber::Pending => unreachable!(), // Already covered
 | ||||
| 				}; | ||||
| 
 | ||||
| 				client_query(id) | ||||
| 			}, | ||||
| 
 | ||||
| 			BlockNumberOrId::Id(id) => client_query(id), | ||||
| 		}; | ||||
| 
 | ||||
| 		match (block, difficulty) { | ||||
| 			(Some(block), Some(total_difficulty)) => { | ||||
| 				let view = block.header_view(); | ||||
| 				Ok(Some(RichBlock { | ||||
| @ -176,29 +246,109 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where | ||||
| 						}, | ||||
| 						extra_data: Bytes::new(view.extra_data()), | ||||
| 					}, | ||||
| 					extra_info: client.block_extra_info(id.clone()).expect(EXTRA_INFO_PROOF), | ||||
| 					extra_info: extra.expect(EXTRA_INFO_PROOF), | ||||
| 				})) | ||||
| 			}, | ||||
| 			_ => Ok(None) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn transaction(&self, id: TransactionId) -> Result<Option<Transaction>> { | ||||
| 		match self.client.transaction(id) { | ||||
| 	fn transaction(&self, id: PendingTransactionId) -> Result<Option<Transaction>> { | ||||
| 		let client_transaction = |id| match self.client.transaction(id) { | ||||
| 			Some(t) => Ok(Some(Transaction::from_localized(t, self.eip86_transition))), | ||||
| 			None => Ok(None), | ||||
| 		}; | ||||
| 
 | ||||
| 		match id { | ||||
| 			PendingTransactionId::Hash(hash) => client_transaction(TransactionId::Hash(hash)), | ||||
| 
 | ||||
| 			PendingTransactionId::Location(PendingOrBlock::Block(block), index) => { | ||||
| 				client_transaction(TransactionId::Location(block, index)) | ||||
| 			}, | ||||
| 
 | ||||
| 			PendingTransactionId::Location(PendingOrBlock::Pending, index) => { | ||||
| 				let info = self.client.chain_info(); | ||||
| 				let pending_block = match self.miner.pending_block(info.best_block_number) { | ||||
| 					Some(block) => block, | ||||
| 					None => return Ok(None), | ||||
| 				}; | ||||
| 
 | ||||
| 				// Implementation stolen from `extract_transaction_at_index`
 | ||||
| 				let transaction = pending_block.transactions.get(index) | ||||
| 					// Verify if transaction signature is correct.
 | ||||
| 					.and_then(|tx| SignedTransaction::new(tx.clone()).ok()) | ||||
| 					.map(|signed_tx| { | ||||
| 						let (signed, sender, _) = signed_tx.deconstruct(); | ||||
| 						let block_hash = pending_block.header.hash(); | ||||
| 						let block_number = pending_block.header.number(); | ||||
| 						let transaction_index = index; | ||||
| 						let cached_sender = Some(sender); | ||||
| 
 | ||||
| 						LocalizedTransaction { | ||||
| 							signed, | ||||
| 							block_number, | ||||
| 							block_hash, | ||||
| 							transaction_index, | ||||
| 							cached_sender, | ||||
| 						} | ||||
| 					}) | ||||
| 					.map(|tx| Transaction::from_localized(tx, self.eip86_transition)); | ||||
| 
 | ||||
| 				Ok(transaction) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn uncle(&self, id: UncleId) -> Result<Option<RichBlock>> { | ||||
| 	fn uncle(&self, id: PendingUncleId) -> Result<Option<RichBlock>> { | ||||
| 		let client = &self.client; | ||||
| 		let uncle: BlockHeader = match client.uncle(id) { | ||||
| 			Some(hdr) => hdr.decode(), | ||||
| 			None => { return Ok(None); } | ||||
| 		}; | ||||
| 		let parent_difficulty = match client.block_total_difficulty(BlockId::Hash(uncle.parent_hash().clone())) { | ||||
| 			Some(difficulty) => difficulty, | ||||
| 			None => { return Ok(None); } | ||||
| 
 | ||||
| 		let (uncle, parent_difficulty, extra) = match id { | ||||
| 			PendingUncleId { id: PendingOrBlock::Pending, position } => { | ||||
| 				let info = self.client.chain_info(); | ||||
| 
 | ||||
| 				let pending_block = match self.miner.pending_block(info.best_block_number) { | ||||
| 					Some(block) => block, | ||||
| 					None => return Ok(None), | ||||
| 				}; | ||||
| 
 | ||||
| 				let uncle = match pending_block.uncles.get(position) { | ||||
| 					Some(uncle) => uncle.clone(), | ||||
| 					None => return Ok(None), | ||||
| 				}; | ||||
| 
 | ||||
| 				let difficulty = { | ||||
| 					let latest_difficulty = self.client.block_total_difficulty(BlockId::Latest).expect("blocks in chain have details; qed"); | ||||
| 					let pending_difficulty = self.miner.pending_block_header(info.best_block_number).map(|header| *header.difficulty()); | ||||
| 
 | ||||
| 					if let Some(difficulty) = pending_difficulty { | ||||
| 						difficulty + latest_difficulty | ||||
| 					} else { | ||||
| 						latest_difficulty | ||||
| 					} | ||||
| 				}; | ||||
| 
 | ||||
| 				let extra = self.client.engine().extra_info(&pending_block.header); | ||||
| 
 | ||||
| 				(uncle, difficulty, extra) | ||||
| 			}, | ||||
| 
 | ||||
| 			PendingUncleId { id: PendingOrBlock::Block(block_id), position } => { | ||||
| 				let uncle_id = UncleId { block: block_id, position }; | ||||
| 
 | ||||
| 				let uncle = match client.uncle(uncle_id) { | ||||
| 					Some(hdr) => hdr.decode(), | ||||
| 					None => { return Ok(None); } | ||||
| 				}; | ||||
| 
 | ||||
| 				let parent_difficulty = match client.block_total_difficulty(BlockId::Hash(uncle.parent_hash().clone())) { | ||||
| 					Some(difficulty) => difficulty, | ||||
| 					None => { return Ok(None); } | ||||
| 				}; | ||||
| 
 | ||||
| 				let extra = client.uncle_extra_info(uncle_id).expect(EXTRA_INFO_PROOF); | ||||
| 
 | ||||
| 				(uncle, parent_difficulty, extra) | ||||
| 			} | ||||
| 		}; | ||||
| 
 | ||||
| 		let size = client.block(BlockId::Hash(uncle.hash())) | ||||
| @ -229,7 +379,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where | ||||
| 				uncles: vec![], | ||||
| 				transactions: BlockTransactions::Hashes(vec![]), | ||||
| 			}, | ||||
| 			extra_info: client.uncle_extra_info(id).expect(EXTRA_INFO_PROOF), | ||||
| 			extra_info: extra, | ||||
| 		}; | ||||
| 		Ok(Some(block)) | ||||
| 	} | ||||
| @ -241,6 +391,24 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where | ||||
| 			.and_then(|_| store.dapp_addresses(dapp)) | ||||
| 			.map_err(|e| errors::account("Could not fetch accounts.", e)) | ||||
| 	} | ||||
| 
 | ||||
| 	fn get_state(&self, number: BlockNumber) -> StateOrBlock { | ||||
| 		match number { | ||||
| 			BlockNumber::Num(num) => BlockId::Number(num).into(), | ||||
| 			BlockNumber::Earliest => BlockId::Earliest.into(), | ||||
| 			BlockNumber::Latest => BlockId::Latest.into(), | ||||
| 
 | ||||
| 			BlockNumber::Pending => { | ||||
| 				let info = self.client.chain_info(); | ||||
| 
 | ||||
| 				self.miner | ||||
| 					.pending_state(info.best_block_number) | ||||
| 					.map(|s| Box::new(s) as Box<StateInfo>) | ||||
| 					.unwrap_or(Box::new(self.client.latest_state()) as Box<StateInfo>) | ||||
| 					.into() | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn pending_logs<M>(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFilter) -> Vec<Log> where M: MinerService { | ||||
| @ -265,20 +433,27 @@ pub fn pending_logs<M>(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFi | ||||
| fn check_known<C>(client: &C, number: BlockNumber) -> Result<()> where C: MiningBlockChainClient { | ||||
| 	use ethcore::block_status::BlockStatus; | ||||
| 
 | ||||
| 	match client.block_status(number.into()) { | ||||
| 	let id = match number { | ||||
| 		BlockNumber::Pending => return Ok(()), | ||||
| 
 | ||||
| 		BlockNumber::Num(n) => BlockId::Number(n), | ||||
| 		BlockNumber::Latest => BlockId::Latest, | ||||
| 		BlockNumber::Earliest => BlockId::Earliest, | ||||
| 	}; | ||||
| 
 | ||||
| 	match client.block_status(id) { | ||||
| 		BlockStatus::InChain => Ok(()), | ||||
| 		BlockStatus::Pending => Ok(()), | ||||
| 		_ => Err(errors::unknown_block()), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4;	// because uncles go back 6.
 | ||||
| 
 | ||||
| impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 	C: MiningBlockChainClient + 'static, | ||||
| impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 	C: MiningBlockChainClient + StateClient<State=T> + Call<State=T> + EngineInfo + 'static, | ||||
| 	SN: SnapshotService + 'static, | ||||
| 	S: SyncProvider + 'static, | ||||
| 	M: MinerService + 'static, | ||||
| 	M: MinerService<State=T> + 'static, | ||||
| 	EM: ExternalMinerService + 'static, | ||||
| { | ||||
| 	type Metadata = Metadata; | ||||
| @ -357,10 +532,10 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 	fn balance(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256> { | ||||
| 		let address = address.into(); | ||||
| 
 | ||||
| 		let id = num.unwrap_or_default(); | ||||
| 		let num = num.unwrap_or_default(); | ||||
| 
 | ||||
| 		try_bf!(check_known(&*self.client, id.clone())); | ||||
| 		let res = match self.client.balance(&address, id.into()) { | ||||
| 		try_bf!(check_known(&*self.client, num.clone())); | ||||
| 		let res = match self.client.balance(&address, self.get_state(num)) { | ||||
| 			Some(balance) => Ok(balance.into()), | ||||
| 			None => Err(errors::state_pruned()), | ||||
| 		}; | ||||
| @ -372,10 +547,10 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 		let address: Address = RpcH160::into(address); | ||||
| 		let position: U256 = RpcU256::into(pos); | ||||
| 
 | ||||
| 		let id = num.unwrap_or_default(); | ||||
| 		let num = num.unwrap_or_default(); | ||||
| 
 | ||||
| 		try_bf!(check_known(&*self.client, id.clone())); | ||||
| 		let res = match self.client.storage_at(&address, &H256::from(position), id.into()) { | ||||
| 		try_bf!(check_known(&*self.client, num.clone())); | ||||
| 		let res = match self.client.storage_at(&address, &H256::from(position), self.get_state(num)) { | ||||
| 			Some(s) => Ok(s.into()), | ||||
| 			None => Err(errors::state_pruned()), | ||||
| 		}; | ||||
| @ -390,15 +565,33 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 			BlockNumber::Pending if self.options.pending_nonce_from_queue => { | ||||
| 				let nonce = self.miner.last_nonce(&address) | ||||
| 					.map(|n| n + 1.into()) | ||||
| 					.or_else(|| self.client.nonce(&address, BlockNumber::Pending.into())); | ||||
| 					.or_else(|| self.client.nonce(&address, BlockId::Latest)); | ||||
| 
 | ||||
| 				match nonce { | ||||
| 					Some(nonce) => Ok(nonce.into()), | ||||
| 					None => Err(errors::database("latest nonce missing")) | ||||
| 				} | ||||
| 			} | ||||
| 			id => { | ||||
| 				try_bf!(check_known(&*self.client, id.clone())); | ||||
| 				match self.client.nonce(&address, id.into()) { | ||||
| 			}, | ||||
| 
 | ||||
| 			BlockNumber::Pending => { | ||||
| 				let info = self.client.chain_info(); | ||||
| 				let nonce = self.miner | ||||
| 					.pending_state(info.best_block_number) | ||||
| 					.and_then(|s| s.nonce(&address).ok()) | ||||
| 					.or_else(|| { | ||||
| 						warn!("Fallback to `BlockId::Latest`"); | ||||
| 						self.client.nonce(&address, BlockId::Latest) | ||||
| 					}); | ||||
| 
 | ||||
| 				match nonce { | ||||
| 					Some(nonce) => Ok(nonce.into()), | ||||
| 					None => Err(errors::database("latest nonce missing")) | ||||
| 				} | ||||
| 			}, | ||||
| 
 | ||||
| 			number => { | ||||
| 				try_bf!(check_known(&*self.client, number.clone())); | ||||
| 				match self.client.nonce(&address, block_number_to_id(number)) { | ||||
| 					Some(nonce) => Ok(nonce.into()), | ||||
| 					None => Err(errors::state_pruned()), | ||||
| 				} | ||||
| @ -419,7 +612,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 				self.miner.status().transactions_in_pending_block.into() | ||||
| 			), | ||||
| 			_ => | ||||
| 				self.client.block(num.into()) | ||||
| 				self.client.block(block_number_to_id(num)) | ||||
| 					.map(|block| block.transactions_count().into()) | ||||
| 		})) | ||||
| 	} | ||||
| @ -432,7 +625,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 	fn block_uncles_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> { | ||||
| 		Box::new(future::ok(match num { | ||||
| 			BlockNumber::Pending => Some(0.into()), | ||||
| 			_ => self.client.block(num.into()) | ||||
| 			_ => self.client.block(block_number_to_id(num)) | ||||
| 					.map(|block| block.uncles_count().into() | ||||
| 			), | ||||
| 		})) | ||||
| @ -441,10 +634,10 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 	fn code_at(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<Bytes> { | ||||
| 		let address: Address = RpcH160::into(address); | ||||
| 
 | ||||
| 		let id = num.unwrap_or_default(); | ||||
| 		try_bf!(check_known(&*self.client, id.clone())); | ||||
| 		let num = num.unwrap_or_default(); | ||||
| 		try_bf!(check_known(&*self.client, num.clone())); | ||||
| 
 | ||||
| 		let res = match self.client.code(&address, id.into()) { | ||||
| 		let res = match self.client.code(&address, self.get_state(num)) { | ||||
| 			Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)), | ||||
| 			None => Err(errors::state_pruned()), | ||||
| 		}; | ||||
| @ -453,17 +646,17 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 	} | ||||
| 
 | ||||
| 	fn block_by_hash(&self, hash: RpcH256, include_txs: bool) -> BoxFuture<Option<RichBlock>> { | ||||
| 		Box::new(future::done(self.block(BlockId::Hash(hash.into()), include_txs))) | ||||
| 		Box::new(future::done(self.rich_block(BlockId::Hash(hash.into()).into(), include_txs))) | ||||
| 	} | ||||
| 
 | ||||
| 	fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture<Option<RichBlock>> { | ||||
| 		Box::new(future::done(self.block(num.into(), include_txs))) | ||||
| 		Box::new(future::done(self.rich_block(num.into(), include_txs))) | ||||
| 	} | ||||
| 
 | ||||
| 	fn transaction_by_hash(&self, hash: RpcH256) -> BoxFuture<Option<Transaction>> { | ||||
| 		let hash: H256 = hash.into(); | ||||
| 		let block_number = self.client.chain_info().best_block_number; | ||||
| 		let tx = try_bf!(self.transaction(TransactionId::Hash(hash))).or_else(|| { | ||||
| 		let tx = try_bf!(self.transaction(PendingTransactionId::Hash(hash))).or_else(|| { | ||||
| 			self.miner.transaction(block_number, &hash) | ||||
| 				.map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)) | ||||
| 		}); | ||||
| @ -472,15 +665,20 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 	} | ||||
| 
 | ||||
| 	fn transaction_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> BoxFuture<Option<Transaction>> { | ||||
| 		Box::new(future::done( | ||||
| 			self.transaction(TransactionId::Location(BlockId::Hash(hash.into()), index.value())) | ||||
| 		)) | ||||
| 		let id = PendingTransactionId::Location(PendingOrBlock::Block(BlockId::Hash(hash.into())), index.value()); | ||||
| 		Box::new(future::done(self.transaction(id))) | ||||
| 	} | ||||
| 
 | ||||
| 	fn transaction_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> BoxFuture<Option<Transaction>> { | ||||
| 		Box::new(future::done( | ||||
| 			self.transaction(TransactionId::Location(num.into(), index.value())) | ||||
| 		)) | ||||
| 		let block_id = match num { | ||||
| 			BlockNumber::Latest => PendingOrBlock::Block(BlockId::Latest), | ||||
| 			BlockNumber::Earliest => PendingOrBlock::Block(BlockId::Earliest), | ||||
| 			BlockNumber::Num(num) => PendingOrBlock::Block(BlockId::Number(num)), | ||||
| 			BlockNumber::Pending => PendingOrBlock::Pending, | ||||
| 		}; | ||||
| 
 | ||||
| 		let transaction_id = PendingTransactionId::Location(block_id, index.value()); | ||||
| 		Box::new(future::done(self.transaction(transaction_id))) | ||||
| 	} | ||||
| 
 | ||||
| 	fn transaction_receipt(&self, hash: RpcH256) -> BoxFuture<Option<Receipt>> { | ||||
| @ -497,17 +695,22 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 	} | ||||
| 
 | ||||
| 	fn uncle_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> BoxFuture<Option<RichBlock>> { | ||||
| 		Box::new(future::done(self.uncle(UncleId { | ||||
| 			block: BlockId::Hash(hash.into()), | ||||
| 		Box::new(future::done(self.uncle(PendingUncleId { | ||||
| 			id: PendingOrBlock::Block(BlockId::Hash(hash.into())), | ||||
| 			position: index.value() | ||||
| 		}))) | ||||
| 	} | ||||
| 
 | ||||
| 	fn uncle_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> BoxFuture<Option<RichBlock>> { | ||||
| 		Box::new(future::done(self.uncle(UncleId { | ||||
| 			block: num.into(), | ||||
| 			position: index.value() | ||||
| 		}))) | ||||
| 		let id = match num { | ||||
| 			BlockNumber::Latest => PendingUncleId { id: PendingOrBlock::Block(BlockId::Latest), position: index.value() }, | ||||
| 			BlockNumber::Earliest => PendingUncleId { id: PendingOrBlock::Block(BlockId::Earliest), position: index.value() }, | ||||
| 			BlockNumber::Num(num) => PendingUncleId { id: PendingOrBlock::Block(BlockId::Number(num)), position: index.value() }, | ||||
| 
 | ||||
| 			BlockNumber::Pending => PendingUncleId { id: PendingOrBlock::Pending, position: index.value() }, | ||||
| 		}; | ||||
| 
 | ||||
| 		Box::new(future::done(self.uncle(id))) | ||||
| 	} | ||||
| 
 | ||||
| 	fn compilers(&self) -> Result<Vec<String>> { | ||||
| @ -630,7 +833,28 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 		let signed = try_bf!(fake_sign::sign_call(request, meta.is_dapp())); | ||||
| 
 | ||||
| 		let num = num.unwrap_or_default(); | ||||
| 		let result = self.client.call(&signed, Default::default(), num.into()); | ||||
| 
 | ||||
| 		let (mut state, header) = if num == BlockNumber::Pending { | ||||
| 			let info = self.client.chain_info(); | ||||
| 			let state = try_bf!(self.miner.pending_state(info.best_block_number).ok_or(errors::state_pruned())); | ||||
| 			let header = try_bf!(self.miner.pending_block_header(info.best_block_number).ok_or(errors::state_pruned())); | ||||
| 
 | ||||
| 			(state, header) | ||||
| 		} else { | ||||
| 			let id = match num { | ||||
| 				BlockNumber::Num(num) => BlockId::Number(num), | ||||
| 				BlockNumber::Earliest => BlockId::Earliest, | ||||
| 				BlockNumber::Latest => BlockId::Latest, | ||||
| 				BlockNumber::Pending => unreachable!(), // Already covered
 | ||||
| 			}; | ||||
| 
 | ||||
| 			let state = try_bf!(self.client.state_at(id).ok_or(errors::state_pruned())); | ||||
| 			let header = try_bf!(self.client.block_header(id).ok_or(errors::state_pruned())); | ||||
| 
 | ||||
| 			(state, header.decode()) | ||||
| 		}; | ||||
| 
 | ||||
| 		let result = self.client.call(&signed, Default::default(), &mut state, &header); | ||||
| 
 | ||||
| 		Box::new(future::done(result | ||||
| 			.map(|b| b.output.into()) | ||||
| @ -641,7 +865,29 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where | ||||
| 	fn estimate_gas(&self, meta: Self::Metadata, request: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256> { | ||||
| 		let request = CallRequest::into(request); | ||||
| 		let signed = try_bf!(fake_sign::sign_call(request, meta.is_dapp())); | ||||
| 		Box::new(future::done(self.client.estimate_gas(&signed, num.unwrap_or_default().into()) | ||||
| 		let num = num.unwrap_or_default(); | ||||
| 
 | ||||
| 		let (state, header) = if num == BlockNumber::Pending { | ||||
| 			let info = self.client.chain_info(); | ||||
| 			let state = try_bf!(self.miner.pending_state(info.best_block_number).ok_or(errors::state_pruned())); | ||||
| 			let header = try_bf!(self.miner.pending_block_header(info.best_block_number).ok_or(errors::state_pruned())); | ||||
| 
 | ||||
| 			(state, header) | ||||
| 		} else { | ||||
| 			let id = match num { | ||||
| 				BlockNumber::Num(num) => BlockId::Number(num), | ||||
| 				BlockNumber::Earliest => BlockId::Earliest, | ||||
| 				BlockNumber::Latest => BlockId::Latest, | ||||
| 				BlockNumber::Pending => unreachable!(), // Already covered
 | ||||
| 			}; | ||||
| 
 | ||||
| 			let state = try_bf!(self.client.state_at(id).ok_or(errors::state_pruned())); | ||||
| 			let header = try_bf!(self.client.block_header(id).ok_or(errors::state_pruned())); | ||||
| 
 | ||||
| 			(state, header.decode()) | ||||
| 		}; | ||||
| 
 | ||||
| 		Box::new(future::done(self.client.estimate_gas(&signed, &state, &header) | ||||
| 			.map(Into::into) | ||||
| 			.map_err(errors::call) | ||||
| 		)) | ||||
|  | ||||
| @ -65,6 +65,23 @@ pub struct EthClient<T> { | ||||
| 	gas_price_percentile: usize, | ||||
| } | ||||
| 
 | ||||
| impl<T> EthClient<T> { | ||||
| 	fn num_to_id(num: BlockNumber) -> BlockId { | ||||
| 		// Note: Here we treat `Pending` as `Latest`.
 | ||||
| 		//       Since light clients don't produce pending blocks
 | ||||
| 		//       (they don't have state) we can safely fallback to `Latest`.
 | ||||
| 		match num { | ||||
| 			BlockNumber::Num(n) => BlockId::Number(n), | ||||
| 			BlockNumber::Earliest => BlockId::Earliest, | ||||
| 			BlockNumber::Latest => BlockId::Latest, | ||||
| 			BlockNumber::Pending => { | ||||
| 				warn!("`Pending` is deprecated and may be removed in future versions. Falling back to `Latest`"); | ||||
| 				BlockId::Latest | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<T> Clone for EthClient<T> { | ||||
| 	fn clone(&self) -> Self { | ||||
| 		// each instance should have its own poll manager.
 | ||||
| @ -264,7 +281,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> { | ||||
| 	} | ||||
| 
 | ||||
| 	fn balance(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256> { | ||||
| 		Box::new(self.fetcher().account(address.into(), num.unwrap_or_default().into()) | ||||
| 		Box::new(self.fetcher().account(address.into(), Self::num_to_id(num.unwrap_or_default())) | ||||
| 			.map(|acc| acc.map_or(0.into(), |a| a.balance).into())) | ||||
| 	} | ||||
| 
 | ||||
| @ -277,11 +294,11 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> { | ||||
| 	} | ||||
| 
 | ||||
| 	fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture<Option<RichBlock>> { | ||||
| 		Box::new(self.rich_block(num.into(), include_txs).map(Some)) | ||||
| 		Box::new(self.rich_block(Self::num_to_id(num), include_txs).map(Some)) | ||||
| 	} | ||||
| 
 | ||||
| 	fn transaction_count(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256> { | ||||
| 		Box::new(self.fetcher().account(address.into(), num.unwrap_or_default().into()) | ||||
| 		Box::new(self.fetcher().account(address.into(), Self::num_to_id(num.unwrap_or_default())) | ||||
| 			.map(|acc| acc.map_or(0.into(), |a| a.nonce).into())) | ||||
| 	} | ||||
| 
 | ||||
| @ -304,7 +321,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> { | ||||
| 	fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> { | ||||
| 		let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone()); | ||||
| 
 | ||||
| 		Box::new(self.fetcher().header(num.into()).and_then(move |hdr| { | ||||
| 		Box::new(self.fetcher().header(Self::num_to_id(num)).and_then(move |hdr| { | ||||
| 			if hdr.transactions_root() == KECCAK_NULL_RLP { | ||||
| 				Either::A(future::ok(Some(U256::from(0).into()))) | ||||
| 			} else { | ||||
| @ -336,7 +353,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> { | ||||
| 	fn block_uncles_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> { | ||||
| 		let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone()); | ||||
| 
 | ||||
| 		Box::new(self.fetcher().header(num.into()).and_then(move |hdr| { | ||||
| 		Box::new(self.fetcher().header(Self::num_to_id(num)).and_then(move |hdr| { | ||||
| 			if hdr.uncles_hash() == KECCAK_EMPTY_LIST_RLP { | ||||
| 				Either::B(future::ok(Some(U256::from(0).into()))) | ||||
| 			} else { | ||||
| @ -350,7 +367,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> { | ||||
| 	} | ||||
| 
 | ||||
| 	fn code_at(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<Bytes> { | ||||
| 		Box::new(self.fetcher().code(address.into(), num.unwrap_or_default().into()).map(Into::into)) | ||||
| 		Box::new(self.fetcher().code(address.into(), Self::num_to_id(num.unwrap_or_default())).map(Into::into)) | ||||
| 	} | ||||
| 
 | ||||
| 	fn send_raw_transaction(&self, raw: Bytes) -> Result<RpcH256> { | ||||
| @ -422,7 +439,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> { | ||||
| 
 | ||||
| 	fn transaction_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> BoxFuture<Option<Transaction>> { | ||||
| 		let eip86 = self.client.eip86_transition(); | ||||
| 		Box::new(self.fetcher().block(num.into()).map(move |block| { | ||||
| 		Box::new(self.fetcher().block(Self::num_to_id(num)).map(move |block| { | ||||
| 			light_fetch::extract_transaction_at_index(block, idx.value(), eip86) | ||||
| 		})) | ||||
| 	} | ||||
| @ -467,7 +484,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> { | ||||
| 
 | ||||
| 	fn uncle_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> BoxFuture<Option<RichBlock>> { | ||||
| 		let client = self.client.clone(); | ||||
| 		Box::new(self.fetcher().block(num.into()).map(move |block| { | ||||
| 		Box::new(self.fetcher().block(Self::num_to_id(num)).map(move |block| { | ||||
| 			extract_uncle_at_index(block, idx, client) | ||||
| 		})) | ||||
| 	} | ||||
|  | ||||
| @ -27,6 +27,7 @@ use ethsync::LightSyncProvider; | ||||
| use ethcore::account_provider::AccountProvider; | ||||
| use ethcore_logger::RotatingLogger; | ||||
| use node_health::{NodeHealth, Health}; | ||||
| use ethcore::ids::BlockId; | ||||
| 
 | ||||
| use light::client::LightChainClient; | ||||
| 
 | ||||
| @ -405,7 +406,16 @@ impl Parity for ParityClient { | ||||
| 			} | ||||
| 		}; | ||||
| 
 | ||||
| 		Box::new(self.fetcher().header(number.unwrap_or_default().into()).map(from_encoded)) | ||||
| 		// Note: Here we treat `Pending` as `Latest`.
 | ||||
| 		//       Since light clients don't produce pending blocks
 | ||||
| 		//       (they don't have state) we can safely fallback to `Latest`.
 | ||||
| 		let id = match number.unwrap_or_default() { | ||||
| 			BlockNumber::Num(n) => BlockId::Number(n), | ||||
| 			BlockNumber::Earliest => BlockId::Earliest, | ||||
| 			BlockNumber::Latest | BlockNumber::Pending => BlockId::Latest, | ||||
| 		}; | ||||
| 
 | ||||
| 		Box::new(self.fetcher().header(id).map(from_encoded)) | ||||
| 	} | ||||
| 
 | ||||
| 	fn ipfs_cid(&self, content: Bytes) -> Result<String> { | ||||
|  | ||||
| @ -27,10 +27,11 @@ use ethkey::{Brain, Generator}; | ||||
| use ethstore::random_phrase; | ||||
| use ethsync::{SyncProvider, ManageNetwork}; | ||||
| use ethcore::account_provider::AccountProvider; | ||||
| use ethcore::client::{MiningBlockChainClient}; | ||||
| use ethcore::client::{MiningBlockChainClient, StateClient, Call}; | ||||
| use ethcore::ids::BlockId; | ||||
| use ethcore::miner::MinerService; | ||||
| use ethcore::mode::Mode; | ||||
| use ethcore::state::StateInfo; | ||||
| use ethcore_logger::RotatingLogger; | ||||
| use node_health::{NodeHealth, Health}; | ||||
| use updater::{Service as UpdateService}; | ||||
| @ -48,7 +49,8 @@ use v1::types::{ | ||||
| 	TransactionStats, LocalTransactionStatus, | ||||
| 	BlockNumber, ConsensusCapability, VersionInfo, | ||||
| 	OperationsInfo, DappId, ChainStatus, | ||||
| 	AccountInfo, HwAccountInfo, RichHeader | ||||
| 	AccountInfo, HwAccountInfo, RichHeader, | ||||
| 	block_number_to_id | ||||
| }; | ||||
| use Host; | ||||
| 
 | ||||
| @ -112,9 +114,10 @@ impl<C, M, U> ParityClient<C, M, U> where | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<C, M, U> Parity for ParityClient<C, M, U> where | ||||
| 	C: MiningBlockChainClient + 'static, | ||||
| 	M: MinerService + 'static, | ||||
| impl<C, M, U, S> Parity for ParityClient<C, M, U> where | ||||
| 	S: StateInfo + 'static, | ||||
| 	C: MiningBlockChainClient + StateClient<State=S> + Call<State=S> + 'static, | ||||
| 	M: MinerService<State=S> + 'static, | ||||
| 	U: UpdateService + 'static, | ||||
| { | ||||
| 	type Metadata = Metadata; | ||||
| @ -275,14 +278,32 @@ impl<C, M, U> Parity for ParityClient<C, M, U> where | ||||
| 	} | ||||
| 
 | ||||
| 	fn list_accounts(&self, count: u64, after: Option<H160>, block_number: Trailing<BlockNumber>) -> Result<Option<Vec<H160>>> { | ||||
| 		let number = match block_number.unwrap_or_default() { | ||||
| 			BlockNumber::Pending => { | ||||
| 				warn!("BlockNumber::Pending is unsupported"); | ||||
| 				return Ok(None); | ||||
| 			}, | ||||
| 
 | ||||
| 			num => block_number_to_id(num) | ||||
| 		}; | ||||
| 
 | ||||
| 		Ok(self.client | ||||
| 			.list_accounts(block_number.unwrap_or_default().into(), after.map(Into::into).as_ref(), count) | ||||
| 			.list_accounts(number, after.map(Into::into).as_ref(), count) | ||||
| 			.map(|a| a.into_iter().map(Into::into).collect())) | ||||
| 	} | ||||
| 
 | ||||
| 	fn list_storage_keys(&self, address: H160, count: u64, after: Option<H256>, block_number: Trailing<BlockNumber>) -> Result<Option<Vec<H256>>> { | ||||
| 		let number = match block_number.unwrap_or_default() { | ||||
| 			BlockNumber::Pending => { | ||||
| 				warn!("BlockNumber::Pending is unsupported"); | ||||
| 				return Ok(None); | ||||
| 			}, | ||||
| 
 | ||||
| 			num => block_number_to_id(num) | ||||
| 		}; | ||||
| 
 | ||||
| 		Ok(self.client | ||||
| 			.list_storage(block_number.unwrap_or_default().into(), &address.into(), after.map(Into::into).as_ref(), count) | ||||
| 			.list_storage(number, &address.into(), after.map(Into::into).as_ref(), count) | ||||
| 			.map(|a| a.into_iter().map(Into::into).collect())) | ||||
| 	} | ||||
| 
 | ||||
| @ -396,17 +417,31 @@ impl<C, M, U> Parity for ParityClient<C, M, U> where | ||||
| 	} | ||||
| 
 | ||||
| 	fn block_header(&self, number: Trailing<BlockNumber>) -> BoxFuture<RichHeader> { | ||||
| 		const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched earlier), extra_info is always available if object exists; qed"; | ||||
| 		const EXTRA_INFO_PROOF: &str = "Object exists in blockchain (fetched earlier), extra_info is always available if object exists; qed"; | ||||
| 		let number = number.unwrap_or_default(); | ||||
| 
 | ||||
| 		let id: BlockId = number.unwrap_or_default().into(); | ||||
| 		let encoded = match self.client.block_header(id.clone()) { | ||||
| 			Some(encoded) => encoded, | ||||
| 			None => return Box::new(future::err(errors::unknown_block())), | ||||
| 		let (header, extra) = if number == BlockNumber::Pending { | ||||
| 			let info = self.client.chain_info(); | ||||
| 			let header = try_bf!(self.miner.pending_block_header(info.best_block_number).ok_or(errors::unknown_block())); | ||||
| 
 | ||||
| 			(header.encoded(), None) | ||||
| 		} else { | ||||
| 			let id = match number { | ||||
| 				BlockNumber::Num(num) => BlockId::Number(num), | ||||
| 				BlockNumber::Earliest => BlockId::Earliest, | ||||
| 				BlockNumber::Latest => BlockId::Latest, | ||||
| 				BlockNumber::Pending => unreachable!(), // Already covered
 | ||||
| 			}; | ||||
| 
 | ||||
| 			let header = try_bf!(self.client.block_header(id.clone()).ok_or(errors::unknown_block())); | ||||
| 			let info = self.client.block_extra_info(id).expect(EXTRA_INFO_PROOF); | ||||
| 
 | ||||
| 			(header, Some(info)) | ||||
| 		}; | ||||
| 
 | ||||
| 		Box::new(future::ok(RichHeader { | ||||
| 			inner: encoded.into(), | ||||
| 			extra_info: self.client.block_extra_info(id).expect(EXTRA_INFO_PROOF), | ||||
| 			inner: header.into(), | ||||
| 			extra_info: extra.unwrap_or_default(), | ||||
| 		})) | ||||
| 	} | ||||
| 
 | ||||
| @ -414,7 +449,7 @@ impl<C, M, U> Parity for ParityClient<C, M, U> where | ||||
| 		ipfs::cid(content) | ||||
| 	} | ||||
| 
 | ||||
| 	fn call(&self, meta: Self::Metadata, requests: Vec<CallRequest>, block: Trailing<BlockNumber>) -> Result<Vec<Bytes>> { | ||||
| 	fn call(&self, meta: Self::Metadata, requests: Vec<CallRequest>, num: Trailing<BlockNumber>) -> Result<Vec<Bytes>> { | ||||
| 		let requests = requests | ||||
| 			.into_iter() | ||||
| 			.map(|request| Ok(( | ||||
| @ -423,9 +458,29 @@ impl<C, M, U> Parity for ParityClient<C, M, U> where | ||||
| 			))) | ||||
| 			.collect::<Result<Vec<_>>>()?; | ||||
| 
 | ||||
| 		let block = block.unwrap_or_default(); | ||||
| 		let num = num.unwrap_or_default(); | ||||
| 
 | ||||
| 		self.client.call_many(&requests, block.into()) | ||||
| 		let (mut state, header) = if num == BlockNumber::Pending { | ||||
| 			let info = self.client.chain_info(); | ||||
| 			let state = self.miner.pending_state(info.best_block_number).ok_or(errors::state_pruned())?; | ||||
| 			let header = self.miner.pending_block_header(info.best_block_number).ok_or(errors::state_pruned())?; | ||||
| 
 | ||||
| 			(state, header) | ||||
| 		} else { | ||||
| 			let id = match num { | ||||
| 				BlockNumber::Num(num) => BlockId::Number(num), | ||||
| 				BlockNumber::Earliest => BlockId::Earliest, | ||||
| 				BlockNumber::Latest => BlockId::Latest, | ||||
| 				BlockNumber::Pending => unreachable!(), // Already covered
 | ||||
| 			}; | ||||
| 
 | ||||
| 			let state = self.client.state_at(id).ok_or(errors::state_pruned())?; | ||||
| 			let header = self.client.block_header(id).ok_or(errors::state_pruned())?; | ||||
| 
 | ||||
| 			(state, header.decode()) | ||||
| 		}; | ||||
| 
 | ||||
| 		self.client.call_many(&requests, &mut state, &header) | ||||
| 				.map(|res| res.into_iter().map(|res| res.output.into()).collect()) | ||||
| 				.map_err(errors::call) | ||||
| 	} | ||||
|  | ||||
| @ -18,7 +18,7 @@ | ||||
| 
 | ||||
| use std::sync::Arc; | ||||
| 
 | ||||
| use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId}; | ||||
| use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId, StateClient, StateInfo, Call, BlockId}; | ||||
| use rlp::UntrustedRlp; | ||||
| use transaction::SignedTransaction; | ||||
| 
 | ||||
| @ -27,7 +27,7 @@ use jsonrpc_macros::Trailing; | ||||
| use v1::Metadata; | ||||
| use v1::traits::Traces; | ||||
| use v1::helpers::{errors, fake_sign}; | ||||
| use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256}; | ||||
| use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256, block_number_to_id}; | ||||
| 
 | ||||
| fn to_call_analytics(flags: TraceOptions) -> CallAnalytics { | ||||
| 	CallAnalytics { | ||||
| @ -51,7 +51,10 @@ impl<C> TracesClient<C> { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<C> Traces for TracesClient<C> where C: MiningBlockChainClient + 'static { | ||||
| impl<C, S> Traces for TracesClient<C> where | ||||
| 	S: StateInfo + 'static, | ||||
| 	C: MiningBlockChainClient + StateClient<State=S> + Call<State=S> + 'static | ||||
| { | ||||
| 	type Metadata = Metadata; | ||||
| 
 | ||||
| 	fn filter(&self, filter: TraceFilter) -> Result<Option<Vec<LocalizedTrace>>> { | ||||
| @ -60,7 +63,12 @@ impl<C> Traces for TracesClient<C> where C: MiningBlockChainClient + 'static { | ||||
| 	} | ||||
| 
 | ||||
| 	fn block_traces(&self, block_number: BlockNumber) -> Result<Option<Vec<LocalizedTrace>>> { | ||||
| 		Ok(self.client.block_traces(block_number.into()) | ||||
| 		let id = match block_number { | ||||
| 			BlockNumber::Pending => return Ok(None), | ||||
| 			num => block_number_to_id(num) | ||||
| 		}; | ||||
| 
 | ||||
| 		Ok(self.client.block_traces(id) | ||||
| 			.map(|traces| traces.into_iter().map(LocalizedTrace::from).collect())) | ||||
| 	} | ||||
| 
 | ||||
| @ -85,7 +93,18 @@ impl<C> Traces for TracesClient<C> where C: MiningBlockChainClient + 'static { | ||||
| 		let request = CallRequest::into(request); | ||||
| 		let signed = fake_sign::sign_call(request, meta.is_dapp())?; | ||||
| 
 | ||||
| 		self.client.call(&signed, to_call_analytics(flags), block.into()) | ||||
| 		let id = match block { | ||||
| 			BlockNumber::Num(num) => BlockId::Number(num), | ||||
| 			BlockNumber::Earliest => BlockId::Earliest, | ||||
| 			BlockNumber::Latest => BlockId::Latest, | ||||
| 
 | ||||
| 			BlockNumber::Pending => return Err(errors::invalid_params("`BlockNumber::Pending` is not supported", ())), | ||||
| 		}; | ||||
| 
 | ||||
| 		let mut state = self.client.state_at(id).ok_or(errors::state_pruned())?; | ||||
| 		let header = self.client.block_header(id).ok_or(errors::state_pruned())?; | ||||
| 
 | ||||
| 		self.client.call(&signed, to_call_analytics(flags), &mut state, &header.decode()) | ||||
| 			.map(TraceResults::from) | ||||
| 			.map_err(errors::call) | ||||
| 	} | ||||
| @ -101,7 +120,18 @@ impl<C> Traces for TracesClient<C> where C: MiningBlockChainClient + 'static { | ||||
| 			}) | ||||
| 			.collect::<Result<Vec<_>>>()?; | ||||
| 
 | ||||
| 		self.client.call_many(&requests, block.into()) | ||||
| 		let id = match block { | ||||
| 			BlockNumber::Num(num) => BlockId::Number(num), | ||||
| 			BlockNumber::Earliest => BlockId::Earliest, | ||||
| 			BlockNumber::Latest => BlockId::Latest, | ||||
| 
 | ||||
| 			BlockNumber::Pending => return Err(errors::invalid_params("`BlockNumber::Pending` is not supported", ())), | ||||
| 		}; | ||||
| 
 | ||||
| 		let mut state = self.client.state_at(id).ok_or(errors::state_pruned())?; | ||||
| 		let header = self.client.block_header(id).ok_or(errors::state_pruned())?; | ||||
| 
 | ||||
| 		self.client.call_many(&requests, &mut state, &header.decode()) | ||||
| 			.map(|results| results.into_iter().map(TraceResults::from).collect()) | ||||
| 			.map_err(errors::call) | ||||
| 	} | ||||
| @ -112,7 +142,18 @@ impl<C> Traces for TracesClient<C> where C: MiningBlockChainClient + 'static { | ||||
| 		let tx = UntrustedRlp::new(&raw_transaction.into_vec()).as_val().map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?; | ||||
| 		let signed = SignedTransaction::new(tx).map_err(errors::transaction)?; | ||||
| 
 | ||||
| 		self.client.call(&signed, to_call_analytics(flags), block.into()) | ||||
| 		let id = match block { | ||||
| 			BlockNumber::Num(num) => BlockId::Number(num), | ||||
| 			BlockNumber::Earliest => BlockId::Earliest, | ||||
| 			BlockNumber::Latest => BlockId::Latest, | ||||
| 
 | ||||
| 			BlockNumber::Pending => return Err(errors::invalid_params("`BlockNumber::Pending` is not supported", ())), | ||||
| 		}; | ||||
| 
 | ||||
| 		let mut state = self.client.state_at(id).ok_or(errors::state_pruned())?; | ||||
| 		let header = self.client.block_header(id).ok_or(errors::state_pruned())?; | ||||
| 
 | ||||
| 		self.client.call(&signed, to_call_analytics(flags), &mut state, &header.decode()) | ||||
| 			.map(TraceResults::from) | ||||
| 			.map_err(errors::call) | ||||
| 	} | ||||
| @ -124,7 +165,15 @@ impl<C> Traces for TracesClient<C> where C: MiningBlockChainClient + 'static { | ||||
| 	} | ||||
| 
 | ||||
| 	fn replay_block_transactions(&self, block_number: BlockNumber, flags: TraceOptions) -> Result<Vec<TraceResults>> { | ||||
| 		self.client.replay_block_transactions(block_number.into(), to_call_analytics(flags)) | ||||
| 		let id = match block_number { | ||||
| 			BlockNumber::Num(num) => BlockId::Number(num), | ||||
| 			BlockNumber::Earliest => BlockId::Earliest, | ||||
| 			BlockNumber::Latest => BlockId::Latest, | ||||
| 
 | ||||
| 			BlockNumber::Pending => return Err(errors::invalid_params("`BlockNumber::Pending` is not supported", ())), | ||||
| 		}; | ||||
| 
 | ||||
| 		self.client.replay_block_transactions(id, to_call_analytics(flags)) | ||||
| 			.map(|results| results.into_iter().map(TraceResults::from).collect()) | ||||
| 			.map_err(errors::call) | ||||
| 	} | ||||
|  | ||||
| @ -22,10 +22,10 @@ use std::time::Duration; | ||||
| use ethereum_types::{U256, H256, Address}; | ||||
| use ethcore::account_provider::AccountProvider; | ||||
| use ethcore::block::Block; | ||||
| use ethcore::client::{BlockChainClient, Client, ClientConfig}; | ||||
| use ethcore::client::{BlockChainClient, Client, ClientConfig, ChainInfo, ImportBlock}; | ||||
| use ethcore::ethereum; | ||||
| use ethcore::ids::BlockId; | ||||
| use ethcore::miner::{MinerOptions, Banning, GasPricer, MinerService, Miner, PendingSet, GasLimit}; | ||||
| use ethcore::miner::{MinerOptions, Banning, GasPricer, Miner, PendingSet, GasLimit}; | ||||
| use ethcore::spec::{Genesis, Spec}; | ||||
| use ethcore::views::BlockView; | ||||
| use ethjson::blockchain::BlockChain; | ||||
| @ -101,7 +101,7 @@ fn make_spec(chain: &BlockChain) -> Spec { | ||||
| 
 | ||||
| struct EthTester { | ||||
| 	client: Arc<Client>, | ||||
| 	_miner: Arc<MinerService>, | ||||
| 	_miner: Arc<Miner>, | ||||
| 	_snapshot: Arc<TestSnapshotService>, | ||||
| 	accounts: Arc<AccountProvider>, | ||||
| 	handler: IoHandler<Metadata>, | ||||
|  | ||||
| @ -18,16 +18,19 @@ | ||||
| 
 | ||||
| use std::collections::{BTreeMap, HashMap}; | ||||
| use std::collections::hash_map::Entry; | ||||
| use ethereum_types::{H256, U256, Address}; | ||||
| 
 | ||||
| use bytes::Bytes; | ||||
| use ethcore::account_provider::SignError as AccountError; | ||||
| use ethcore::block::ClosedBlock; | ||||
| use ethcore::client::MiningBlockChainClient; | ||||
| use ethcore::block::{Block, ClosedBlock}; | ||||
| use ethcore::client::{Nonce, PrepareOpenBlock, StateClient, EngineInfo}; | ||||
| use ethcore::engines::EthEngine; | ||||
| use ethcore::error::Error; | ||||
| use ethcore::header::BlockNumber; | ||||
| use ethcore::header::{BlockNumber, Header}; | ||||
| use ethcore::ids::BlockId; | ||||
| use ethcore::miner::{MinerService, MinerStatus}; | ||||
| use miner::local_transactions::Status as LocalTransactionStatus; | ||||
| use ethcore::receipt::{Receipt, RichReceipt}; | ||||
| use ethereum_types::{H256, U256, Address}; | ||||
| use miner::local_transactions::Status as LocalTransactionStatus; | ||||
| use parking_lot::{RwLock, Mutex}; | ||||
| use transaction::{UnverifiedTransaction, SignedTransaction, PendingTransaction, ImportResult as TransactionImportResult}; | ||||
| 
 | ||||
| @ -92,7 +95,39 @@ impl TestMinerService { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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<Self::State> { | ||||
| 		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<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 | ||||
| 	} | ||||
| 
 | ||||
| 	/// Returns miner's status.
 | ||||
| 	fn status(&self) -> MinerStatus { | ||||
| @ -164,7 +199,7 @@ impl MinerService for TestMinerService { | ||||
| 	} | ||||
| 
 | ||||
| 	/// Imports transactions to transaction queue.
 | ||||
| 	fn import_external_transactions(&self, _chain: &MiningBlockChainClient, transactions: Vec<UnverifiedTransaction>) -> | ||||
| 	fn import_external_transactions<C>(&self, _chain: &C, transactions: Vec<UnverifiedTransaction>) -> | ||||
| 		Vec<Result<TransactionImportResult, Error>> { | ||||
| 		// lets assume that all txs are valid
 | ||||
| 		let transactions: Vec<_> = transactions.into_iter().map(|tx| SignedTransaction::new(tx).unwrap()).collect(); | ||||
| @ -181,7 +216,7 @@ impl MinerService for TestMinerService { | ||||
| 	} | ||||
| 
 | ||||
| 	/// Imports transactions to transaction queue.
 | ||||
| 	fn import_own_transaction(&self, chain: &MiningBlockChainClient, pending: PendingTransaction) -> | ||||
| 	fn import_own_transaction<C: Nonce>(&self, chain: &C, pending: PendingTransaction) -> | ||||
| 		Result<TransactionImportResult, Error> { | ||||
| 
 | ||||
| 		// keep the pending nonces up to date
 | ||||
| @ -201,12 +236,12 @@ impl MinerService for TestMinerService { | ||||
| 	} | ||||
| 
 | ||||
| 	/// Removes all transactions from the queue and restart mining operation.
 | ||||
| 	fn clear_and_reset(&self, _chain: &MiningBlockChainClient) { | ||||
| 	fn clear_and_reset<C>(&self, _chain: &C) { | ||||
| 		unimplemented!(); | ||||
| 	} | ||||
| 
 | ||||
| 	/// Called when blocks are imported to chain, updates transactions queue.
 | ||||
| 	fn chain_new_blocks(&self, _chain: &MiningBlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { | ||||
| 	fn chain_new_blocks<C>(&self, _chain: &C, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { | ||||
| 		unimplemented!(); | ||||
| 	} | ||||
| 
 | ||||
| @ -216,11 +251,11 @@ impl MinerService for TestMinerService { | ||||
| 	} | ||||
| 
 | ||||
| 	/// New chain head event. Restart mining operation.
 | ||||
| 	fn update_sealing(&self, _chain: &MiningBlockChainClient) { | ||||
| 	fn update_sealing<C>(&self, _chain: &C) { | ||||
| 		unimplemented!(); | ||||
| 	} | ||||
| 
 | ||||
| 	fn map_sealing_work<F, T>(&self, chain: &MiningBlockChainClient, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T { | ||||
| 	fn map_sealing_work<C: PrepareOpenBlock, F, T>(&self, chain: &C, 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())) | ||||
| 	} | ||||
| @ -229,7 +264,7 @@ impl MinerService for TestMinerService { | ||||
| 		self.pending_transactions.lock().get(hash).cloned().map(Into::into) | ||||
| 	} | ||||
| 
 | ||||
| 	fn remove_pending_transaction(&self, _chain: &MiningBlockChainClient, hash: &H256) -> Option<PendingTransaction> { | ||||
| 	fn remove_pending_transaction<C>(&self, _chain: &C, hash: &H256) -> Option<PendingTransaction> { | ||||
| 		self.pending_transactions.lock().remove(hash).map(Into::into) | ||||
| 	} | ||||
| 
 | ||||
| @ -279,7 +314,7 @@ impl MinerService for TestMinerService { | ||||
| 
 | ||||
| 	/// 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, _chain: &MiningBlockChainClient, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> { | ||||
| 	fn submit_seal<C>(&self, _chain: &C, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> { | ||||
| 		unimplemented!(); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -82,7 +82,7 @@ fn should_subscribe_to_new_heads() { | ||||
| fn should_subscribe_to_logs() { | ||||
| 	use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; | ||||
| 	use ethcore::ids::BlockId; | ||||
| 	use ethcore::client::BlockChainClient; | ||||
| 	use ethcore::client::BlockInfo; | ||||
| 
 | ||||
| 	// given
 | ||||
| 	let el = EventLoop::spawn(); | ||||
|  | ||||
| @ -91,14 +91,14 @@ impl<'a> Visitor<'a> for BlockNumberVisitor { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl Into<BlockId> for BlockNumber { | ||||
| 	fn into(self) -> BlockId { | ||||
| 		match self { | ||||
| 			BlockNumber::Num(n) => BlockId::Number(n), | ||||
| 			BlockNumber::Earliest => BlockId::Earliest, | ||||
| 			BlockNumber::Latest => BlockId::Latest, | ||||
| 			BlockNumber::Pending => BlockId::Pending, | ||||
| 		} | ||||
| /// Converts `BlockNumber` to `BlockId`, panics on `BlockNumber::Pending`
 | ||||
| pub fn block_number_to_id(number: BlockNumber) -> BlockId { | ||||
| 	match number { | ||||
| 		BlockNumber::Num(num) => BlockId::Number(num), | ||||
| 		BlockNumber::Earliest => BlockId::Earliest, | ||||
| 		BlockNumber::Latest => BlockId::Latest, | ||||
| 
 | ||||
| 		BlockNumber::Pending => panic!("`BlockNumber::Pending` should be handled manually") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -122,11 +122,17 @@ mod tests { | ||||
| 	} | ||||
| 
 | ||||
| 	#[test] | ||||
| 	fn block_number_into() { | ||||
| 		assert_eq!(BlockId::Number(100), BlockNumber::Num(100).into()); | ||||
| 		assert_eq!(BlockId::Earliest, BlockNumber::Earliest.into()); | ||||
| 		assert_eq!(BlockId::Latest, BlockNumber::Latest.into()); | ||||
| 		assert_eq!(BlockId::Pending, BlockNumber::Pending.into()); | ||||
| 	fn normal_block_number_to_id() { | ||||
| 		assert_eq!(block_number_to_id(BlockNumber::Num(100)), BlockId::Number(100)); | ||||
| 		assert_eq!(block_number_to_id(BlockNumber::Earliest), BlockId::Earliest); | ||||
| 		assert_eq!(block_number_to_id(BlockNumber::Latest), BlockId::Latest); | ||||
| 	} | ||||
| 
 | ||||
| 	#[test] | ||||
| 	#[should_panic] | ||||
| 	fn pending_block_number_to_id() { | ||||
| 		// Since this function is not allowed to be called in such way, panic should happen
 | ||||
| 		block_number_to_id(BlockNumber::Pending); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -72,9 +72,15 @@ pub struct Filter { | ||||
| 
 | ||||
| impl Into<EthFilter> for Filter { | ||||
| 	fn into(self) -> EthFilter { | ||||
| 		let num_to_id = |num| match num { | ||||
| 			BlockNumber::Num(n) => BlockId::Number(n), | ||||
| 			BlockNumber::Earliest => BlockId::Earliest, | ||||
| 			BlockNumber::Latest | BlockNumber::Pending => BlockId::Latest, | ||||
| 		}; | ||||
| 
 | ||||
| 		EthFilter { | ||||
| 			from_block: self.from_block.map_or_else(|| BlockId::Latest, Into::into), | ||||
| 			to_block: self.to_block.map_or_else(|| BlockId::Latest, Into::into), | ||||
| 			from_block: self.from_block.map_or_else(|| BlockId::Latest, &num_to_id), | ||||
| 			to_block: self.to_block.map_or_else(|| BlockId::Latest, &num_to_id), | ||||
| 			address: self.address.and_then(|address| match address { | ||||
| 				VariadicValue::Null => None, | ||||
| 				VariadicValue::Single(a) => Some(vec![a.into()]), | ||||
|  | ||||
| @ -50,7 +50,7 @@ pub mod pubsub; | ||||
| pub use self::account_info::{AccountInfo, ExtAccountInfo, HwAccountInfo}; | ||||
| pub use self::bytes::Bytes; | ||||
| pub use self::block::{RichBlock, Block, BlockTransactions, Header, RichHeader, Rich}; | ||||
| pub use self::block_number::BlockNumber; | ||||
| pub use self::block_number::{BlockNumber, block_number_to_id}; | ||||
| pub use self::call_request::CallRequest; | ||||
| pub use self::confirmations::{ | ||||
| 	ConfirmationPayload, ConfirmationRequest, ConfirmationResponse, ConfirmationResponseWithToken, | ||||
|  | ||||
| @ -44,8 +44,17 @@ pub struct TraceFilter { | ||||
| 
 | ||||
| impl Into<client::TraceFilter> for TraceFilter { | ||||
| 	fn into(self) -> client::TraceFilter { | ||||
| 		let start = self.from_block.map_or(BlockId::Latest, Into::into); | ||||
| 		let end = self.to_block.map_or(BlockId::Latest, Into::into); | ||||
| 		let num_to_id = |num| match num { | ||||
| 			BlockNumber::Num(n) => BlockId::Number(n), | ||||
| 			BlockNumber::Earliest => BlockId::Earliest, | ||||
| 			BlockNumber::Latest => BlockId::Latest, | ||||
| 			BlockNumber::Pending => { | ||||
| 				warn!("Pending traces are not supported and might be removed in future versions. Falling back to Latest"); | ||||
| 				BlockId::Latest | ||||
| 			} | ||||
| 		}; | ||||
| 		let start = self.from_block.map_or(BlockId::Latest, &num_to_id); | ||||
| 		let end = self.to_block.map_or(BlockId::Latest, &num_to_id); | ||||
| 		client::TraceFilter { | ||||
| 			range: start..end, | ||||
| 			from_address: self.from_address.map_or_else(Vec::new, |x| x.into_iter().map(Into::into).collect()), | ||||
|  | ||||
| @ -18,7 +18,7 @@ use std::sync::Arc; | ||||
| use std::collections::{HashMap, HashSet}; | ||||
| use parking_lot::{Mutex, RwLock}; | ||||
| use ethkey::public_to_address; | ||||
| use ethcore::client::{BlockChainClient, BlockId, ChainNotify}; | ||||
| use ethcore::client::{BlockId, ChainNotify, CallContract, RegistryInfo}; | ||||
| use ethereum_types::{H256, Address}; | ||||
| use bytes::Bytes; | ||||
| use trusted_client::TrustedClient; | ||||
|  | ||||
| @ -18,8 +18,8 @@ use std::sync::Arc; | ||||
| use std::net::SocketAddr; | ||||
| use std::collections::{BTreeMap, HashSet}; | ||||
| use parking_lot::Mutex; | ||||
| use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify, CallContract, RegistryInfo}; | ||||
| use ethcore::filter::Filter; | ||||
| use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify}; | ||||
| use ethkey::public_to_address; | ||||
| use hash::keccak; | ||||
| use ethereum_types::{H256, Address}; | ||||
| @ -281,7 +281,7 @@ impl CachedContract { | ||||
| 
 | ||||
| 	fn start_migration(&mut self, migration_id: H256) { | ||||
| 		// trust is not needed here, because it is the reaction to the read of the trusted client
 | ||||
| 		if let (Some(client), Some(contract_address)) = (self.client.get_untrusted(), self.contract_address) { | ||||
| 		if let (Some(client), Some(contract_address)) = (self.client.get_untrusted(), self.contract_address.as_ref()) { | ||||
| 			// check if we need to send start migration transaction
 | ||||
| 			if !update_last_transaction_block(&*client, &migration_id, &mut self.start_migration_tx) { | ||||
| 				return; | ||||
| @ -291,7 +291,7 @@ impl CachedContract { | ||||
| 			let transaction_data = self.contract.functions().start_migration().input(migration_id); | ||||
| 
 | ||||
| 			// send transaction
 | ||||
| 			if let Err(error) = client.transact_contract(contract_address, transaction_data) { | ||||
| 			if let Err(error) = client.transact_contract(*contract_address, transaction_data) { | ||||
| 				warn!(target: "secretstore_net", "{}: failed to submit auto-migration start transaction: {}", | ||||
| 					self.self_key_pair.public(), error); | ||||
| 			} else { | ||||
|  | ||||
| @ -17,7 +17,7 @@ | ||||
| use std::sync::Arc; | ||||
| use parking_lot::RwLock; | ||||
| use ethcore::filter::Filter; | ||||
| use ethcore::client::{Client, BlockChainClient, BlockId}; | ||||
| use ethcore::client::{Client, BlockChainClient, BlockId, RegistryInfo, CallContract}; | ||||
| use ethkey::{Public, Signature, public_to_address}; | ||||
| use hash::keccak; | ||||
| use ethereum_types::{H256, U256, Address}; | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| use std::sync::{Arc, Weak}; | ||||
| use ethcore::client::{Client, BlockChainClient}; | ||||
| use ethcore::client::{Client, BlockChainClient, ChainInfo}; | ||||
| use ethsync::SyncProvider; | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
|  | ||||
| @ -2232,7 +2232,7 @@ mod tests { | ||||
| 	use ::SyncConfig; | ||||
| 	use super::{PeerInfo, PeerAsking}; | ||||
| 	use ethcore::header::*; | ||||
| 	use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient}; | ||||
| 	use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient, ChainInfo, BlockInfo}; | ||||
| 	use ethcore::miner::MinerService; | ||||
| 	use transaction::UnverifiedTransaction; | ||||
| 
 | ||||
|  | ||||
| @ -16,7 +16,7 @@ | ||||
| 
 | ||||
| use tests::helpers::TestNet; | ||||
| 
 | ||||
| use ethcore::client::{BlockChainClient, BlockId, EachBlockWith}; | ||||
| use ethcore::client::{BlockInfo, BlockId, EachBlockWith}; | ||||
| 
 | ||||
| mod test_net; | ||||
| 
 | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| use std::sync::Arc; | ||||
| use ethcore::client::{TestBlockChainClient, BlockChainClient, BlockId, EachBlockWith}; | ||||
| use ethcore::client::{TestBlockChainClient, BlockChainClient, BlockId, EachBlockWith, ChainInfo, BlockInfo}; | ||||
| use chain::{SyncState}; | ||||
| use super::helpers::*; | ||||
| use SyncConfig; | ||||
|  | ||||
| @ -18,7 +18,7 @@ use std::sync::Arc; | ||||
| use hash::keccak; | ||||
| use ethereum_types::{U256, Address}; | ||||
| use io::{IoHandler, IoContext, IoChannel}; | ||||
| use ethcore::client::{BlockChainClient, Client}; | ||||
| use ethcore::client::{Client, ChainInfo}; | ||||
| use ethcore::service::ClientIoMessage; | ||||
| use ethcore::spec::Spec; | ||||
| use ethcore::miner::MinerService; | ||||
|  | ||||
| @ -52,7 +52,7 @@ pub mod overlaydb; | ||||
| /// Export the `JournalDB` trait.
 | ||||
| pub use self::traits::JournalDB; | ||||
| 
 | ||||
| /// A journal database algorithm.
 | ||||
| /// Journal database operating strategy.
 | ||||
| #[derive(Debug, PartialEq, Clone, Copy)] | ||||
| pub enum Algorithm { | ||||
| 	/// Keep all keys forever.
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user