fc_storage/overrides/
runtime_api.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};
22// Substrate
23use sp_api::{ApiExt, ApiRef, ProvideRuntimeApi};
24use sp_runtime::{traits::Block as BlockT, Permill};
25// Frontier
26use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus};
27
28use crate::overrides::StorageOverride;
29
30/// A storage override for runtimes that use runtime API.
31#[derive(Clone)]
32pub struct RuntimeApiStorageOverride<B, C> {
33	client: Arc<C>,
34	_marker: PhantomData<B>,
35}
36
37impl<B, C> RuntimeApiStorageOverride<B, C> {
38	pub fn new(client: Arc<C>) -> Self {
39		Self {
40			client,
41			_marker: PhantomData,
42		}
43	}
44}
45
46impl<B, C> RuntimeApiStorageOverride<B, C>
47where
48	B: BlockT,
49	C: ProvideRuntimeApi<B>,
50	C::Api: EthereumRuntimeRPCApi<B>,
51{
52	fn api_version(api: &ApiRef<'_, C::Api>, block_hash: B::Hash) -> Option<u32> {
53		match api.api_version::<dyn EthereumRuntimeRPCApi<B>>(block_hash) {
54			Ok(Some(api_version)) => Some(api_version),
55			_ => None,
56		}
57	}
58}
59
60impl<B, C> StorageOverride<B> for RuntimeApiStorageOverride<B, C>
61where
62	B: BlockT,
63	C: ProvideRuntimeApi<B> + Send + Sync,
64	C::Api: EthereumRuntimeRPCApi<B>,
65{
66	fn account_code_at(&self, block_hash: B::Hash, address: Address) -> Option<Vec<u8>> {
67		self.client
68			.runtime_api()
69			.account_code_at(block_hash, address)
70			.ok()
71	}
72
73	fn account_storage_at(
74		&self,
75		block_hash: B::Hash,
76		address: Address,
77		index: U256,
78	) -> Option<H256> {
79		self.client
80			.runtime_api()
81			.storage_at(block_hash, address, index)
82			.ok()
83	}
84
85	fn current_block(&self, block_hash: B::Hash) -> Option<ethereum::BlockV3> {
86		let api = self.client.runtime_api();
87
88		let api_version = Self::api_version(&api, block_hash)?;
89		if api_version == 1 {
90			#[allow(deprecated)]
91			let old_block = api.current_block_before_version_2(block_hash).ok()?;
92			old_block.map(|block| block.into())
93		} else {
94			api.current_block(block_hash).ok()?
95		}
96	}
97
98	fn current_receipts(&self, block_hash: B::Hash) -> Option<Vec<ethereum::ReceiptV4>> {
99		let api = self.client.runtime_api();
100
101		let api_version = Self::api_version(&api, block_hash)?;
102		if api_version < 4 {
103			#[allow(deprecated)]
104			let old_receipts = api.current_receipts_before_version_4(block_hash).ok()?;
105			old_receipts.map(|receipts| {
106				receipts
107					.into_iter()
108					.map(|r| {
109						ethereum::ReceiptV4::Legacy(ethereum::EIP658ReceiptData {
110							status_code: r.state_root.to_low_u64_be() as u8,
111							used_gas: r.used_gas,
112							logs_bloom: r.logs_bloom,
113							logs: r.logs,
114						})
115					})
116					.collect()
117			})
118		} else {
119			self.client
120				.runtime_api()
121				.current_receipts(block_hash)
122				.ok()?
123		}
124	}
125
126	fn current_transaction_statuses(&self, block_hash: B::Hash) -> Option<Vec<TransactionStatus>> {
127		self.client
128			.runtime_api()
129			.current_transaction_statuses(block_hash)
130			.ok()?
131	}
132
133	fn elasticity(&self, block_hash: B::Hash) -> Option<Permill> {
134		if self.is_eip1559(block_hash) {
135			self.client.runtime_api().elasticity(block_hash).ok()?
136		} else {
137			None
138		}
139	}
140
141	fn is_eip1559(&self, block_hash: B::Hash) -> bool {
142		let api = self.client.runtime_api();
143		if let Some(api_version) = Self::api_version(&api, block_hash) {
144			api_version >= 2
145		} else {
146			false
147		}
148	}
149}