1use core::{borrow::Borrow, iter::once, marker::PhantomData, ops::Range};
20use hash_db::Hasher;
21use parity_scale_codec as codec;
22use parity_scale_codec::{Compact, Decode, Encode, Input, Output};
23use trie_db::{
24 nibble_ops,
25 node::{NibbleSlicePlan, NodeHandlePlan, NodePlan, Value, ValuePlan},
26 ChildReference, NodeCodec as NodeCodecT, TrieConfiguration, TrieLayout,
27};
28
29mod trie_constants {
31 const FIRST_PREFIX: u8 = 0b_00 << 6;
32 pub const LEAF_PREFIX_MASK: u8 = 0b_01 << 6;
33 pub const BRANCH_WITHOUT_MASK: u8 = 0b_10 << 6;
34 pub const BRANCH_WITH_MASK: u8 = 0b_11 << 6;
35 pub const EMPTY_TRIE: u8 = FIRST_PREFIX | (0b_00 << 4);
36 pub const ALT_HASHING_LEAF_PREFIX_MASK: u8 = FIRST_PREFIX | (0b_1 << 5);
37 pub const ALT_HASHING_BRANCH_WITH_MASK: u8 = FIRST_PREFIX | (0b_01 << 4);
38 pub const ESCAPE_COMPACT_HEADER: u8 = EMPTY_TRIE | 0b_00_01;
39}
40
41pub const TRIE_VALUE_NODE_THRESHOLD: u32 = 33;
42
43#[derive(Default, Clone)]
45pub struct TrieStream {
46 buffer: Vec<u8>,
48}
49
50fn branch_node_bit_mask(has_children: impl Iterator<Item = bool>) -> (u8, u8) {
51 let mut bitmap: u16 = 0;
52 let mut cursor: u16 = 1;
53 for v in has_children {
54 if v {
55 bitmap |= cursor
56 }
57 cursor <<= 1;
58 }
59 ((bitmap % 256) as u8, (bitmap / 256) as u8)
60}
61
62fn fuse_nibbles_node(nibbles: &[u8], kind: NodeKind) -> impl Iterator<Item = u8> + '_ {
64 let size = nibbles.len();
65 let iter_start = match kind {
66 NodeKind::Leaf => size_and_prefix_iterator(size, trie_constants::LEAF_PREFIX_MASK, 2),
67 NodeKind::BranchNoValue =>
68 size_and_prefix_iterator(size, trie_constants::BRANCH_WITHOUT_MASK, 2),
69 NodeKind::BranchWithValue =>
70 size_and_prefix_iterator(size, trie_constants::BRANCH_WITH_MASK, 2),
71 NodeKind::HashedValueLeaf =>
72 size_and_prefix_iterator(size, trie_constants::ALT_HASHING_LEAF_PREFIX_MASK, 3),
73 NodeKind::HashedValueBranch =>
74 size_and_prefix_iterator(size, trie_constants::ALT_HASHING_BRANCH_WITH_MASK, 4),
75 };
76 iter_start
77 .chain(if nibbles.len() % 2 == 1 { Some(nibbles[0]) } else { None })
78 .chain(nibbles[nibbles.len() % 2..].chunks(2).map(|ch| ch[0] << 4 | ch[1]))
79}
80
81use trie_root::Value as TrieStreamValue;
82impl trie_root::TrieStream for TrieStream {
83 fn new() -> Self {
84 Self { buffer: Vec::new() }
85 }
86
87 fn append_empty_data(&mut self) {
88 self.buffer.push(trie_constants::EMPTY_TRIE);
89 }
90
91 fn append_leaf(&mut self, key: &[u8], value: TrieStreamValue) {
92 let kind = match &value {
93 TrieStreamValue::Inline(..) => NodeKind::Leaf,
94 TrieStreamValue::Node(..) => NodeKind::HashedValueLeaf,
95 };
96 self.buffer.extend(fuse_nibbles_node(key, kind));
97 match &value {
98 TrieStreamValue::Inline(value) => {
99 Compact(value.len() as u32).encode_to(&mut self.buffer);
100 self.buffer.extend_from_slice(value);
101 },
102 TrieStreamValue::Node(hash) => {
103 self.buffer.extend_from_slice(hash.as_slice());
104 },
105 };
106 }
107
108 fn begin_branch(
109 &mut self,
110 maybe_partial: Option<&[u8]>,
111 maybe_value: Option<TrieStreamValue>,
112 has_children: impl Iterator<Item = bool>,
113 ) {
114 if let Some(partial) = maybe_partial {
115 let kind = match &maybe_value {
116 None => NodeKind::BranchNoValue,
117 Some(TrieStreamValue::Inline(..)) => NodeKind::BranchWithValue,
118 Some(TrieStreamValue::Node(..)) => NodeKind::HashedValueBranch,
119 };
120
121 self.buffer.extend(fuse_nibbles_node(partial, kind));
122 let bm = branch_node_bit_mask(has_children);
123 self.buffer.extend([bm.0, bm.1].iter());
124 } else {
125 unreachable!("trie stream codec only for no extension trie");
126 }
127 match maybe_value {
128 None => (),
129 Some(TrieStreamValue::Inline(value)) => {
130 Compact(value.len() as u32).encode_to(&mut self.buffer);
131 self.buffer.extend_from_slice(value);
132 },
133 Some(TrieStreamValue::Node(hash)) => {
134 self.buffer.extend_from_slice(hash.as_slice());
135 },
136 }
137 }
138
139 fn append_extension(&mut self, _key: &[u8]) {
140 debug_assert!(false, "trie stream codec only for no extension trie");
141 }
142
143 fn append_substream<H: Hasher>(&mut self, other: Self) {
144 let data = other.out();
145 match data.len() {
146 0..=31 => data.encode_to(&mut self.buffer),
147 _ => H::hash(&data).as_ref().encode_to(&mut self.buffer),
148 }
149 }
150
151 fn out(self) -> Vec<u8> {
152 self.buffer
153 }
154}
155
156struct ByteSliceInput<'a> {
160 data: &'a [u8],
161 offset: usize,
162}
163
164impl<'a> ByteSliceInput<'a> {
165 fn new(data: &'a [u8]) -> Self {
166 ByteSliceInput { data, offset: 0 }
167 }
168
169 fn take(&mut self, count: usize) -> Result<Range<usize>, codec::Error> {
170 if self.offset + count > self.data.len() {
171 return Err("out of data".into())
172 }
173
174 let range = self.offset..(self.offset + count);
175 self.offset += count;
176 Ok(range)
177 }
178}
179
180impl<'a> Input for ByteSliceInput<'a> {
181 fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
182 Ok(Some(self.data.len().saturating_sub(self.offset)))
183 }
184
185 fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> {
186 let range = self.take(into.len())?;
187 into.copy_from_slice(&self.data[range]);
188 Ok(())
189 }
190
191 fn read_byte(&mut self) -> Result<u8, codec::Error> {
192 if self.offset + 1 > self.data.len() {
193 return Err("out of data".into())
194 }
195
196 let byte = self.data[self.offset];
197 self.offset += 1;
198 Ok(byte)
199 }
200}
201
202#[derive(Default, Clone)]
206pub struct NodeCodec<H>(PhantomData<H>);
207
208impl<H> NodeCodecT for NodeCodec<H>
209where
210 H: Hasher,
211{
212 const ESCAPE_HEADER: Option<u8> = Some(trie_constants::ESCAPE_COMPACT_HEADER);
213 type Error = Error<H::Out>;
214 type HashOut = H::Out;
215
216 fn hashed_null_node() -> <H as Hasher>::Out {
217 H::hash(<Self as NodeCodecT>::empty_node())
218 }
219
220 fn decode_plan(data: &[u8]) -> Result<NodePlan, Self::Error> {
221 let mut input = ByteSliceInput::new(data);
222
223 let header = NodeHeader::decode(&mut input)?;
224 let contains_hash = header.contains_hash_of_value();
225
226 let branch_has_value = if let NodeHeader::Branch(has_value, _) = &header {
227 *has_value
228 } else {
229 true
231 };
232
233 match header {
234 NodeHeader::Null => Ok(NodePlan::Empty),
235 NodeHeader::HashedValueBranch(nibble_count) | NodeHeader::Branch(_, nibble_count) => {
236 let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0;
237 if padding && nibble_ops::pad_left(data[input.offset]) != 0 {
239 return Err(Error::BadFormat)
240 }
241 let partial = input.take(
242 (nibble_count + (nibble_ops::NIBBLE_PER_BYTE - 1)) /
243 nibble_ops::NIBBLE_PER_BYTE,
244 )?;
245 let partial_padding = nibble_ops::number_padding(nibble_count);
246 let bitmap_range = input.take(BITMAP_LENGTH)?;
247 let bitmap = Bitmap::decode(&data[bitmap_range])?;
248 let value = if branch_has_value {
249 Some(if contains_hash {
250 ValuePlan::Node(input.take(H::LENGTH)?)
251 } else {
252 let count = <Compact<u32>>::decode(&mut input)?.0 as usize;
253 ValuePlan::Inline(input.take(count)?)
254 })
255 } else {
256 None
257 };
258 let mut children = [
259 None, None, None, None, None, None, None, None, None, None, None, None, None,
260 None, None, None,
261 ];
262 for i in 0..nibble_ops::NIBBLE_LENGTH {
263 if bitmap.value_at(i) {
264 let count = <Compact<u32>>::decode(&mut input)?.0 as usize;
265 let range = input.take(count)?;
266 children[i] = Some(if count == H::LENGTH {
267 NodeHandlePlan::Hash(range)
268 } else {
269 NodeHandlePlan::Inline(range)
270 });
271 }
272 }
273 Ok(NodePlan::NibbledBranch {
274 partial: NibbleSlicePlan::new(partial, partial_padding),
275 value,
276 children,
277 })
278 },
279 NodeHeader::HashedValueLeaf(nibble_count) | NodeHeader::Leaf(nibble_count) => {
280 let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0;
281 if padding && nibble_ops::pad_left(data[input.offset]) != 0 {
283 return Err(Error::BadFormat)
284 }
285 let partial = input.take(
286 (nibble_count + (nibble_ops::NIBBLE_PER_BYTE - 1)) /
287 nibble_ops::NIBBLE_PER_BYTE,
288 )?;
289 let partial_padding = nibble_ops::number_padding(nibble_count);
290 let value = if contains_hash {
291 ValuePlan::Node(input.take(H::LENGTH)?)
292 } else {
293 let count = <Compact<u32>>::decode(&mut input)?.0 as usize;
294 ValuePlan::Inline(input.take(count)?)
295 };
296
297 Ok(NodePlan::Leaf {
298 partial: NibbleSlicePlan::new(partial, partial_padding),
299 value,
300 })
301 },
302 }
303 }
304
305 fn is_empty_node(data: &[u8]) -> bool {
306 data == <Self as NodeCodecT>::empty_node()
307 }
308
309 fn empty_node() -> &'static [u8] {
310 &[trie_constants::EMPTY_TRIE]
311 }
312
313 fn leaf_node(partial: impl Iterator<Item = u8>, number_nibble: usize, value: Value) -> Vec<u8> {
314 let contains_hash = matches!(&value, Value::Node(..));
315 let mut output = if contains_hash {
316 partial_from_iterator_encode(partial, number_nibble, NodeKind::HashedValueLeaf)
317 } else {
318 partial_from_iterator_encode(partial, number_nibble, NodeKind::Leaf)
319 };
320 match value {
321 Value::Inline(value) => {
322 Compact(value.len() as u32).encode_to(&mut output);
323 output.extend_from_slice(value);
324 },
325 Value::Node(hash) => {
326 debug_assert!(hash.len() == H::LENGTH);
327 output.extend_from_slice(hash);
328 },
329 }
330 output
331 }
332
333 fn extension_node(
334 _partial: impl Iterator<Item = u8>,
335 _nbnibble: usize,
336 _child: ChildReference<<H as Hasher>::Out>,
337 ) -> Vec<u8> {
338 unreachable!("No extension codec.")
339 }
340
341 fn branch_node(
342 _children: impl Iterator<Item = impl Borrow<Option<ChildReference<<H as Hasher>::Out>>>>,
343 _maybe_value: Option<Value>,
344 ) -> Vec<u8> {
345 unreachable!("No extension codec.")
346 }
347
348 fn branch_node_nibbled(
349 partial: impl Iterator<Item = u8>,
350 number_nibble: usize,
351 children: impl Iterator<Item = impl Borrow<Option<ChildReference<<H as Hasher>::Out>>>>,
352 value: Option<Value>,
353 ) -> Vec<u8> {
354 let contains_hash = matches!(&value, Some(Value::Node(..)));
355 let mut output = match (&value, contains_hash) {
356 (&None, _) =>
357 partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchNoValue),
358 (_, false) =>
359 partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchWithValue),
360 (_, true) =>
361 partial_from_iterator_encode(partial, number_nibble, NodeKind::HashedValueBranch),
362 };
363
364 let bitmap_index = output.len();
365 let mut bitmap: [u8; BITMAP_LENGTH] = [0; BITMAP_LENGTH];
366 (0..BITMAP_LENGTH).for_each(|_| output.push(0));
367 match value {
368 Some(Value::Inline(value)) => {
369 Compact(value.len() as u32).encode_to(&mut output);
370 output.extend_from_slice(value);
371 },
372 Some(Value::Node(hash)) => {
373 debug_assert!(hash.len() == H::LENGTH);
374 output.extend_from_slice(hash);
375 },
376 None => (),
377 }
378 Bitmap::encode(
379 children.map(|maybe_child| match maybe_child.borrow() {
380 Some(ChildReference::Hash(h)) => {
381 h.as_ref().encode_to(&mut output);
382 true
383 },
384 &Some(ChildReference::Inline(inline_data, len)) => {
385 inline_data.as_ref()[..len].encode_to(&mut output);
386 true
387 },
388 None => false,
389 }),
390 bitmap.as_mut(),
391 );
392 output[bitmap_index..bitmap_index + BITMAP_LENGTH]
393 .copy_from_slice(&bitmap[..BITMAP_LENGTH]);
394 output
395 }
396}
397
398fn partial_from_iterator_encode<I: Iterator<Item = u8>>(
403 partial: I,
404 nibble_count: usize,
405 node_kind: NodeKind,
406) -> Vec<u8> {
407 let mut output = Vec::with_capacity(4 + (nibble_count / nibble_ops::NIBBLE_PER_BYTE));
408 match node_kind {
409 NodeKind::Leaf => NodeHeader::Leaf(nibble_count).encode_to(&mut output),
410 NodeKind::BranchWithValue => NodeHeader::Branch(true, nibble_count).encode_to(&mut output),
411 NodeKind::BranchNoValue => NodeHeader::Branch(false, nibble_count).encode_to(&mut output),
412 NodeKind::HashedValueLeaf =>
413 NodeHeader::HashedValueLeaf(nibble_count).encode_to(&mut output),
414 NodeKind::HashedValueBranch =>
415 NodeHeader::HashedValueBranch(nibble_count).encode_to(&mut output),
416 };
417 output.extend(partial);
418 output
419}
420
421const BITMAP_LENGTH: usize = 2;
422
423pub(crate) struct Bitmap(u16);
428
429impl Bitmap {
430 pub fn decode(data: &[u8]) -> Result<Self, codec::Error> {
431 let value = u16::decode(&mut &data[..])?;
432 if value == 0 {
433 Err("Bitmap without a child.".into())
434 } else {
435 Ok(Bitmap(value))
436 }
437 }
438
439 pub fn value_at(&self, i: usize) -> bool {
440 self.0 & (1u16 << i) != 0
441 }
442
443 pub fn encode<I: Iterator<Item = bool>>(has_children: I, dest: &mut [u8]) {
444 let mut bitmap: u16 = 0;
445 let mut cursor: u16 = 1;
446 for v in has_children {
447 if v {
448 bitmap |= cursor
449 }
450 cursor <<= 1;
451 }
452 dest[0] = (bitmap % 256) as u8;
453 dest[1] = (bitmap / 256) as u8;
454 }
455}
456
457pub struct LayoutV0<H>(PhantomData<H>);
459
460pub struct LayoutV1<H>(PhantomData<H>);
462
463impl<H> TrieLayout for LayoutV0<H>
464where
465 H: Hasher + core::fmt::Debug,
466{
467 const USE_EXTENSION: bool = false;
468 const ALLOW_EMPTY: bool = true;
469 const MAX_INLINE_VALUE: Option<u32> = None;
470
471 type Hash = H;
472 type Codec = NodeCodec<Self::Hash>;
473}
474
475impl<H> TrieConfiguration for LayoutV0<H>
476where
477 H: Hasher + core::fmt::Debug,
478{
479 fn trie_root<I, A, B>(input: I) -> <Self::Hash as Hasher>::Out
480 where
481 I: IntoIterator<Item = (A, B)>,
482 A: AsRef<[u8]> + Ord,
483 B: AsRef<[u8]>,
484 {
485 trie_root::trie_root_no_extension::<H, TrieStream, _, _, _>(input, Self::MAX_INLINE_VALUE)
486 }
487
488 fn trie_root_unhashed<I, A, B>(input: I) -> Vec<u8>
489 where
490 I: IntoIterator<Item = (A, B)>,
491 A: AsRef<[u8]> + Ord,
492 B: AsRef<[u8]>,
493 {
494 trie_root::unhashed_trie_no_extension::<H, TrieStream, _, _, _>(
495 input,
496 Self::MAX_INLINE_VALUE,
497 )
498 }
499
500 fn encode_index(input: u32) -> Vec<u8> {
501 codec::Encode::encode(&codec::Compact(input))
502 }
503}
504
505impl<H> TrieLayout for LayoutV1<H>
506where
507 H: Hasher + core::fmt::Debug,
508{
509 const USE_EXTENSION: bool = false;
510 const ALLOW_EMPTY: bool = true;
511 const MAX_INLINE_VALUE: Option<u32> = Some(TRIE_VALUE_NODE_THRESHOLD);
512
513 type Hash = H;
514 type Codec = NodeCodec<Self::Hash>;
515}
516
517impl<H> TrieConfiguration for LayoutV1<H>
518where
519 H: Hasher + core::fmt::Debug,
520{
521 fn trie_root<I, A, B>(input: I) -> <Self::Hash as Hasher>::Out
522 where
523 I: IntoIterator<Item = (A, B)>,
524 A: AsRef<[u8]> + Ord,
525 B: AsRef<[u8]>,
526 {
527 trie_root::trie_root_no_extension::<H, TrieStream, _, _, _>(input, Self::MAX_INLINE_VALUE)
528 }
529
530 fn trie_root_unhashed<I, A, B>(input: I) -> Vec<u8>
531 where
532 I: IntoIterator<Item = (A, B)>,
533 A: AsRef<[u8]> + Ord,
534 B: AsRef<[u8]>,
535 {
536 trie_root::unhashed_trie_no_extension::<H, TrieStream, _, _, _>(
537 input,
538 Self::MAX_INLINE_VALUE,
539 )
540 }
541
542 fn encode_index(input: u32) -> Vec<u8> {
543 codec::Encode::encode(&codec::Compact(input))
544 }
545}
546
547#[derive(Copy, Clone, PartialEq, Eq, Debug)]
549pub(crate) enum NodeHeader {
550 Null,
551 Branch(bool, usize),
553 Leaf(usize),
555 HashedValueBranch(usize),
557 HashedValueLeaf(usize),
559}
560
561impl NodeHeader {
562 pub(crate) fn contains_hash_of_value(&self) -> bool {
563 matches!(self, NodeHeader::HashedValueBranch(_) | NodeHeader::HashedValueLeaf(_))
564 }
565}
566
567pub(crate) enum NodeKind {
569 Leaf,
570 BranchNoValue,
571 BranchWithValue,
572 HashedValueLeaf,
573 HashedValueBranch,
574}
575
576impl Encode for NodeHeader {
577 fn encode_to<T: Output + ?Sized>(&self, output: &mut T) {
578 match self {
579 NodeHeader::Null => output.push_byte(trie_constants::EMPTY_TRIE),
580 NodeHeader::Branch(true, nibble_count) =>
581 encode_size_and_prefix(*nibble_count, trie_constants::BRANCH_WITH_MASK, 2, output),
582 NodeHeader::Branch(false, nibble_count) => encode_size_and_prefix(
583 *nibble_count,
584 trie_constants::BRANCH_WITHOUT_MASK,
585 2,
586 output,
587 ),
588 NodeHeader::Leaf(nibble_count) =>
589 encode_size_and_prefix(*nibble_count, trie_constants::LEAF_PREFIX_MASK, 2, output),
590 NodeHeader::HashedValueBranch(nibble_count) => encode_size_and_prefix(
591 *nibble_count,
592 trie_constants::ALT_HASHING_BRANCH_WITH_MASK,
593 4,
594 output,
595 ),
596 NodeHeader::HashedValueLeaf(nibble_count) => encode_size_and_prefix(
597 *nibble_count,
598 trie_constants::ALT_HASHING_LEAF_PREFIX_MASK,
599 3,
600 output,
601 ),
602 }
603 }
604}
605
606impl codec::EncodeLike for NodeHeader {}
607
608impl Decode for NodeHeader {
609 fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
610 let i = input.read_byte()?;
611 if i == trie_constants::EMPTY_TRIE {
612 return Ok(NodeHeader::Null)
613 }
614 match i & (0b11 << 6) {
615 trie_constants::LEAF_PREFIX_MASK => Ok(NodeHeader::Leaf(decode_size(i, input, 2)?)),
616 trie_constants::BRANCH_WITH_MASK =>
617 Ok(NodeHeader::Branch(true, decode_size(i, input, 2)?)),
618 trie_constants::BRANCH_WITHOUT_MASK =>
619 Ok(NodeHeader::Branch(false, decode_size(i, input, 2)?)),
620 trie_constants::EMPTY_TRIE => {
621 if i & (0b111 << 5) == trie_constants::ALT_HASHING_LEAF_PREFIX_MASK {
622 Ok(NodeHeader::HashedValueLeaf(decode_size(i, input, 3)?))
623 } else if i & (0b1111 << 4) == trie_constants::ALT_HASHING_BRANCH_WITH_MASK {
624 Ok(NodeHeader::HashedValueBranch(decode_size(i, input, 4)?))
625 } else {
626 Err("Unallowed encoding".into())
628 }
629 },
630 _ => unreachable!(),
631 }
632 }
633}
634
635pub(crate) fn size_and_prefix_iterator(
639 size: usize,
640 prefix: u8,
641 prefix_mask: usize,
642) -> impl Iterator<Item = u8> {
643 let max_value = 255u8 >> prefix_mask;
644 let l1 = core::cmp::min((max_value as usize).saturating_sub(1), size);
645 let (first_byte, mut rem) = if size == l1 {
646 (once(prefix + l1 as u8), 0)
647 } else {
648 (once(prefix + max_value as u8), size - l1)
649 };
650 let next_bytes = move || {
651 if rem > 0 {
652 if rem < 256 {
653 let result = rem - 1;
654 rem = 0;
655 Some(result as u8)
656 } else {
657 rem = rem.saturating_sub(255);
658 Some(255)
659 }
660 } else {
661 None
662 }
663 };
664 first_byte.chain(core::iter::from_fn(next_bytes))
665}
666
667fn encode_size_and_prefix<W>(size: usize, prefix: u8, prefix_mask: usize, out: &mut W)
669where
670 W: Output + ?Sized,
671{
672 for b in size_and_prefix_iterator(size, prefix, prefix_mask) {
673 out.push_byte(b)
674 }
675}
676
677fn decode_size(
679 first: u8,
680 input: &mut impl Input,
681 prefix_mask: usize,
682) -> Result<usize, codec::Error> {
683 let max_value = 255u8 >> prefix_mask;
684 let mut result = (first & max_value) as usize;
685 if result < max_value as usize {
686 return Ok(result)
687 }
688 result -= 1;
689 loop {
690 let n = input.read_byte()? as usize;
691 if n < 255 {
692 return Ok(result + n + 1)
693 }
694 result += 255;
695 }
696}
697
698#[derive(Debug, PartialEq, Eq, Clone)]
700pub enum Error<H> {
701 BadFormat,
702 Decode(codec::Error),
703 InvalidRecording(Vec<u8>, bool),
704 TrieError(Box<trie_db::TrieError<H, Self>>),
705}
706
707impl<H> core::fmt::Display for Error<H> {
708 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
709 fmt.write_str("Error")
710 }
711}
712
713impl<H> std::error::Error for Error<H> where H: core::fmt::Debug {}
714
715impl<H> From<codec::Error> for Error<H> {
716 fn from(x: codec::Error) -> Self {
717 Error::Decode(x)
718 }
719}
720
721impl<H> From<Box<trie_db::TrieError<H, Self>>> for Error<H> {
722 fn from(x: Box<trie_db::TrieError<H, Self>>) -> Self {
723 Error::TrieError(x)
724 }
725}