1
// This file is part of Substrate.
2

            
3
// Copyright (C) Parity Technologies (UK) Ltd.
4
// SPDX-License-Identifier: Apache-2.0
5

            
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
//
10
// 	http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17

            
18
//! # Merkle Mountain Range
19
//!
20
//! ## Overview
21
//!
22
//! Details on Merkle Mountain Ranges (MMRs) can be found here:
23
//! <https://github.com/mimblewimble/grin/blob/master/doc/mmr.md>
24
//!
25
//! The MMR pallet constructs an MMR from leaf data obtained on every block from
26
//! `LeafDataProvider`. MMR nodes are stored both in:
27
//! - on-chain storage - hashes only; not full leaf content;
28
//! - off-chain storage - via Indexing API we push full leaf content (and all internal nodes as
29
//! well) to the Off-chain DB, so that the data is available for Off-chain workers.
30
//! Hashing used for MMR is configurable independently from the rest of the runtime (i.e. not using
31
//! `frame_system::Hashing`) so something compatible with external chains can be used (like
32
//! Keccak256 for Ethereum compatibility).
33
//!
34
//! Depending on the usage context (off-chain vs on-chain) the pallet is able to:
35
//! - verify MMR leaf proofs (on-chain)
36
//! - generate leaf proofs (off-chain)
37
//!
38
//! See [primitives::Compact] documentation for how you can optimize proof size for leafs that are
39
//! composed from multiple elements.
40
//!
41
//! ## What for?
42
//!
43
//! Primary use case for this pallet is to generate MMR root hashes, that can latter on be used by
44
//! BEEFY protocol (see <https://github.com/paritytech/grandpa-bridge-gadget>).
45
//! MMR root hashes along with BEEFY will make it possible to build Super Light Clients (SLC) of
46
//! Substrate-based chains. The SLC will be able to follow finality and can be shown proofs of more
47
//! details that happened on the source chain.
48
//! In that case the chain which contains the pallet generates the Root Hashes and Proofs, which
49
//! are then presented to another chain acting as a light client which can verify them.
50
//!
51
//! Secondary use case is to archive historical data, but still be able to retrieve them on-demand
52
//! if needed. For instance if parent block hashes are stored in the MMR it's possible at any point
53
//! in time to provide an MMR proof about some past block hash, while this data can be safely pruned
54
//! from on-chain storage.
55
//!
56
//! NOTE This pallet is experimental and not proven to work in production.
57
#![cfg_attr(not(feature = "std"), no_std)]
58

            
59
extern crate alloc;
60

            
61
use alloc::vec::Vec;
62
use frame_support::weights::Weight;
63
use frame_system::pallet_prelude::{BlockNumberFor, HeaderFor};
64
use log;
65
use sp_mmr_primitives::utils;
66
use sp_runtime::{
67
	traits::{self, One, Saturating},
68
	SaturatedConversion,
69
};
70

            
71
pub use pallet::*;
72
pub use sp_mmr_primitives::{
73
	self as primitives, utils::NodesUtils, Error, LeafDataProvider, LeafIndex, NodeIndex,
74
};
75

            
76
#[cfg(feature = "runtime-benchmarks")]
77
mod benchmarking;
78
mod default_weights;
79
mod mmr;
80
#[cfg(test)]
81
mod mock;
82
#[cfg(test)]
83
mod tests;
84

            
85
/// The most common use case for MMRs is to store historical block hashes,
86
/// so that any point in time in the future we can receive a proof about some past
87
/// blocks without using excessive on-chain storage.
88
///
89
/// Hence we implement the [LeafDataProvider] for [ParentNumberAndHash] which is a
90
/// crate-local wrapper over [frame_system::Pallet]. Since the current block hash
91
/// is not available (since the block is not finished yet),
92
/// we use the `parent_hash` here along with parent block number.
93
pub struct ParentNumberAndHash<T: frame_system::Config> {
94
	_phantom: core::marker::PhantomData<T>,
95
}
96

            
97
impl<T: frame_system::Config> LeafDataProvider for ParentNumberAndHash<T> {
98
	type LeafData = (BlockNumberFor<T>, <T as frame_system::Config>::Hash);
99

            
100
194763
	fn leaf_data() -> Self::LeafData {
101
194763
		(
102
194763
			frame_system::Pallet::<T>::block_number().saturating_sub(One::one()),
103
194763
			frame_system::Pallet::<T>::parent_hash(),
104
194763
		)
105
194763
	}
106
}
107

            
108
/// Block hash provider for a given block number.
109
pub trait BlockHashProvider<BlockNumber, BlockHash> {
110
	fn block_hash(block_number: BlockNumber) -> BlockHash;
111
}
112

            
113
/// Default implementation of BlockHashProvider using frame_system.
114
pub struct DefaultBlockHashProvider<T: frame_system::Config> {
115
	_phantom: core::marker::PhantomData<T>,
116
}
117

            
118
impl<T: frame_system::Config> BlockHashProvider<BlockNumberFor<T>, T::Hash>
119
	for DefaultBlockHashProvider<T>
