Skip to content
client.rs 92.2 KiB
Newer Older
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
Gav Wood's avatar
Gav Wood committed
// 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::{
	marker::PhantomData, collections::{HashSet, BTreeMap, HashMap}, sync::Arc,
	panic::UnwindSafe, result, cell::RefCell,
use log::{info, trace, warn};
use parking_lot::{Mutex, RwLock};
use codec::{Encode, Decode};
use hash_db::{Hasher, Prefix};
use primitives::{
	Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash,
	NeverNativeValue, ExecutionContext, NativeOrEncoded,
	storage::{StorageKey, StorageData, well_known_keys},
	traits::CodeExecutor,
};
use substrate_telemetry::{telemetry, SUBSTRATE_INFO};
use sr_primitives::{
	Justification, BuildStorage,
	generic::{BlockId, SignedBlock, DigestItem},
	traits::{
		Block as BlockT, Header as HeaderT, Zero, NumberFor,
		ApiRef, ProvideRuntimeApi, SaturatedConversion, One, DigestFor,
	},
	DBValue, Backend as StateBackend, ChangesTrieAnchorBlockId, ExecutionStrategy, ExecutionManager,
	prove_read, prove_child_read, ChangesTrieRootsStorage, ChangesTrieStorage,
	ChangesTrieTransaction, ChangesTrieConfigurationRange, key_changes, key_changes_proof,
	OverlayedChanges, BackendTrustLevel, StorageProof, merge_storage_proofs,
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
use executor::{RuntimeVersion, RuntimeInfo};
use consensus::{
	Error as ConsensusError, BlockStatus, BlockImportParams, BlockCheckParams,
	ImportResult, BlockOrigin, ForkChoiceStrategy,
	SelectChain, self,
};
use sp_blockchain::{self as blockchain,
	Backend as ChainBackend,
	HeaderBackend as ChainHeaderBackend, ProvideCache, Cache,
	well_known_cache_keys::Id as CacheKeyId,
	HeaderMetadata, CachedHeaderMetadata,
};
use sr_api::{CallRuntimeAt, ConstructRuntimeApi, Core as CoreApi, ProofRecorder, InitializeBlock};
use block_builder::BlockBuilderApi;

	backend::{
		self, BlockImportOperation, PrunableStateChangesTrieStorage,
		ClientImportOperation, Finalizer, ImportSummary, NewBlockState,
	client::{
		ImportNotifications, FinalityNotification, FinalityNotifications, BlockImportNotification,
		ClientInfo, BlockchainEvents, BlockBody, ProvideUncles, ForkBlocks,
	execution_extensions::{ExecutionExtensions, ExecutionStrategies},
	notifications::{StorageNotifications, StorageEventStream},
	CallExecutor,
use crate::{
	call_executor::LocalCallExecutor,
	light::{call_executor::prove_execution, fetcher::ChangesProof},
	in_mem, genesis, cht,
};
Gavin Wood's avatar
Gavin Wood committed
type StorageUpdate<B, Block> = <
	<
		<B as backend::Backend<Block, Blake2Hasher>>::BlockImportOperation
			as BlockImportOperation<Block, Blake2Hasher>
	>::State as state_machine::Backend<Blake2Hasher>>::Transaction;
type ChangesUpdate<Block> = ChangesTrieTransaction<Blake2Hasher, NumberFor<Block>>;
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
/// Substrate Client
pub struct Client<B, E, Block, RA> 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>>>>,
	// holds the block hash currently being imported. TODO: replace this with block queue
	importing_block: RwLock<Option<Block::Hash>>,
	fork_blocks: ForkBlocks<Block>,
	execution_extensions: ExecutionExtensions<Block>,
// used in importing a block, where additional changes are made after the runtime
// executed.
enum PrePostHeader<H> {
	// they are the same: no post-runtime digest items.
	Same(H),
	// different headers (pre, post).
	Different(H, H),
}

impl<H> PrePostHeader<H> {
	// get a reference to the "pre-header" -- the header as it should be just after the runtime.
	fn pre(&self) -> &H {
		match *self {
			PrePostHeader::Same(ref h) => h,
			PrePostHeader::Different(ref h, _) => h,
		}
	}

	// get a reference to the "post-header" -- the header as it should be after all changes are applied.
	fn post(&self) -> &H {
		match *self {
			PrePostHeader::Same(ref h) => h,
			PrePostHeader::Different(_, ref h) => h,
		}
	}

	// convert to the "post-header" -- the header as it should be after all changes are applied.
	fn into_post(self) -> H {
		match self {
			PrePostHeader::Same(h) => h,
			PrePostHeader::Different(_, h) => h,
		}
	}
}

Gav Wood's avatar
Gav Wood committed
/// Create an instance of in-memory client.
pub fn new_in_mem<E, Block, S, RA>(
Gav Wood's avatar
Gav Wood committed
	executor: E,
Gav Wood's avatar
Gav Wood committed
	genesis_storage: S,
	keystore: Option<primitives::traits::BareCryptoStorePtr>,
Gavin Wood's avatar
Gavin Wood committed
	in_mem::Backend<Block, Blake2Hasher>,
	LocalCallExecutor<in_mem::Backend<Block, Blake2Hasher>, E>,
	Block,
	RA
>> where
	E: CodeExecutor + RuntimeInfo,
Gavin Wood's avatar
Gavin Wood committed
	S: BuildStorage,
	Block: BlockT<Hash=H256>,
	new_with_backend(Arc::new(in_mem::Backend::new()), executor, genesis_storage, keystore)
/// Create a client with the explicitly provided backend.
/// This is useful for testing backend implementations.
pub fn new_with_backend<B, E, Block, S, RA>(
	backend: Arc<B>,
	executor: E,
	build_genesis_storage: S,
	keystore: Option<primitives::traits::BareCryptoStorePtr>,
) -> sp_blockchain::Result<Client<B, LocalCallExecutor<B, E>, Block, RA>>
		E: CodeExecutor + RuntimeInfo,
		S: BuildStorage,
		Block: BlockT<Hash=H256>,
		B: backend::LocalBackend<Block, Blake2Hasher>
	let call_executor = LocalCallExecutor::new(backend.clone(), executor);
	let extensions = ExecutionExtensions::new(Default::default(), keystore);
	Client::new(backend, call_executor, build_genesis_storage, Default::default(), extensions)
impl<B, E, Block, RA> BlockOf for Client<B, E, Block, RA> where
	B: backend::Backend<Block, Blake2Hasher>,
	E: CallExecutor<Block, Blake2Hasher>,
	Block: BlockT<Hash=H256>,
{
	type Type = Block;
}

impl<B, E, Block, RA> Client<B, E, Block, RA> where
	B: backend::Backend<Block, Blake2Hasher>,
	E: CallExecutor<Block, Blake2Hasher>,
	Block: BlockT<Hash=H256>,
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,
		fork_blocks: ForkBlocks<Block>,
		execution_extensions: ExecutionExtensions<Block>,
Loading full blame...