fc_storage/
lib.rs

1// This file is part of Frontier.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19#![warn(unused_crate_dependencies)]
20
21pub mod overrides;
22
23use std::sync::Arc;
24
25use ethereum::{BlockV3, ReceiptV4};
26use ethereum_types::{Address, H256, U256};
27// Substrate
28use sc_client_api::{backend::Backend, StorageProvider};
29use sp_api::ProvideRuntimeApi;
30use sp_runtime::{traits::Block as BlockT, Permill};
31// Frontier
32use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus};
33use fp_storage::EthereumStorageSchema;
34
35pub use self::overrides::*;
36
37/// A storage override for runtimes that use different ethereum schema.
38///
39/// It fetches data from the state backend, with some assumptions about pallet-ethereum's storage
40/// schema, as a preference. However, if there is no ethereum schema in the state, it'll use the
41/// runtime API as fallback implementation.
42///
43/// It is used to avoid spawning the runtime and the overhead associated with it.
44#[derive(Clone)]
45pub struct StorageOverrideHandler<B, C, BE> {
46	querier: StorageQuerier<B, C, BE>,
47	fallback: RuntimeApiStorageOverride<B, C>,
48}
49
50impl<B, C, BE> StorageOverrideHandler<B, C, BE> {
51	pub fn new(client: Arc<C>) -> Self {
52		Self {
53			querier: StorageQuerier::new(client.clone()),
54			fallback: RuntimeApiStorageOverride::<B, C>::new(client),
55		}
56	}
57}
58
59impl<B, C, BE> StorageOverride<B> for StorageOverrideHandler<B, C, BE>
60where
61	B: BlockT,
62	C: ProvideRuntimeApi<B>,
63	C::Api: EthereumRuntimeRPCApi<B>,
64	C: StorageProvider<B, BE> + Send + Sync + 'static,
65	BE: Backend<B> + 'static,
66{
67	fn account_code_at(&self, at: B::Hash, address: Address) -> Option<Vec<u8>> {
68		match self.querier.storage_schema(at) {
69			Some(EthereumStorageSchema::V1) => {
70				SchemaV1StorageOverrideRef::new(&self.querier).account_code_at(at, address)
71			}
72			Some(EthereumStorageSchema::V2) => {
73				SchemaV2StorageOverrideRef::new(&self.querier).account_code_at(at, address)
74			}
75			Some(EthereumStorageSchema::V3) => {
76				SchemaV3StorageOverrideRef::new(&self.querier).account_code_at(at, address)
77			}
78			None => self.fallback.account_code_at(at, address),
79		}
80	}
81
82	fn account_storage_at(&self, at: B::Hash, address: Address, index: U256) -> Option<H256> {
83		match self.querier.storage_schema(at) {
84			Some(EthereumStorageSchema::V1) => SchemaV1StorageOverrideRef::new(&self.querier)
85				.account_storage_at(at, address, index),
86			Some(EthereumStorageSchema::V2) => SchemaV2StorageOverrideRef::new(&self.querier)
87				.account_storage_at(at, address, index),
88			Some(EthereumStorageSchema::V3) => SchemaV3StorageOverrideRef::new(&self.querier)
89				.account_storage_at(at, address, index),
90			None => self.fallback.account_storage_at(at, address, index),
91		}
92	}
93
94	fn current_block(&self, at: B::Hash) -> Option<BlockV3> {
95		match self.querier.storage_schema(at) {
96			Some(EthereumStorageSchema::V1) => {
97				SchemaV1StorageOverrideRef::new(&self.querier).current_block(at)
98			}
99			Some(EthereumStorageSchema::V2) => {
100				SchemaV2StorageOverrideRef::new(&self.querier).current_block(at)
101			}
102			Some(EthereumStorageSchema::V3) => {
103				SchemaV3StorageOverrideRef::new(&self.querier).current_block(at)
104			}
105			None => self.fallback.current_block(at),
106		}
107	}
108
109	fn current_receipts(&self, at: B::Hash) -> Option<Vec<ReceiptV4>> {
110		match self.querier.storage_schema(at) {
111			Some(EthereumStorageSchema::V1) => {
112				SchemaV1StorageOverrideRef::new(&self.querier).current_receipts(at)
113			}
114			Some(EthereumStorageSchema::V2) => {
115				SchemaV2StorageOverrideRef::new(&self.querier).current_receipts(at)
116			}
117			Some(EthereumStorageSchema::V3) => {
118				SchemaV3StorageOverrideRef::new(&self.querier).current_receipts(at)
119			}
120			None => self.fallback.current_receipts(at),
121		}
122	}
123
124	fn current_transaction_statuses(&self, at: B::Hash) -> Option<Vec<TransactionStatus>> {
125		match self.querier.storage_schema(at) {
126			Some(EthereumStorageSchema::V1) => {
127				SchemaV1StorageOverrideRef::new(&self.querier).current_transaction_statuses(at)
128			}
129			Some(EthereumStorageSchema::V2) => {
130				SchemaV2StorageOverrideRef::new(&self.querier).current_transaction_statuses(at)
131			}
132			Some(EthereumStorageSchema::V3) => {
133				SchemaV3StorageOverrideRef::new(&self.querier).current_transaction_statuses(at)
134			}
135			None => self.fallback.current_transaction_statuses(at),
136		}
137	}
138
139	fn elasticity(&self, at: B::Hash) -> Option<Permill> {
140		match self.querier.storage_schema(at) {
141			Some(EthereumStorageSchema::V1) => {
142				SchemaV1StorageOverrideRef::new(&self.querier).elasticity(at)
143			}
144			Some(EthereumStorageSchema::V2) => {
145				SchemaV2StorageOverrideRef::new(&self.querier).elasticity(at)
146			}
147			Some(EthereumStorageSchema::V3) => {
148				SchemaV3StorageOverrideRef::new(&self.querier).elasticity(at)
149			}
150			None => self.fallback.elasticity(at),
151		}
152	}
153
154	fn is_eip1559(&self, at: B::Hash) -> bool {
155		match self.querier.storage_schema(at) {
156			Some(EthereumStorageSchema::V1) => {
157				SchemaV1StorageOverrideRef::new(&self.querier).is_eip1559(at)
158			}
159			Some(EthereumStorageSchema::V2) => {
160				SchemaV2StorageOverrideRef::new(&self.querier).is_eip1559(at)
161			}
162			Some(EthereumStorageSchema::V3) => {
163				SchemaV3StorageOverrideRef::new(&self.querier).is_eip1559(at)
164			}
165			None => self.fallback.is_eip1559(at),
166		}
167	}
168}