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