120
{
121
	fn block_hash(block_number: BlockNumberFor<T>) -> T::Hash {
122
		frame_system::Pallet::<T>::block_hash(block_number)
123
	}
124
}
125

            
126
pub trait WeightInfo {
127
	fn on_initialize(peaks: NodeIndex) -> Weight;
128
}
129

            
130
/// An MMR specific to the pallet.
131
type ModuleMmr<StorageType, T, I> = mmr::Mmr<StorageType, T, I, LeafOf<T, I>>;
132

            
133
/// Leaf data.
134
type LeafOf<T, I> = <<T as Config<I>>::LeafData as primitives::LeafDataProvider>::LeafData;
135

            
136
/// Hashing used for the pallet.
137
pub(crate) type HashingOf<T, I> = <T as Config<I>>::Hashing;
138
/// Hash type used for the pallet.
139
pub(crate) type HashOf<T, I> = <<T as Config<I>>::Hashing as traits::Hash>::Output;
140

            
141
#[frame_support::pallet]
142
pub mod pallet {
143
	use super::*;
144
	use frame_support::pallet_prelude::*;
145

            
146
1698
	#[pallet::pallet]
147
	pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
148

            
149
	/// This pallet's configuration trait
150
	#[pallet::config]
151
	pub trait Config<I: 'static = ()>: frame_system::Config {
152
		/// Prefix for elements stored in the Off-chain DB via Indexing API.
153
		///
154
		/// Each node of the MMR is inserted both on-chain and off-chain via Indexing API.
155
		/// The former does not store full leaf content, just its compact version (hash),
156
		/// and some of the inner mmr nodes might be pruned from on-chain storage.
157
		/// The latter will contain all the entries in their full form.
158
		///
159
		/// Each node is stored in the Off-chain DB under key derived from the
160
		/// [`Self::INDEXING_PREFIX`] and its in-tree index (MMR position).
161
		const INDEXING_PREFIX: &'static [u8];
162

            
163
		/// A hasher type for MMR.
164
		///
165
		/// To construct trie nodes that result in merging (bagging) two peaks, depending on the
166
		/// node kind we take either:
167
		/// - The node (hash) itself if it's an inner node.
168
		/// - The hash of SCALE-encoding of the leaf data if it's a leaf node.
169
		///
170
		/// Then we create a tuple of these two hashes, SCALE-encode it (concatenate) and
171
		/// hash, to obtain a new MMR inner node - the new peak.
172
		type Hashing: traits::Hash;
173

            
174
		/// Data stored in the leaf nodes.
175
		///
176
		/// The [LeafData](primitives::LeafDataProvider) is responsible for returning the entire
177
		/// leaf data that will be inserted to the MMR.
178
		/// [LeafDataProvider](primitives::LeafDataProvider)s can be composed into tuples to put
179
		/// multiple elements into the tree. In such a case it might be worth using
180
		/// [primitives::Compact] to make MMR proof for one element of the tuple leaner.
181
		///
182
		/// Note that the leaf at each block MUST be unique. You may want to include a block hash or
183
		/// block number as an easiest way to ensure that.
184
		/// Also note that the leaf added by each block is expected to only reference data coming
185
		/// from ancestor blocks (leaves are saved offchain using `(pos, parent_hash)` key to be
186
		/// fork-resistant, as such conflicts could only happen on 1-block deep forks, which means
187
		/// two forks with identical line of ancestors compete to write the same offchain key, but
188
		/// that's fine as long as leaves only contain data coming from ancestors - conflicting
189
		/// writes are identical).
190
		type LeafData: primitives::LeafDataProvider;
191

            
192
		/// A hook to act on the new MMR root.
193
		///
194
		/// For some applications it might be beneficial to make the MMR root available externally
195
		/// apart from having it in the storage. For instance you might output it in the header
196
		/// digest (see [`frame_system::Pallet::deposit_log`]) to make it available for Light
197
		/// Clients. Hook complexity should be `O(1)`.
198
		type OnNewRoot: primitives::OnNewRoot<HashOf<Self, I>>;
199

            
200
		/// Block hash provider for a given block number.
201
		type BlockHashProvider: BlockHashProvider<
202
			BlockNumberFor<Self>,
203
			<Self as frame_system::Config>::Hash,
204
		>;
205

            
206
		/// Weights for this pallet.
207
		type WeightInfo: WeightInfo;
208
	}
