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 primitive types.
19

            
20
#![cfg_attr(not(feature = "std"), no_std)]
21
#![warn(missing_docs)]
22

            
23
extern crate alloc;
24

            
25
pub use mmr_lib;
26

            
27
#[cfg(not(feature = "std"))]
28
use alloc::vec::Vec;
29
use core::fmt;
30
use scale_info::TypeInfo;
31
use sp_debug_derive::RuntimeDebug;
32
use sp_runtime::traits;
33

            
34
pub mod utils;
35

            
36
/// Prefix for elements stored in the Off-chain DB via Indexing API.
37
pub const INDEXING_PREFIX: &'static [u8] = b"mmr";
38

            
39
/// A type to describe node position in the MMR (node index).
40
pub type NodeIndex = u64;
41

            
42
/// A type to describe leaf position in the MMR.
43
///
44
/// Note this is different from [`NodeIndex`], which can be applied to
45
/// both leafs and inner nodes. Leafs will always have consecutive `LeafIndex`,
46
/// but might be actually at different positions in the MMR `NodeIndex`.
47
pub type LeafIndex = u64;
48

            
49
/// A provider of the MMR's leaf data.
50
pub trait LeafDataProvider {
51
	/// A type that should end up in the leaf of MMR.
52
	type LeafData: FullLeaf + codec::Decode;
53

            
54
	/// The method to return leaf data that should be placed
55
	/// in the leaf node appended MMR at this block.
56
	///
57
	/// This is being called by the `on_initialize` method of
58
	/// this pallet at the very beginning of each block.
59
	fn leaf_data() -> Self::LeafData;
60
}
61

            
62
impl LeafDataProvider for () {
63
	type LeafData = ();
64

            
65
	fn leaf_data() -> Self::LeafData {
66
		()
67
	}
68
}
69

            
70
/// New MMR root notification hook.
71
pub trait OnNewRoot<Hash> {
72
	/// Function called by the pallet in case new MMR root has been computed.
73
	fn on_new_root(root: &Hash);
74
}
75

            
76
/// No-op implementation of [OnNewRoot].
77
impl<Hash> OnNewRoot<Hash> for () {
78
	fn on_new_root(_root: &Hash) {}
79
}
80

            
81
/// A full leaf content stored in the offchain-db.
82
pub trait FullLeaf: Clone + PartialEq + fmt::Debug {
83
	/// Encode the leaf either in its full or compact form.
84
	///
85
	/// NOTE the encoding returned here MUST be `Decode`able into `FullLeaf`.
86
	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F, compact: bool) -> R;
87
}
88

            
89
impl<T: codec::Encode + codec::Decode + Clone + PartialEq + fmt::Debug> FullLeaf for T {
90
502974
	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F, _compact: bool) -> R {
91
502974
		codec::Encode::using_encoded(self, f)
92
502974
	}
93
}
94

            
95
/// A helper type to allow using arbitrary SCALE-encoded leaf data in the RuntimeApi.
96
///
97
/// The point is to be able to verify MMR proofs from external MMRs, where we don't
98
/// know the exact leaf type, but it's enough for us to have it SCALE-encoded.
99
///
100
/// Note the leaf type should be encoded in its compact form when passed through this type.
101
/// See [FullLeaf] documentation for details.
102
///
103
/// This type does not implement SCALE encoding/decoding on purpose to avoid confusion,
104
/// it would have to be SCALE-compatible with the concrete leaf type, but due to SCALE limitations
105
/// it's not possible to know how many bytes the encoding of concrete leaf type uses.
106
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
107
#[derive(RuntimeDebug, Clone, PartialEq)]
108
pub struct OpaqueLeaf(
109
	/// Raw bytes of the leaf type encoded in its compact form.
110
	///
111
	/// NOTE it DOES NOT include length prefix (like `Vec<u8>` encoding would).
112
	#[cfg_attr(feature = "serde", serde(with = "sp_core::bytes"))]
113
	pub Vec<u8>,
114
);
115

            
116
impl OpaqueLeaf {
117
	/// Convert a concrete MMR leaf into an opaque type.
118
	pub fn from_leaf<T: FullLeaf>(leaf: &T) -> Self {
119
		let encoded_leaf = leaf.using_encoded(|d| d.to_vec(), true);
120
		OpaqueLeaf::from_encoded_leaf(encoded_leaf)
121
	}
122

            
123
	/// Create a `OpaqueLeaf` given raw bytes of compact-encoded leaf.
124
	pub fn from_encoded_leaf(encoded_leaf: Vec<u8>) -> Self {
125
		OpaqueLeaf(encoded_leaf)
126
	}
127

            
128
	/// Attempt to decode the leaf into expected concrete type.
129
	pub fn try_decode<T: codec::Decode>(&self) -> Option<T> {
130
		codec::Decode::decode(&mut &*self.0).ok()
131
	}
132
}
133

            
134
impl FullLeaf for OpaqueLeaf {
135
	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F, _compact: bool) -> R {
136
		f(&self.0)
137
	}
