1use ethereum_types::{H160, H256, U256};
20use jsonrpsee::core::RpcResult;
21use scale_codec::Encode;
22use sc_client_api::backend::{Backend, StorageProvider};
24use sc_transaction_pool_api::{InPoolTransaction, TransactionPool};
25use sp_api::ProvideRuntimeApi;
26use sp_block_builder::BlockBuilder as BlockBuilderApi;
27use sp_blockchain::HeaderBackend;
28use sp_inherents::CreateInherentDataProviders;
29use sp_runtime::traits::Block as BlockT;
30use fc_rpc_core::types::*;
32use fp_rpc::EthereumRuntimeRPCApi;
33
34use crate::{eth::Eth, frontier_backend_client, internal_err};
35
36impl<B, C, P, CT, BE, CIDP, EC> Eth<B, C, P, CT, BE, CIDP, EC>
37where
38 B: BlockT,
39 C: ProvideRuntimeApi<B>,
40 C::Api: BlockBuilderApi<B> + EthereumRuntimeRPCApi<B>,
41 C: HeaderBackend<B> + StorageProvider<B, BE> + 'static,
42 BE: Backend<B> + 'static,
43 P: TransactionPool<Block = B, Hash = B::Hash> + 'static,
44 CIDP: CreateInherentDataProviders<B, ()> + Send + 'static,
45{
46 pub async fn balance(
47 &self,
48 address: H160,
49 number_or_hash: Option<BlockNumberOrHash>,
50 ) -> RpcResult<U256> {
51 let number_or_hash = number_or_hash.unwrap_or(BlockNumberOrHash::Latest);
52 if number_or_hash == BlockNumberOrHash::Pending {
53 let (hash, api) = self
54 .pending_runtime_api()
55 .await
56 .map_err(|err| internal_err(format!("Create pending runtime api error: {err}")))?;
57 Ok(api
58 .account_basic(hash, address)
59 .map_err(|err| internal_err(format!("Fetch account balances failed: {err}")))?
60 .balance)
61 } else if let Ok(Some(id)) = frontier_backend_client::native_block_id::<B, C>(
62 self.client.as_ref(),
63 self.backend.as_ref(),
64 Some(number_or_hash),
65 )
66 .await
67 {
68 let substrate_hash = self
69 .client
70 .expect_block_hash_from_id(&id)
71 .map_err(|_| internal_err(format!("Expect block number from id: {id}")))?;
72
73 Ok(self
74 .client
75 .runtime_api()
76 .account_basic(substrate_hash, address)
77 .map_err(|err| internal_err(format!("Fetch account balances failed: {err:?}")))?
78 .balance)
79 } else {
80 Ok(U256::zero())
81 }
82 }
83
84 pub async fn storage_at(
85 &self,
86 address: H160,
87 index: U256,
88 number_or_hash: Option<BlockNumberOrHash>,
89 ) -> RpcResult<H256> {
90 let number_or_hash = number_or_hash.unwrap_or(BlockNumberOrHash::Latest);
91 if number_or_hash == BlockNumberOrHash::Pending {
92 let (hash, api) = self
93 .pending_runtime_api()
94 .await
95 .map_err(|err| internal_err(format!("Create pending runtime api error: {err}")))?;
96 Ok(api.storage_at(hash, address, index).unwrap_or_default())
97 } else if let Ok(Some(id)) = frontier_backend_client::native_block_id::<B, C>(
98 self.client.as_ref(),
99 self.backend.as_ref(),
100 Some(number_or_hash),
101 )
102 .await
103 {
104 let substrate_hash = self
105 .client
106 .expect_block_hash_from_id(&id)
107 .map_err(|_| internal_err(format!("Expect block number from id: {id}")))?;
108 Ok(self
109 .storage_override
110 .account_storage_at(substrate_hash, address, index)
111 .unwrap_or_default())
112 } else {
113 Ok(H256::default())
114 }
115 }
116
117 pub async fn transaction_count(
118 &self,
119 address: H160,
120 number_or_hash: Option<BlockNumberOrHash>,
121 ) -> RpcResult<U256> {
122 if let Some(BlockNumberOrHash::Pending) = number_or_hash {
123 let substrate_hash = self.client.info().best_hash;
124
125 let nonce = self
126 .client
127 .runtime_api()
128 .account_basic(substrate_hash, address)
129 .map_err(|err| internal_err(format!("Fetch account nonce failed: {err}")))?
130 .nonce;
131
132 let mut current_nonce = nonce;
133 let mut current_tag = (address, nonce).encode();
134 for tx in self.pool.ready() {
135 if tx.provides().first() == Some(¤t_tag) {
138 current_nonce = current_nonce.saturating_add(1.into());
139 current_tag = (address, current_nonce).encode();
140 }
141 }
142
143 return Ok(current_nonce);
144 }
145
146 let id = match frontier_backend_client::native_block_id::<B, C>(
147 self.client.as_ref(),
148 self.backend.as_ref(),
149 number_or_hash,
150 )
151 .await?
152 {
153 Some(id) => id,
154 None => return Ok(U256::zero()),
155 };
156
157 let substrate_hash = self
158 .client
159 .expect_block_hash_from_id(&id)
160 .map_err(|_| internal_err(format!("Expect block number from id: {id}")))?;
161
162 Ok(self
163 .client
164 .runtime_api()
165 .account_basic(substrate_hash, address)
166 .map_err(|err| internal_err(format!("Fetch account nonce failed: {err}")))?
167 .nonce)
168 }
169
170 pub async fn code_at(
171 &self,
172 address: H160,
173 number_or_hash: Option<BlockNumberOrHash>,
174 ) -> RpcResult<Bytes> {
175 let number_or_hash = number_or_hash.unwrap_or(BlockNumberOrHash::Latest);
176 if number_or_hash == BlockNumberOrHash::Pending {
177 let (hash, api) = self
178 .pending_runtime_api()
179 .await
180 .map_err(|err| internal_err(format!("Create pending runtime api error: {err}")))?;
181 Ok(api
182 .account_code_at(hash, address)
183 .unwrap_or_default()
184 .into())
185 } else if let Ok(Some(id)) = frontier_backend_client::native_block_id::<B, C>(
186 self.client.as_ref(),
187 self.backend.as_ref(),
188 Some(number_or_hash),
189 )
190 .await
191 {
192 let substrate_hash = self
193 .client
194 .expect_block_hash_from_id(&id)
195 .map_err(|_| internal_err(format!("Expect block number from id: {id}")))?;
196 Ok(self
197 .storage_override
198 .account_code_at(substrate_hash, address)
199 .unwrap_or_default()
200 .into())
201 } else {
202 Ok(Bytes(vec![]))
203 }
204 }
205}