209

            
210
	/// Latest MMR Root hash.
211
389526
	#[pallet::storage]
212
	pub type RootHash<T: Config<I>, I: 'static = ()> = StorageValue<_, HashOf<T, I>, ValueQuery>;
213

            
214
	/// Current size of the MMR (number of leaves).
215
1558104
	#[pallet::storage]
216
	#[pallet::getter(fn mmr_leaves)]
217
	pub type NumberOfLeaves<T, I = ()> = StorageValue<_, LeafIndex, ValueQuery>;
218

            
219
	/// Hashes of the nodes in the MMR.
220
	///
221
	/// Note this collection only contains MMR peaks, the inner nodes (and leaves)
222
	/// are pruned and only stored in the Offchain DB.
223
654867
	#[pallet::storage]
224
	#[pallet::getter(fn mmr_peak)]
225
	pub type Nodes<T: Config<I>, I: 'static = ()> =
226
		StorageMap<_, Identity, NodeIndex, HashOf<T, I>, OptionQuery>;
227

            
228
554367
	#[pallet::hooks]
229
	impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
230
194763
		fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
231
			use primitives::LeafDataProvider;
232
194763
			let leaves = NumberOfLeaves::<T, I>::get();
233
194763
			let peaks_before = sp_mmr_primitives::utils::NodesUtils::new(leaves).number_of_peaks();
234
194763
			let data = T::LeafData::leaf_data();
235
194763

            
236
194763
			// append new leaf to MMR
237
194763
			let mut mmr: ModuleMmr<mmr::storage::RuntimeStorage, T, I> = mmr::Mmr::new(leaves);
238
194763
			// MMR push never fails, but better safe than sorry.
239
194763
			if mmr.push(data).is_none() {
240
				log::error!(target: "runtime::mmr", "MMR push failed");
241
				return T::WeightInfo::on_initialize(peaks_before)
242
194763
			}
243
			// Update the size, `mmr.finalize()` should also never fail.
244
194763
			let (leaves, root) = match mmr.finalize() {
245
194763
				Ok((leaves, root)) => (leaves, root),
246
				Err(e) => {
247
					log::error!(target: "runtime::mmr", "MMR finalize failed: {:?}", e);
248
					return T::WeightInfo::on_initialize(peaks_before)
249
				},
250
			};
251
194763
			<T::OnNewRoot as primitives::OnNewRoot<_>>::on_new_root(&root);
252
194763

            
253
194763
			NumberOfLeaves::<T, I>::put(leaves);
254
194763
			RootHash::<T, I>::put(root);
255
194763

            
256
194763
			let peaks_after = sp_mmr_primitives::utils::NodesUtils::new(leaves).number_of_peaks();
257
194763

            
258
194763
			T::WeightInfo::on_initialize(peaks_before.max(peaks_after))
259
194763
		}
260
	}
261
}
262

            
263
/// Stateless MMR proof verification for batch of leaves.
264
///
265
/// This function can be used to verify received MMR [primitives::LeafProof] (`proof`)
266
/// for given leaves set (`leaves`) against a known MMR root hash (`root`).
267
/// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the
268
/// same position in both the `leaves` vector and the `leaf_indices` vector contained in the
269
/// [primitives::LeafProof].
270
pub fn verify_leaves_proof<H, L>(
271
	root: H::Output,
272
	leaves: Vec<mmr::Node<H, L>>,
273
	proof: primitives::LeafProof<H::Output>,
274
) -> Result<(), primitives::Error>
275
where
276
	H: traits::Hash,
