Skip to content
client.rs 54.1 KiB
Newer Older
Gav Wood's avatar
Gav Wood committed
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate.

// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Substrate.  If not, see <http://www.gnu.org/licenses/>.

//! Substrate Client

use std::sync::Arc;
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
use futures::sync::mpsc;
use parking_lot::{Mutex, RwLock};
Gav Wood's avatar
Gav Wood committed
use primitives::AuthorityId;
use runtime_primitives::{bft::Justification, generic::{BlockId, SignedBlock, Block as RuntimeBlock}};
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash};
use runtime_primitives::BuildStorage;
use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration};
Gav Wood's avatar
Gav Wood committed
use primitives::storage::{StorageKey, StorageData};
use primitives::storage::well_known_keys;
use codec::{Encode, Decode};
Gav Wood's avatar
Gav Wood committed
	Backend as StateBackend, CodeExecutor,
	ExecutionStrategy, ExecutionManager, prove_read,
	key_changes, key_changes_proof,
Gav Wood's avatar
Gav Wood committed

use backend::{self, BlockImportOperation};
use blockchain::{self, Info as ChainInfo, Backend as ChainBackend, HeaderBackend as ChainHeaderBackend};
use call_executor::{CallExecutor, LocalCallExecutor};
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
use executor::{RuntimeVersion, RuntimeInfo};
use notifications::{StorageNotifications, StorageEventStream};
Gav Wood's avatar
Gav Wood committed
use {cht, error, in_mem, block_builder, bft, genesis};
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
/// Type that implements `futures::Stream` of block import events.
pub type ImportNotifications<Block> = mpsc::UnboundedReceiver<BlockImportNotification<Block>>;

/// A stream of block finality notifications.
pub type FinalityNotifications<Block> = mpsc::UnboundedReceiver<FinalityNotification<Block>>;
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
/// Substrate Client
Gav Wood's avatar
Gav Wood committed
pub struct Client<B, E, Block> where Block: BlockT {
Gav Wood's avatar
Gav Wood committed
	executor: E,
	storage_notifications: Mutex<StorageNotifications<Block>>,
Gav Wood's avatar
Gav Wood committed
	import_notification_sinks: Mutex<Vec<mpsc::UnboundedSender<BlockImportNotification<Block>>>>,
	finality_notification_sinks: Mutex<Vec<mpsc::UnboundedSender<FinalityNotification<Block>>>>,
	import_lock: Mutex<()>,
Gav Wood's avatar
Gav Wood committed
	importing_block: RwLock<Option<Block::Hash>>, // holds the block hash currently being imported. TODO: replace this with block queue
	block_execution_strategy: ExecutionStrategy,
	api_execution_strategy: ExecutionStrategy,
	changes_trie_config: Option<ChangesTrieConfiguration>,
/// A source of blockchain events.
Gav Wood's avatar
Gav Wood committed
pub trait BlockchainEvents<Block: BlockT> {
	/// Get block import event stream. Not guaranteed to be fired for every
	/// imported block.
	fn import_notification_stream(&self) -> ImportNotifications<Block>;

	/// Get a stream of finality notifications. Not guaranteed to be fired for every
	/// finalized block.
	fn finality_notification_stream(&self) -> FinalityNotifications<Block>;

