// Copyright 2017-2019 Parity Technologies (UK) Ltd. // 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 . //! Generic implementation of a digest. #[cfg(feature = "std")] use serde_derive::Serialize; use rstd::prelude::*; use crate::codec::{Decode, Encode, Codec, Input}; use crate::traits::{self, Member, DigestItem as DigestItemT, MaybeHash}; use substrate_primitives::hash::H512 as Signature; /// Generic header digest. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Serialize))] pub struct Digest { /// A list of logs in the digest. pub logs: Vec, } impl Default for Digest { fn default() -> Self { Digest { logs: Vec::new(), } } } impl traits::Digest for Digest where Item: DigestItemT + Codec { type Hash = Item::Hash; type Item = Item; fn logs(&self) -> &[Self::Item] { &self.logs } fn push(&mut self, item: Self::Item) { self.logs.push(item); } fn pop(&mut self) -> Option { self.logs.pop() } } /// Digest item that is able to encode/decode 'system' digest items and /// provide opaque access to other items. #[derive(PartialEq, Eq, Clone)] #[cfg_attr(feature = "std", derive(Debug))] pub enum DigestItem { /// System digest item announcing that authorities set has been changed /// in the block. Contains the new set of authorities. AuthoritiesChange(Vec), /// System digest item that contains the root of changes trie at given /// block. It is created for every block iff runtime supports changes /// trie creation. ChangesTrieRoot(Hash), /// Put a Seal on it Seal(u64, Signature), /// Any 'non-system' digest item, opaque to the native code. Other(Vec), } #[cfg(feature = "std")] impl ::serde::Serialize for DigestItem { fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { self.using_encoded(|bytes| { ::substrate_primitives::bytes::serialize(bytes, seq) }) } } /// A 'referencing view' for digest item. Does not own its contents. Used by /// final runtime implementations for encoding/decoding its log items. #[derive(PartialEq, Eq, Clone)] #[cfg_attr(feature = "std", derive(Debug))] pub enum DigestItemRef<'a, Hash: 'a, AuthorityId: 'a> { /// Reference to `DigestItem::AuthoritiesChange`. AuthoritiesChange(&'a [AuthorityId]), /// Reference to `DigestItem::ChangesTrieRoot`. ChangesTrieRoot(&'a Hash), /// A sealed signature for testing Seal(&'a u64, &'a Signature), /// Any 'non-system' digest item, opaque to the native code. /// Reference to `DigestItem::Other`. Other(&'a Vec), } /// Type of the digest item. Used to gain explicit control over `DigestItem` encoding /// process. We need an explicit control, because final runtimes are encoding their own /// digest items using `DigestItemRef` type and we can't auto-derive `Decode` /// trait for `DigestItemRef`. #[repr(u32)] #[derive(Encode, Decode)] enum DigestItemType { Other = 0, AuthoritiesChange, ChangesTrieRoot, Seal, } impl DigestItem { /// Returns Some if `self` is a `DigestItem::Other`. pub fn as_other(&self) -> Option<&Vec> { match *self { DigestItem::Other(ref v) => Some(v), _ => None, } } /// Returns a 'referencing view' for this digest item. fn dref<'a>(&'a self) -> DigestItemRef<'a, Hash, AuthorityId> { match *self { DigestItem::AuthoritiesChange(ref v) => DigestItemRef::AuthoritiesChange(v), DigestItem::ChangesTrieRoot(ref v) => DigestItemRef::ChangesTrieRoot(v), DigestItem::Seal(ref v, ref s) => DigestItemRef::Seal(v, s), DigestItem::Other(ref v) => DigestItemRef::Other(v), } } } impl< Hash: Codec + Member, AuthorityId: Codec + Member + MaybeHash, > traits::DigestItem for DigestItem { type Hash = Hash; type AuthorityId = AuthorityId; fn as_authorities_change(&self) -> Option<&[Self::AuthorityId]> { self.dref().as_authorities_change() } fn as_changes_trie_root(&self) -> Option<&Self::Hash> { self.dref().as_changes_trie_root() } } impl Encode for DigestItem { fn encode(&self) -> Vec { self.dref().encode() } } impl Decode for DigestItem { fn decode(input: &mut I) -> Option { let item_type: DigestItemType = Decode::decode(input)?; match item_type { DigestItemType::AuthoritiesChange => Some(DigestItem::AuthoritiesChange( Decode::decode(input)?, )), DigestItemType::ChangesTrieRoot => Some(DigestItem::ChangesTrieRoot( Decode::decode(input)?, )), DigestItemType::Seal => { let vals: (u64, Signature) = Decode::decode(input)?; Some(DigestItem::Seal(vals.0, vals.1)) }, DigestItemType::Other => Some(DigestItem::Other( Decode::decode(input)?, )), } } } impl<'a, Hash: Codec + Member, AuthorityId: Codec + Member> DigestItemRef<'a, Hash, AuthorityId> { /// Cast this digest item into `AuthoritiesChange`. pub fn as_authorities_change(&self) -> Option<&'a [AuthorityId]> { match *self { DigestItemRef::AuthoritiesChange(ref authorities) => Some(authorities), _ => None, } } /// Cast this digest item into `ChangesTrieRoot`. pub fn as_changes_trie_root(&self) -> Option<&'a Hash> { match *self { DigestItemRef::ChangesTrieRoot(ref changes_trie_root) => Some(changes_trie_root), _ => None, } } } impl<'a, Hash: Encode, AuthorityId: Encode> Encode for DigestItemRef<'a, Hash, AuthorityId> { fn encode(&self) -> Vec { let mut v = Vec::new(); match *self { DigestItemRef::AuthoritiesChange(authorities) => { DigestItemType::AuthoritiesChange.encode_to(&mut v); authorities.encode_to(&mut v); }, DigestItemRef::ChangesTrieRoot(changes_trie_root) => { DigestItemType::ChangesTrieRoot.encode_to(&mut v); changes_trie_root.encode_to(&mut v); }, DigestItemRef::Seal(val, sig) => { DigestItemType::Seal.encode_to(&mut v); (val, sig).encode_to(&mut v); }, DigestItemRef::Other(val) => { DigestItemType::Other.encode_to(&mut v); val.encode_to(&mut v); }, } v } } #[cfg(test)] mod tests { use super::*; #[test] fn should_serialize_digest() { let digest = Digest { logs: vec![ DigestItem::AuthoritiesChange(vec![1]), DigestItem::ChangesTrieRoot(4), DigestItem::Seal(1, Signature::from_low_u64_be(15)), DigestItem::Other(vec![1, 2, 3]), ], }; assert_eq!( ::serde_json::to_string(&digest).unwrap(), r#"{"logs":["0x010401000000","0x0204000000","0x0301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f","0x000c010203"]}"# ); } }