1#![cfg_attr(not(feature = "std"), no_std)]
19#![allow(clippy::large_enum_variant)]
20#![warn(unused_crate_dependencies)]
21
22extern crate alloc;
23
24use alloc::vec::Vec;
25use scale_codec::{Decode, DecodeWithMemTracking, Encode};
26use sp_core::H256;
27use sp_runtime::{
28 generic::{Digest, OpaqueDigestItemId},
29 ConsensusEngineId,
30};
31
32pub const FRONTIER_ENGINE_ID: ConsensusEngineId = [b'f', b'r', b'o', b'n'];
33
34#[derive(Clone, PartialEq, Eq)]
35pub enum Log {
36 Pre(PreLog),
37 Post(PostLog),
38}
39
40#[derive(Decode, Encode, Clone, PartialEq, Eq)]
41pub enum PreLog {
42 #[codec(index = 3)]
43 Block(ethereum::BlockV3),
44}
45
46#[derive(Decode, Encode, Clone, PartialEq, Eq)]
47pub enum PostLog {
48 #[codec(index = 1)]
50 Hashes(Hashes),
51 #[codec(index = 2)]
53 Block(ethereum::BlockV3),
54 #[codec(index = 3)]
56 BlockHash(H256),
57}
58
59#[derive(Decode, DecodeWithMemTracking, Encode, Clone, PartialEq, Eq)]
60pub struct Hashes {
61 pub block_hash: H256,
63 pub transaction_hashes: Vec<H256>,
65}
66
67impl Hashes {
68 pub fn from_block(block: ethereum::BlockV3) -> Self {
69 Hashes {
70 block_hash: block.header.hash(),
71 transaction_hashes: block
72 .transactions
73 .into_iter()
74 .map(|txn| txn.hash())
75 .collect(),
76 }
77 }
78}
79
80#[derive(Clone, Debug)]
81pub enum FindLogError {
82 NotFound,
83 MultipleLogs,
84}
85
86pub fn find_pre_log(digest: &Digest) -> Result<PreLog, FindLogError> {
87 _find_log(digest, OpaqueDigestItemId::PreRuntime(&FRONTIER_ENGINE_ID))
88}
89
90pub fn find_post_log(digest: &Digest) -> Result<PostLog, FindLogError> {
91 _find_log(digest, OpaqueDigestItemId::Consensus(&FRONTIER_ENGINE_ID))
92}
93
94fn _find_log<Log: Decode>(
95 digest: &Digest,
96 digest_item_id: OpaqueDigestItemId,
97) -> Result<Log, FindLogError> {
98 let mut found = None;
99
100 for log in digest.logs() {
101 let log = log.try_to::<Log>(digest_item_id);
102 match (log, found.is_some()) {
103 (Some(_), true) => return Err(FindLogError::MultipleLogs),
104 (Some(log), false) => found = Some(log),
105 (None, _) => (),
106 }
107 }
108
109 found.ok_or(FindLogError::NotFound)
110}
111
112pub fn find_log(digest: &Digest) -> Result<Log, FindLogError> {
113 let mut found = None;
114
115 for log in digest.logs() {
116 let pre_log = log.try_to::<PreLog>(OpaqueDigestItemId::PreRuntime(&FRONTIER_ENGINE_ID));
117 match (pre_log, found.is_some()) {
118 (Some(_), true) => return Err(FindLogError::MultipleLogs),
119 (Some(pre_log), false) => found = Some(Log::Pre(pre_log)),
120 (None, _) => (),
121 }
122
123 let post_log = log.try_to::<PostLog>(OpaqueDigestItemId::Consensus(&FRONTIER_ENGINE_ID));
124 match (post_log, found.is_some()) {
125 (Some(_), true) => return Err(FindLogError::MultipleLogs),
126 (Some(post_log), false) => found = Some(Log::Post(post_log)),
127 (None, _) => (),
128 }
129 }
130
131 found.ok_or(FindLogError::NotFound)
132}
133
134pub fn ensure_log(digest: &Digest) -> Result<(), FindLogError> {
135 find_log(digest).map(|_log| ())
136}