client/rpc/impls/cfx/
light.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use cfx_types::{
6    AddressSpaceUtil, BigEndianHash, Space, H160, H256, H520, U128, U256, U64,
7};
8use cfx_util_macros::bail;
9use cfxcore::{
10    block_data_manager::BlockDataManager,
11    errors::account_result_to_rpc_result,
12    light_protocol::{self, query_service::TxInfo, Error as LightError},
13    verification::EpochReceiptProof,
14    ConsensusGraph, LightQueryService, PeerInfo, SharedConsensusGraph,
15};
16use cfxcore_accounts::AccountProvider;
17use delegate::delegate;
18use diem_types::transaction::TransactionPayload;
19use futures::future::{self, FutureExt};
20use jsonrpc_core::{BoxFuture, Error as RpcError, Result as JsonRpcResult};
21use log::{debug, info};
22use network::{
23    node_table::{Node, NodeId},
24    throttling, SessionDetails, UpdateNodeOperation,
25};
26use primitives::{
27    Account, DepositInfo, StorageRoot, TransactionWithSignature, VoteStakeInfo,
28};
29use rlp::Encodable;
30use std::{collections::BTreeMap, net::SocketAddr, sync::Arc};
31// To convert from CoreResult to BoxFuture by delegate! macro automatically.
32use crate::{
33    common::delegate_convert,
34    rpc::{
35        errors::{self, invalid_params_check},
36        helpers::{build_block, MAX_FEE_HISTORY_CACHE_BLOCK_COUNT},
37        impls::common::{self, RpcImpl as CommonImpl},
38        traits::{cfx::Cfx, debug::LocalRpc, test::TestRpc},
39        types::{
40            cfx::check_rpc_address_network,
41            pos::{Block as PosBlock, PoSEpochReward},
42            Account as RpcAccount, AccountPendingInfo,
43            AccountPendingTransactions, BlameInfo, Block as RpcBlock,
44            BlockHashOrEpochNumber, Bytes, CfxFeeHistory, CfxRpcLogFilter,
45            CheckBalanceAgainstTransactionResponse, ConsensusGraphStates,
46            EpochNumber, EstimateGasAndCollateralResponse, FeeHistory,
47            Log as RpcLog, PoSEconomics, Receipt as RpcReceipt,
48            RewardInfo as RpcRewardInfo, RpcAddress, SponsorInfo,
49            StatOnGasLoad, Status as RpcStatus, StorageCollateralInfo,
50            SyncGraphStates, TokenSupplyInfo, Transaction as RpcTransaction,
51            TransactionRequest, VoteParamsInfo, WrapTransaction, U64 as HexU64,
52        },
53        CoreBoxFuture, CoreResult,
54    },
55};
56use cfx_addr::Network;
57use cfx_parameters::rpc::GAS_PRICE_DEFAULT_VALUE;
58use cfxcore::{errors::Error::LightProtocol, light_protocol::QueryService};
59use diem_types::account_address::AccountAddress;
60
61// macro for reducing boilerplate for unsupported methods
62macro_rules! not_supported {
63    () => {};
64    ( fn $fn:ident ( &self $(, $name:ident : $type:ty)* ) $( -> BoxFuture<$ret:ty> )? ; $($tail:tt)* ) => {
65        #[allow(unused_variables)]
66        fn $fn ( &self $(, $name : $type)* ) $( -> BoxFuture<$ret> )? {
67            async {
68                Err(errors::unimplemented(Some("Tracking issue: https://github.com/Conflux-Chain/conflux-rust/issues/1461".to_string())))
69            }.boxed()
70        }
71
72        not_supported!($($tail)*);
73    };
74    ( fn $fn:ident ( &self $(, $name:ident : $type:ty)* ) $( -> $ret:ty )? ; $($tail:tt)* ) => {
75        #[allow(unused_variables)]
76        fn $fn ( &self $(, $name : $type)* ) $( -> $ret )? {
77            Err(errors::unimplemented(Some("Tracking issue: https://github.com/Conflux-Chain/conflux-rust/issues/1461".to_string())))
78        }
79
80        not_supported!($($tail)*);
81    };
82}
83
84pub struct RpcImpl {
85    // account provider used for signing transactions
86    accounts: Arc<AccountProvider>,
87
88    // consensus graph
89    consensus: SharedConsensusGraph,
90
91    // block data manager
92    data_man: Arc<BlockDataManager>,
93
94    // helper API for retrieving verified information from peers
95    light: Arc<LightQueryService>,
96}
97
98impl RpcImpl {
99    pub fn new(
100        light: Arc<LightQueryService>, accounts: Arc<AccountProvider>,
101        consensus: SharedConsensusGraph, data_man: Arc<BlockDataManager>,
102    ) -> Self {
103        RpcImpl {
104            accounts,
105            consensus,
106            data_man,
107            light,
108        }
109    }
110
111    fn check_address_network(
112        network: Network, light: &QueryService,
113    ) -> CoreResult<()> {
114        invalid_params_check(
115            "address",
116            check_rpc_address_network(Some(network), light.get_network_type()),
117        )
118        .map_err(|e| e.into())
119    }
120
121    fn get_epoch_number_with_pivot_check(
122        consensus_graph: SharedConsensusGraph,
123        block_hash_or_epoch_number: Option<BlockHashOrEpochNumber>,
124    ) -> CoreResult<EpochNumber> {
125        match block_hash_or_epoch_number {
126            Some(BlockHashOrEpochNumber::BlockHashWithOption {
127                hash,
128                require_pivot,
129            }) => {
130                let epoch_number = consensus_graph
131                    .get_block_epoch_number_with_pivot_check(
132                        &hash,
133                        require_pivot.unwrap_or(true),
134                    )?;
135                Ok(EpochNumber::Num(U64::from(epoch_number)))
136            }
137            Some(BlockHashOrEpochNumber::EpochNumber(epoch_number)) => {
138                Ok(epoch_number)
139            }
140            None => Ok(EpochNumber::LatestState),
141        }
142    }
143
144    fn account(
145        &self, address: RpcAddress, num: Option<EpochNumber>,
146    ) -> CoreBoxFuture<RpcAccount> {
147        let epoch = num.unwrap_or(EpochNumber::LatestState).into();
148
149        info!(
150            "RPC Request: cfx_getAccount address={:?} epoch={:?}",
151            address, epoch
152        );
153
154        // clone `self.light` to avoid lifetime issues due to capturing `self`
155        let light = self.light.clone();
156
157        let fut = async move {
158            Self::check_address_network(address.network, &light)?;
159            let network = address.network;
160
161            let account = invalid_params_check(
162                "epoch",
163                light.get_account(epoch, address.hex_address).await,
164            )?;
165
166            let account = account.unwrap_or(account_result_to_rpc_result(
167                "address",
168                Ok(Account::new_empty_with_balance(
169                    &address.hex_address.with_native_space(),
170                    &U256::zero(), /* balance */
171                    &U256::zero(), /* nonce */
172                )),
173            )?);
174
175            Ok(RpcAccount::try_from(account, network)?)
176        };
177
178        fut.boxed()
179    }
180
181    fn balance(
182        &self, address: RpcAddress,
183        block_hash_or_epoch_number: Option<BlockHashOrEpochNumber>,
184    ) -> CoreBoxFuture<U256> {
185        info!(
186            "RPC Request: cfx_getBalance address={:?} epoch={:?}",
187            address,
188            block_hash_or_epoch_number
189                .as_ref()
190                .ok_or(EpochNumber::LatestState)
191        );
192
193        // clone `self.light` to avoid lifetime issues due to capturing `self`
194        let light = self.light.clone();
195        let consensus_graph = self.consensus.clone();
196
197        let fut = async move {
198            let epoch = Self::get_epoch_number_with_pivot_check(
199                consensus_graph,
200                block_hash_or_epoch_number,
201            )?
202            .into();
203            Self::check_address_network(address.network, &light)?;
204
205            let account = invalid_params_check(
206                "address",
207                light.get_account(epoch, address.into()).await,
208            )?;
209
210            Ok(account
211                .map(|account| account.balance.into())
212                .unwrap_or_default())
213        };
214
215        fut.boxed()
216    }
217
218    fn admin(
219        &self, address: RpcAddress, num: Option<EpochNumber>,
220    ) -> CoreBoxFuture<Option<RpcAddress>> {
221        let epoch = num.unwrap_or(EpochNumber::LatestState).into();
222        let network = address.network;
223
224        info!(
225            "RPC Request: cfx_getAdmin address={:?} epoch={:?}",
226            address, epoch
227        );
228
229        // clone `self.light` to avoid lifetime issues due to capturing `self`
230        let light = self.light.clone();
231
232        let fut = async move {
233            Self::check_address_network(address.network, &light)?;
234
235            let account = invalid_params_check(
236                "address",
237                light.get_account(epoch, address.into()).await,
238            )?;
239
240            match account {
241                None => Ok(None),
242                Some(acc) => {
243                    Ok(Some(RpcAddress::try_from_h160(acc.admin, network)?))
244                }
245            }
246        };
247
248        fut.boxed()
249    }
250
251    fn sponsor_info(
252        &self, address: RpcAddress, num: Option<EpochNumber>,
253    ) -> CoreBoxFuture<SponsorInfo> {
254        let epoch = num.unwrap_or(EpochNumber::LatestState).into();
255
256        info!(
257            "RPC Request: cfx_getSponsorInfo address={:?} epoch={:?}",
258            address, epoch
259        );
260
261        // clone `self.light` to avoid lifetime issues due to capturing `self`
262        let light = self.light.clone();
263
264        let fut = async move {
265            Self::check_address_network(address.network, &light)?;
266            let network = address.network;
267
268            let account = invalid_params_check(
269                "address",
270                light.get_account(epoch, address.into()).await,
271            )?;
272
273            match account {
274                None => Ok(SponsorInfo::default(network)?),
275                Some(acc) => {
276                    Ok(SponsorInfo::try_from(acc.sponsor_info, network)?)
277                }
278            }
279        };
280
281        fut.boxed()
282    }
283
284    fn staking_balance(
285        &self, address: RpcAddress, num: Option<EpochNumber>,
286    ) -> CoreBoxFuture<U256> {
287        let epoch = num.unwrap_or(EpochNumber::LatestState).into();
288
289        info!(
290            "RPC Request: cfx_getStakingBalance address={:?} epoch={:?}",
291            address, epoch
292        );
293
294        // clone `self.light` to avoid lifetime issues due to capturing `self`
295        let light = self.light.clone();
296
297        let fut = async move {
298            Self::check_address_network(address.network, &light)?;
299
300            let account = invalid_params_check(
301                "address",
302                light.get_account(epoch, address.into()).await,
303            )?;
304
305            Ok(account
306                .map(|account| account.staking_balance.into())
307                .unwrap_or_default())
308        };
309
310        fut.boxed()
311    }
312
313    fn deposit_list(
314        &self, address: RpcAddress, num: Option<EpochNumber>,
315    ) -> CoreBoxFuture<Vec<DepositInfo>> {
316        let epoch = num.unwrap_or(EpochNumber::LatestState).into();
317
318        info!(
319            "RPC Request: cfx_getDepositList address={:?} epoch_num={:?}",
320            address, epoch
321        );
322
323        // clone `self.light` to avoid lifetime issues due to capturing `self`
324        let light = self.light.clone();
325
326        let fut = async move {
327            Self::check_address_network(address.network, &light)?;
328
329            let maybe_list = invalid_params_check(
330                "address",
331                light.get_deposit_list(epoch, address.into()).await,
332            )?;
333
334            match maybe_list {
335                None => Ok(vec![]),
336                Some(deposit_list) => Ok(deposit_list.0),
337            }
338        };
339
340        fut.boxed()
341    }
342
343    pub fn account_pending_info(
344        &self, address: RpcAddress,
345    ) -> CoreBoxFuture<Option<AccountPendingInfo>> {
346        info!("RPC Request: cfx_getAccountPendingInfo({:?})", address);
347
348        let fut = async move {
349            // TODO impl light node rpc
350            Ok(None)
351        };
352        fut.boxed()
353    }
354
355    fn vote_list(
356        &self, address: RpcAddress, num: Option<EpochNumber>,
357    ) -> CoreBoxFuture<Vec<VoteStakeInfo>> {
358        let epoch = num.unwrap_or(EpochNumber::LatestState).into();
359
360        info!(
361            "RPC Request: cfx_getVoteList address={:?} epoch_num={:?}",
362            address, epoch
363        );
364
365        // clone `self.light` to avoid lifetime issues due to capturing `self`
366        let light = self.light.clone();
367
368        let fut = async move {
369            Self::check_address_network(address.network, &light)?;
370
371            let maybe_list = invalid_params_check(
372                "address",
373                light.get_vote_list(epoch, address.into()).await,
374            )?;
375
376            match maybe_list {
377                None => Ok(vec![]),
378                Some(vote_list) => Ok(vote_list.0),
379            }
380        };
381
382        fut.boxed()
383    }
384
385    fn collateral_for_storage(
386        &self, address: RpcAddress, num: Option<EpochNumber>,
387    ) -> CoreBoxFuture<U256> {
388        let epoch = num.unwrap_or(EpochNumber::LatestState).into();
389
390        info!(
391            "RPC Request: cfx_getCollateralForStorage address={:?} epoch={:?}",
392            address, epoch
393        );
394
395        // clone `self.light` to avoid lifetime issues due to capturing `self`
396        let light = self.light.clone();
397
398        let fut = async move {
399            Self::check_address_network(address.network, &light)?;
400
401            let account = invalid_params_check(
402                "address",
403                light.get_account(epoch, address.into()).await,
404            )?;
405
406            Ok(account
407                .map(|account| account.collateral_for_storage.into())
408                .unwrap_or_default())
409        };
410
411        fut.boxed()
412    }
413
414    fn code(
415        &self, address: RpcAddress,
416        block_hash_or_epoch_number: Option<BlockHashOrEpochNumber>,
417    ) -> CoreBoxFuture<Bytes> {
418        info!(
419            "RPC Request: cfx_getCode address={:?} epoch={:?}",
420            address,
421            block_hash_or_epoch_number
422                .as_ref()
423                .ok_or(EpochNumber::LatestState)
424        );
425
426        // clone `self.light` to avoid lifetime issues due to capturing `self`
427        let light = self.light.clone();
428        let consensus_graph = self.consensus.clone();
429
430        let fut = async move {
431            let epoch = Self::get_epoch_number_with_pivot_check(
432                consensus_graph,
433                block_hash_or_epoch_number,
434            )?
435            .into();
436            Self::check_address_network(address.network, &light)?;
437
438            // FIMXE:
439            //  We should get rid of the invalid_params_check when the
440            //  error conversion is done within the light service methods.
441            //  Same for all other usages here in this file.
442            Ok(Bytes::new(
443                invalid_params_check(
444                    "address",
445                    light.get_code(epoch, address.into()).await,
446                )?
447                .unwrap_or_default(),
448            ))
449        };
450
451        fut.boxed()
452    }
453
454    fn get_logs(&self, filter: CfxRpcLogFilter) -> CoreBoxFuture<Vec<RpcLog>> {
455        info!("RPC Request: cfx_getLogs filter={:?}", filter);
456
457        // clone `self.light` to avoid lifetime issues due to capturing `self`
458        let light = self.light.clone();
459
460        let fut = async move {
461            // all addresses specified should be for the correct network
462            if let Some(addresses) = &filter.address {
463                for address in addresses.iter() {
464                    invalid_params_check(
465                        "filter.address",
466                        check_rpc_address_network(
467                            Some(address.network),
468                            light.get_network_type(),
469                        ),
470                    )?;
471                }
472            }
473
474            let filter = filter.into_primitive()?;
475
476            let logs = light
477                .get_logs(filter)
478                .await
479                .map_err(|e| e.to_string()) // TODO(thegaram): return meaningful error
480                .map_err(RpcError::invalid_params)?;
481
482            Ok(logs
483                .into_iter()
484                .map(|l| {
485                    RpcLog::try_from_localized(l, *light.get_network_type())
486                })
487                .collect::<Result<_, _>>()?)
488        };
489
490        fut.boxed()
491    }
492
493    fn send_tx_helper(
494        light: Arc<LightQueryService>, raw: Bytes,
495    ) -> CoreResult<H256> {
496        let raw: Vec<u8> = raw.into_vec();
497
498        // decode tx so that we have its hash
499        // this way we also avoid spamming peers with invalid txs
500        let tx: TransactionWithSignature =
501            TransactionWithSignature::from_raw(&raw.clone())
502                .map_err(|e| format!("Failed to decode tx: {:?}", e))
503                .map_err(RpcError::invalid_params)?;
504
505        debug!("Deserialized tx: {:?}", tx);
506
507        // TODO(thegaram): consider adding a light node specific tx pool;
508        // light nodes would track those txs and maintain their statuses
509        // for future queries
510
511        match /* success = */ light.send_raw_tx(raw) {
512            true => Ok(tx.hash().into()),
513            false => bail!(LightProtocol(light_protocol::Error::InternalError("Unable to relay tx".into()).into())),
514        }
515    }
516
517    fn send_raw_transaction(&self, raw: Bytes) -> CoreResult<H256> {
518        info!("RPC Request: cfx_sendRawTransaction bytes={:?}", raw);
519        Self::send_tx_helper(self.light.clone(), raw)
520    }
521
522    fn send_transaction(
523        &self, mut tx: TransactionRequest, password: Option<String>,
524    ) -> CoreBoxFuture<H256> {
525        info!("RPC Request: cfx_sendTransaction tx={:?}", tx);
526
527        // clone `self.light` to avoid lifetime issues due to capturing `self`
528        let light = self.light.clone();
529        let accounts = self.accounts.clone();
530
531        let fut = async move {
532            tx.check_rpc_address_network("tx", light.get_network_type())?;
533
534            if tx.nonce.is_none() {
535                // TODO(thegaram): consider adding a light node specific tx pool
536                // to track the nonce
537
538                let address =
539                    tx.from.clone().ok_or("from should exist")?.into();
540                let epoch = EpochNumber::LatestState.into_primitive();
541
542                let nonce = light
543                    .get_account(epoch, address)
544                    .await?
545                    .map(|a| a.nonce)
546                    .unwrap_or(U256::zero());
547
548                tx.nonce.replace(nonce.into());
549                debug!("after loading nonce in latest state, tx = {:?}", tx);
550            }
551
552            let epoch_height = light.get_latest_verifiable_epoch_number().map_err(|_| {
553               format!("the light client cannot retrieve/verify the latest mined pivot block.")
554            })?;
555            let chain_id = light.get_latest_verifiable_chain_id().map_err(|_| {
556                format!("the light client cannot retrieve/verify the latest chain_id.")
557            })?;
558            let tx = tx.sign_with(
559                epoch_height,
560                chain_id.in_native_space(),
561                password,
562                accounts,
563            )?;
564
565            Self::send_tx_helper(light, Bytes::new(tx.rlp_bytes()))
566        };
567
568        fut.boxed()
569    }
570
571    fn storage_root(
572        &self, address: RpcAddress, epoch_num: Option<EpochNumber>,
573    ) -> CoreBoxFuture<Option<StorageRoot>> {
574        let epoch_num = epoch_num.unwrap_or(EpochNumber::LatestState);
575
576        info!(
577            "RPC Request: cfx_getStorageRoot address={:?} epoch={:?})",
578            address, epoch_num
579        );
580
581        // clone `self.light` to avoid lifetime issues due to capturing `self`
582        let light = self.light.clone();
583
584        let fut = async move {
585            Self::check_address_network(address.network, &light)?;
586
587            let root = invalid_params_check(
588                "address",
589                light
590                    .get_storage_root(epoch_num.into(), address.into())
591                    .await,
592            )?;
593
594            Ok(Some(root))
595        };
596
597        fut.boxed()
598    }
599
600    fn storage_at(
601        &self, address: RpcAddress, position: U256,
602        block_hash_or_epoch_number: Option<BlockHashOrEpochNumber>,
603    ) -> CoreBoxFuture<Option<H256>> {
604        let position: H256 = H256::from_uint(&position);
605        // let epoch_num = epoch_num.unwrap_or(EpochNumber::LatestState);
606
607        info!(
608            "RPC Request: cfx_getStorageAt address={:?} position={:?} epoch={:?})",
609            address,
610            position,
611            block_hash_or_epoch_number
612                .as_ref()
613                .ok_or(EpochNumber::LatestState)
614        );
615
616        // clone `self.light` to avoid lifetime issues due to capturing `self`
617        let light = self.light.clone();
618        let consensus_graph = self.consensus.clone();
619
620        let fut = async move {
621            let epoch_num = Self::get_epoch_number_with_pivot_check(
622                consensus_graph,
623                block_hash_or_epoch_number,
624            )?;
625            Self::check_address_network(address.network, &light)?;
626
627            let maybe_entry = light
628                .get_storage(epoch_num.into(), address.into(), position)
629                .await
630                .map_err(|e| e.to_string()) // TODO(thegaram): return meaningful error
631                .map_err(RpcError::invalid_params)?;
632
633            Ok(maybe_entry.map(Into::into))
634        };
635
636        fut.boxed()
637    }
638
639    fn transaction_by_hash(
640        &self, hash: H256,
641    ) -> CoreBoxFuture<Option<RpcTransaction>> {
642        info!("RPC Request: cfx_getTransactionByHash hash={:?}", hash);
643
644        // TODO(thegaram): try to retrieve from local tx pool or cache first
645
646        // clone `self.light` to avoid lifetime issues due to capturing `self`
647        let light = self.light.clone();
648
649        let fut = async move {
650            let tx = light
651                .get_tx(hash.into())
652                .await
653                .map_err(|e| e.to_string()) // TODO(thegaram): return meaningful error
654                .map_err(RpcError::invalid_params)?;
655
656            Ok(Some(RpcTransaction::from_signed(
657                &tx,
658                None,
659                *light.get_network_type(),
660            )?))
661        };
662
663        fut.boxed()
664    }
665
666    fn transaction_receipt(
667        &self, tx_hash: H256,
668    ) -> CoreBoxFuture<Option<RpcReceipt>> {
669        let hash: H256 = tx_hash.into();
670        info!("RPC Request: cfx_getTransactionReceipt hash={:?}", hash);
671
672        // clone `self.light` to avoid lifetime issues due to capturing `self`
673        let light = self.light.clone();
674        let data_man = self.data_man.clone();
675
676        let fut = async move {
677            // TODO:
678            //  return an RpcReceipt directly after splitting cfxcore into
679            //  smaller crates. It's impossible now because of circular
680            //  dependency.
681
682            // return `null` on timeout
683            let tx_info = match light.get_tx_info(hash).await {
684                Ok(t) => t,
685                Err(LightError::Timeout(_)) => return Ok(None),
686                Err(e) => {
687                    bail!(RpcError::invalid_params(e.to_string()))
688                }
689            };
690
691            let TxInfo {
692                tx,
693                maybe_block_number,
694                receipt,
695                tx_index,
696                maybe_epoch,
697                maybe_state_root,
698                prior_gas_used,
699            } = tx_info;
700
701            if maybe_block_number.is_none() || tx_index.is_phantom {
702                return Ok(None);
703            }
704
705            let maybe_base_price = data_man
706                .block_header_by_hash(&tx_index.block_hash)
707                .and_then(|x| x.base_price());
708
709            let receipt = RpcReceipt::new(
710                tx,
711                receipt,
712                tx_index,
713                prior_gas_used,
714                maybe_epoch,
715                maybe_block_number.unwrap(),
716                maybe_base_price,
717                maybe_state_root,
718                // Can not offer error_message from light node.
719                None,
720                *light.get_network_type(),
721                false,
722                true,
723            )?;
724
725            Ok(Some(receipt))
726        };
727
728        fut.boxed()
729    }
730
731    pub fn epoch_number(&self, epoch: Option<EpochNumber>) -> CoreResult<U256> {
732        let epoch = epoch.unwrap_or(EpochNumber::LatestMined);
733        info!("RPC Request: cfx_epochNumber epoch={:?}", epoch);
734
735        invalid_params_check(
736            "epoch",
737            self.light
738                .get_height_from_epoch_number(epoch.into())
739                .map(|height| height.into()),
740        )
741        .map_err(|e| e.into())
742    }
743
744    pub fn next_nonce(
745        &self, address: RpcAddress, num: Option<BlockHashOrEpochNumber>,
746    ) -> CoreBoxFuture<U256> {
747        info!(
748            "RPC Request: cfx_getNextNonce address={:?} num={:?}",
749            address, num
750        );
751
752        // clone to avoid lifetime issues due to capturing `self`
753        let consensus_graph = self.consensus.clone();
754        let light = self.light.clone();
755
756        let fut = async move {
757            Self::check_address_network(address.network, &light)?;
758
759            let epoch =
760                Self::get_epoch_number_with_pivot_check(consensus_graph, num)?
761                    .into();
762
763            let account = invalid_params_check(
764                "address",
765                light.get_account(epoch, address.into()).await,
766            )?;
767
768            Ok(account
769                .map(|account| account.nonce.into())
770                .unwrap_or_default())
771        };
772
773        fut.boxed()
774    }
775
776    pub fn block_by_hash(
777        &self, hash: H256, include_txs: bool,
778    ) -> CoreBoxFuture<Option<RpcBlock>> {
779        let hash = hash.into();
780
781        info!(
782            "RPC Request: cfx_getBlockByHash hash={:?} include_txs={:?}",
783            hash, include_txs
784        );
785
786        // clone to avoid lifetime issues due to capturing `self`
787        let consensus_graph = self.consensus.clone();
788        let data_man = self.data_man.clone();
789        let light = self.light.clone();
790
791        let fut = async move {
792            let block = match light.retrieve_block(hash).await? {
793                None => return Ok(None),
794                Some(b) => b,
795            };
796
797            let inner = consensus_graph.inner.read();
798
799            Ok(Some(build_block(
800                &block,
801                *light.get_network_type(),
802                &*consensus_graph,
803                &*inner,
804                &data_man,
805                include_txs,
806                Some(Space::Native),
807            )?))
808        };
809
810        fut.boxed()
811    }
812
813    pub fn block_by_hash_with_pivot_assumption(
814        &self, block_hash: H256, pivot_hash: H256, epoch_number: U64,
815    ) -> CoreBoxFuture<RpcBlock> {
816        let block_hash = block_hash.into();
817        let pivot_hash = pivot_hash.into();
818        let epoch_number = epoch_number.as_u64();
819
820        info!(
821            "RPC Request: cfx_getBlockByHashWithPivotAssumption block_hash={:?} pivot_hash={:?} epoch_number={:?}",
822            block_hash, pivot_hash, epoch_number
823        );
824
825        // clone to avoid lifetime issues due to capturing `self`
826        let consensus_graph = self.consensus.clone();
827        let data_man = self.data_man.clone();
828        let light = self.light.clone();
829
830        let fut = async move {
831            // check pivot assumption
832            // make sure not to hold the lock through await's
833            consensus_graph
834                .inner
835                .read()
836                .check_block_pivot_assumption(&pivot_hash, epoch_number)
837                .map_err(RpcError::invalid_params)?;
838
839            // retrieve block body
840            let block = light
841                .retrieve_block(block_hash)
842                .await?
843                .ok_or_else(|| RpcError::invalid_params("Block not found"))?;
844
845            let inner = consensus_graph.inner.read();
846
847            Ok(build_block(
848                &block,
849                *light.get_network_type(),
850                &*consensus_graph,
851                &*inner,
852                &data_man,
853                true,
854                Some(Space::Native),
855            )?)
856        };
857
858        fut.boxed()
859    }
860
861    pub fn block_by_epoch_number(
862        &self, epoch: EpochNumber, include_txs: bool,
863    ) -> CoreBoxFuture<Option<RpcBlock>> {
864        info!(
865            "RPC Request: cfx_getBlockByEpochNumber epoch={:?} include_txs={:?}",
866            epoch, include_txs
867        );
868
869        // clone to avoid lifetime issues due to capturing `self`
870        let consensus_graph = self.consensus.clone();
871        let data_man = self.data_man.clone();
872        let light = self.light.clone();
873
874        let fut = async move {
875            let epoch: u64 = light
876                .get_height_from_epoch_number(epoch.into())
877                .map_err(|e| e.to_string())
878                .map_err(RpcError::invalid_params)?;
879
880            // make sure not to hold the lock through await's
881            let hash = consensus_graph
882                .inner
883                .read()
884                .get_pivot_hash_from_epoch_number(epoch)
885                .map_err(RpcError::invalid_params)?;
886
887            // retrieve block body
888            let block = match light.retrieve_block(hash).await? {
889                None => return Ok(None),
890                Some(b) => b,
891            };
892
893            let inner = consensus_graph.inner.read();
894
895            Ok(Some(build_block(
896                &block,
897                *light.get_network_type(),
898                &*consensus_graph,
899                &*inner,
900                &data_man,
901                include_txs,
902                Some(Space::Native),
903            )?))
904        };
905
906        fut.boxed()
907    }
908
909    pub fn blocks_by_epoch(&self, epoch: EpochNumber) -> CoreResult<Vec<H256>> {
910        info!("RPC Request: cfx_getBlocksByEpoch epoch_number={:?}", epoch);
911
912        let height = self
913            .light
914            .get_height_from_epoch_number(epoch.into())
915            .map_err(|e| e.to_string())
916            .map_err(RpcError::invalid_params)?;
917
918        let hashes = self
919            .consensus
920            .inner
921            .read()
922            .block_hashes_by_epoch(height)
923            .map_err(|e| e.to_string())
924            .map_err(RpcError::invalid_params)?;
925
926        Ok(hashes)
927    }
928
929    pub fn gas_price(&self) -> CoreBoxFuture<U256> {
930        info!("RPC Request: cfx_gasPrice");
931
932        let light = self.light.clone();
933
934        let fut = async move {
935            Ok(light
936                .gas_price()
937                .await
938                .map_err(|e| e.to_string())
939                .map_err(RpcError::invalid_params)?
940                .unwrap_or(GAS_PRICE_DEFAULT_VALUE.into()))
941        };
942
943        fut.boxed()
944    }
945
946    pub fn interest_rate(
947        &self, epoch: Option<EpochNumber>,
948    ) -> CoreBoxFuture<U256> {
949        let epoch = epoch.unwrap_or(EpochNumber::LatestState).into();
950        info!("RPC Request: cfx_getInterestRate epoch={:?}", epoch);
951
952        // clone to avoid lifetime issues due to capturing `self`
953        let light = self.light.clone();
954
955        let fut = async move {
956            Ok(light
957                .get_interest_rate(epoch)
958                .await
959                .map_err(|e| e.to_string())
960                .map_err(RpcError::invalid_params)?)
961        };
962
963        fut.boxed()
964    }
965
966    pub fn accumulate_interest_rate(
967        &self, epoch: Option<EpochNumber>,
968    ) -> CoreBoxFuture<U256> {
969        let epoch = epoch.unwrap_or(EpochNumber::LatestState).into();
970
971        info!(
972            "RPC Request: cfx_getAccumulateInterestRate epoch={:?}",
973            epoch
974        );
975
976        // clone to avoid lifetime issues due to capturing `self`
977        let light = self.light.clone();
978
979        let fut = async move {
980            Ok(light
981                .get_accumulate_interest_rate(epoch)
982                .await
983                .map_err(|e| e.to_string())
984                .map_err(RpcError::invalid_params)?)
985        };
986
987        fut.boxed()
988    }
989
990    pub fn pos_economics(
991        &self, epoch: Option<EpochNumber>,
992    ) -> CoreBoxFuture<PoSEconomics> {
993        let epoch = epoch.unwrap_or(EpochNumber::LatestState).into();
994
995        info!("RPC Request: cfx_getPoSEconomics epoch={:?}", epoch);
996
997        // clone to avoid lifetime issues due to capturing `self`
998        let light = self.light.clone();
999
1000        let fut = async move {
1001            Ok(light
1002                .get_pos_economics(epoch)
1003                .await
1004                .map(|ans| PoSEconomics {
1005                    total_pos_staking_tokens: ans[0],
1006                    distributable_pos_interest: ans[1],
1007                    last_distribute_block: ans[2].as_u64().into(),
1008                })
1009                .map_err(|e| e.to_string())
1010                .map_err(RpcError::invalid_params)?)
1011        };
1012
1013        fut.boxed()
1014    }
1015
1016    fn check_balance_against_transaction(
1017        &self, account_addr: RpcAddress, contract_addr: RpcAddress,
1018        gas_limit: U256, gas_price: U256, storage_limit: U256,
1019        epoch: Option<EpochNumber>,
1020    ) -> CoreBoxFuture<CheckBalanceAgainstTransactionResponse> {
1021        let epoch: primitives::EpochNumber =
1022            epoch.unwrap_or(EpochNumber::LatestState).into();
1023
1024        info!(
1025            "RPC Request: cfx_checkBalanceAgainstTransaction account_addr={:?} contract_addr={:?} gas_limit={:?} gas_price={:?} storage_limit={:?} epoch={:?}",
1026            account_addr, contract_addr, gas_limit, gas_price, storage_limit, epoch
1027        );
1028
1029        // clone to avoid lifetime issues due to capturing `self`
1030        let light = self.light.clone();
1031
1032        let fut = async move {
1033            Self::check_address_network(account_addr.network, &light)?;
1034            Self::check_address_network(contract_addr.network, &light)?;
1035
1036            let account_addr: H160 = account_addr.into();
1037            let contract_addr: H160 = contract_addr.into();
1038
1039            if storage_limit > U256::from(std::u64::MAX) {
1040                bail!(RpcError::invalid_params(format!("storage_limit has to be within the range of u64 but {} supplied!", storage_limit)));
1041            }
1042
1043            // retrieve accounts and sponsor info in parallel
1044            let (user_account, contract_account, is_sponsored) =
1045                future::try_join3(
1046                    light.get_account(epoch.clone(), account_addr),
1047                    light.get_account(epoch.clone(), contract_addr),
1048                    light.is_user_sponsored(epoch, contract_addr, account_addr),
1049                )
1050                .await?;
1051
1052            Ok(common::check_balance_against_transaction(
1053                user_account,
1054                contract_account,
1055                is_sponsored,
1056                gas_limit,
1057                gas_price,
1058                storage_limit,
1059            ))
1060        };
1061
1062        fut.boxed()
1063    }
1064
1065    fn fee_history(
1066        &self, mut block_count: HexU64, newest_block: EpochNumber,
1067        reward_percentiles: Option<Vec<f64>>,
1068    ) -> CoreBoxFuture<CfxFeeHistory> {
1069        info!(
1070            "RPC Request: cfx_feeHistory: block_count={}, newest_block={:?}, reward_percentiles={:?}",
1071            block_count, newest_block, reward_percentiles
1072        );
1073
1074        if block_count.as_u64() == 0 {
1075            return async { Ok(FeeHistory::new().into()) }.boxed();
1076        }
1077
1078        if block_count.as_u64() > MAX_FEE_HISTORY_CACHE_BLOCK_COUNT {
1079            block_count = HexU64::from(MAX_FEE_HISTORY_CACHE_BLOCK_COUNT);
1080        }
1081
1082        // clone to avoid lifetime issues due to capturing `self`
1083        let consensus_graph = self.consensus.clone();
1084        let light = self.light.clone();
1085        let reward_percentiles = reward_percentiles.unwrap_or_default();
1086
1087        let fut = async move {
1088            let start_height: u64 = light
1089                .get_height_from_epoch_number(newest_block.into())
1090                .map_err(|e| e.to_string())
1091                .map_err(RpcError::invalid_params)?;
1092
1093            let mut current_height = start_height;
1094
1095            let mut fee_history = FeeHistory::new();
1096
1097            while current_height
1098                >= start_height.saturating_sub(block_count.as_u64() - 1)
1099            {
1100                let block = fetch_block_for_fee_history(
1101                    consensus_graph.clone(),
1102                    light.clone(),
1103                    current_height,
1104                )
1105                .await?;
1106
1107                let transactions = block
1108                    .transactions
1109                    .iter()
1110                    .filter(|tx| tx.space() == Space::Native)
1111                    .map(|x| &**x);
1112                // Internal error happens only if the fetch header has
1113                // inconsistent block height
1114                fee_history
1115                    .push_front_block(
1116                        Space::Native,
1117                        &reward_percentiles,
1118                        &block.block_header,
1119                        transactions,
1120                    )
1121                    .map_err(|_| RpcError::internal_error())?;
1122
1123                if current_height == 0 {
1124                    break;
1125                } else {
1126                    current_height -= 1;
1127                }
1128            }
1129
1130            let block = fetch_block_for_fee_history(
1131                consensus_graph.clone(),
1132                light.clone(),
1133                start_height + 1,
1134            )
1135            .await?;
1136            let oldest_block = if current_height == 0 {
1137                0
1138            } else {
1139                current_height + 1
1140            };
1141            fee_history.finish(
1142                oldest_block,
1143                block.block_header.base_price().as_ref(),
1144                Space::Native,
1145            );
1146            Ok(fee_history.into())
1147        };
1148
1149        fut.boxed()
1150    }
1151}
1152
1153async fn fetch_block_for_fee_history(
1154    consensus_graph: Arc<ConsensusGraph>, light: Arc<QueryService>, height: u64,
1155) -> cfxcore::errors::Result<primitives::Block> {
1156    let hash = consensus_graph
1157        .inner
1158        .read()
1159        .get_pivot_hash_from_epoch_number(height)
1160        .map_err(RpcError::invalid_params)?;
1161
1162    match light.retrieve_block(hash).await? {
1163        None => Err(RpcError::internal_error().into()),
1164        Some(b) => Ok(b),
1165    }
1166}
1167
1168pub struct CfxHandler {
1169    common: Arc<CommonImpl>,
1170    rpc_impl: Arc<RpcImpl>,
1171}
1172
1173impl CfxHandler {
1174    pub fn new(common: Arc<CommonImpl>, rpc_impl: Arc<RpcImpl>) -> Self {
1175        CfxHandler { common, rpc_impl }
1176    }
1177}
1178
1179impl Cfx for CfxHandler {
1180    delegate! {
1181        to self.common {
1182            fn best_block_hash(&self) -> JsonRpcResult<H256>;
1183            fn confirmation_risk_by_hash(&self, block_hash: H256) -> JsonRpcResult<Option<U256>>;
1184            fn get_client_version(&self) -> JsonRpcResult<String>;
1185            fn get_status(&self) -> JsonRpcResult<RpcStatus>;
1186            fn skipped_blocks_by_epoch(&self, num: EpochNumber) -> JsonRpcResult<Vec<H256>>;
1187            fn account_pending_info(&self, addr: RpcAddress) -> BoxFuture<JsonRpcResult<Option<AccountPendingInfo>>>;
1188        }
1189
1190        to self.rpc_impl {
1191            fn account(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<RpcAccount>>;
1192            fn accumulate_interest_rate(&self, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<U256>>;
1193            fn admin(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<Option<RpcAddress>>>;
1194            fn balance(&self, address: RpcAddress, block_hash_or_epoch_number: Option<BlockHashOrEpochNumber>) -> BoxFuture<JsonRpcResult<U256>>;
1195            fn block_by_epoch_number(&self, epoch_num: EpochNumber, include_txs: bool) -> BoxFuture<JsonRpcResult<Option<RpcBlock>>>;
1196            fn block_by_hash_with_pivot_assumption(&self, block_hash: H256, pivot_hash: H256, epoch_number: U64) -> BoxFuture<JsonRpcResult<RpcBlock>>;
1197            fn block_by_hash(&self, hash: H256, include_txs: bool) -> BoxFuture<JsonRpcResult<Option<RpcBlock>>>;
1198            fn blocks_by_epoch(&self, num: EpochNumber) -> JsonRpcResult<Vec<H256>>;
1199            fn check_balance_against_transaction(&self, account_addr: RpcAddress, contract_addr: RpcAddress, gas_limit: U256, gas_price: U256, storage_limit: U256, epoch: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<CheckBalanceAgainstTransactionResponse>>;
1200            fn code(&self, address: RpcAddress, block_hash_or_epoch_num: Option<BlockHashOrEpochNumber>) -> BoxFuture<JsonRpcResult<Bytes>>;
1201            fn collateral_for_storage(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<U256>>;
1202            fn deposit_list(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<Vec<DepositInfo>>>;
1203            fn epoch_number(&self, epoch_num: Option<EpochNumber>) -> JsonRpcResult<U256>;
1204            fn gas_price(&self) -> BoxFuture<JsonRpcResult<U256>>;
1205            fn get_logs(&self, filter: CfxRpcLogFilter) -> BoxFuture<JsonRpcResult<Vec<RpcLog>>>;
1206            fn interest_rate(&self, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<U256>>;
1207            fn next_nonce(&self, address: RpcAddress, num: Option<BlockHashOrEpochNumber>) -> BoxFuture<JsonRpcResult<U256>>;
1208            fn pos_economics(&self, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<PoSEconomics>>;
1209            fn send_raw_transaction(&self, raw: Bytes) -> JsonRpcResult<H256>;
1210            fn sponsor_info(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<SponsorInfo>>;
1211            fn staking_balance(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<U256>>;
1212            fn storage_at(&self, addr: RpcAddress, pos: U256, block_hash_or_epoch_number: Option<BlockHashOrEpochNumber>) -> BoxFuture<JsonRpcResult<Option<H256>>>;
1213            fn storage_root(&self, address: RpcAddress, epoch_num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<Option<StorageRoot>>>;
1214            fn transaction_by_hash(&self, hash: H256) -> BoxFuture<JsonRpcResult<Option<RpcTransaction>>>;
1215            fn transaction_receipt(&self, tx_hash: H256) -> BoxFuture<JsonRpcResult<Option<RpcReceipt>>>;
1216            fn vote_list(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<Vec<VoteStakeInfo>>>;
1217            fn fee_history(&self, block_count: HexU64, newest_block: EpochNumber, reward_percentiles: Option<Vec<f64>>) -> BoxFuture<JsonRpcResult<CfxFeeHistory>>;
1218        }
1219    }
1220
1221    // TODO(thegaram): add support for these
1222    not_supported! {
1223        fn account_pending_transactions(&self, address: RpcAddress, maybe_start_nonce: Option<U256>, maybe_limit: Option<U64>) -> BoxFuture<JsonRpcResult<AccountPendingTransactions>>;
1224        fn block_by_block_number(&self, block_number: U64, include_txs: bool) -> BoxFuture<JsonRpcResult<Option<RpcBlock>>>;
1225        fn call(&self, request: TransactionRequest, block_hash_or_epoch_number: Option<BlockHashOrEpochNumber>) -> JsonRpcResult<Bytes>;
1226        fn estimate_gas_and_collateral(&self, request: TransactionRequest, epoch_num: Option<EpochNumber>) -> JsonRpcResult<EstimateGasAndCollateralResponse>;
1227        fn get_block_reward_info(&self, num: EpochNumber) -> JsonRpcResult<Vec<RpcRewardInfo>>;
1228        fn get_supply_info(&self, epoch_num: Option<EpochNumber>) -> JsonRpcResult<TokenSupplyInfo>;
1229        fn get_collateral_info(&self, epoch_num: Option<EpochNumber>) -> JsonRpcResult<StorageCollateralInfo>;
1230        fn get_vote_params(&self, epoch_num: Option<EpochNumber>) -> JsonRpcResult<VoteParamsInfo>;
1231        fn get_pos_reward_by_epoch(&self, epoch: EpochNumber) -> JsonRpcResult<Option<PoSEpochReward>>;
1232        fn get_fee_burnt(&self, epoch: Option<EpochNumber>) -> JsonRpcResult<U256>;
1233        fn max_priority_fee_per_gas(&self) -> BoxFuture<JsonRpcResult<U256>>;
1234    }
1235}
1236
1237pub struct TestRpcImpl {
1238    common: Arc<CommonImpl>,
1239    // rpc_impl: Arc<RpcImpl>,
1240}
1241
1242impl TestRpcImpl {
1243    pub fn new(common: Arc<CommonImpl>, _rpc_impl: Arc<RpcImpl>) -> Self {
1244        TestRpcImpl {
1245            common, /* , rpc_impl */
1246        }
1247    }
1248}
1249
1250impl TestRpc for TestRpcImpl {
1251    delegate! {
1252        to self.common {
1253            fn add_latency(&self, id: NodeId, latency_ms: f64) -> JsonRpcResult<()>;
1254            fn add_peer(&self, node_id: NodeId, address: SocketAddr) -> JsonRpcResult<()>;
1255            fn chain(&self) -> JsonRpcResult<Vec<RpcBlock>>;
1256            fn drop_peer(&self, node_id: NodeId, address: SocketAddr) -> JsonRpcResult<()>;
1257            fn get_block_count(&self) -> JsonRpcResult<u64>;
1258            fn get_goodput(&self) -> JsonRpcResult<String>;
1259            fn get_nodeid(&self, challenge: Vec<u8>) -> JsonRpcResult<Vec<u8>>;
1260            fn get_peer_info(&self) -> JsonRpcResult<Vec<PeerInfo>>;
1261            fn save_node_db(&self) -> JsonRpcResult<()>;
1262            fn say_hello(&self) -> JsonRpcResult<String>;
1263            fn stop(&self) -> JsonRpcResult<()>;
1264            fn pos_register(&self, voting_power: U64, version: Option<u8>) -> JsonRpcResult<(Bytes, AccountAddress)>;
1265            fn pos_update_voting_power(
1266                &self, pos_account: AccountAddress, increased_voting_power: U64,
1267            ) -> JsonRpcResult<()>;
1268            fn pos_stop_election(&self) -> JsonRpcResult<Option<u64>>;
1269            fn pos_start_voting(&self, initialize: bool) -> JsonRpcResult<()>;
1270            fn pos_stop_voting(&self) -> JsonRpcResult<()>;
1271            fn pos_voting_status(&self) -> JsonRpcResult<bool>;
1272            fn pos_start(&self) -> JsonRpcResult<()>;
1273            fn pos_force_vote_proposal(&self, block_id: H256) -> JsonRpcResult<()>;
1274            fn pos_force_propose(&self, round: U64, parent_block_id: H256, payload: Vec<TransactionPayload>) -> JsonRpcResult<()>;
1275            fn pos_trigger_timeout(&self, timeout_type: String) -> JsonRpcResult<()>;
1276            fn pos_force_sign_pivot_decision(&self, block_hash: H256, height: U64) -> JsonRpcResult<()>;
1277            fn pos_get_chosen_proposal(&self) -> JsonRpcResult<Option<PosBlock>>;
1278        }
1279    }
1280
1281    not_supported! {
1282        fn expire_block_gc(&self, timeout: u64) -> JsonRpcResult<()>;
1283        fn generate_block_with_blame_info(&self, num_txs: usize, block_size_limit: usize, blame_info: BlameInfo) -> JsonRpcResult<H256>;
1284        fn generate_block_with_fake_txs(&self, raw_txs_without_data: Bytes, adaptive: Option<bool>, tx_data_len: Option<usize>) -> JsonRpcResult<H256>;
1285        fn generate_block_with_nonce_and_timestamp(&self, parent: H256, referees: Vec<H256>, raw: Bytes, nonce: U256, timestamp: u64, adaptive: bool) -> JsonRpcResult<H256>;
1286        fn generate_custom_block(&self, parent_hash: H256, referee: Vec<H256>, raw_txs: Bytes, adaptive: Option<bool>, custom: Option<Vec<Bytes>>) -> JsonRpcResult<H256>;
1287        fn generate_empty_blocks(&self, num_blocks: usize) -> JsonRpcResult<Vec<H256>>;
1288        fn generate_fixed_block(&self, parent_hash: H256, referee: Vec<H256>, num_txs: usize, adaptive: bool, difficulty: Option<u64>, pos_reference: Option<H256>) -> JsonRpcResult<H256>;
1289        fn generate_one_block_with_direct_txgen(&self, num_txs: usize, block_size_limit: usize, num_txs_simple: usize, num_txs_erc20: usize) -> JsonRpcResult<H256>;
1290        fn generate_one_block(&self, num_txs: usize, block_size_limit: usize) -> JsonRpcResult<H256>;
1291        fn get_block_status(&self, block_hash: H256) -> JsonRpcResult<(u8, bool)>;
1292        fn get_executed_info(&self, block_hash: H256) -> JsonRpcResult<(H256, H256)> ;
1293        fn get_pivot_chain_and_weight(&self, height_range: Option<(u64, u64)>) -> JsonRpcResult<Vec<(H256, U256)>>;
1294        fn send_usable_genesis_accounts(&self, account_start_index: usize) -> JsonRpcResult<Bytes>;
1295        fn set_db_crash(&self, crash_probability: f64, crash_exit_code: i32) -> JsonRpcResult<()>;
1296    }
1297}
1298
1299pub struct DebugRpcImpl {
1300    common: Arc<CommonImpl>,
1301    rpc_impl: Arc<RpcImpl>,
1302}
1303
1304impl DebugRpcImpl {
1305    pub fn new(common: Arc<CommonImpl>, rpc_impl: Arc<RpcImpl>) -> Self {
1306        DebugRpcImpl { common, rpc_impl }
1307    }
1308}
1309
1310impl LocalRpc for DebugRpcImpl {
1311    delegate! {
1312        to self.common {
1313            fn txpool_content(&self, address: Option<RpcAddress>) -> JsonRpcResult<
1314                BTreeMap<String, BTreeMap<String, BTreeMap<usize, Vec<RpcTransaction>>>>>;
1315            fn txpool_inspect(&self, address: Option<RpcAddress>) -> JsonRpcResult<
1316                BTreeMap<String, BTreeMap<String, BTreeMap<usize, Vec<String>>>>>;
1317            fn txpool_get_account_transactions(&self, address: RpcAddress) -> JsonRpcResult<Vec<RpcTransaction>>;
1318            fn txpool_clear(&self) -> JsonRpcResult<()>;
1319            fn accounts(&self) -> JsonRpcResult<Vec<RpcAddress>>;
1320            fn lock_account(&self, address: RpcAddress) -> JsonRpcResult<bool>;
1321            fn net_disconnect_node(&self, id: NodeId, op: Option<UpdateNodeOperation>) -> JsonRpcResult<bool>;
1322            fn net_node(&self, id: NodeId) -> JsonRpcResult<Option<(String, Node)>>;
1323            fn net_sessions(&self, node_id: Option<NodeId>) -> JsonRpcResult<Vec<SessionDetails>>;
1324            fn net_throttling(&self) -> JsonRpcResult<throttling::Service>;
1325            fn new_account(&self, password: String) -> JsonRpcResult<RpcAddress>;
1326            fn sign(&self, data: Bytes, address: RpcAddress, password: Option<String>) -> JsonRpcResult<H520>;
1327            fn unlock_account(&self, address: RpcAddress, password: String, duration: Option<U128>) -> JsonRpcResult<bool>;
1328        }
1329
1330        to self.rpc_impl {
1331            fn send_transaction(&self, tx: TransactionRequest, password: Option<String>) -> BoxFuture<JsonRpcResult<H256>>;
1332        }
1333    }
1334
1335    not_supported! {
1336        fn consensus_graph_state(&self) -> JsonRpcResult<ConsensusGraphStates>;
1337        fn current_sync_phase(&self) -> JsonRpcResult<String>;
1338        fn epoch_receipts(&self, epoch: BlockHashOrEpochNumber, include_eth_recepits: Option<bool>) -> JsonRpcResult<Option<Vec<Vec<RpcReceipt>>>>;
1339        fn epoch_receipt_proof_by_transaction(&self, tx_hash: H256) -> JsonRpcResult<Option<EpochReceiptProof>>;
1340        fn stat_on_gas_load(&self, epoch: EpochNumber, time_window: U64) -> JsonRpcResult<Option<StatOnGasLoad>>;
1341        fn sign_transaction(&self, tx: TransactionRequest, password: Option<String>) -> JsonRpcResult<String>;
1342        fn sync_graph_state(&self) -> JsonRpcResult<SyncGraphStates>;
1343        fn transactions_by_epoch(&self, epoch_number: U64) -> JsonRpcResult<Vec<WrapTransaction>>;
1344        fn transactions_by_block(&self, block_hash: H256) -> JsonRpcResult<Vec<WrapTransaction>>;
1345    }
1346}