277
	L: primitives::FullLeaf,
278
{
279
	let is_valid = mmr::verify_leaves_proof::<H, L>(root, leaves, proof)?;
280
	if is_valid {
281
		Ok(())
282
	} else {
283
		Err(primitives::Error::Verify.log_debug(("The proof is incorrect.", root)))
284
	}
285
}
286

            
287
/// Stateless ancestry proof verification.
288
pub fn verify_ancestry_proof<H, L>(
289
	root: H::Output,
290
	ancestry_proof: primitives::AncestryProof<H::Output>,
291
) -> Result<H::Output, Error>
292
where
293
	H: traits::Hash,
294
	L: primitives::FullLeaf,
295
{
296
	mmr::verify_ancestry_proof::<H, L>(root, ancestry_proof)
297
		.map_err(|_| Error::Verify.log_debug(("The ancestry proof is incorrect.", root)))
298
}
299

            
300
impl<T: Config<I>, I: 'static> Pallet<T, I> {
301
	/// Build offchain key from `parent_hash` of block that originally added node `pos` to MMR.
302
	///
303
	/// This combination makes the offchain (key,value) entry resilient to chain forks.
304
323562
	fn node_temp_offchain_key(
305
323562
		pos: NodeIndex,
306
323562
		parent_hash: <T as frame_system::Config>::Hash,
307
323562
	) -> Vec<u8> {
308
323562
		NodesUtils::node_temp_offchain_key::<HeaderFor<T>>(&T::INDEXING_PREFIX, pos, parent_hash)
309
323562
	}
310

            
311
	/// Build canonical offchain key for node `pos` in MMR.
312
	///
313
	/// Used for nodes added by now finalized blocks.
314
	/// Never read keys using `node_canon_offchain_key` unless you sure that
315
	/// there's no `node_offchain_key` key in the storage.
316
	fn node_canon_offchain_key(pos: NodeIndex) -> Vec<u8> {
317
		NodesUtils::node_canon_offchain_key(&T::INDEXING_PREFIX, pos)
318
	}
319

            
320
	/// Provide the parent number for the block that added `leaf_index` to the MMR.
321
	fn leaf_index_to_parent_block_num(leaf_index: LeafIndex) -> BlockNumberFor<T> {
322
		// leaves are zero-indexed and were added one per block since pallet activation,
323
		// while block numbers are one-indexed, so block number that added `leaf_idx` is:
324
		// `block_num = block_num_when_pallet_activated + leaf_idx + 1`
325
		// `block_num = (current_block_num - leaves_count) + leaf_idx + 1`
326
		// `parent_block_num = current_block_num - leaves_count + leaf_idx`.
327
		<frame_system::Pallet<T>>::block_number()
328
			.saturating_sub(Self::mmr_leaves().saturated_into())
329
			.saturating_add(leaf_index.saturated_into())
330
	}
331

            
332
	/// Convert a block number into a leaf index.
333
	fn block_num_to_leaf_index(block_num: BlockNumberFor<T>) -> Result<LeafIndex, Error>
334
	where
335
		T: frame_system::Config,
336
	{
337
		let first_mmr_block = utils::first_mmr_block_num::<HeaderFor<T>>(
338
			<frame_system::Pallet<T>>::block_number(),
339
			NumberOfLeaves::<T, I>::get(),
340
		)?;
341

            
342
		utils::block_num_to_leaf_index::<HeaderFor<T>>(block_num, first_mmr_block)
343
	}
344

            
345
	/// Convert a block number into a leaf index.
346
	pub fn block_num_to_leaf_count(block_num: BlockNumberFor<T>) -> Result<LeafIndex, Error>
347
	where
348
		T: frame_system::Config,
349
	{
350
		let leaf_index = Self::block_num_to_leaf_index(block_num)?;
351
		Ok(leaf_index.saturating_add(1))
352
	}
353

            
354
	/// Generate an MMR proof for the given `block_numbers`.
355
	/// If `best_known_block_number = Some(n)`, this generates a historical proof for
356
	/// the chain with head at height `n`.
