fc_storage/overrides/
mod.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
19use std::{marker::PhantomData, sync::Arc};
20
21use ethereum_types::{Address, H256, U256};
22use scale_codec::Decode;
23// Substrate
24use sc_client_api::{Backend, StorageProvider};
25use sp_io::hashing::{blake2_128, twox_128};
26use sp_runtime::{traits::Block as BlockT, Permill};
27use sp_storage::StorageKey;
28// Frontier
29use fp_rpc::TransactionStatus;
30use fp_storage::{constants::*, EthereumStorageSchema, PALLET_ETHEREUM_SCHEMA};
31
32mod runtime_api;
33mod schema;
34
35pub use self::{
36	runtime_api::RuntimeApiStorageOverride,
37	schema::{
38		v1::{
39			SchemaStorageOverride as SchemaV1StorageOverride,
40			SchemaStorageOverrideRef as SchemaV1StorageOverrideRef,
41		},
42		v2::{
43			SchemaStorageOverride as SchemaV2StorageOverride,
44			SchemaStorageOverrideRef as SchemaV2StorageOverrideRef,
45		},
46		v3::{
47			SchemaStorageOverride as SchemaV3StorageOverride,
48			SchemaStorageOverrideRef as SchemaV3StorageOverrideRef,
49		},
50	},
51};
52
53/// This trait is used to obtain Ethereum-related data.
54pub trait StorageOverride<Block: BlockT>: Send + Sync {
55	/// Return the code with the given address.
56	fn account_code_at(&self, at: Block::Hash, address: Address) -> Option<Vec<u8>>;
57	/// Return the storage data with the given address and storage index.
58	fn account_storage_at(&self, at: Block::Hash, address: Address, index: U256) -> Option<H256>;
59
60	/// Return the current ethereum block.
61	fn current_block(&self, at: Block::Hash) -> Option<ethereum::BlockV3>;
62	/// Return the current ethereum transaction receipt.
63	fn current_receipts(&self, at: Block::Hash) -> Option<Vec<ethereum::ReceiptV4>>;
64	/// Return the current ethereum transaction status.
65	fn current_transaction_statuses(&self, at: Block::Hash) -> Option<Vec<TransactionStatus>>;
66
67	/// Return the elasticity multiplier at the given post-eip1559 block.
68	fn elasticity(&self, at: Block::Hash) -> Option<Permill>;
69	/// Return `true` if the request block is post-eip1559.
70	fn is_eip1559(&self, at: Block::Hash) -> bool;
71}
72
73fn storage_prefix_build(module: &[u8], storage: &[u8]) -> Vec<u8> {
74	[twox_128(module), twox_128(storage)].concat().to_vec()
75}
76
77fn blake2_128_extend(bytes: &[u8]) -> Vec<u8> {
78	let mut ext: Vec<u8> = blake2_128(bytes).to_vec();
79	ext.extend_from_slice(bytes);
80	ext
81}
82
83/// A useful utility for querying storage.
84#[derive(Clone)]
85pub struct StorageQuerier<B, C, BE> {
86	client: Arc<C>,
87	_marker: PhantomData<(B, BE)>,
88}
89
90impl<B, C, BE> StorageQuerier<B, C, BE> {
91	pub fn new(client: Arc<C>) -> Self {
92		Self {
93			client,
94			_marker: PhantomData,
95		}
96	}
97}
98
99impl<B, C, BE> StorageQuerier<B, C, BE>
100where
101	B: BlockT,
102	C: StorageProvider<B, BE>,
103	BE: Backend<B>,
104{
105	pub fn query<T: Decode>(&self, at: B::Hash, key: &StorageKey) -> Option<T> {
106		if let Ok(Some(data)) = self.client.storage(at, key) {
107			if let Ok(result) = Decode::decode(&mut &data.0[..]) {
108				return Some(result);
109			}
110		}
111		None
112	}
113
114	pub fn storage_schema(&self, at: B::Hash) -> Option<EthereumStorageSchema> {
115		let key = PALLET_ETHEREUM_SCHEMA.to_vec();
116		self.query::<EthereumStorageSchema>(at, &StorageKey(key))
117	}
118
119	pub fn account_code(&self, at: B::Hash, address: Address) -> Option<Vec<u8>> {
120		let mut key: Vec<u8> = storage_prefix_build(PALLET_EVM, EVM_ACCOUNT_CODES);
121		key.extend(blake2_128_extend(address.as_bytes()));
122		self.query::<Vec<u8>>(at, &StorageKey(key))
123	}
124
125	pub fn account_storage(&self, at: B::Hash, address: Address, index: U256) -> Option<H256> {
126		let mut key: Vec<u8> = storage_prefix_build(PALLET_EVM, EVM_ACCOUNT_STORAGES);
127		key.extend(blake2_128_extend(address.as_bytes()));
128		key.extend(blake2_128_extend(&index.to_big_endian()));
129
130		self.query::<H256>(at, &StorageKey(key))
131	}
132
133	pub fn current_block<Block: Decode>(&self, at: B::Hash) -> Option<Block> {
134		let key = storage_prefix_build(PALLET_ETHEREUM, ETHEREUM_CURRENT_BLOCK);
135		self.query::<Block>(at, &StorageKey(key))
136	}
137
138	pub fn current_receipts<Receipt: Decode>(&self, at: B::Hash) -> Option<Vec<Receipt>> {
139		let key = storage_prefix_build(PALLET_ETHEREUM, ETHEREUM_CURRENT_RECEIPTS);
140		self.query::<Vec<Receipt>>(at, &StorageKey(key))
141	}
142
143	pub fn current_transaction_statuses(&self, at: B::Hash) -> Option<Vec<TransactionStatus>> {
144		let key = storage_prefix_build(PALLET_ETHEREUM, ETHEREUM_CURRENT_TRANSACTION_STATUSES);
145		self.query::<Vec<TransactionStatus>>(at, &StorageKey(key))
146	}
147
148	pub fn elasticity(&self, at: B::Hash) -> Option<Permill> {
149		let key = storage_prefix_build(PALLET_BASE_FEE, BASE_FEE_ELASTICITY);
150		self.query::<Permill>(at, &StorageKey(key))
151	}
152}