138
}
139

            
140
/// A type-safe wrapper for the concrete leaf type.
141
///
142
/// This structure serves merely to avoid passing raw `Vec<u8>` around.
143
/// It must be `Vec<u8>`-encoding compatible.
144
///
145
/// It is different from [`OpaqueLeaf`], because it does implement `Codec`
146
/// and the encoding has to match raw `Vec<u8>` encoding.
147
#[derive(codec::Encode, codec::Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)]
148
pub struct EncodableOpaqueLeaf(pub Vec<u8>);
149

            
150
impl EncodableOpaqueLeaf {
151
	/// Convert a concrete leaf into encodable opaque version.
152
	pub fn from_leaf<T: FullLeaf>(leaf: &T) -> Self {
153
		let opaque = OpaqueLeaf::from_leaf(leaf);
154
		Self::from_opaque_leaf(opaque)
155
	}
156

            
157
	/// Given an opaque leaf, make it encodable.
158
	pub fn from_opaque_leaf(opaque: OpaqueLeaf) -> Self {
159
		Self(opaque.0)
160
	}
161

            
162
	/// Try to convert into a [OpaqueLeaf].
163
	pub fn into_opaque_leaf(self) -> OpaqueLeaf {
164
		// wrap into `OpaqueLeaf` type
165
		OpaqueLeaf::from_encoded_leaf(self.0)
166
	}
167
}
168

            
169
/// An element representing either full data or its hash.
170
///
171
/// See [Compact] to see how it may be used in practice to reduce the size
172
/// of proofs in case multiple [LeafDataProvider]s are composed together.
173
/// This is also used internally by the MMR to differentiate leaf nodes (data)
174
/// and inner nodes (hashes).
175
///
176
/// [DataOrHash::hash] method calculates the hash of this element in its compact form,
177
/// so should be used instead of hashing the encoded form (which will always be non-compact).
178
#[derive(RuntimeDebug, Clone, PartialEq)]
179
pub enum DataOrHash<H: traits::Hash, L> {
180
	/// Arbitrary data in its full form.
181
	Data(L),
182
	/// A hash of some data.
183
	Hash(H::Output),
184
}
185

            
186
impl<H: traits::Hash, L> From<L> for DataOrHash<H, L> {
187
	fn from(l: L) -> Self {
188
		Self::Data(l)
189
	}
190
}
191

            
192
mod encoding {
193
	use super::*;
194

            
195
	/// A helper type to implement [codec::Codec] for [DataOrHash].
196
	#[derive(codec::Encode, codec::Decode)]
197
	enum Either<A, B> {
198
		Left(A),
199
		Right(B),
200
	}
201

            
202
	impl<H: traits::Hash, L: FullLeaf> codec::Encode for DataOrHash<H, L> {
203
323562
		fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
204
323562
			match self {
205
194763
				Self::Data(l) => l.using_encoded(
206
259684
					|data| Either::<&[u8], &H::Output>::Left(data).encode_to(dest),
207
194763
					false,
208
194763
				),
209
128799
				Self::Hash(h) => Either::<&[u8], &H::Output>::Right(h).encode_to(dest),
210
			}
211
323562
		}
212
	}
213

            
214
	impl<H: traits::Hash, L: FullLeaf + codec::Decode> codec::Decode for DataOrHash<H, L> {
215
		fn decode<I: codec::Input>(value: &mut I) -> Result<Self, codec::Error> {
216
			let decoded: Either<Vec<u8>, H::Output> = Either::decode(value)?;
217
			Ok(match decoded {
218
				Either::Left(l) => DataOrHash::Data(L::decode(&mut &*l)?),
219
				Either::Right(r) => DataOrHash::Hash(r),
220
			})
221
		}
222
	}
