fp_consensus/
lib.rs

1// This file is part of Frontier.
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#![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	/// Ethereum block hash and txn hashes.
49	#[codec(index = 1)]
50	Hashes(Hashes),
51	/// Ethereum block.
52	#[codec(index = 2)]
53	Block(ethereum::BlockV3),
54	/// Ethereum block hash.
55	#[codec(index = 3)]
56	BlockHash(H256),
57}
58
59#[derive(Decode, DecodeWithMemTracking, Encode, Clone, PartialEq, Eq)]
60pub struct Hashes {
61	/// Ethereum block hash.
62	pub block_hash: H256,
63	/// Transaction hashes of the Ethereum block.
64	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}