Skip to content
client.rs 79.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, rc::Rc,
};
use crate::error::Error;
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
use futures::sync::mpsc;
use parking_lot::{Mutex, RwLock};
use primitives::NativeOrEncoded;
use runtime_primitives::{
	generic::{BlockId, SignedBlock},
	Error as ConsensusError, ErrorKind as ConsensusErrorKind, ImportBlock,
	ImportResult, BlockOrigin, ForkChoiceStrategy,
	well_known_cache_keys::Id as CacheKeyId,
use runtime_primitives::traits::{
	Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight,
	BlockNumberToHash, ApiRef, ProvideRuntimeApi, Digest, DigestItem
use runtime_primitives::BuildStorage;
use crate::runtime_api::{
	CallRuntimeAt, ConstructRuntimeApi, Core as CoreApi, ProofRecorder,
	InitializeBlock,
};
use primitives::{
	Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash,
	NeverNativeValue, ExecutionContext
};
Gav Wood's avatar
Gav Wood committed
use primitives::storage::{StorageKey, StorageData};
use primitives::storage::well_known_keys;
use parity_codec::{Encode, Decode};
	DBValue, Backend as StateBackend, CodeExecutor, ChangesTrieAnchorBlockId,
cheme's avatar
cheme committed
	ExecutionStrategy, ExecutionManager, prove_read, prove_child_read,
	ChangesTrieRootsStorage, ChangesTrieStorage,
	key_changes, key_changes_proof, OverlayedChanges, NeverOffchainExt,
use crate::backend::{self, BlockImportOperation, PrunableStateChangesTrieStorage};
use crate::blockchain::{
	self, Info as ChainInfo, Backend as ChainBackend,
	HeaderBackend as ChainHeaderBackend, ProvideCache, Cache,
use crate::call_executor::{CallExecutor, LocalCallExecutor};
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
use executor::{RuntimeVersion, RuntimeInfo};
use crate::notifications::{StorageNotifications, StorageEventStream};
use crate::light::{call_executor::prove_execution, fetcher::ChangesProof};
use crate::cht;
use crate::error;
use crate::in_mem;
use crate::block_builder::{self, api::BlockBuilder as BlockBuilderAPI};
use crate::genesis;
use substrate_telemetry::{telemetry, SUBSTRATE_INFO};

use log::{info, trace, warn};
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>>;
type StorageUpdate<B, Block> = <<<B as backend::Backend<Block, Blake2Hasher>>::BlockImportOperation as BlockImportOperation<Block, Blake2Hasher>>::State as state_machine::Backend<Blake2Hasher>>::Transaction;
type ChangesUpdate = trie::MemoryDB<Blake2Hasher>;

/// Execution strategies settings.
#[derive(Debug, Clone)]
pub struct ExecutionStrategies {
	/// Execution strategy used when syncing.
	pub syncing: ExecutionStrategy,
	/// Execution strategy used when importing blocks.
	pub importing: ExecutionStrategy,
	/// Execution strategy used when constructing blocks.
	pub block_construction: ExecutionStrategy,
	/// Execution strategy used for offchain workers.
	pub offchain_worker: ExecutionStrategy,
	/// Execution strategy used in other cases.
	pub other: ExecutionStrategy,
}

impl Default for ExecutionStrategies {
	fn default() -> ExecutionStrategies {
		ExecutionStrategies {
			syncing: ExecutionStrategy::NativeElseWasm,
			importing: ExecutionStrategy::NativeElseWasm,
			block_construction: ExecutionStrategy::AlwaysWasm,
			offchain_worker: ExecutionStrategy::NativeWhenPossible,
			other: ExecutionStrategy::NativeElseWasm,
		}
	}
}

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>>>>,
	import_lock: Arc<Mutex<()>>,
	// holds the block hash currently being imported. TODO: replace this with block queue
	importing_block: RwLock<Option<Block::Hash>>,
	execution_strategies: ExecutionStrategies,
/// Client import operation, a wrapper for the backend.
pub struct ClientImportOperation<Block: BlockT, H: Hasher<Out=Block::Hash>, B: backend::Backend<Block, H>> {
	op: B::BlockImportOperation,
	notify_imported: Option<(Block::Hash, BlockOrigin, Block::Header, bool, Option<Vec<(Vec<u8>, Option<Vec<u8>>)>>)>,
	notify_finalized: Vec<Block::Hash>,
}

/// 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>>;
/// 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
#[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 status.
#[derive(Debug, PartialEq, Eq)]
pub enum BlockStatus {
	/// Added to the import queue.
	Queued,
	/// Already in the blockchain and the state is available.
	InChainWithState,
	/// In the blockchain, but the state is not available.
	InChainPruned,
Gav Wood's avatar
Gav Wood committed
	/// Block or parent is known to be bad.
	KnownBad,
	/// Not in the queue or the blockchain.
	Unknown,
}

Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
/// 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.
Loading full blame...