	/// Get storage changes event stream.
	///
	/// Passing `None` as `filter_keys` subscribes to all storage changes.
	fn storage_changes_notification_stream(&self, filter_keys: Option<&[StorageKey]>) -> error::Result<StorageEventStream<Block::Hash>>;
/// Chain head information.
Gav Wood's avatar
Gav Wood committed
pub trait ChainHead<Block: BlockT> {
	/// Get best block header.
Gav Wood's avatar
Gav Wood committed
	fn best_block_header(&self) -> Result<<Block as BlockT>::Header, error::Error>;
/// Fetch block body by ID.
pub trait BlockBody<Block: BlockT> {
	/// Get block body by ID. Returns `None` if the body is not stored.
	fn block_body(&self, id: &BlockId<Block>) -> error::Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
}

Gav Wood's avatar
Gav Wood committed
/// Client info
// TODO: split queue info from chain info and amalgamate into single struct.
#[derive(Debug)]
Gav Wood's avatar
Gav Wood committed
pub struct ClientInfo<Block: BlockT> {
Gav Wood's avatar
Gav Wood committed
	/// Best block hash.
Gav Wood's avatar
Gav Wood committed
	pub chain: ChainInfo<Block>,
Gav Wood's avatar
Gav Wood committed
	/// Best block number in the queue.
Gav Wood's avatar
Gav Wood committed
	pub best_queued_number: Option<<<Block as BlockT>::Header as HeaderT>::Number>,
Gav Wood's avatar
Gav Wood committed
	/// Best queued block hash.
Gav Wood's avatar
Gav Wood committed
	pub best_queued_hash: Option<Block::Hash>,
Gav Wood's avatar
Gav Wood committed
}

/// Block import result.
#[derive(Debug)]
pub enum ImportResult {
	/// Added to the import queue.
	Queued,
	/// Already in the import queue.
	AlreadyQueued,
	/// Already in the blockchain.
	AlreadyInChain,
	/// Block or parent is known to be bad.
	KnownBad,
	/// Block parent is not in the chain.
	UnknownParent,
}

/// Block status.
#[derive(Debug, PartialEq, Eq)]
pub enum BlockStatus {
	/// Added to the import queue.
	Queued,
	/// Already in the blockchain.
	InChain,
	/// Block or parent is known to be bad.
	KnownBad,
	/// Not in the queue or the blockchain.
	Unknown,
}

Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
/// Block data origin.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
pub enum BlockOrigin {
	/// Genesis block built into the client.
	Genesis,
	/// Block is part of the initial sync with the network.
	NetworkInitialSync,
	/// Block was broadcasted on the network.
	NetworkBroadcast,
	/// Block that was received from the network and validated in the consensus process.
	ConsensusBroadcast,
	/// Block that was collated by this node.
	Own,
	/// Block was imported from a file.
	File,
}

/// Summary of an imported block
#[derive(Clone, Debug)]
Gav Wood's avatar
Gav Wood committed
pub struct BlockImportNotification<Block: BlockT> {
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	/// Imported block header hash.
Gav Wood's avatar
Gav Wood committed
	pub hash: Block::Hash,
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	/// Imported block origin.
	pub origin: BlockOrigin,
	/// Imported block header.
Gav Wood's avatar
Gav Wood committed
	pub header: Block::Header,
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	/// Is this the new best block.
	pub is_new_best: bool,
}

/// Summary of a finalized block.
#[derive(Clone, Debug)]
pub struct FinalityNotification<Block: BlockT> {
	/// Imported block header hash.
	pub hash: Block::Hash,
	/// Imported block header.
	pub header: Block::Header,
}

Gav Wood's avatar
Gav Wood committed
/// A header paired with a justification which has already been checked.
#[derive(Debug, PartialEq, Eq, Clone)]
Gav Wood's avatar
Gav Wood committed
pub struct JustifiedHeader<Block: BlockT> {
	header: <Block as BlockT>::Header,
	justification: ::bft::Justification<Block::Hash>,
	authorities: Vec<AuthorityId>,
Gav Wood's avatar
Gav Wood committed
impl<Block: BlockT> JustifiedHeader<Block> {
Gav Wood's avatar
Gav Wood committed
	/// Deconstruct the justified header into parts.
	pub fn into_inner(self) -> (<Block as BlockT>::Header, ::bft::Justification<Block::Hash>, Vec<AuthorityId>) {
		(self.header, self.justification, self.authorities)
Gav Wood's avatar
Gav Wood committed
	}
}

/// Create an instance of in-memory client.
pub fn new_in_mem<E, Block, S>(
Gav Wood's avatar
Gav Wood committed
	executor: E,
Gav Wood's avatar
Gav Wood committed
	genesis_storage: S,
) -> error::Result<Client<in_mem::Backend<Block, Blake2Hasher>, LocalCallExecutor<in_mem::Backend<Block, Blake2Hasher>, E>, Block>>
Gav Wood's avatar
Gav Wood committed
	where
		E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
		S: BuildStorage,
Gav Wood's avatar
Gav Wood committed
		Block: BlockT,
	new_with_backend(Arc::new(in_mem::Backend::new()), executor, genesis_storage)
}

/// Create a client with the explicitely provided backend.
/// This is useful for testing backend implementations.
pub fn new_with_backend<B, E, Block, S>(
	backend: Arc<B>,
	executor: E,
	build_genesis_storage: S,
) -> error::Result<Client<B, LocalCallExecutor<B, E>, Block>>
	where
		E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
		S: BuildStorage,
		Block: BlockT,
		H256: From<Block::Hash>,
		B: backend::LocalBackend<Block, Blake2Hasher>
{
	let call_executor = LocalCallExecutor::new(backend.clone(), executor);
	Client::new(backend, call_executor, build_genesis_storage, ExecutionStrategy::NativeWhenPossible, ExecutionStrategy::NativeWhenPossible)
impl<B, E, Block> Client<B, E, Block> where
	B: backend::Backend<Block, Blake2Hasher>,
	E: CallExecutor<Block, Blake2Hasher>,
Gav Wood's avatar
Gav Wood committed
	Block: BlockT,
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	/// Creates new Substrate Client with given blockchain and code executor.
	pub fn new<S: BuildStorage>(
Gav Wood's avatar
Gav Wood committed
		executor: E,
		build_genesis_storage: S,
		block_execution_strategy: ExecutionStrategy,
		api_execution_strategy: ExecutionStrategy,
	) -> error::Result<Self> {
Gav Wood's avatar
Gav Wood committed
		if backend.blockchain().header(BlockId::Number(Zero::zero()))?.is_none() {
			let genesis_storage = build_genesis_storage.build_storage()?;
			let genesis_block = genesis::construct_genesis_block::<Block>(&genesis_storage);
			info!("Initialising Genesis block/state (state: {}, header-hash: {})", genesis_block.header().state_root(), genesis_block.header().hash());
Gav Wood's avatar
Gav Wood committed
			let mut op = backend.begin_operation(BlockId::Hash(Default::default()))?;
			op.reset_storage(genesis_storage.into_iter())?;
			op.set_block_data(
				genesis_block.deconstruct().0,
				Some(vec![]),
				None,
				::backend::NewBlockState::Final
			)?;
Gav Wood's avatar
Gav Wood committed
			backend.commit_operation(op)?;
		}

		// changes trie configuration should never change => we can read it in advance
		let changes_trie_config = backend.state_at(BlockId::Number(Zero::zero()))?
			.storage(well_known_keys::CHANGES_TRIE_CONFIG)
			.map_err(|e| error::Error::from_state(Box::new(e)))?
			.and_then(|c| Decode::decode(&mut &*c));

Gav Wood's avatar
Gav Wood committed
		Ok(Client {
			backend,
			executor,
			storage_notifications: Default::default(),
			import_notification_sinks: Default::default(),
			finality_notification_sinks: Default::default(),
			import_lock: Default::default(),
			importing_block: Default::default(),
			block_execution_strategy,
			api_execution_strategy,
Gav Wood's avatar
Gav Wood committed
		})
	}

	/// Get a reference to the state at a given block.
Gav Wood's avatar
Gav Wood committed
	pub fn state_at(&self, block: &BlockId<Block>) -> error::Result<B::State> {
Gav Wood's avatar
Gav Wood committed
		self.backend.state_at(*block)
	}

	/// Expose backend reference. To be used in tests only
	pub fn backend(&self) -> &Arc<B> {
Gav Wood's avatar
Gav Wood committed
		&self.backend
	}

	/// Return single storage entry of contract under given address in state in a block of given hash.
	pub fn storage(&self, id: &BlockId<Block>, key: &StorageKey) -> error::Result<Option<StorageData>> {
		Ok(self.state_at(id)?
			.storage(&key.0).map_err(|e| error::Error::from_state(Box::new(e)))?
Gav Wood's avatar
Gav Wood committed
	}

	/// Get the code at a given block.
Gav Wood's avatar
Gav Wood committed
	pub fn code_at(&self, id: &BlockId<Block>) -> error::Result<Vec<u8>> {
		Ok(self.storage(id, &StorageKey(well_known_keys::CODE.to_vec()))?
			.expect("None is returned if there's no value stored for the given key; ':code' key is always defined; qed").0)
	/// Get the set of authorities at a given block.
Gav Wood's avatar
Gav Wood committed
	pub fn authorities_at(&self, id: &BlockId<Block>) -> error::Result<Vec<AuthorityId>> {
		match self.backend.blockchain().cache().and_then(|cache| cache.authorities_at(*id)) {
			Some(cached_value) => Ok(cached_value),
			None => self.executor.call(id, "authorities",&[])
				.and_then(|r| Vec::<AuthorityId>::decode(&mut &r.return_data[..])
					.ok_or(error::ErrorKind::InvalidAuthoritiesSet.into()))
	/// Get the RuntimeVersion at a given block.
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	pub fn runtime_version_at(&self, id: &BlockId<Block>) -> error::Result<RuntimeVersion> {
		// TODO: Post Poc-2 return an error if version is missing
		self.executor.runtime_version(id)
	/// Get call executor reference.
	pub fn executor(&self) -> &E {
		&self.executor
	/// Returns the runtime metadata.
	pub fn metadata(&self, id: &BlockId<Block>) -> error::Result<Vec<u8>> {
		self.executor.call(id, "metadata",&[]).map(|v| v.return_data)
	/// Reads storage value at a given block + key, returning read proof.
	pub fn read_proof(&self, id: &BlockId<Block>, key: &[u8]) -> error::Result<Vec<Vec<u8>>> {
		self.state_at(id)
			.and_then(|state| prove_read(state, key)
				.map(|(_, proof)| proof)
				.map_err(Into::into))
	}

	/// Execute a call to a contract on top of state in a block of given hash
	/// AND returning execution proof.
Gav Wood's avatar
Gav Wood committed
	///
	/// No changes are made.
Gav Wood's avatar
Gav Wood committed
	pub fn execution_proof(&self, id: &BlockId<Block>, method: &str, call_data: &[u8]) -> error::Result<(Vec<u8>, Vec<Vec<u8>>)> {
		self.state_at(id).and_then(|state| self.executor.prove_at_state(state, &mut Default::default(), method, call_data))
	/// Reads given header and generates CHT-based header proof.
	pub fn header_proof(&self, id: &BlockId<Block>) -> error::Result<(Block::Header, Vec<Vec<u8>>)> {
		self.header_proof_with_cht_size(id, cht::SIZE)
	}

	/// Reads given header and generates CHT-based header proof for CHT of given size.
	pub fn header_proof_with_cht_size(&self, id: &BlockId<Block>, cht_size: u64) -> error::Result<(Block::Header, Vec<Vec<u8>>)> {
		let proof_error = || error::ErrorKind::Backend(format!("Failed to generate header proof for {:?}", id));
		let header = self.header(id)?.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", id)))?;
		let block_num = *header.number();
		let cht_num = cht::block_to_cht_number(cht_size, block_num).ok_or_else(proof_error)?;
		let cht_start = cht::start_number(cht_size, cht_num);
		let headers = (cht_start.as_()..).map(|num| self.block_hash(As::sa(num)).unwrap_or_default());
		let proof = cht::build_proof::<Block::Header, Blake2Hasher, _>(cht_size, cht_num, block_num, headers)
			.ok_or_else(proof_error)?;
		Ok((header, proof))
	}

	/// Get pairs of (block, extrinsic) where key has been changed at given blocks range.
	/// Works only for runtimes that are supporting changes tries.
	pub fn key_changes(
		&self,
		first: Block::Hash,
		last: Block::Hash,
		key: &[u8]
	) -> error::Result<Vec<(NumberFor<Block>, u32)>> {
		let config = self.changes_trie_config.as_ref();
		let storage = self.backend.changes_trie_storage();
		let (config, storage) = match (config, storage) {
			(Some(config), Some(storage)) => (config, storage),
			_ => return Err(error::ErrorKind::ChangesTriesNotSupported.into()),
		};

		key_changes::<_, Blake2Hasher>(
			config,
			storage,
			self.require_block_number_from_id(&BlockId::Hash(first))?.as_(),
			self.require_block_number_from_id(&BlockId::Hash(last))?.as_(),
			self.backend.blockchain().info()?.best_number.as_(),
			key)
		.map_err(|err| error::ErrorKind::ChangesTrieAccessFailed(err).into())
		.map(|r| r.into_iter().map(|(b, e)| (As::sa(b), e)).collect())
	}

	/// Get proof for computation of (block, extrinsic) pairs where key has been changed at given blocks range.
	/// `max` is the hash of the last block known to the requester - we can't use changes tries from descendants
	/// of this block.
	/// Works only for runtimes that are supporting changes tries.
	pub fn key_changes_proof(
		&self,
		first: Block::Hash,
		last: Block::Hash,
		max: Block::Hash,
		key: &[u8]
	) -> error::Result<(NumberFor<Block>, Vec<Vec<u8>>)> {
		let config = self.changes_trie_config.as_ref();
		let storage = self.backend.changes_trie_storage();
		let (config, storage) = match (config, storage) {
			(Some(config), Some(storage)) => (config, storage),
			_ => return Err(error::ErrorKind::ChangesTriesNotSupported.into()),
		};

		let max_number = ::std::cmp::min(
			self.backend.blockchain().info()?.best_number,
			self.require_block_number_from_id(&BlockId::Hash(max))?,
		);
		key_changes_proof::<_, Blake2Hasher>(
			config,
			storage,
			self.require_block_number_from_id(&BlockId::Hash(first))?.as_(),
			self.require_block_number_from_id(&BlockId::Hash(last))?.as_(),
			max_number.as_(),
			key)
		.map_err(|err| error::ErrorKind::ChangesTrieAccessFailed(err).into())
		.map(|proof| (max_number, proof))
	}

Gav Wood's avatar
Gav Wood committed
	/// Create a new block, built on the head of the chain.
	pub fn new_block(&self) -> error::Result<block_builder::BlockBuilder<B, E, Block, Blake2Hasher>>
Gav Wood's avatar
Gav Wood committed
		block_builder::BlockBuilder::new(self)
	}

	/// Create a new block, built on top of `parent`.
	pub fn new_block_at(&self, parent: &BlockId<Block>) -> error::Result<block_builder::BlockBuilder<B, E, Block, Blake2Hasher>>
Gav Wood's avatar
Gav Wood committed
		block_builder::BlockBuilder::at_block(parent, &self)
	}

Gav Wood's avatar
Gav Wood committed
	/// Set up the native execution environment to call into a native runtime code.
	pub fn call_api<A, R>(&self, function: &'static str, args: &A) -> error::Result<R>
		where A: Encode, R: Decode
	{
		self.call_api_at(&BlockId::Number(self.info()?.chain.best_number), function, args)
	}

	/// Call a runtime function at given block.
Gav Wood's avatar
Gav Wood committed
	pub fn call_api_at<A, R>(&self, at: &BlockId<Block>, function: &'static str, args: &A) -> error::Result<R>
		where A: Encode, R: Decode
	{
		let parent = at;
		let header = <<Block as BlockT>::Header as HeaderT>::new(
			self.block_number_from_id(&parent)?
				.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))? + As::sa(1),
			Default::default(),
			Default::default(),
			self.block_hash_from_id(&parent)?
				.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))?,
			Default::default()
		);
		self.state_at(&parent).and_then(|state| {
			let mut overlay = Default::default();
			let execution_manager = || match self.api_execution_strategy {
				ExecutionStrategy::NativeWhenPossible => ExecutionManager::NativeWhenPossible,
				ExecutionStrategy::AlwaysWasm => ExecutionManager::AlwaysWasm,
				ExecutionStrategy::Both => ExecutionManager::Both(|wasm_result, native_result| {
					warn!("Consensus error between wasm and native runtime execution at block {:?}", at);
					warn!("   Function {:?}", function);
					warn!("   Native result {:?}", native_result);
					warn!("   Wasm result {:?}", wasm_result);
					wasm_result
				}),
			};
			self.executor().call_at_state(
				&state,
				&mut overlay,
				"initialise_block",
				&header.encode(),
				execution_manager()
			)?;
			let (r, _, _) = args.using_encoded(|input|
				self.executor().call_at_state(
				&state,
				&mut overlay,
				function,
				input,
				execution_manager()
			))?;
			Ok(R::decode(&mut &r[..])
			   .ok_or_else(|| error::Error::from(error::ErrorKind::CallResultDecode(function)))?)
		})
	}

Gav Wood's avatar
Gav Wood committed
	/// Check a header's justification.
	pub fn check_justification(
		&self,
Gav Wood's avatar
Gav Wood committed
		header: <Block as BlockT>::Header,
		justification: ::bft::UncheckedJustification<Block::Hash>,
	) -> error::Result<JustifiedHeader<Block>> {
		let parent_hash = header.parent_hash().clone();
		let authorities = self.authorities_at(&BlockId::Hash(parent_hash))?;
		let just = ::bft::check_justification::<Block>(&authorities[..], parent_hash, justification)
			.map_err(|_|
				error::ErrorKind::BadJustification(
					format!("{}", header.hash())
				)
			)?;
Gav Wood's avatar
Gav Wood committed
		Ok(JustifiedHeader {
			header,
			justification: just,
Gav Wood's avatar
Gav Wood committed
		})
	}

	/// Queue a block for import.
	pub fn import_block(
		&self,
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		origin: BlockOrigin,
Gav Wood's avatar
Gav Wood committed
		header: JustifiedHeader<Block>,
		body: Option<Vec<<Block as BlockT>::Extrinsic>>,
Gav Wood's avatar
Gav Wood committed
	) -> error::Result<ImportResult> {
		let (header, justification, authorities) = header.into_inner();
Gav Wood's avatar
Gav Wood committed
		let parent_hash = header.parent_hash().clone();
		match self.backend.blockchain().status(BlockId::Hash(parent_hash))? {
			blockchain::BlockStatus::InChain => {},
Gav Wood's avatar
Gav Wood committed
			blockchain::BlockStatus::Unknown => return Ok(ImportResult::UnknownParent),
		}
Gav Wood's avatar
Gav Wood committed
		let hash = header.hash();
		let _import_lock = self.import_lock.lock();
		let height: u64 = header.number().as_();
		*self.importing_block.write() = Some(hash);

		let result = self.execute_and_import_block(
			origin,
			hash,
			header,
			justification,
			body,
			authorities,
			finalized
		);

		*self.importing_block.write() = None;
		telemetry!("block.import";
			"height" => height,
			"best" => ?hash,
			"origin" => ?origin
		);
		result
	}

	fn execute_and_import_block(
		&self,
		origin: BlockOrigin,
Gav Wood's avatar
Gav Wood committed
		hash: Block::Hash,
		header: Block::Header,
		justification: bft::Justification<Block::Hash>,
		body: Option<Vec<Block::Extrinsic>>,
		authorities: Vec<AuthorityId>,
	) -> error::Result<ImportResult> {
Gav Wood's avatar
Gav Wood committed
		let parent_hash = header.parent_hash().clone();
		match self.backend.blockchain().status(BlockId::Hash(hash))? {
			blockchain::BlockStatus::InChain => return Ok(ImportResult::AlreadyInChain),
			blockchain::BlockStatus::Unknown => {},
		}
		let (last_best, last_best_number) = {
			let info = self.backend.blockchain().info()?;
			(info.best_hash, info.best_number)
		};

		// this is a fairly arbitrary choice of where to draw the line on making notifications,
		// but the general goal is to only make notifications when we are already fully synced
		// and get a new chain head.
		let make_notifications = match origin {
			BlockOrigin::NetworkBroadcast | BlockOrigin::Own | BlockOrigin::ConsensusBroadcast => true,
			BlockOrigin::Genesis | BlockOrigin::NetworkInitialSync | BlockOrigin::File => false,
		};

		// ensure parent block is finalized to maintain invariant that
		// finality is called sequentially.
		if finalized {
			self.apply_finality(parent_hash, last_best, make_notifications)?;
		}

Gav Wood's avatar
Gav Wood committed
		let mut transaction = self.backend.begin_operation(BlockId::Hash(parent_hash))?;
		let (storage_update, changes_update, storage_changes) = match transaction.state()? {
			Some(transaction_state) => {
				let mut overlay = Default::default();
Gav Wood's avatar
Gav Wood committed
				let mut r = self.executor.call_at_state(
					transaction_state,
					&mut overlay,
					"execute_block",
Gav Wood's avatar
Gav Wood committed
					&<Block as BlockT>::new(header.clone(), body.clone().unwrap_or_default()).encode(),
					match (origin, self.block_execution_strategy) {
Gav Wood's avatar
Gav Wood committed
						(BlockOrigin::NetworkInitialSync, _) | (_, ExecutionStrategy::NativeWhenPossible) =>
							ExecutionManager::NativeWhenPossible,
						(_, ExecutionStrategy::AlwaysWasm) => ExecutionManager::AlwaysWasm,
						_ => ExecutionManager::Both(|wasm_result, native_result| {
							warn!("Consensus error between wasm and native block execution at block {}", hash);
							warn!("   Header {:?}", header);
							warn!("   Native result {:?}", native_result);
							warn!("   Wasm result {:?}", wasm_result);
							telemetry!("block.execute.consensus_failure";
								"hash" => ?hash,
								"origin" => ?origin,
								"header" => ?header
							);
							wasm_result
						}),
					},
				);
				let (_, storage_update, changes_update) = r?;
				overlay.commit_prospective();
				(Some(storage_update), Some(changes_update), Some(overlay.into_committed()))
		// TODO: non longest-chain rule.
		let is_new_best = finalized || header.number() > &last_best_number;
		let leaf_state = if finalized {
			::backend::NewBlockState::Final
		} else if is_new_best {
			::backend::NewBlockState::Best
		} else {
			::backend::NewBlockState::Normal
		};

Gav Wood's avatar
Gav Wood committed
		trace!("Imported {}, (#{}), best={}, origin={:?}", hash, header.number(), is_new_best, origin);
		let unchecked: bft::UncheckedJustification<_> = justification.uncheck().into();

		transaction.set_block_data(
			header.clone(),
			body,
			Some(unchecked.into()),
			leaf_state,
		)?;

		transaction.update_authorities(authorities);
		if let Some(storage_update) = storage_update {
			transaction.update_storage(storage_update)?;
		}
		if let Some(Some(changes_update)) = changes_update {
			transaction.update_changes_trie(changes_update)?;
		}
Gav Wood's avatar
Gav Wood committed
		self.backend.commit_operation(transaction)?;
		if make_notifications {
			if let Some(storage_changes) = storage_changes {
				// TODO [ToDr] How to handle re-orgs? Should we re-emit all storage changes?
				self.storage_notifications.lock()
					.trigger(&hash, storage_changes);
			}

			if finalized {
				let notification = FinalityNotification::<Block> {
					hash,
					header: header.clone(),
				};

				self.finality_notification_sinks.lock()
					.retain(|sink| sink.unbounded_send(notification.clone()).is_ok());
			}

Gav Wood's avatar
Gav Wood committed
			let notification = BlockImportNotification::<Block> {
				hash,
				origin,
				header,
				is_new_best,
Tomasz Drwięga's avatar
Tomasz Drwięga committed
			self.import_notification_sinks.lock()
				.retain(|sink| sink.unbounded_send(notification.clone()).is_ok());
Gav Wood's avatar
Gav Wood committed
		Ok(ImportResult::Queued)
	}

	/// Finalizes all blocks up to given.
	fn apply_finality(&self, block: Block::Hash, best_block: Block::Hash, notify: bool) -> error::Result<()> {
		// find tree route from last finalized to given block.
		let last_finalized = self.backend.blockchain().last_finalized()?;

		if block == last_finalized { return Ok(()) }
		let route_from_finalized = ::blockchain::tree_route(
			self.backend.blockchain(),
			BlockId::Hash(last_finalized),
			BlockId::Hash(block),
		)?;

		if let Some(retracted) = route_from_finalized.retracted().get(0) {
			warn!("Safety violation: attempted to revert finalized block {:?} which is not in the \
				same chain as last finalized {:?}", retracted, last_finalized);

			bail!(error::ErrorKind::NotInFinalizedChain);
		}

		let route_from_best = ::blockchain::tree_route(
			self.backend.blockchain(),
			BlockId::Hash(best_block),
			BlockId::Hash(block),
		)?;

		// if the block is not a direct ancestor of the current best chain,
		// then some other block is the common ancestor.
		if route_from_best.common_block().hash != block {
			// TODO: reorganize best block to be the best chain containing
			// `block`.
		}

		for finalize_new in route_from_finalized.enacted() {
			self.backend.finalize_block(BlockId::Hash(finalize_new.hash))?;
		}

		if notify {
			// sometimes when syncing, tons of blocks can be finalized at once.
			// we'll send notifications spuriously in that case.
			const MAX_TO_NOTIFY: usize = 256;
			let enacted = route_from_finalized.enacted();
			let start = enacted.len() - ::std::cmp::min(enacted.len(), MAX_TO_NOTIFY);
			let mut sinks = self.finality_notification_sinks.lock();
			for finalized in &enacted[start..] {
				let header = self.header(&BlockId::Hash(finalized.hash))?
					.expect("header already known to exist in DB because it is indicated in the tree route; qed");
				let notification = FinalityNotification {
					header,
					hash: finalized.hash,
				};

				sinks.retain(|sink| sink.unbounded_send(notification.clone()).is_ok());
			}
		}

		Ok(())
	}

	/// Finalize a block. This will implicitly finalize all blocks up to it and
	/// fire finality notifications.
	///
	/// Pass a flag to indicate whether finality notifications should be propagated.
	/// This is usually tied to some synchronization state, where we don't send notifications
	/// while performing major synchronization work.
	pub fn finalize_block(&self, id: BlockId<Block>, notify: bool) -> error::Result<()> {
		let last_best = self.backend.blockchain().info()?.best_hash;
		let to_finalize_hash = match id {
			BlockId::Hash(h) => h,
			BlockId::Number(n) => self.backend.blockchain().hash(n)?
				.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("No block with number {:?}", n)))?,
		};

		self.apply_finality(to_finalize_hash, last_best, notify)
	}

	/// Attempts to revert the chain by `n` blocks. Returns the number of blocks that were
	/// successfully reverted.
	pub fn revert(&self, n: NumberFor<Block>) -> error::Result<NumberFor<Block>> {
		Ok(self.backend.revert(n)?)
	}

Gav Wood's avatar
Gav Wood committed
	/// Get blockchain info.
Gav Wood's avatar
Gav Wood committed
	pub fn info(&self) -> error::Result<ClientInfo<Block>> {
Gav Wood's avatar
Gav Wood committed
		let info = self.backend.blockchain().info().map_err(|e| error::Error::from_blockchain(Box::new(e)))?;
		Ok(ClientInfo {
			chain: info,
			best_queued_hash: None,
			best_queued_number: None,
		})
	}

	/// Get block status.
Gav Wood's avatar
Gav Wood committed
	pub fn block_status(&self, id: &BlockId<Block>) -> error::Result<BlockStatus> {
Gav Wood's avatar
Gav Wood committed
		// TODO: more efficient implementation
		if let BlockId::Hash(ref h) = id {
			if self.importing_block.read().as_ref().map_or(false, |importing| h == importing) {
				return Ok(BlockStatus::Queued);
			}
		}
Gav Wood's avatar
Gav Wood committed
		match self.backend.blockchain().header(*id).map_err(|e| error::Error::from_blockchain(Box::new(e)))?.is_some() {
			true => Ok(BlockStatus::InChain),
			false => Ok(BlockStatus::Unknown),
		}
	}

	/// Get block hash by number.
Gav Wood's avatar
Gav Wood committed
	pub fn block_hash(&self, block_number: <<Block as BlockT>::Header as HeaderT>::Number) -> error::Result<Option<Block::Hash>> {
Gav Wood's avatar
Gav Wood committed
		self.backend.blockchain().hash(block_number)
	}

	/// Convert an arbitrary block ID into a block hash.
Gav Wood's avatar
Gav Wood committed
	pub fn block_hash_from_id(&self, id: &BlockId<Block>) -> error::Result<Option<Block::Hash>> {
Gav Wood's avatar
Gav Wood committed
		match *id {
			BlockId::Hash(h) => Ok(Some(h)),
			BlockId::Number(n) => self.block_hash(n),
		}
	}

	/// Convert an arbitrary block ID into a block hash.
	pub fn block_number_from_id(&self, id: &BlockId<Block>) -> error::Result<Option<NumberFor<Block>>> {
Gav Wood's avatar
Gav Wood committed
		match *id {
Gav Wood's avatar
Gav Wood committed
			BlockId::Hash(_) => Ok(self.header(id)?.map(|h| h.number().clone())),
Gav Wood's avatar
Gav Wood committed
			BlockId::Number(n) => Ok(Some(n)),
		}
	}

	/// Convert an arbitrary block ID into a block hash, returning error if the block is unknown.
	fn require_block_number_from_id(&self, id: &BlockId<Block>) -> error::Result<NumberFor<Block>> {
		self.block_number_from_id(id)
			.and_then(|n| n.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{}", id)).into()))
	}

Gav Wood's avatar
Gav Wood committed
	/// Get block header by id.
Gav Wood's avatar
Gav Wood committed
	pub fn header(&self, id: &BlockId<Block>) -> error::Result<Option<<Block as BlockT>::Header>> {
Gav Wood's avatar
Gav Wood committed
		self.backend.blockchain().header(*id)
	}

	/// Get block body by id.
Gav Wood's avatar
Gav Wood committed
	pub fn body(&self, id: &BlockId<Block>) -> error::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
Gav Wood's avatar
Gav Wood committed
		self.backend.blockchain().body(*id)
	}

	/// Get block justification set by id.
Gav Wood's avatar
Gav Wood committed
	pub fn justification(&self, id: &BlockId<Block>) -> error::Result<Option<Justification<Block::Hash>>> {
Gav Wood's avatar
Gav Wood committed
		self.backend.blockchain().justification(*id)
	}
	/// Get full block by id.
	pub fn block(&self, id: &BlockId<Block>) -> error::Result<Option<SignedBlock<Block::Header, Block::Extrinsic, Block::Hash>>> {
		Ok(match (self.header(id)?, self.body(id)?, self.justification(id)?) {
			(Some(header), Some(extrinsics), Some(justification)) =>
				Some(SignedBlock { block: RuntimeBlock { header, extrinsics }, justification }),
			_ => None,
		})
	}

	/// Get best block header.
Gav Wood's avatar
Gav Wood committed
	pub fn best_block_header(&self) -> error::Result<<Block as BlockT>::Header> {
		let info = self.backend.blockchain().info().map_err(|e| error::Error::from_blockchain(Box::new(e)))?;
		Ok(self.header(&BlockId::Hash(info.best_hash))?.expect("Best block header must always exist"))
	}

	/// Get the most recent block hash of the best (longest) chains
	/// that contain block with the given `target_hash`.
	/// If `maybe_max_block_number` is `Some(max_block_number)`
	/// the search is limited to block `numbers <= max_block_number`.
	/// in other words as if there were no blocks greater `max_block_number`.
	/// TODO [snd] possibly implement this on blockchain::Backend and just redirect here
	/// Returns `Ok(None)` if `target_hash` is not found in search space.
	/// TODO [snd] write down time complexity
	pub fn best_containing(&self, target_hash: Block::Hash, maybe_max_number: Option<NumberFor<Block>>) -> error::Result<Option<Block::Hash>> {
		let target_header = {
			match self.backend.blockchain().header(BlockId::Hash(target_hash))? {
				Some(x) => x,
				// target not in blockchain
				None => { return Ok(None); },
			}
		};

		if let Some(max_number) = maybe_max_number {
			// target outside search range
			if target_header.number() > &max_number {
				return Ok(None);
			}
		}

		let (leaves, best_already_checked) = {
			// ensure no blocks are imported during this code block.
			// an import could trigger a reorg which could change the canonical chain.
			// we depend on the canonical chain staying the same during this code block.
			let _import_lock = self.import_lock.lock();

			let info = self.backend.blockchain().info()?;

			let canon_hash = self.backend.blockchain().hash(*target_header.number())?
				.ok_or_else(|| error::Error::from(format!("failed to get hash for block number {}", target_header.number())))?;

			if canon_hash == target_hash {
				if let Some(max_number) = maybe_max_number {
					// something has to guarantee that max_number is in chain
					return Ok(Some(self.backend.blockchain().hash(max_number)?.ok_or_else(|| error::Error::from(format!("failed to get hash for block number {}", max_number)))?));
				} else {
					return Ok(Some(info.best_hash));
				}
			}
			(self.backend.blockchain().leaves()?, info.best_hash)
		};

		// for each chain. longest chain first. shortest last
		for leaf_hash in leaves {
			// ignore canonical chain which we already checked above
			if leaf_hash == best_already_checked {
				continue;
			}

			// start at the leaf
			let mut current_hash = leaf_hash;

			// if search is not restricted then the leaf is the best
			let mut best_hash = leaf_hash;

			// go backwards entering the search space
			// waiting until we are <= max_number
			if let Some(max_number) = maybe_max_number {
				loop {
					// TODO [snd] this should be a panic
					let current_header = self.backend.blockchain().header(BlockId::Hash(current_hash.clone()))?
						.ok_or_else(|| error::Error::from(format!("failed to get header for hash {}", current_hash)))?;

					if current_header.number() <= &max_number {
						best_hash = current_header.hash();
						break;
					}

					current_hash = *current_header.parent_hash();
				}
			}

			// go backwards through the chain (via parent links)
			loop {
				// until we find target
				if current_hash == target_hash {
					return Ok(Some(best_hash));
				}

				// TODO [snd] this should be a panic
				let current_header = self.backend.blockchain().header(BlockId::Hash(current_hash.clone()))?
					.ok_or_else(|| error::Error::from(format!("failed to get header for hash {}", current_hash)))?;

				// stop search in this chain once we go below the target's block number
				if current_header.number() < target_header.number() {
					break;
				}

				current_hash = *current_header.parent_hash();
			}
		}

		unreachable!("this is a bug. `target_hash` is in blockchain but wasn't found following all leaves backwards");
	}
impl<B, E, Block> CurrentHeight for Client<B, E, Block> where
	B: backend::Backend<Block, Blake2Hasher>,
	E: CallExecutor<Block, Blake2Hasher> + Clone,
Gav Wood's avatar
Gav Wood committed
	Block: BlockT,
{
	type BlockNumber = <Block::Header as HeaderT>::Number;
	fn current_height(&self) -> Self::BlockNumber {
Gav Wood's avatar
Gav Wood committed
		self.backend.blockchain().info().map(|i| i.best_number).unwrap_or_else(|_| Zero::zero())
	}
}

impl<B, E, Block> BlockNumberToHash for Client<B, E, Block> where
	B: backend::Backend<Block, Blake2Hasher>,
	E: CallExecutor<Block, Blake2Hasher> + Clone,
Gav Wood's avatar
Gav Wood committed
	Block: BlockT,
{
	type BlockNumber = <Block::Header as HeaderT>::Number;
	type Hash = Block::Hash;
	fn block_number_to_hash(&self, n: Self::BlockNumber) -> Option<Self::Hash> {
		self.block_hash(n).unwrap_or(None)
	}
}

Gav Wood's avatar
Gav Wood committed
impl<B, E, Block> bft::BlockImport<Block> for Client<B, E, Block>
Gav Wood's avatar
Gav Wood committed
	where
		B: backend::Backend<Block, Blake2Hasher>,
		E: CallExecutor<Block, Blake2Hasher>,
Gav Wood's avatar
Gav Wood committed
		Block: BlockT,
	fn import_block(
		&self,
		block: Block,
		justification: ::bft::Justification<Block::Hash>,
		authorities: &[AuthorityId],
Gav Wood's avatar
Gav Wood committed
		let (header, extrinsics) = block.deconstruct();
Gav Wood's avatar
Gav Wood committed
		let justified_header = JustifiedHeader {
Gav Wood's avatar
Gav Wood committed
			header: header,
Gav Wood's avatar
Gav Wood committed
			justification,
			authorities: authorities.to_vec(),
		// TODO [rob]: non-instant finality.
		self.import_block(
			BlockOrigin::ConsensusBroadcast,
			justified_header,
			Some(extrinsics),
			true
		).is_ok()
Gav Wood's avatar
Gav Wood committed
impl<B, E, Block> bft::Authorities<Block> for Client<B, E, Block>
Gav Wood's avatar
Gav Wood committed
	where
		B: backend::Backend<Block, Blake2Hasher>,
		E: CallExecutor<Block, Blake2Hasher>,
Gav Wood's avatar
Gav Wood committed
		Block: BlockT,
Gav Wood's avatar
Gav Wood committed
	fn authorities(&self, at: &BlockId<Block>) -> Result<Vec<AuthorityId>, bft::Error> {
Gav Wood's avatar
Gav Wood committed
		let on_chain_version: Result<_, bft::Error> = self.runtime_version_at(at)
			.map_err(|e| { trace!("Error getting runtime version {:?}", e); bft::ErrorKind::RuntimeVersionMissing.into() });
		let on_chain_version = on_chain_version?;
		let native_version: Result<_, bft::Error> = self.executor.native_runtime_version()
			.ok_or_else(|| bft::ErrorKind::NativeRuntimeMissing.into());
		let native_version = native_version?;
		if !native_version.can_author_with(&on_chain_version) {
			return Err(bft::ErrorKind::IncompatibleAuthoringRuntime(on_chain_version, native_version.runtime_version.clone()).into())
Gav Wood's avatar
Gav Wood committed
		self.authorities_at(at).map_err(|_| {
			let descriptor = format!("{:?}", at);
			bft::ErrorKind::StateUnavailable(descriptor).into()
		})
Gav Wood's avatar
Gav Wood committed
impl<B, E, Block> BlockchainEvents<Block> for Client<B, E, Block>