223
}
224

            
225
impl<H: traits::Hash, L: FullLeaf> DataOrHash<H, L> {
226
	/// Retrieve a hash of this item.
227
	///
228
	/// Depending on the node type it's going to either be a contained value for [DataOrHash::Hash]
229
	/// node, or a hash of SCALE-encoded [DataOrHash::Data] data.
230
1052136
	pub fn hash(&self) -> H::Output {
231
1052136
		match *self {
232
308211
			Self::Data(ref leaf) => leaf.using_encoded(<H as traits::Hash>::hash, true),
233
743925
			Self::Hash(ref hash) => *hash,
234
		}
235
1052136
	}
236
}
237

            
238
/// A composition of multiple leaf elements with compact form representation.
239
///
240
/// When composing together multiple [LeafDataProvider]s you will end up with
241
/// a tuple of `LeafData` that each element provides.
242
///
243
/// However this will cause the leaves to have significant size, while for some
244
/// use cases it will be enough to prove only one element of the tuple.
245
/// That's the rationale for [Compact] struct. We wrap each element of the tuple
246
/// into [DataOrHash] and each tuple element is hashed first before constructing
247
/// the final hash of the entire tuple. This allows you to replace tuple elements
248
/// you don't care about with their hashes.
249
#[derive(RuntimeDebug, Clone, PartialEq)]
250
pub struct Compact<H, T> {
251
	/// Internal tuple representation.
252
	pub tuple: T,
253
	_hash: core::marker::PhantomData<H>,
254
}
255

            
256
impl<H, T> core::ops::Deref for Compact<H, T> {
257
	type Target = T;
258

            
259
	fn deref(&self) -> &Self::Target {
260
		&self.tuple
261
	}
262
}
263

            
264
impl<H, T> Compact<H, T> {
265
	/// Create a new [Compact] wrapper for a tuple.
266
	pub fn new(tuple: T) -> Self {
267
		Self { tuple, _hash: Default::default() }
268
	}
269
}
270

            
271
impl<H, T: codec::Decode> codec::Decode for Compact<H, T> {
272
	fn decode<I: codec::Input>(value: &mut I) -> Result<Self, codec::Error> {
273
		T::decode(value).map(Compact::new)
274
	}
275
}
276

            
277
macro_rules! impl_leaf_data_for_tuple {
278
	( $( $name:ident : $id:tt ),+ ) => {
279
		/// [FullLeaf] implementation for `Compact<H, (DataOrHash<H, Tuple>, ...)>`
280
		impl<H, $( $name ),+> FullLeaf for Compact<H, ( $( DataOrHash<H, $name>, )+ )> where
281
			H: traits::Hash,
282
			$( $name: FullLeaf ),+
283
		{
284
			fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F, compact: bool) -> R {
285
				if compact {
286
					codec::Encode::using_encoded(&(
287
						$( DataOrHash::<H, $name>::Hash(self.tuple.$id.hash()), )+
288
					), f)
289
				} else {
290
					codec::Encode::using_encoded(&self.tuple, f)
291
				}
292
			}
293
		}
294

            
295
		/// [LeafDataProvider] implementation for `Compact<H, (DataOrHash<H, Tuple>, ...)>`
296
		///
297
		/// This provides a compact-form encoding for tuples wrapped in [Compact].
298
		impl<H, $( $name ),+> LeafDataProvider for Compact<H, ( $( $name, )+ )> where
299
			H: traits::Hash,
300
			$( $name: LeafDataProvider ),+
301
		{
302
			type LeafData = Compact<
303
				H,
304
				( $( DataOrHash<H, $name::LeafData>, )+ ),
305
			>;
306

            
307
			fn leaf_data() -> Self::LeafData {
308
				let tuple = (
309
					$( DataOrHash::Data($name::leaf_data()), )+
310
				);
311
				Compact::new(tuple)
312
			}
313
		}
314

            
315
		/// [LeafDataProvider] implementation for `(Tuple, ...)`
316
		///
317
		/// This provides regular (non-compactable) composition of [LeafDataProvider]s.
318
		impl<$( $name ),+> LeafDataProvider for ( $( $name, )+ ) where
319
			( $( $name::LeafData, )+ ): FullLeaf,
320
			$( $name: LeafDataProvider ),+
321
		{
322
			type LeafData = ( $( $name::LeafData, )+ );
323

            
324
			fn leaf_data() -> Self::LeafData {
325
				(
326
					$( $name::leaf_data(), )+
327
				)
328
			}
329
		}
330
	}
