1#[cfg(feature = "std")]
21use serde::{Deserialize, Serialize};
22
23use tetcore_std::prelude::*;
24
25use crate::ConsensusEngineId;
26use crate::codec::{Decode, Encode, Input, Error};
27use tet_core::{ChangesTrieConfiguration, RuntimeDebug};
28
29#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)]
31#[cfg_attr(feature = "std", derive(Serialize, Deserialize, tetsy_util_mem::MallocSizeOf))]
32pub struct Digest<Hash> {
33 #[cfg_attr(
35 feature = "std",
36 serde(bound(serialize = "Hash: codec::Codec", deserialize = "Hash: codec::Codec"))
37 )]
38 pub logs: Vec<DigestItem<Hash>>,
39}
40
41impl<Item> Default for Digest<Item> {
42 fn default() -> Self {
43 Digest { logs: Vec::new(), }
44 }
45}
46
47impl<Hash> Digest<Hash> {
48 pub fn logs(&self) -> &[DigestItem<Hash>] {
50 &self.logs
51 }
52
53 pub fn push(&mut self, item: DigestItem<Hash>) {
55 self.logs.push(item);
56 }
57
58 pub fn pop(&mut self) -> Option<DigestItem<Hash>> {
60 self.logs.pop()
61 }
62
63 pub fn log<T: ?Sized, F: Fn(&DigestItem<Hash>) -> Option<&T>>(&self, predicate: F) -> Option<&T> {
65 self.logs().iter()
66 .filter_map(predicate)
67 .next()
68 }
69
70 pub fn convert_first<T, F: Fn(&DigestItem<Hash>) -> Option<T>>(&self, predicate: F) -> Option<T> {
72 self.logs().iter()
73 .filter_map(predicate)
74 .next()
75 }
76}
77
78
79#[derive(PartialEq, Eq, Clone, RuntimeDebug)]
82#[cfg_attr(feature = "std", derive(tetsy_util_mem::MallocSizeOf))]
83pub enum DigestItem<Hash> {
84 ChangesTrieRoot(Hash),
88
89 PreRuntime(ConsensusEngineId, Vec<u8>),
102
103 Consensus(ConsensusEngineId, Vec<u8>),
107
108 Seal(ConsensusEngineId, Vec<u8>),
111
112 ChangesTrieSignal(ChangesTrieSignal),
115
116 Other(Vec<u8>),
118}
119
120#[derive(PartialEq, Eq, Clone, Encode, Decode)]
122#[cfg_attr(feature = "std", derive(Debug, tetsy_util_mem::MallocSizeOf))]
123pub enum ChangesTrieSignal {
124 NewConfiguration(Option<ChangesTrieConfiguration>),
136}
137
138#[cfg(feature = "std")]
139impl<Hash: Encode> serde::Serialize for DigestItem<Hash> {
140 fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
141 self.using_encoded(|bytes| {
142 tet_core::bytes::serialize(bytes, seq)
143 })
144 }
145}
146
147#[cfg(feature = "std")]
148impl<'a, Hash: Decode> serde::Deserialize<'a> for DigestItem<Hash> {
149 fn deserialize<D>(de: D) -> Result<Self, D::Error> where
150 D: serde::Deserializer<'a>,
151 {
152 let r = tet_core::bytes::deserialize(de)?;
153 Decode::decode(&mut &r[..])
154 .map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e)))
155 }
156}
157
158#[derive(PartialEq, Eq, Clone, RuntimeDebug)]
161pub enum DigestItemRef<'a, Hash: 'a> {
162 ChangesTrieRoot(&'a Hash),
164 PreRuntime(&'a ConsensusEngineId, &'a Vec<u8>),
171 Consensus(&'a ConsensusEngineId, &'a Vec<u8>),
175 Seal(&'a ConsensusEngineId, &'a Vec<u8>),
178 ChangesTrieSignal(&'a ChangesTrieSignal),
181 Other(&'a Vec<u8>),
183}
184
185#[repr(u32)]
190#[derive(Encode, Decode)]
191pub enum DigestItemType {
192 Other = 0,
193 ChangesTrieRoot = 2,
194 Consensus = 4,
195 Seal = 5,
196 PreRuntime = 6,
197 ChangesTrieSignal = 7,
198}
199
200#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
203pub enum OpaqueDigestItemId<'a> {
204 PreRuntime(&'a ConsensusEngineId),
206 Consensus(&'a ConsensusEngineId),
208 Seal(&'a ConsensusEngineId),
210 Other,
212}
213
214impl<Hash> DigestItem<Hash> {
215 pub fn dref<'a>(&'a self) -> DigestItemRef<'a, Hash> {
217 match *self {
218 DigestItem::ChangesTrieRoot(ref v) => DigestItemRef::ChangesTrieRoot(v),
219 DigestItem::PreRuntime(ref v, ref s) => DigestItemRef::PreRuntime(v, s),
220 DigestItem::Consensus(ref v, ref s) => DigestItemRef::Consensus(v, s),
221 DigestItem::Seal(ref v, ref s) => DigestItemRef::Seal(v, s),
222 DigestItem::ChangesTrieSignal(ref s) => DigestItemRef::ChangesTrieSignal(s),
223 DigestItem::Other(ref v) => DigestItemRef::Other(v),
224 }
225 }
226
227 pub fn as_changes_trie_root(&self) -> Option<&Hash> {
229 self.dref().as_changes_trie_root()
230 }
231
232 pub fn as_pre_runtime(&self) -> Option<(ConsensusEngineId, &[u8])> {
234 self.dref().as_pre_runtime()
235 }
236
237 pub fn as_consensus(&self) -> Option<(ConsensusEngineId, &[u8])> {
239 self.dref().as_consensus()
240 }
241
242 pub fn as_seal(&self) -> Option<(ConsensusEngineId, &[u8])> {
244 self.dref().as_seal()
245 }
246
247 pub fn as_changes_trie_signal(&self) -> Option<&ChangesTrieSignal> {
249 self.dref().as_changes_trie_signal()
250 }
251
252 pub fn as_other(&self) -> Option<&[u8]> {
254 match *self {
255 DigestItem::Other(ref v) => Some(&v[..]),
256 _ => None,
257 }
258 }
259
260 pub fn try_as_raw(&self, id: OpaqueDigestItemId) -> Option<&[u8]> {
262 self.dref().try_as_raw(id)
263 }
264
265 pub fn try_to<T: Decode>(&self, id: OpaqueDigestItemId) -> Option<T> {
268 self.dref().try_to::<T>(id)
269 }
270}
271
272impl<Hash: Encode> Encode for DigestItem<Hash> {
273 fn encode(&self) -> Vec<u8> {
274 self.dref().encode()
275 }
276}
277
278impl<Hash: Encode> codec::EncodeLike for DigestItem<Hash> {}
279
280impl<Hash: Decode> Decode for DigestItem<Hash> {
281 #[allow(deprecated)]
282 fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
283 let item_type: DigestItemType = Decode::decode(input)?;
284 match item_type {
285 DigestItemType::ChangesTrieRoot => Ok(DigestItem::ChangesTrieRoot(
286 Decode::decode(input)?,
287 )),
288 DigestItemType::PreRuntime => {
289 let vals: (ConsensusEngineId, Vec<u8>) = Decode::decode(input)?;
290 Ok(DigestItem::PreRuntime(vals.0, vals.1))
291 },
292 DigestItemType::Consensus => {
293 let vals: (ConsensusEngineId, Vec<u8>) = Decode::decode(input)?;
294 Ok(DigestItem::Consensus(vals.0, vals.1))
295 }
296 DigestItemType::Seal => {
297 let vals: (ConsensusEngineId, Vec<u8>) = Decode::decode(input)?;
298 Ok(DigestItem::Seal(vals.0, vals.1))
299 },
300 DigestItemType::ChangesTrieSignal => Ok(DigestItem::ChangesTrieSignal(
301 Decode::decode(input)?,
302 )),
303 DigestItemType::Other => Ok(DigestItem::Other(
304 Decode::decode(input)?,
305 )),
306 }
307 }
308}
309
310impl<'a, Hash> DigestItemRef<'a, Hash> {
311 pub fn as_changes_trie_root(&self) -> Option<&'a Hash> {
313 match *self {
314 DigestItemRef::ChangesTrieRoot(ref changes_trie_root) => Some(changes_trie_root),
315 _ => None,
316 }
317 }
318
319 pub fn as_pre_runtime(&self) -> Option<(ConsensusEngineId, &'a [u8])> {
321 match *self {
322 DigestItemRef::PreRuntime(consensus_engine_id, ref data) => Some((*consensus_engine_id, data)),
323 _ => None,
324 }
325 }
326
327 pub fn as_consensus(&self) -> Option<(ConsensusEngineId, &'a [u8])> {
329 match *self {
330 DigestItemRef::Consensus(consensus_engine_id, ref data) => Some((*consensus_engine_id, data)),
331 _ => None,
332 }
333 }
334
335 pub fn as_seal(&self) -> Option<(ConsensusEngineId, &'a [u8])> {
337 match *self {
338 DigestItemRef::Seal(consensus_engine_id, ref data) => Some((*consensus_engine_id, data)),
339 _ => None,
340 }
341 }
342
343 pub fn as_changes_trie_signal(&self) -> Option<&'a ChangesTrieSignal> {
345 match *self {
346 DigestItemRef::ChangesTrieSignal(ref changes_trie_signal) => Some(changes_trie_signal),
347 _ => None,
348 }
349 }
350
351 pub fn as_other(&self) -> Option<&'a [u8]> {
353 match *self {
354 DigestItemRef::Other(ref data) => Some(data),
355 _ => None,
356 }
357 }
358
359 pub fn try_as_raw(&self, id: OpaqueDigestItemId) -> Option<&'a [u8]> {
362 match (id, self) {
363 (OpaqueDigestItemId::Consensus(w), &DigestItemRef::Consensus(v, s)) |
364 (OpaqueDigestItemId::Seal(w), &DigestItemRef::Seal(v, s)) |
365 (OpaqueDigestItemId::PreRuntime(w), &DigestItemRef::PreRuntime(v, s))
366 if v == w => Some(&s[..]),
367 (OpaqueDigestItemId::Other, &DigestItemRef::Other(s)) => Some(&s[..]),
368 _ => None,
369 }
370 }
371
372 pub fn try_to<T: Decode>(&self, id: OpaqueDigestItemId) -> Option<T> {
375 self.try_as_raw(id).and_then(|mut x| Decode::decode(&mut x).ok())
376 }
377}
378
379impl<'a, Hash: Encode> Encode for DigestItemRef<'a, Hash> {
380 fn encode(&self) -> Vec<u8> {
381 let mut v = Vec::new();
382
383 match *self {
384 DigestItemRef::ChangesTrieRoot(changes_trie_root) => {
385 DigestItemType::ChangesTrieRoot.encode_to(&mut v);
386 changes_trie_root.encode_to(&mut v);
387 },
388 DigestItemRef::Consensus(val, data) => {
389 DigestItemType::Consensus.encode_to(&mut v);
390 (val, data).encode_to(&mut v);
391 },
392 DigestItemRef::Seal(val, sig) => {
393 DigestItemType::Seal.encode_to(&mut v);
394 (val, sig).encode_to(&mut v);
395 },
396 DigestItemRef::PreRuntime(val, data) => {
397 DigestItemType::PreRuntime.encode_to(&mut v);
398 (val, data).encode_to(&mut v);
399 },
400 DigestItemRef::ChangesTrieSignal(changes_trie_signal) => {
401 DigestItemType::ChangesTrieSignal.encode_to(&mut v);
402 changes_trie_signal.encode_to(&mut v);
403 },
404 DigestItemRef::Other(val) => {
405 DigestItemType::Other.encode_to(&mut v);
406 val.encode_to(&mut v);
407 },
408 }
409
410 v
411 }
412}
413
414impl ChangesTrieSignal {
415 pub fn as_new_configuration(&self) -> Option<&Option<ChangesTrieConfiguration>> {
417 match self {
418 ChangesTrieSignal::NewConfiguration(config) => Some(config),
419 }
420 }
421}
422
423impl<'a, Hash: Encode> codec::EncodeLike for DigestItemRef<'a, Hash> {}
424
425#[cfg(test)]
426mod tests {
427 use super::*;
428
429 #[test]
430 fn should_serialize_digest() {
431 let digest = Digest {
432 logs: vec![
433 DigestItem::ChangesTrieRoot(4),
434 DigestItem::Other(vec![1, 2, 3]),
435 DigestItem::Seal(*b"test", vec![1, 2, 3])
436 ],
437 };
438
439 assert_eq!(
440 ::serde_json::to_string(&digest).unwrap(),
441 r#"{"logs":["0x0204000000","0x000c010203","0x05746573740c010203"]}"#
442 );
443 }
444}