sc_client_api/
backend.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Substrate Client data backend
20
21use std::collections::HashSet;
22
23use parking_lot::RwLock;
24
25use sp_consensus::BlockOrigin;
26use sp_core::offchain::OffchainStorage;
27use sp_runtime::{
28	traits::{Block as BlockT, HashingFor, NumberFor},
29	Justification, Justifications, StateVersion, Storage,
30};
31use sp_state_machine::{
32	backend::AsTrieBackend, ChildStorageCollection, IndexOperation, IterArgs,
33	OffchainChangesCollection, StorageCollection, StorageIterator,
34};
35use sp_storage::{ChildInfo, StorageData, StorageKey};
36pub use sp_trie::MerkleValue;
37
38use crate::{blockchain::Backend as BlockchainBackend, UsageInfo};
39
40pub use sp_state_machine::{Backend as StateBackend, BackendTransaction, KeyValueStates};
41
42/// Extracts the state backend type for the given backend.
43pub type StateBackendFor<B, Block> = <B as Backend<Block>>::State;
44
45/// Describes which block import notification stream should be notified.
46#[derive(Debug, Clone, Copy)]
47pub enum ImportNotificationAction {
48	/// Notify only when the node has synced to the tip or there is a re-org.
49	RecentBlock,
50	/// Notify for every single block no matter what the sync state is.
51	EveryBlock,
52	/// Both block import notifications above should be fired.
53	Both,
54	/// No block import notification should be fired.
55	None,
56}
57
58/// Import operation summary.
59///
60/// Contains information about the block that just got imported,
61/// including storage changes, reorged blocks, etc.
62pub struct ImportSummary<Block: BlockT> {
63	/// Block hash of the imported block.
64	pub hash: Block::Hash,
65	/// Import origin.
66	pub origin: BlockOrigin,
67	/// Header of the imported block.
68	pub header: Block::Header,
69	/// Is this block a new best block.
70	pub is_new_best: bool,
71	/// Optional storage changes.
72	pub storage_changes: Option<(StorageCollection, ChildStorageCollection)>,
73	/// Tree route from old best to new best.
74	///
75	/// If `None`, there was no re-org while importing.
76	pub tree_route: Option<sp_blockchain::TreeRoute<Block>>,
77	/// What notify action to take for this import.
78	pub import_notification_action: ImportNotificationAction,
79}
80
81/// Finalization operation summary.
82///
83/// Contains information about the block that just got finalized,
84/// including tree heads that became stale at the moment of finalization.
85pub struct FinalizeSummary<Block: BlockT> {
86	/// Last finalized block header.
87	pub header: Block::Header,
88	/// Blocks that were finalized.
89	/// The last entry is the one that has been explicitly finalized.
90	pub finalized: Vec<Block::Hash>,
91	/// Heads that became stale during this finalization operation.
92	pub stale_heads: Vec<Block::Hash>,
93}
94
95/// Import operation wrapper.
96pub struct ClientImportOperation<Block: BlockT, B: Backend<Block>> {
97	/// DB Operation.
98	pub op: B::BlockImportOperation,
99	/// Summary of imported block.
100	pub notify_imported: Option<ImportSummary<Block>>,
101	/// Summary of finalized block.
102	pub notify_finalized: Option<FinalizeSummary<Block>>,
103}
104
105/// Helper function to apply auxiliary data insertion into an operation.
106pub fn apply_aux<'a, 'b: 'a, 'c: 'a, B, Block, D, I>(
107	operation: &mut ClientImportOperation<Block, B>,
108	insert: I,
109	delete: D,
110) -> sp_blockchain::Result<()>
111where
112	Block: BlockT,
113	B: Backend<Block>,
114	I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
115	D: IntoIterator<Item = &'a &'b [u8]>,
116{
117	operation.op.insert_aux(
118		insert
119			.into_iter()
120			.map(|(k, v)| (k.to_vec(), Some(v.to_vec())))
121			.chain(delete.into_iter().map(|k| (k.to_vec(), None))),
122	)
123}
124
125/// State of a new block.
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127pub enum NewBlockState {
128	/// Normal block.
129	Normal,
130	/// New best block.
131	Best,
132	/// Newly finalized block (implicitly best).
133	Final,
134}
135
136impl NewBlockState {
137	/// Whether this block is the new best block.
138	pub fn is_best(self) -> bool {
139		match self {
140			NewBlockState::Best | NewBlockState::Final => true,
141			NewBlockState::Normal => false,
142		}
143	}
144
145	/// Whether this block is considered final.
146	pub fn is_final(self) -> bool {
147		match self {
148			NewBlockState::Final => true,
149			NewBlockState::Best | NewBlockState::Normal => false,
150		}
151	}
152}
153
154/// Block insertion operation.
155///
156/// Keeps hold if the inserted block state and data.
157pub trait BlockImportOperation<Block: BlockT> {
158	/// Associated state backend type.
159	type State: StateBackend<HashingFor<Block>>;
160
161	/// Returns pending state.
162	///
163	/// Returns None for backends with locally-unavailable state data.
164	fn state(&self) -> sp_blockchain::Result<Option<&Self::State>>;
165
166	/// Append block data to the transaction.
167	fn set_block_data(
168		&mut self,
169		header: Block::Header,
170		body: Option<Vec<Block::Extrinsic>>,
171		indexed_body: Option<Vec<Vec<u8>>>,
172		justifications: Option<Justifications>,
173		state: NewBlockState,
174	) -> sp_blockchain::Result<()>;
175
176	/// Inject storage data into the database.
177	fn update_db_storage(
178		&mut self,
179		update: BackendTransaction<HashingFor<Block>>,
180	) -> sp_blockchain::Result<()>;
181
182	/// Set genesis state. If `commit` is `false` the state is saved in memory, but is not written
183	/// to the database.
184	fn set_genesis_state(
185		&mut self,
186		storage: Storage,
187		commit: bool,
188		state_version: StateVersion,
189	) -> sp_blockchain::Result<Block::Hash>;
190
191	/// Inject storage data into the database replacing any existing data.
192	fn reset_storage(
193		&mut self,
194		storage: Storage,
195		state_version: StateVersion,
196	) -> sp_blockchain::Result<Block::Hash>;
197
198	/// Set storage changes.
199	fn update_storage(
200		&mut self,
201		update: StorageCollection,
202		child_update: ChildStorageCollection,
203	) -> sp_blockchain::Result<()>;
204
205	/// Write offchain storage changes to the database.
206	fn update_offchain_storage(
207		&mut self,
208		_offchain_update: OffchainChangesCollection,
209	) -> sp_blockchain::Result<()> {
210		Ok(())
211	}
212
213	/// Insert auxiliary keys.
214	///
215	/// Values are `None` if should be deleted.
216	fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()>
217	where
218		I: IntoIterator<Item = (Vec<u8>, Option<Vec<u8>>)>;
219
220	/// Mark a block as finalized, if multiple blocks are finalized in the same operation then they
221	/// must be marked in ascending order.
222	fn mark_finalized(
223		&mut self,
224		hash: Block::Hash,
225		justification: Option<Justification>,
226	) -> sp_blockchain::Result<()>;
227
228	/// Mark a block as new head. If both block import and set head are specified, set head
229	/// overrides block import's best block rule.
230	fn mark_head(&mut self, hash: Block::Hash) -> sp_blockchain::Result<()>;
231
232	/// Add a transaction index operation.
233	fn update_transaction_index(&mut self, index: Vec<IndexOperation>)
234		-> sp_blockchain::Result<()>;
235
236	/// Configure whether to create a block gap if newly imported block is missing parent
237	fn set_create_gap(&mut self, create_gap: bool);
238}
239
240/// Interface for performing operations on the backend.
241pub trait LockImportRun<Block: BlockT, B: Backend<Block>> {
242	/// Lock the import lock, and run operations inside.
243	fn lock_import_and_run<R, Err, F>(&self, f: F) -> Result<R, Err>
244	where
245		F: FnOnce(&mut ClientImportOperation<Block, B>) -> Result<R, Err>,
246		Err: From<sp_blockchain::Error>;
247}
248
249/// Finalize Facilities
250pub trait Finalizer<Block: BlockT, B: Backend<Block>> {
251	/// Mark all blocks up to given as finalized in operation.
252	///
253	/// If `justification` is provided it is stored with the given finalized
254	/// block (any other finalized blocks are left unjustified).
255	///
256	/// If the block being finalized is on a different fork from the current
257	/// best block the finalized block is set as best, this might be slightly
258	/// inaccurate (i.e. outdated). Usages that require determining an accurate
259	/// best block should use `SelectChain` instead of the client.
260	fn apply_finality(
261		&self,
262		operation: &mut ClientImportOperation<Block, B>,
263		block: Block::Hash,
264		justification: Option<Justification>,
265		notify: bool,
266	) -> sp_blockchain::Result<()>;
267
268	/// Finalize a block.
269	///
270	/// This will implicitly finalize all blocks up to it and
271	/// fire finality notifications.
272	///
273	/// If the block being finalized is on a different fork from the current
274	/// best block, the finalized block is set as best. This might be slightly
275	/// inaccurate (i.e. outdated). Usages that require determining an accurate
276	/// best block should use `SelectChain` instead of the client.
277	///
278	/// Pass a flag to indicate whether finality notifications should be propagated.
279	/// This is usually tied to some synchronization state, where we don't send notifications
280	/// while performing major synchronization work.
281	fn finalize_block(
282		&self,
283		block: Block::Hash,
284		justification: Option<Justification>,
285		notify: bool,
286	) -> sp_blockchain::Result<()>;
287}
288
289/// Provides access to an auxiliary database.
290///
291/// This is a simple global database not aware of forks. Can be used for storing auxiliary
292/// information like total block weight/difficulty for fork resolution purposes as a common use
293/// case.
294pub trait AuxStore {
295	/// Insert auxiliary data into key-value store.
296	///
297	/// Deletions occur after insertions.
298	fn insert_aux<
299		'a,
300		'b: 'a,
301		'c: 'a,
302		I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
303		D: IntoIterator<Item = &'a &'b [u8]>,
304	>(
305		&self,
306		insert: I,
307		delete: D,
308	) -> sp_blockchain::Result<()>;
309
310	/// Query auxiliary data from key-value store.
311	fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>>;
312}
313
314/// An `Iterator` that iterates keys in a given block under a prefix.
315pub struct KeysIter<State, Block>
316where
317	State: StateBackend<HashingFor<Block>>,
318	Block: BlockT,
319{
320	inner: <State as StateBackend<HashingFor<Block>>>::RawIter,
321	state: State,
322}
323
324impl<State, Block> KeysIter<State, Block>
325where
326	State: StateBackend<HashingFor<Block>>,
327	Block: BlockT,
328{
329	/// Create a new iterator over storage keys.
330	pub fn new(
331		state: State,
332		prefix: Option<&StorageKey>,
333		start_at: Option<&StorageKey>,
334	) -> Result<Self, State::Error> {
335		let mut args = IterArgs::default();
336		args.prefix = prefix.as_ref().map(|prefix| prefix.0.as_slice());
337		args.start_at = start_at.as_ref().map(|start_at| start_at.0.as_slice());
338		args.start_at_exclusive = true;
339
340		Ok(Self { inner: state.raw_iter(args)?, state })
341	}
342
343	/// Create a new iterator over a child storage's keys.
344	pub fn new_child(
345		state: State,
346		child_info: ChildInfo,
347		prefix: Option<&StorageKey>,
348		start_at: Option<&StorageKey>,
349	) -> Result<Self, State::Error> {
350		let mut args = IterArgs::default();
351		args.prefix = prefix.as_ref().map(|prefix| prefix.0.as_slice());
352		args.start_at = start_at.as_ref().map(|start_at| start_at.0.as_slice());
353		args.child_info = Some(child_info);
354		args.start_at_exclusive = true;
355
356		Ok(Self { inner: state.raw_iter(args)?, state })
357	}
358}
359
360impl<State, Block> Iterator for KeysIter<State, Block>
361where
362	Block: BlockT,
363	State: StateBackend<HashingFor<Block>>,
364{
365	type Item = StorageKey;
366
367	fn next(&mut self) -> Option<Self::Item> {
368		self.inner.next_key(&self.state)?.ok().map(StorageKey)
369	}
370}
371
372/// An `Iterator` that iterates keys and values in a given block under a prefix.
373pub struct PairsIter<State, Block>
374where
375	State: StateBackend<HashingFor<Block>>,
376	Block: BlockT,
377{
378	inner: <State as StateBackend<HashingFor<Block>>>::RawIter,
379	state: State,
380}
381
382impl<State, Block> Iterator for PairsIter<State, Block>
383where
384	Block: BlockT,
385	State: StateBackend<HashingFor<Block>>,
386{
387	type Item = (StorageKey, StorageData);
388
389	fn next(&mut self) -> Option<Self::Item> {
390		self.inner
391			.next_pair(&self.state)?
392			.ok()
393			.map(|(key, value)| (StorageKey(key), StorageData(value)))
394	}
395}
396
397impl<State, Block> PairsIter<State, Block>
398where
399	State: StateBackend<HashingFor<Block>>,
400	Block: BlockT,
401{
402	/// Create a new iterator over storage key and value pairs.
403	pub fn new(
404		state: State,
405		prefix: Option<&StorageKey>,
406		start_at: Option<&StorageKey>,
407	) -> Result<Self, State::Error> {
408		let mut args = IterArgs::default();
409		args.prefix = prefix.as_ref().map(|prefix| prefix.0.as_slice());
410		args.start_at = start_at.as_ref().map(|start_at| start_at.0.as_slice());
411		args.start_at_exclusive = true;
412
413		Ok(Self { inner: state.raw_iter(args)?, state })
414	}
415}
416
417/// Provides access to storage primitives
418pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
419	/// Given a block's `Hash` and a key, return the value under the key in that block.
420	fn storage(
421		&self,
422		hash: Block::Hash,
423		key: &StorageKey,
424	) -> sp_blockchain::Result<Option<StorageData>>;
425
426	/// Given a block's `Hash` and a key, return the value under the hash in that block.
427	fn storage_hash(
428		&self,
429		hash: Block::Hash,
430		key: &StorageKey,
431	) -> sp_blockchain::Result<Option<Block::Hash>>;
432
433	/// Given a block's `Hash` and a key prefix, returns a `KeysIter` iterates matching storage
434	/// keys in that block.
435	fn storage_keys(
436		&self,
437		hash: Block::Hash,
438		prefix: Option<&StorageKey>,
439		start_key: Option<&StorageKey>,
440	) -> sp_blockchain::Result<KeysIter<B::State, Block>>;
441
442	/// Given a block's `Hash` and a key prefix, returns an iterator over the storage keys and
443	/// values in that block.
444	fn storage_pairs(
445		&self,
446		hash: <Block as BlockT>::Hash,
447		prefix: Option<&StorageKey>,
448		start_key: Option<&StorageKey>,
449	) -> sp_blockchain::Result<PairsIter<B::State, Block>>;
450
451	/// Given a block's `Hash`, a key and a child storage key, return the value under the key in
452	/// that block.
453	fn child_storage(
454		&self,
455		hash: Block::Hash,
456		child_info: &ChildInfo,
457		key: &StorageKey,
458	) -> sp_blockchain::Result<Option<StorageData>>;
459
460	/// Given a block's `Hash` and a key `prefix` and a child storage key,
461	/// returns a `KeysIter` that iterates matching storage keys in that block.
462	fn child_storage_keys(
463		&self,
464		hash: Block::Hash,
465		child_info: ChildInfo,
466		prefix: Option<&StorageKey>,
467		start_key: Option<&StorageKey>,
468	) -> sp_blockchain::Result<KeysIter<B::State, Block>>;
469
470	/// Given a block's `Hash`, a key and a child storage key, return the hash under the key in that
471	/// block.
472	fn child_storage_hash(
473		&self,
474		hash: Block::Hash,
475		child_info: &ChildInfo,
476		key: &StorageKey,
477	) -> sp_blockchain::Result<Option<Block::Hash>>;
478
479	/// Given a block's `Hash` and a key, return the closest merkle value.
480	fn closest_merkle_value(
481		&self,
482		hash: Block::Hash,
483		key: &StorageKey,
484	) -> sp_blockchain::Result<Option<MerkleValue<Block::Hash>>>;
485
486	/// Given a block's `Hash`, a key and a child storage key, return the closest merkle value.
487	fn child_closest_merkle_value(
488		&self,
489		hash: Block::Hash,
490		child_info: &ChildInfo,
491		key: &StorageKey,
492	) -> sp_blockchain::Result<Option<MerkleValue<Block::Hash>>>;
493}
494
495/// Client backend.
496///
497/// Manages the data layer.
498///
499/// # State Pruning
500///
501/// While an object from `state_at` is alive, the state
502/// should not be pruned. The backend should internally reference-count
503/// its state objects.
504///
505/// The same applies for live `BlockImportOperation`s: while an import operation building on a
506/// parent `P` is alive, the state for `P` should not be pruned.
507///
508/// # Block Pruning
509///
510/// Users can pin blocks in memory by calling `pin_block`. When
511/// a block would be pruned, its value is kept in an in-memory cache
512/// until it is unpinned via `unpin_block`.
513///
514/// While a block is pinned, its state is also preserved.
515///
516/// The backend should internally reference count the number of pin / unpin calls.
517pub trait Backend<Block: BlockT>: AuxStore + Send + Sync {
518	/// Associated block insertion operation type.
519	type BlockImportOperation: BlockImportOperation<Block, State = Self::State>;
520	/// Associated blockchain backend type.
521	type Blockchain: BlockchainBackend<Block>;
522	/// Associated state backend type.
523	type State: StateBackend<HashingFor<Block>>
524		+ Send
525		+ AsTrieBackend<
526			HashingFor<Block>,
527			TrieBackendStorage = <Self::State as StateBackend<HashingFor<Block>>>::TrieBackendStorage,
528		>;
529	/// Offchain workers local storage.
530	type OffchainStorage: OffchainStorage;
531
532	/// Begin a new block insertion transaction with given parent block id.
533	///
534	/// When constructing the genesis, this is called with all-zero hash.
535	fn begin_operation(&self) -> sp_blockchain::Result<Self::BlockImportOperation>;
536
537	/// Note an operation to contain state transition.
538	fn begin_state_operation(
539		&self,
540		operation: &mut Self::BlockImportOperation,
541		block: Block::Hash,
542	) -> sp_blockchain::Result<()>;
543
544	/// Commit block insertion.
545	fn commit_operation(
546		&self,
547		transaction: Self::BlockImportOperation,
548	) -> sp_blockchain::Result<()>;
549
550	/// Finalize block with given `hash`.
551	///
552	/// This should only be called if the parent of the given block has been finalized.
553	fn finalize_block(
554		&self,
555		hash: Block::Hash,
556		justification: Option<Justification>,
557	) -> sp_blockchain::Result<()>;
558
559	/// Append justification to the block with the given `hash`.
560	///
561	/// This should only be called for blocks that are already finalized.
562	fn append_justification(
563		&self,
564		hash: Block::Hash,
565		justification: Justification,
566	) -> sp_blockchain::Result<()>;
567
568	/// Returns reference to blockchain backend.
569	fn blockchain(&self) -> &Self::Blockchain;
570
571	/// Returns current usage statistics.
572	fn usage_info(&self) -> Option<UsageInfo>;
573
574	/// Returns a handle to offchain storage.
575	fn offchain_storage(&self) -> Option<Self::OffchainStorage>;
576
577	/// Pin the block to keep body, justification and state available after pruning.
578	/// Number of pins are reference counted. Users need to make sure to perform
579	/// one call to [`Self::unpin_block`] per call to [`Self::pin_block`].
580	fn pin_block(&self, hash: Block::Hash) -> sp_blockchain::Result<()>;
581
582	/// Unpin the block to allow pruning.
583	fn unpin_block(&self, hash: Block::Hash);
584
585	/// Returns true if state for given block is available.
586	fn have_state_at(&self, hash: Block::Hash, _number: NumberFor<Block>) -> bool {
587		self.state_at(hash).is_ok()
588	}
589
590	/// Returns state backend with post-state of given block.
591	fn state_at(&self, hash: Block::Hash) -> sp_blockchain::Result<Self::State>;
592
593	/// Attempts to revert the chain by `n` blocks. If `revert_finalized` is set it will attempt to
594	/// revert past any finalized block, this is unsafe and can potentially leave the node in an
595	/// inconsistent state. All blocks higher than the best block are also reverted and not counting
596	/// towards `n`.
597	///
598	/// Returns the number of blocks that were successfully reverted and the list of finalized
599	/// blocks that has been reverted.
600	fn revert(
601		&self,
602		n: NumberFor<Block>,
603		revert_finalized: bool,
604	) -> sp_blockchain::Result<(NumberFor<Block>, HashSet<Block::Hash>)>;
605
606	/// Discard non-best, unfinalized leaf block.
607	fn remove_leaf_block(&self, hash: Block::Hash) -> sp_blockchain::Result<()>;
608
609	/// Insert auxiliary data into key-value store.
610	fn insert_aux<
611		'a,
612		'b: 'a,
613		'c: 'a,
614		I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
615		D: IntoIterator<Item = &'a &'b [u8]>,
616	>(
617		&self,
618		insert: I,
619		delete: D,
620	) -> sp_blockchain::Result<()> {
621		AuxStore::insert_aux(self, insert, delete)
622	}
623	/// Query auxiliary data from key-value store.
624	fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>> {
625		AuxStore::get_aux(self, key)
626	}
627
628	/// Gain access to the import lock around this backend.
629	///
630	/// _Note_ Backend isn't expected to acquire the lock by itself ever. Rather
631	/// the using components should acquire and hold the lock whenever they do
632	/// something that the import of a block would interfere with, e.g. importing
633	/// a new block or calculating the best head.
634	fn get_import_lock(&self) -> &RwLock<()>;
635
636	/// Tells whether the backend requires full-sync mode.
637	fn requires_full_sync(&self) -> bool;
638}
639
640/// Mark for all Backend implementations, that are making use of state data, stored locally.
641pub trait LocalBackend<Block: BlockT>: Backend<Block> {}