client.rs 79.8 KiB
Newer Older
keorn's avatar
keorn committed
	}

	/// Get a copy of the best block's state.
	pub fn latest_state(&self) -> State<StateDB> {
		let header = self.best_block_header();
		State::from_existing(
			self.state_db.read().boxed_clone_canon(&header.hash()),
			*header.state_root(),
			self.engine.account_start_nonce(header.number()),
			self.factories.clone()
		)
		.expect("State root of best block header always valid.")
	}

	/// 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.
	pub fn state_at(&self, id: BlockId) -> Option<State<StateDB>> {
		// fast path for latest state.
			BlockId::Latest => return Some(self.latest_state()),
		let block_number = match self.block_number(id) {
asynchronous rob's avatar
asynchronous rob committed
			Some(num) => num,
			None => return None,
		};
		self.block_header(id).and_then(|header| {
Tomasz Drwięga's avatar
Tomasz Drwięga committed
			let db = self.state_db.read().boxed_clone();
			// early exit for pruned blocks
			if db.is_pruned() && self.pruning_info().earliest_state > block_number {
			let root = header.state_root();
			State::from_existing(db, root, self.engine.account_start_nonce(block_number), self.factories.clone()).ok()
	/// Attempt to get a copy of a specific block's beginning state.
	///
	/// This will not fail if given BlockId::Latest.
	/// Otherwise, this can fail (but may not) if the DB prunes state.
	pub fn state_at_beginning(&self, id: BlockId) -> Option<State<StateDB>> {
		match self.block_number(id) {
			None => None,
			Some(0) => self.state_at(id),
			Some(n) => self.state_at(BlockId::Number(n - 1)),
	/// Get a copy of the best block's state.
	pub fn state(&self) -> Box<StateInfo> {
		Box::new(self.latest_state()) as Box<_>
Gav Wood's avatar
Gav Wood committed
	/// Get info on the cache.
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	pub fn blockchain_cache_info(&self) -> BlockChainCacheSize {
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		self.chain.read().cache_size()
Gav Wood's avatar
Gav Wood committed
	}

Gav Wood's avatar
Gav Wood committed
	/// Get the report.
	pub fn report(&self) -> ClientReport {
		let mut report = self.report.read().clone();
Tomasz Drwięga's avatar
Tomasz Drwięga committed
		report.state_db_mem = self.state_db.read().mem_used();
Gav Wood's avatar
Gav Wood committed
		report
Gav Wood's avatar
Gav Wood committed
	/// Tick the client.
	// TODO: manage by real events.
	pub fn tick(&self, prevent_sleep: bool) {
Gav Wood's avatar
Gav Wood committed
		self.check_garbage();
		if !prevent_sleep {
			self.check_snooze();
		}
Gav Wood's avatar
Gav Wood committed
	}

	fn check_garbage(&self) {
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		self.chain.read().collect_garbage();
		self.importer.block_queue.collect_garbage();
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		self.tracedb.read().collect_garbage();
Gav Wood's avatar
Gav Wood committed
	}
Gav Wood's avatar
Gav Wood committed
	fn check_snooze(&self) {
Gav Wood's avatar
Gav Wood committed
		let mode = self.mode.lock().clone();
		match mode {
			Mode::Dark(timeout) => {
				let mut ss = self.sleep_state.lock();
				if let Some(t) = ss.last_activity {
					if Instant::now() > t + timeout {
						self.sleep();
						ss.last_activity = None;
					}
				}
			}
			Mode::Passive(timeout, wakeup_after) => {
				let mut ss = self.sleep_state.lock();
				let now = Instant::now();
				if let Some(t) = ss.last_activity {
					if now > t + timeout {
						self.sleep();
						ss.last_activity = None;
						ss.last_autosleep = Some(now);
					}
				}
				if let Some(t) = ss.last_autosleep {
					if now > t + wakeup_after {
						self.wake_up();
						ss.last_activity = Some(now);
						ss.last_autosleep = None;
					}
				}
			}
			_ => {}
		}
	/// Take a snapshot at the given block.
	/// If the ID given is "latest", this will default to 1000 blocks behind.
	pub fn take_snapshot<W: snapshot_io::SnapshotWriter + Send>(&self, writer: W, at: BlockId, p: &snapshot::Progress) -> Result<(), EthcoreError> {
Tomasz Drwięga's avatar
Tomasz Drwięga committed
		let db = self.state_db.read().journal_db().boxed_clone();
		let best_block_number = self.chain_info().best_block_number;
		let block_number = self.block_number(at).ok_or(snapshot::Error::InvalidStartingBlock(at))?;
		if db.is_pruned() && self.pruning_info().earliest_state > block_number {
			return Err(snapshot::Error::OldBlockPrunedDB.into());
		}

		let history = ::std::cmp::min(self.history, 1000);

			BlockId::Latest => {
				let start_num = match db.earliest_era() {
					Some(era) => ::std::cmp::max(era, best_block_number.saturating_sub(history)),
					None => best_block_number.saturating_sub(history),
				match self.block_hash(BlockId::Number(start_num)) {
					Some(h) => h,
					None => return Err(snapshot::Error::InvalidStartingBlock(at).into()),
				}
			}
			_ => match self.block_hash(at) {
				Some(hash) => hash,
				None => return Err(snapshot::Error::InvalidStartingBlock(at).into()),
			},
		snapshot::take_snapshot(&*self.engine, &self.chain.read(), start_hash, db.as_hashdb(), writer, p)?;
	/// Ask the client what the history parameter is.
	pub fn pruning_history(&self) -> u64 {
		self.history
	}

	fn block_hash(chain: &BlockChain, id: BlockId) -> Option<H256> {
			BlockId::Hash(hash) => Some(hash),
			BlockId::Number(number) => chain.block_hash(number),
			BlockId::Earliest => chain.block_hash(0),
Tomasz Drwięga's avatar
Tomasz Drwięga committed
			BlockId::Latest => Some(chain.best_block_hash()),
	fn transaction_address(&self, id: TransactionId) -> Option<TransactionAddress> {
Marek Kotewicz's avatar
Marek Kotewicz committed
		match id {
			TransactionId::Hash(ref hash) => self.chain.read().transaction_address(hash),
			TransactionId::Location(id, index) => Self::block_hash(&self.chain.read(), id).map(|hash| TransactionAddress {
Marek Kotewicz's avatar
Marek Kotewicz committed
				block_hash: hash,
				index: index,

	fn wake_up(&self) {
		if !self.liveness.load(AtomicOrdering::Relaxed) {
			self.liveness.store(true, AtomicOrdering::Relaxed);
			self.notify(|n| n.start());
			info!(target: "mode", "wake_up: Waking.");
		}
	}

	fn sleep(&self) {
		if self.liveness.load(AtomicOrdering::Relaxed) {
			// only sleep if the import queue is mostly empty.
			if self.queue_info().total_queue_size() <= MAX_QUEUE_SIZE_TO_SLEEP_ON {
				self.liveness.store(false, AtomicOrdering::Relaxed);
				self.notify(|n| n.stop());
				info!(target: "mode", "sleep: Sleeping.");
				info!(target: "mode", "sleep: Cannot sleep - syncing ongoing.");
				// TODO: Consider uncommenting.
				//(*self.sleep_state.lock()).last_activity = Some(Instant::now());

	// transaction for calling contracts from services like engine.
	// from the null sender, with 50M gas.
	fn contract_call_tx(&self, block_id: BlockId, address: Address, data: Bytes) -> SignedTransaction {
		let from = Address::default();
		Transaction {
			nonce: self.nonce(&from, block_id).unwrap_or_else(|| self.engine.account_start_nonce(0)),
			action: Action::Call(address),
			gas: U256::from(50_000_000),
			gas_price: U256::default(),
			value: U256::default(),
			data: data,
		}.fake_sign(from)
	}
	fn do_virtual_call(
		machine: &::machine::EthereumMachine,
		env_info: &EnvInfo,
		state: &mut State<StateDB>,
		t: &SignedTransaction,
		analytics: CallAnalytics,
	) -> Result<Executed, CallError> {
		fn call<V, T>(
			state: &mut State<StateDB>,
			env_info: &EnvInfo,
			machine: &::machine::EthereumMachine,
			state_diff: bool,
			transaction: &SignedTransaction,
			options: TransactOptions<T, V>,
		) -> Result<Executed<T::Output, V::Output>, CallError> where
			T: trace::Tracer,
			V: trace::VMTracer,
		{
			let options = options
				.dont_check_nonce()
				.save_output_from_contract();
			let original_state = if state_diff { Some(state.clone()) } else { None };
			let mut ret = Executive::new(state, env_info, machine).transact_virtual(transaction, options)?;
			if let Some(original) = original_state {
				ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?);
			}
			Ok(ret)
		let state_diff = analytics.state_diffing;

		match (analytics.transaction_tracing, analytics.vm_tracing) {
			(true, true) => call(state, env_info, machine, state_diff, t, TransactOptions::with_tracing_and_vm_tracing()),
			(true, false) => call(state, env_info, machine, state_diff, t, TransactOptions::with_tracing()),
			(false, true) => call(state, env_info, machine, state_diff, t, TransactOptions::with_vm_tracing()),
			(false, false) => call(state, env_info, machine, state_diff, t, TransactOptions::with_no_tracing()),
	fn block_number_ref(&self, id: &BlockId) -> Option<BlockNumber> {
		match *id {
			BlockId::Number(number) => Some(number),
			BlockId::Hash(ref hash) => self.chain.read().block_number(hash),
			BlockId::Earliest => Some(0),
			BlockId::Latest => Some(self.chain.read().best_block_number()),
		}
	}

	/// Retrieve a decoded header given `BlockId`
	///
	/// This method optimizes access patterns for latest block header
	/// to avoid excessive RLP encoding, decoding and hashing.
	fn block_header_decoded(&self, id: BlockId) -> Option<Header> {
		match id {
			BlockId::Latest
				=> Some(self.chain.read().best_block_header()),
			BlockId::Hash(ref hash) if hash == &self.chain.read().best_block_hash()
				=> Some(self.chain.read().best_block_header()),
			BlockId::Number(number) if number == self.chain.read().best_block_number()
				=> Some(self.chain.read().best_block_header()),
David's avatar
David committed
			_   => self.block_header(id).and_then(|h| h.decode().ok())
}

impl snapshot::DatabaseRestore for Client {
	/// Restart the client with a new backend
	fn restore_db(&self, new_db: &str) -> Result<(), EthcoreError> {
		trace!(target: "snapshot", "Replacing client database with {:?}", new_db);

		let _import_lock = self.importer.import_lock.lock();
		let mut state_db = self.state_db.write();
		let mut chain = self.chain.write();
		let mut tracedb = self.tracedb.write();
		self.importer.miner.clear();
		let db = self.db.write();
		db.key_value().restore(new_db)?;
		db.blooms().reopen()?;
		db.trace_blooms().reopen()?;

		let cache_size = state_db.cache_size();
		*state_db = StateDB::new(journaldb::new(db.key_value().clone(), self.pruning, ::db::COL_STATE), cache_size);
		*chain = Arc::new(BlockChain::new(self.config.blockchain.clone(), &[], db.clone()));
		*tracedb = TraceDB::new(self.config.tracing.clone(), db.clone(), chain.clone());
		Ok(())
	}
}

impl Nonce for Client {
	fn nonce(&self, address: &Address, id: BlockId) -> Option<U256> {
		self.state_at(id).and_then(|s| s.nonce(address).ok())
	}
}

impl Balance for Client {
	fn balance(&self, address: &Address, state: StateOrBlock) -> Option<U256> {
		match state {
			StateOrBlock::State(s) => s.balance(address).ok(),
			StateOrBlock::Block(id) => self.state_at(id).and_then(|s| s.balance(address).ok())
		}
	}
}

impl AccountData for Client {}

impl ChainInfo for Client {
	fn chain_info(&self) -> BlockChainInfo {
		let mut chain_info = self.chain.read().chain_info();
		chain_info.pending_total_difficulty = chain_info.total_difficulty + self.importer.block_queue.total_difficulty();
		chain_info
	}
}

impl BlockInfo for Client {
	fn block_header(&self, id: BlockId) -> Option<::encoded::Header> {
		let chain = self.chain.read();

		Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash))
	}

	fn best_block_header(&self) -> Header {
		self.chain.read().best_block_header()
	}

	fn block(&self, id: BlockId) -> Option<encoded::Block> {
		let chain = self.chain.read();

		Self::block_hash(&chain, id).and_then(|hash| chain.block(&hash))
	}

	fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256> {
		self.state_at(id).and_then(|s| s.code_hash(address).ok())
	}
}

impl TransactionInfo for Client {
	fn transaction_block(&self, id: TransactionId) -> Option<H256> {
		self.transaction_address(id).map(|addr| addr.block_hash)
	}
}

impl BlockChainTrait for Client {}

impl RegistryInfo for Client {
	fn registry_address(&self, name: String, block: BlockId) -> Option<Address> {
		let address = self.registrar_address?;

		self.registrar.functions()
			.get_address()
			.call(keccak(name.as_bytes()), "A", &|data| self.call_contract(block, address, data))
			.ok()
			.and_then(|a| if a.is_zero() {
				None
			} else {
				Some(a)
			})
	}
}

impl CallContract for Client {
	fn call_contract(&self, block_id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String> {
		let state_pruned = || CallError::StatePruned.to_string();
		let state = &mut self.state_at(block_id).ok_or_else(&state_pruned)?;
		let header = self.block_header_decoded(block_id).ok_or_else(&state_pruned)?;

		let transaction = self.contract_call_tx(block_id, address, data);

		self.call(&transaction, Default::default(), state, &header)
			.map_err(|e| format!("{:?}", e))
			.map(|executed| executed.output)
	}
}

impl ImportBlock for Client {
	fn import_block(&self, bytes: Bytes) -> Result<H256, BlockImportError> {
		use verification::queue::kind::BlockLike;
		use verification::queue::kind::blocks::Unverified;

		// create unverified block here so the `keccak` calculation can be cached.
		let unverified = Unverified::from_rlp(bytes)?;

		{
			if self.chain.read().is_known(&unverified.hash()) {
				bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain));
			}
			let status = self.block_status(BlockId::Hash(unverified.parent_hash()));
			if status == BlockStatus::Unknown || status == BlockStatus::Pending {
				bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(unverified.parent_hash())));
			}
		}
		Ok(self.importer.block_queue.import(unverified)?)
	}
impl StateClient for Client {
	type State = State<::state_db::StateDB>;
	fn latest_state(&self) -> Self::State {
		Client::latest_state(self)
	}
	fn state_at(&self, id: BlockId) -> Option<Self::State> {
		Client::state_at(self, id)
impl Call for Client {
	type State = State<::state_db::StateDB>;

	fn call(&self, transaction: &SignedTransaction, analytics: CallAnalytics, state: &mut Self::State, header: &Header) -> Result<Executed, CallError> {
		let env_info = EnvInfo {
			number: header.number(),
			author: header.author().clone(),
			timestamp: header.timestamp(),
			difficulty: header.difficulty().clone(),
			last_hashes: self.build_last_hashes(header.parent_hash()),
			gas_used: U256::default(),
			gas_limit: U256::max_value(),
		};
		let machine = self.engine.machine();
		Self::do_virtual_call(&machine, &env_info, state, transaction, analytics)
	fn call_many(&self, transactions: &[(SignedTransaction, CallAnalytics)], state: &mut Self::State, header: &Header) -> Result<Vec<Executed>, CallError> {
		let mut env_info = EnvInfo {
			number: header.number(),
			author: header.author().clone(),
			timestamp: header.timestamp(),
			difficulty: header.difficulty().clone(),
			last_hashes: self.build_last_hashes(header.parent_hash()),
			gas_used: U256::default(),
			gas_limit: U256::max_value(),
		};
Tomasz Drwięga's avatar
Tomasz Drwięga committed

		let mut results = Vec::with_capacity(transactions.len());
		let machine = self.engine.machine();
Tomasz Drwięga's avatar
Tomasz Drwięga committed

		for &(ref t, analytics) in transactions {
			let ret = Self::do_virtual_call(machine, &env_info, state, t, analytics)?;
Tomasz Drwięga's avatar
Tomasz Drwięga committed
			env_info.gas_used = ret.cumulative_gas_used;
			results.push(ret);
Tomasz Drwięga's avatar
Tomasz Drwięga committed
		Ok(results)
	fn estimate_gas(&self, t: &SignedTransaction, state: &Self::State, header: &Header) -> Result<U256, CallError> {
		let (mut upper, max_upper, env_info) = {
			let init = *header.gas_limit();
			let max = init * U256::from(10);

			let env_info = EnvInfo {
				number: header.number(),
				author: header.author().clone(),
				timestamp: header.timestamp(),
				difficulty: header.difficulty().clone(),
				last_hashes: self.build_last_hashes(header.parent_hash()),
				gas_used: U256::default(),
				gas_limit: max,
			};

			(init, max, env_info)
		let sender = t.sender();
		let options = || TransactOptions::with_tracing().dont_check_nonce();
		let cond = |gas| {
			let mut tx = t.as_unsigned().clone();
			let tx = tx.fake_sign(sender);
			let mut clone = state.clone();
			Ok(Executive::new(&mut clone, &env_info, self.engine.machine())
				.transact_virtual(&tx, options())
				.map(|r| r.exception.is_none())
			upper = max_upper;
				trace!(target: "estimate_gas", "estimate_gas failed with {}", upper);
				let err = ExecutionError::Internal(format!("Requires higher than upper limit of {}", upper));
				return Err(err.into())
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		let lower = t.gas_required(&self.engine.schedule(env_info.number)).into();
			trace!(target: "estimate_gas", "estimate_gas succeeded with {}", lower);
			return Ok(lower)
		}

		/// Find transition point between `lower` and `upper` where `cond` changes from `false` to `true`.
		/// Returns the lowest value between `lower` and `upper` for which `cond` returns true.
		/// We assert: `cond(lower) = false`, `cond(upper) = true`
		fn binary_chop<F, E>(mut lower: U256, mut upper: U256, mut cond: F) -> Result<U256, E>
			where F: FnMut(U256) -> Result<bool, E>
		{
			while upper - lower > 1.into() {
				let mid = (lower + upper) / 2.into();
				trace!(target: "estimate_gas", "{} .. {} .. {}", lower, mid, upper);
				match c {
					true => upper = mid,
					false => lower = mid,
				};
				trace!(target: "estimate_gas", "{} => {} .. {}", c, lower, upper);
			}
		}

		// binary chop to non-excepting call with gas somewhere between 21000 and block gas limit
		trace!(target: "estimate_gas", "estimate_gas chopping {} .. {}", lower, upper);
		binary_chop(lower, upper, cond)
}

impl EngineInfo for Client {
	fn engine(&self) -> &EthEngine {
		Client::engine(self)
	}
}
impl BlockChainClient for Client {
	fn replay(&self, id: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError> {
		let address = self.transaction_address(id).ok_or(CallError::TransactionNotFound)?;
		let block = BlockId::Hash(address.block_hash);
		const PROOF: &'static str = "The transaction address contains a valid index within block; qed";
		Ok(self.replay_block_transactions(block, analytics)?.nth(address.index).expect(PROOF))
	}
	fn replay_block_transactions(&self, block: BlockId, analytics: CallAnalytics) -> Result<Box<Iterator<Item = Executed>>, CallError> {
		let mut env_info = self.env_info(block).ok_or(CallError::StatePruned)?;
		let body = self.block_body(block).ok_or(CallError::StatePruned)?;
		let mut state = self.state_at_beginning(block).ok_or(CallError::StatePruned)?;
		let txs = body.transactions();
		let engine = self.engine.clone();
		const PROOF: &'static str = "Transactions fetched from blockchain; blockchain transactions are valid; qed";
		const EXECUTE_PROOF: &'static str = "Transaction replayed; qed";

		Ok(Box::new(txs.into_iter()
			.map(move |t| {
				let t = SignedTransaction::new(t).expect(PROOF);
				let machine = engine.machine();
				let x = Self::do_virtual_call(machine, &env_info, &mut state, &t, analytics).expect(EXECUTE_PROOF);
				env_info.gas_used = env_info.gas_used + x.gas_used;
				x
			})))
	fn mode(&self) -> Mode {
		let r = self.mode.lock().clone().into();
		trace!(target: "mode", "Asked for mode = {:?}. returning {:?}", &*self.mode.lock(), r);
		r
	}
		self.set_mode(Mode::Off);
		self.enabled.store(false, AtomicOrdering::Relaxed);
Gav Wood's avatar
Gav Wood committed
		self.clear_queue();
	fn set_mode(&self, new_mode: Mode) {
		trace!(target: "mode", "Client::set_mode({:?})", new_mode);
		if !self.enabled.load(AtomicOrdering::Relaxed) {
			return;
		}
		{
			let mut mode = self.mode.lock();
			*mode = new_mode.clone().into();
			trace!(target: "mode", "Mode now {:?}", &*mode);
			if let Some(ref mut f) = *self.on_user_defaults_change.lock() {
Tomasz Drwięga's avatar
Tomasz Drwięga committed
				trace!(target: "mode", "Making callback...");
				f(Some((&*mode).clone()))
			}
		}
		match new_mode {
			Mode::Active => self.wake_up(),
			Mode::Off => self.sleep(),
Gav Wood's avatar
Gav Wood committed
			_ => {(*self.sleep_state.lock()).last_activity = Some(Instant::now()); }
		}
	}

	fn spec_name(&self) -> String {
		self.config.spec_name.clone()
	}

	fn set_spec_name(&self, new_spec_name: String) {
		trace!(target: "mode", "Client::set_spec_name({:?})", new_spec_name);
		if !self.enabled.load(AtomicOrdering::Relaxed) {
			return;
		}
		if let Some(ref h) = *self.exit_handler.lock() {
			(*h)(new_spec_name);
		} else {
			warn!("Not hypervised; cannot change chain.");
		}
	}

Gav Wood's avatar
Gav Wood committed
	fn block_number(&self, id: BlockId) -> Option<BlockNumber> {
		self.block_number_ref(&id)
Gav Wood's avatar
Gav Wood committed
	}

	fn block_body(&self, id: BlockId) -> Option<encoded::Body> {
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		let chain = self.chain.read();
		Self::block_hash(&chain, id).and_then(|hash| chain.block_body(&hash))
	fn block_status(&self, id: BlockId) -> BlockStatus {
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		let chain = self.chain.read();
		match Self::block_hash(&chain, id) {
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
			Some(ref hash) if chain.is_known(hash) => BlockStatus::InChain,
			Some(hash) => self.importer.block_queue.status(&hash).into(),
	fn block_total_difficulty(&self, id: BlockId) -> Option<U256> {
Tomasz Drwięga's avatar
Tomasz Drwięga committed
		let chain = self.chain.read();
		Self::block_hash(&chain, id).and_then(|hash| chain.block_details(&hash)).map(|d| d.total_difficulty)
	fn storage_root(&self, address: &Address, id: BlockId) -> Option<H256> {
		self.state_at(id).and_then(|s| s.storage_root(address).ok()).and_then(|x| x)
	fn block_hash(&self, id: BlockId) -> Option<H256> {
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		let chain = self.chain.read();
		Self::block_hash(&chain, id)
	fn code(&self, address: &Address, state: StateOrBlock) -> Option<Option<Bytes>> {
		let result = match state {
			StateOrBlock::State(s) => s.code(address).ok(),
			StateOrBlock::Block(id) => self.state_at(id).and_then(|s| s.code(address).ok())
		};
		// Converting from `Option<Option<Arc<Bytes>>>` to `Option<Option<Bytes>>`
		result.map(|c| c.map(|c| (&*c).clone()))
	fn storage_at(&self, address: &Address, position: &H256, state: StateOrBlock) -> Option<H256> {
		match state {
			StateOrBlock::State(s) => s.storage_at(address, position).ok(),
			StateOrBlock::Block(id) => self.state_at(id).and_then(|s| s.storage_at(address, position).ok())
		}
	fn list_accounts(&self, id: BlockId, after: Option<&Address>, count: u64) -> Option<Vec<Address>> {
		if !self.factories.trie.is_fat() {
			trace!(target: "fatdb", "list_accounts: Not a fat DB");
			return None;
		}

		let state = match self.state_at(id) {
			Some(state) => state,
			_ => return None,
		};

		let (root, db) = state.drop();
		let trie = match self.factories.trie.readonly(db.as_hashdb(), &root) {
			Ok(trie) => trie,
			_ => {
				trace!(target: "fatdb", "list_accounts: Couldn't open the DB");
				return None;
			}
		};

Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		let mut iter = match trie.iter() {
			Ok(iter) => iter,
			_ => return None,
		};

Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		if let Some(after) = after {
			if let Err(e) = iter.seek(after) {
				trace!(target: "fatdb", "list_accounts: Couldn't seek the DB: {:?}", e);
			}
		}

		let accounts = iter.filter_map(|item| {
			item.ok().map(|(addr, _)| Address::from_slice(&addr))
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		}).take(count as usize).collect();
	fn list_storage(&self, id: BlockId, account: &Address, after: Option<&H256>, count: u64) -> Option<Vec<H256>> {
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		if !self.factories.trie.is_fat() {
			trace!(target: "fatdb", "list_stroage: Not a fat DB");
			return None;
		}

		let state = match self.state_at(id) {
			Some(state) => state,
			_ => return None,
		};

		let root = match state.storage_root(account) {
			Ok(Some(root)) => root,
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
			_ => return None,
		};

		let (_, db) = state.drop();
		let account_db = self.factories.accountdb.readonly(db.as_hashdb(), keccak(account));
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		let trie = match self.factories.trie.readonly(account_db.as_hashdb(), &root) {
			Ok(trie) => trie,
			_ => {
				trace!(target: "fatdb", "list_storage: Couldn't open the DB");
				return None;
			}
		};

		let mut iter = match trie.iter() {
			Ok(iter) => iter,
			_ => return None,
		};

		if let Some(after) = after {
			if let Err(e) = iter.seek(after) {
				trace!(target: "fatdb", "list_accounts: Couldn't seek the DB: {:?}", e);
			}
		}

		let keys = iter.filter_map(|item| {
			item.ok().map(|(key, _)| H256::from_slice(&key))
		}).take(count as usize).collect();

		Some(keys)
	}

	fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction> {
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		self.transaction_address(id).and_then(|address| self.chain.read().transaction(&address))
	fn uncle(&self, id: UncleId) -> Option<encoded::Header> {
NikVolf's avatar
NikVolf committed
		let index = id.position;
		self.block_body(id.block).and_then(|body| body.view().uncle_rlp_at(index))
			.map(encoded::Header::new)
Marek Kotewicz's avatar
Marek Kotewicz committed
	}

	fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt> {
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		let chain = self.chain.read();
		self.transaction_address(id)
			.and_then(|address| chain.block_number(&address.block_hash).and_then(|block_number| {
				let transaction = chain.block_body(&address.block_hash)
					.and_then(|body| body.view().localized_transaction_at(&address.block_hash, block_number, address.index));

				let previous_receipts = (0..address.index + 1)
					.map(|index| {
						let mut address = address.clone();
						address.index = index;
						chain.transaction_receipt(&address)
					.collect();
				match (transaction, previous_receipts) {
					(Some(transaction), Some(previous_receipts)) => {
						Some(transaction_receipt(self.engine().machine(), transaction, previous_receipts))
	fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute> {
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		let chain = self.chain.read();
		match chain.is_known(from) && chain.is_known(to) {
			true => chain.tree_route(from.clone(), to.clone()),
	fn find_uncles(&self, hash: &H256) -> Option<Vec<H256>> {
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		self.chain.read().find_uncle_hashes(hash, self.engine.maximum_uncle_age())
Nikolay Volf's avatar
Nikolay Volf committed
	fn state_data(&self, hash: &H256) -> Option<Bytes> {
Tomasz Drwięga's avatar
Tomasz Drwięga committed
		self.state_db.read().journal_db().state(hash)
	fn block_receipts(&self, hash: &H256) -> Option<Bytes> {
Vurich's avatar
Vurich committed
		self.chain.read().block_receipts(hash).map(|receipts| ::rlp::encode(&receipts).into_vec())
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	fn queue_info(&self) -> BlockQueueInfo {
		self.importer.block_queue.queue_info()
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	fn clear_queue(&self) {
		self.importer.block_queue.clear();
Gav Wood's avatar
Gav Wood committed
	fn additional_params(&self) -> BTreeMap<String, String> {
		self.engine.additional_params().into_iter().collect()
	}

	fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry> {
		// Wrap the logic inside a closure so that we can take advantage of question mark syntax.
		let fetch_logs = || {
			let chain = self.chain.read();

			// First, check whether `filter.from_block` and `filter.to_block` is on the canon chain. If so, we can use the
			// optimized version.
			let is_canon = |id| {
				match id {
					// If it is referred by number, then it is always on the canon chain.
					&BlockId::Earliest | &BlockId::Latest | &BlockId::Number(_) => true,
					// If it is referred by hash, we see whether a hash -> number -> hash conversion gives us the same
					// result.
					&BlockId::Hash(ref hash) => chain.is_canon(hash),
				}
			};
			let blocks = if is_canon(&filter.from_block) && is_canon(&filter.to_block) {
				// If we are on the canon chain, use bloom filter to fetch required hashes.
				let from = self.block_number_ref(&filter.from_block)?;
				let to = self.block_number_ref(&filter.to_block)?;

				chain.blocks_with_bloom(&filter.bloom_possibilities(), from, to)
					.into_iter()
					.filter_map(|n| chain.block_hash(n))
					.collect::<Vec<H256>>()
			} else {
				// Otherwise, we use a slower version that finds a link between from_block and to_block.
				let from_hash = Self::block_hash(&chain, filter.from_block)?;
				let from_number = chain.block_number(&from_hash)?;
				let to_hash = Self::block_hash(&chain, filter.from_block)?;

				let blooms = filter.bloom_possibilities();
				let bloom_match = |header: &encoded::Header| {
					blooms.iter().any(|bloom| header.log_bloom().contains_bloom(bloom))
				};

				let (blocks, last_hash) = {
					let mut blocks = Vec::new();
					let mut current_hash = to_hash;

					loop {
						let header = chain.block_header_data(&current_hash)?;
						if bloom_match(&header) {
							blocks.push(current_hash);
						}

						// Stop if `from` block is reached.
						if header.number() <= from_number {
							break;
						}
						current_hash = header.parent_hash();
					}

					blocks.reverse();
					(blocks, current_hash)
				};

				// Check if we've actually reached the expected `from` block.
				if last_hash != from_hash || blocks.is_empty() {
					return None;
				}

				blocks
			};

			Some(self.chain.read().logs(blocks, |entry| filter.matches(entry), filter.limit))
		};
		fetch_logs().unwrap_or_default()
	fn filter_traces(&self, filter: TraceFilter) -> Option<Vec<LocalizedTrace>> {
		if !self.tracedb.read().tracing_enabled() {
			return None;
		}

		let start = self.block_number(filter.range.start)?;
		let end = self.block_number(filter.range.end)?;
		let db_filter = trace::Filter {
			range: start as usize..end as usize,
			from_address: filter.from_address.into(),
			to_address: filter.to_address.into(),
		};
		let traces = self.tracedb.read()
			.filter(&db_filter)
			.into_iter()
			.skip(filter.after.unwrap_or(0))
			.take(filter.count.unwrap_or(usize::max_value()))
			.collect();
		Some(traces)
	}

	fn trace(&self, trace: TraceId) -> Option<LocalizedTrace> {
		if !self.tracedb.read().tracing_enabled() {
			return None;
		}

		let trace_address = trace.address;
		self.transaction_address(trace.transaction)
			.and_then(|tx_address| {
				self.block_number(BlockId::Hash(tx_address.block_hash))
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
					.and_then(|number| self.tracedb.read().trace(number, tx_address.index, trace_address))
	fn transaction_traces(&self, transaction: TransactionId) -> Option<Vec<LocalizedTrace>> {
		if !self.tracedb.read().tracing_enabled() {
			return None;
		}

		self.transaction_address(transaction)
			.and_then(|tx_address| {
				self.block_number(BlockId::Hash(tx_address.block_hash))
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
					.and_then(|number| self.tracedb.read().transaction_traces(number, tx_address.index))
	fn block_traces(&self, block: BlockId) -> Option<Vec<LocalizedTrace>> {
		if !self.tracedb.read().tracing_enabled() {
			return None;
		}

		self.block_number(block)
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
			.and_then(|number| self.tracedb.read().block_traces(number))
	fn last_hashes(&self) -> LastHashes {
		(*self.build_last_hashes(&self.chain.read().best_block_hash())).clone()
	fn ready_transactions(&self, max_len: usize) -> Vec<Arc<VerifiedTransaction>> {
		self.importer.miner.ready_transactions(self, max_len, ::miner::PendingOrdering::Priority)
	fn signing_chain_id(&self) -> Option<u64> {
		self.engine.signing_chain_id(&self.latest_env_info())
Gav Wood's avatar
Gav Wood committed
	}
	fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> {
		self.block_header_decoded(id)
			.map(|header| self.engine.extra_info(&header))
	fn uncle_extra_info(&self, id: UncleId) -> Option<BTreeMap<String, String>> {
David's avatar
David committed
			.and_then(|h| {
				h.decode().map(|dh| {
					self.engine.extra_info(&dh)
				}).ok()
			})

	fn pruning_info(&self) -> PruningInfo {
		PruningInfo {
asynchronous rob's avatar
asynchronous rob committed
			earliest_chain: self.chain.read().first_block_number().unwrap_or(1),
Tomasz Drwięga's avatar
Tomasz Drwięga committed
			earliest_state: self.state_db.read().journal_db().earliest_era().unwrap_or(0),
	fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error> {
		let authoring_params = self.importer.miner.authoring_params();
keorn's avatar
keorn committed
		let transaction = Transaction {
			nonce: self.latest_nonce(&authoring_params.author),
keorn's avatar
keorn committed
			action: Action::Call(address),
			gas: self.importer.miner.sensible_gas_limit(),
			gas_price: self.importer.miner.sensible_gas_price(),
keorn's avatar
keorn committed
			value: U256::zero(),
			data: data,
		};
		let chain_id = self.engine.signing_chain_id(&self.latest_env_info());
		let signature = self.engine.sign(transaction.hash(chain_id))
			.map_err(|e| transaction::Error::InvalidSignature(e.to_string()))?;
		let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?;
		self.importer.miner.import_own_transaction(self, signed.into())