357
	/// Else it generates a proof for the MMR at the current block height.
358
	///
359
	/// Note this method can only be used from an off-chain context
360
	/// (Offchain Worker or Runtime API call), since it requires
361
	/// all the leaves to be present.
362
	/// It may return an error or panic if used incorrectly.
363
	pub fn generate_proof(
364
		block_numbers: Vec<BlockNumberFor<T>>,
365
		best_known_block_number: Option<BlockNumberFor<T>>,
366
	) -> Result<(Vec<LeafOf<T, I>>, primitives::LeafProof<HashOf<T, I>>), primitives::Error> {
367
		// check whether best_known_block_number provided, else use current best block
368
		let best_known_block_number =
369
			best_known_block_number.unwrap_or_else(|| <frame_system::Pallet<T>>::block_number());
370

            
371
		let leaf_count = Self::block_num_to_leaf_count(best_known_block_number)?;
372

            
373
		// we need to translate the block_numbers into leaf indices.
374
		let leaf_indices = block_numbers
375
			.iter()
376
			.map(|block_num| -> Result<LeafIndex, primitives::Error> {
377
				Self::block_num_to_leaf_index(*block_num)
378
			})
379
			.collect::<Result<Vec<LeafIndex>, _>>()?;
380

            
381
		let mmr: ModuleMmr<mmr::storage::OffchainStorage, T, I> = mmr::Mmr::new(leaf_count);
382
		mmr.generate_proof(leaf_indices)
383
	}
384

            
385
	/// Verify MMR proof for given `leaves`.
386
	///
387
	/// This method is safe to use within the runtime code.
388
	/// It will return `Ok(())` if the proof is valid
389
	/// and an `Err(..)` if MMR is inconsistent (some leaves are missing)
390
	/// or the proof is invalid.
391
	pub fn verify_leaves(
392
		leaves: Vec<LeafOf<T, I>>,
393
		proof: primitives::LeafProof<HashOf<T, I>>,
394
	) -> Result<(), primitives::Error> {
395
		if proof.leaf_count > NumberOfLeaves::<T, I>::get() ||
396
			proof.leaf_count == 0 ||
397
			proof.items.len().saturating_add(leaves.len()) as u64 > proof.leaf_count
398
		{
399
			return Err(primitives::Error::Verify
400
				.log_debug("The proof has incorrect number of leaves or proof items."))
401
		}
402

            
403
		let mmr: ModuleMmr<mmr::storage::OffchainStorage, T, I> = mmr::Mmr::new(proof.leaf_count);
404
		let is_valid = mmr.verify_leaves_proof(leaves, proof)?;
405
		if is_valid {
406
			Ok(())
407
		} else {
408
			Err(primitives::Error::Verify.log_debug("The proof is incorrect."))
409
		}
410
	}
411

            
412
	pub fn generate_ancestry_proof(
413
		prev_block_number: BlockNumberFor<T>,
414
		best_known_block_number: Option<BlockNumberFor<T>>,
415
	) -> Result<primitives::AncestryProof<HashOf<T, I>>, Error> {
416
		// check whether best_known_block_number provided, else use current best block
417
		let best_known_block_number =
418
			best_known_block_number.unwrap_or_else(|| <frame_system::Pallet<T>>::block_number());
419

            
420
		let leaf_count = Self::block_num_to_leaf_count(best_known_block_number)?;
421
		let prev_leaf_count = Self::block_num_to_leaf_count(prev_block_number)?;
422

            
423
		let mmr: ModuleMmr<mmr::storage::OffchainStorage, T, I> = mmr::Mmr::new(leaf_count);
424
		mmr.generate_ancestry_proof(prev_leaf_count)
425
	}
426

            
427
	pub fn verify_ancestry_proof(
428
		root: HashOf<T, I>,
429
		ancestry_proof: primitives::AncestryProof<HashOf<T, I>>,
430
	) -> Result<HashOf<T, I>, Error> {
431
		verify_ancestry_proof::<HashingOf<T, I>, LeafOf<T, I>>(root, ancestry_proof)
432
	}
433

            
434
	/// Return the on-chain MMR root hash.
435
	pub fn mmr_root() -> HashOf<T, I> {
436
		RootHash::<T, I>::get()
437
	}
438
}