331
}
332

            
333
/// Test functions implementation for `Compact<H, (DataOrHash<H, Tuple>, ...)>`
334
#[cfg(test)]
335
impl<H, A, B> Compact<H, (DataOrHash<H, A>, DataOrHash<H, B>)>
336
where
337
	H: traits::Hash,
338
	A: FullLeaf,
339
	B: FullLeaf,
340
{
341
	/// Retrieve a hash of this item in its compact form.
342
	pub fn hash(&self) -> H::Output {
343
		self.using_encoded(<H as traits::Hash>::hash, true)
344
	}
345
}
346

            
347
impl_leaf_data_for_tuple!(A:0);
348
impl_leaf_data_for_tuple!(A:0, B:1);
349
impl_leaf_data_for_tuple!(A:0, B:1, C:2);
350
impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3);
351
impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3, E:4);
352

            
353
/// An MMR proof data for a group of leaves.
354
#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)]
355
pub struct LeafProof<Hash> {
356
	/// The indices of the leaves the proof is for.
357
	pub leaf_indices: Vec<LeafIndex>,
358
	/// Number of leaves in MMR, when the proof was generated.
359
	pub leaf_count: NodeIndex,
360
	/// Proof elements (hashes of siblings of inner nodes on the path to the leafs).
361
	pub items: Vec<Hash>,
362
}
363

            
364
/// An MMR ancestry proof for a prior mmr root.
365
#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)]
366
pub struct AncestryProof<Hash> {
367
	/// Peaks of the ancestor's mmr
368
	pub prev_peaks: Vec<Hash>,
369
	/// Number of leaves in the ancestor's MMR.
370
	pub prev_leaf_count: u64,
371
	/// Number of leaves in MMR, when the proof was generated.
372
	pub leaf_count: NodeIndex,
373
	/// Proof elements
374
	/// (positions and hashes of siblings of inner nodes on the path to the previous peaks).
375
	pub items: Vec<(u64, Hash)>,
376
}
377

            
378
/// Merkle Mountain Range operation error.
379
#[cfg_attr(feature = "std", derive(thiserror::Error))]
380
#[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq, TypeInfo)]
381
pub enum Error {
382
	/// Error during translation of a block number into a leaf index.
383
	#[cfg_attr(feature = "std", error("Error performing numeric op"))]
384
	InvalidNumericOp,
385
	/// Error while pushing new node.
386
	#[cfg_attr(feature = "std", error("Error pushing new node"))]
387
	Push,
388
	/// Error getting the new root.
389
	#[cfg_attr(feature = "std", error("Error getting new root"))]
390
	GetRoot,
391
	/// Error committing changes.
392
	#[cfg_attr(feature = "std", error("Error committing changes"))]
393
	Commit,
394
	/// Error during proof generation.
395
	#[cfg_attr(feature = "std", error("Error generating proof"))]
396
	GenerateProof,
397
	/// Proof verification error.
398
	#[cfg_attr(feature = "std", error("Invalid proof"))]
399
	Verify,
400
	/// Leaf not found in the storage.
401
	#[cfg_attr(feature = "std", error("Leaf was not found"))]
402
	LeafNotFound,
403
	/// Mmr Pallet not included in runtime
404
	#[cfg_attr(feature = "std", error("MMR pallet not included in runtime"))]
405
	PalletNotIncluded,
406
	/// Cannot find the requested leaf index
407
	#[cfg_attr(feature = "std", error("Requested leaf index invalid"))]
408
	InvalidLeafIndex,
409
	/// The provided best know block number is invalid.
410
	#[cfg_attr(feature = "std", error("Provided best known block number invalid"))]
411
	InvalidBestKnownBlock,
412
}
413

            
414
impl Error {
415
	#![allow(unused_variables)]
416
	/// Consume given error `e` with `self` and generate a native log entry with error details.
417
	pub fn log_error(self, e: impl fmt::Debug) -> Self {
418
		log::error!(
419
			target: "runtime::mmr",
420
			"[{:?}] MMR error: {:?}",
421
			self,
422
			e,
423
		);
424
		self
425
	}
426

            
427
	/// Consume given error `e` with `self` and generate a native log entry with error details.
428
	pub fn log_debug(self, e: impl fmt::Debug) -> Self {
429
		log::debug!(
430
			target: "runtime::mmr",
431
			"[{:?}] MMR error: {:?}",
432
			self,
433
			e,
434
		);
435
		self
436
	}
437
}
438

            
439
sp_api::decl_runtime_apis! {
440
	/// API to interact with MMR pallet.
441
	#[api_version(2)]
442
	pub trait MmrApi<Hash: codec::Codec, BlockNumber: codec::Codec> {
443
		/// Return the on-chain MMR root hash.
444
		fn mmr_root() -> Result<Hash, Error>;
445

            
446
		/// Return the number of MMR blocks in the chain.
447
		fn mmr_leaf_count() -> Result<LeafIndex, Error>;
448

            
449
		/// Generate MMR proof for a series of block numbers. If `best_known_block_number = Some(n)`,
450
		/// use historical MMR state at given block height `n`. Else, use current MMR state.
451
		fn generate_proof(
452
			block_numbers: Vec<BlockNumber>,
453
			best_known_block_number: Option<BlockNumber>
454
		) -> Result<(Vec<EncodableOpaqueLeaf>, LeafProof<Hash>), Error>;
455

            
456
		/// Verify MMR proof against on-chain MMR for a batch of leaves.
457
		///
458
		/// Note this function will use on-chain MMR root hash and check if the proof matches the hash.
459
		/// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the
460
		/// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [LeafProof]
461
		fn verify_proof(leaves: Vec<EncodableOpaqueLeaf>, proof: LeafProof<Hash>) -> Result<(), Error>;
462

            
463
		/// Verify MMR proof against given root hash for a batch of leaves.
464
		///
465
		/// Note this function does not require any on-chain storage - the
466
		/// proof is verified against given MMR root hash.
467
		///
468
		/// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the
469
		/// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [LeafProof]
470
		fn verify_proof_stateless(root: Hash, leaves: Vec<EncodableOpaqueLeaf>, proof: LeafProof<Hash>)
471
			-> Result<(), Error>;
472
	}
473
}
474

            
475
#[cfg(test)]
476
mod tests {
477
	use super::*;
478

            
479
	use codec::Decode;
480
	use sp_core::H256;
481
	use sp_runtime::traits::Keccak256;
482

            
483
	pub(crate) fn hex(s: &str) -> H256 {
484
		s.parse().unwrap()
485
	}
486

            
487
	type Test = DataOrHash<Keccak256, String>;
488
	type TestCompact = Compact<Keccak256, (Test, Test)>;
489
	type TestProof = LeafProof<<Keccak256 as traits::Hash>::Output>;
490

            
491
	#[test]
492
	fn should_encode_decode_proof() {
493
		// given
494
		let proof: TestProof = LeafProof {
495
			leaf_indices: vec![5],
496
			leaf_count: 10,
497
			items: vec![
498
				hex("c3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd"),
499
				hex("d3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd"),
500
				hex("e3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd"),
501
			],
502
		};
503

            
504
		// when
505
		let encoded = codec::Encode::encode(&proof);
506
		let decoded = TestProof::decode(&mut &*encoded);
507

            
508
		// then
509
		assert_eq!(decoded, Ok(proof));
510
	}
511

            
512
	#[test]
513
	fn should_encode_decode_correctly_if_no_compact() {
514
		// given
515
		let cases = vec![
516
			Test::Data("Hello World!".into()),
517
			Test::Hash(hex("c3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd")),
518
			Test::Data("".into()),
519
			Test::Data("3e48d6bcd417fb22e044747242451e2c0f3e602d1bcad2767c34808621956417".into()),
520
		];
521

            
522
		// when
523
		let encoded = cases.iter().map(codec::Encode::encode).collect::<Vec<_>>();
524

            
525
		let decoded = encoded.iter().map(|x| Test::decode(&mut &**x)).collect::<Vec<_>>();
526

            
527
		// then
528
		assert_eq!(
529
			decoded,
530
			cases.into_iter().map(Result::<_, codec::Error>::Ok).collect::<Vec<_>>()
531
		);
532
		// check encoding correctness
533
		assert_eq!(
534
			&encoded[0],
535
			&array_bytes::hex2bytes_unchecked("00343048656c6c6f20576f726c6421")
536
		);
537
		assert_eq!(
538
			encoded[1].as_slice(),
539
			array_bytes::hex2bytes_unchecked(
540
				"01c3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd"
541
			)
542
			.as_slice()
543
		);
544
	}
545

            
546
	#[test]
547
	fn should_return_the_hash_correctly() {
548
		// given
549
		let a = Test::Data("Hello World!".into());
550
		let b = Test::Hash(hex("c3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd"));
551

            
552
		// when
553
		let a = a.hash();
554
		let b = b.hash();
555

            
556
		// then
557
		assert_eq!(a, hex("a9c321be8c24ba4dc2bd73f5300bde67dc57228ab8b68b607bb4c39c5374fac9"));
558
		assert_eq!(b, hex("c3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd"));
559
	}
560

            
561
	#[test]
562
	fn compact_should_work() {
563
		// given
564
		let a = Test::Data("Hello World!".into());
565
		let b = Test::Data("".into());
566

            
567
		// when
568
		let c: TestCompact = Compact::new((a.clone(), b.clone()));
569
		let d: TestCompact = Compact::new((Test::Hash(a.hash()), Test::Hash(b.hash())));
570

            
571
		// then
572
		assert_eq!(c.hash(), d.hash());
573
	}
574

            
575
	#[test]
576
	fn compact_should_encode_decode_correctly() {
577
		// given
578
		let a = Test::Data("Hello World!".into());
579
		let b = Test::Data("".into());
580

            
581
		let c: TestCompact = Compact::new((a.clone(), b.clone()));
582
		let d: TestCompact = Compact::new((Test::Hash(a.hash()), Test::Hash(b.hash())));
583
		let cases = vec![c, d.clone()];
584

            
585
		// when
586
		let encoded_compact =
587
			cases.iter().map(|c| c.using_encoded(|x| x.to_vec(), true)).collect::<Vec<_>>();
588

            
589
		let encoded =
590
			cases.iter().map(|c| c.using_encoded(|x| x.to_vec(), false)).collect::<Vec<_>>();
591

            
592
		let decoded_compact = encoded_compact
593
			.iter()
594
			.map(|x| TestCompact::decode(&mut &**x))
595
			.collect::<Vec<_>>();
596

            
597
		let decoded = encoded.iter().map(|x| TestCompact::decode(&mut &**x)).collect::<Vec<_>>();
598

            
599
		// then
600
		assert_eq!(
601
			decoded,
602
			cases.into_iter().map(Result::<_, codec::Error>::Ok).collect::<Vec<_>>()
603
		);
604

            
605
		assert_eq!(decoded_compact, vec![Ok(d.clone()), Ok(d.clone())]);
606
	}
607

            
608
	#[test]
609
	fn opaque_leaves_should_be_full_leaf_compatible() {
610
		// given
611
		let a = Test::Data("Hello World!".into());
612
		let b = Test::Data("".into());
613

            
614
		let c: TestCompact = Compact::new((a.clone(), b.clone()));
615
		let d: TestCompact = Compact::new((Test::Hash(a.hash()), Test::Hash(b.hash())));
616
		let cases = vec![c, d.clone()];
617

            
618
		let encoded_compact = cases
619
			.iter()
620
			.map(|c| c.using_encoded(|x| x.to_vec(), true))
621
			.map(OpaqueLeaf::from_encoded_leaf)
622
			.collect::<Vec<_>>();
623

            
624
		let opaque = cases.iter().map(OpaqueLeaf::from_leaf).collect::<Vec<_>>();
625

            
626
		// then
627
		assert_eq!(encoded_compact, opaque);
628
	}
629

            
630
	#[test]
631
	fn encode_opaque_leaf_should_be_scale_compatible() {
632
		use codec::Encode;
633

            
634
		// given
635
		let a = Test::Data("Hello World!".into());
636
		let case1 = EncodableOpaqueLeaf::from_leaf(&a);
637
		let case2 = EncodableOpaqueLeaf::from_opaque_leaf(OpaqueLeaf(a.encode()));
638
		let case3 = a.encode().encode();
639

            
640
		// when
641
		let encoded = vec![&case1, &case2].into_iter().map(|x| x.encode()).collect::<Vec<_>>();
642
		let decoded = vec![&*encoded[0], &*encoded[1], &*case3]
643
			.into_iter()
644
			.map(|x| EncodableOpaqueLeaf::decode(&mut &*x))
645
			.collect::<Vec<_>>();
646

            
647
		// then
648
		assert_eq!(case1, case2);
649
		assert_eq!(encoded[0], encoded[1]);
650
		// then encoding should also match double-encoded leaf.
651
		assert_eq!(encoded[0], case3);
652

            
653
		assert_eq!(decoded[0], decoded[1]);
654
		assert_eq!(decoded[1], decoded[2]);
655
		assert_eq!(decoded[0], Ok(case2));
656
		assert_eq!(decoded[1], Ok(case1));
657
	}
658
}