fc_storage/overrides/
runtime_api.rs1use std::{marker::PhantomData, sync::Arc};
20
21use ethereum_types::{Address, H256, U256};
22use sp_api::{ApiExt, ApiRef, ProvideRuntimeApi};
24use sp_runtime::{traits::Block as BlockT, Permill};
25use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus};
27
28use crate::overrides::StorageOverride;
29
30#[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}