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_block_number.unwrap(),
720                maybe_base_price,
721                maybe_state_root,
722                // Can not offer error_message from light node.
723                None,
724                *light.get_network_type(),
725                false,
726                true,
727            )?;
728
729            Ok(Some(receipt))
730        };
731
732        fut.boxed()
733    }
734
735    pub fn epoch_number(&self, epoch: Option<EpochNumber>) -> CoreResult<U256> {
736        let epoch = epoch.unwrap_or(EpochNumber::LatestMined);
737        info!("RPC Request: cfx_epochNumber epoch={:?}", epoch);
738
739        invalid_params_check(
740            "epoch",
741            self.light
742                .get_height_from_epoch_number(epoch.into())
743                .map(|height| height.into()),
744        )
745        .map_err(|e| e.into())
746    }
747
748    pub fn next_nonce(
749        &self, address: RpcAddress, num: Option<BlockHashOrEpochNumber>,
750    ) -> CoreBoxFuture<U256> {
751        info!(
752            "RPC Request: cfx_getNextNonce address={:?} num={:?}",
753            address, num
754        );
755
756        // clone to avoid lifetime issues due to capturing `self`
757        let consensus_graph = self.consensus.clone();
758        let light = self.light.clone();
759
760        let fut = async move {
761            Self::check_address_network(address.network, &light)?;
762
763            let epoch =
764                Self::get_epoch_number_with_pivot_check(consensus_graph, num)?
765                    .into();
766
767            let account = invalid_params_check(
768                "address",
769                light.get_account(epoch, address.into()).await,
770            )?;
771
772            Ok(account
773                .map(|account| account.nonce.into())
774                .unwrap_or_default())
775        };
776
777        fut.boxed()
778    }
779
780    pub fn block_by_hash(
781        &self, hash: H256, include_txs: bool,
782    ) -> CoreBoxFuture<Option<RpcBlock>> {
783        let hash = hash.into();
784
785        info!(
786            "RPC Request: cfx_getBlockByHash hash={:?} include_txs={:?}",
787            hash, include_txs
788        );
789
790        // clone to avoid lifetime issues due to capturing `self`
791        let consensus_graph = self.consensus.clone();
792        let data_man = self.data_man.clone();
793        let light = self.light.clone();
794
795        let fut = async move {
796            let block = match light.retrieve_block(hash).await? {
797                None => return Ok(None),
798                Some(b) => b,
799            };
800
801            let inner = consensus_graph.inner.read();
802
803            Ok(Some(build_block(
804                &block,
805                *light.get_network_type(),
806                &*consensus_graph,
807                &*inner,
808                &data_man,
809                include_txs,
810                Some(Space::Native),
811            )?))
812        };
813
814        fut.boxed()
815    }
816
817    pub fn block_by_hash_with_pivot_assumption(
818        &self, block_hash: H256, pivot_hash: H256, epoch_number: U64,
819    ) -> CoreBoxFuture<RpcBlock> {
820        let block_hash = block_hash.into();
821        let pivot_hash = pivot_hash.into();
822        let epoch_number = epoch_number.as_u64();
823
824        info!(
825            "RPC Request: cfx_getBlockByHashWithPivotAssumption block_hash={:?} pivot_hash={:?} epoch_number={:?}",
826            block_hash, pivot_hash, epoch_number
827        );
828
829        // clone to avoid lifetime issues due to capturing `self`
830        let consensus_graph = self.consensus.clone();
831        let data_man = self.data_man.clone();
832        let light = self.light.clone();
833
834        let fut = async move {
835            // check pivot assumption
836            // make sure not to hold the lock through await's
837            consensus_graph
838                .inner
839                .read()
840                .check_block_pivot_assumption(&pivot_hash, epoch_number)
841                .map_err(RpcError::invalid_params)?;
842
843            // retrieve block body
844            let block = light
845                .retrieve_block(block_hash)
846                .await?
847                .ok_or_else(|| RpcError::invalid_params("Block not found"))?;
848
849            let inner = consensus_graph.inner.read();
850
851            Ok(build_block(
852                &block,
853                *light.get_network_type(),
854                &*consensus_graph,
855                &*inner,
856                &data_man,
857                true,
858                Some(Space::Native),
859            )?)
860        };
861
862        fut.boxed()
863    }
864
865    pub fn block_by_epoch_number(
866        &self, epoch: EpochNumber, include_txs: bool,
867    ) -> CoreBoxFuture<Option<RpcBlock>> {
868        info!(
869            "RPC Request: cfx_getBlockByEpochNumber epoch={:?} include_txs={:?}",
870            epoch, include_txs
871        );
872
873        // clone to avoid lifetime issues due to capturing `self`
874        let consensus_graph = self.consensus.clone();
875        let data_man = self.data_man.clone();
876        let light = self.light.clone();
877
878        let fut = async move {
879            let epoch: u64 = light
880                .get_height_from_epoch_number(epoch.into())
881                .map_err(|e| e.to_string())
882                .map_err(RpcError::invalid_params)?;
883
884            // make sure not to hold the lock through await's
885            let hash = consensus_graph
886                .inner
887                .read()
888                .get_pivot_hash_from_epoch_number(epoch)
889                .map_err(RpcError::invalid_params)?;
890
891            // retrieve block body
892            let block = match light.retrieve_block(hash).await? {
893                None => return Ok(None),
894                Some(b) => b,
895            };
896
897            let inner = consensus_graph.inner.read();
898
899            Ok(Some(build_block(
900                &block,
901                *light.get_network_type(),
902                &*consensus_graph,
903                &*inner,
904                &data_man,
905                include_txs,
906                Some(Space::Native),
907            )?))
908        };
909
910        fut.boxed()
911    }
912
913    pub fn blocks_by_epoch(&self, epoch: EpochNumber) -> CoreResult<Vec<H256>> {
914        info!("RPC Request: cfx_getBlocksByEpoch epoch_number={:?}", epoch);
915
916        let height = self
917            .light
918            .get_height_from_epoch_number(epoch.into())
919            .map_err(|e| e.to_string())
920            .map_err(RpcError::invalid_params)?;
921
922        let hashes = self
923            .consensus
924            .inner
925            .read()
926            .block_hashes_by_epoch(height)
927            .map_err(|e| e.to_string())
928            .map_err(RpcError::invalid_params)?;
929
930        Ok(hashes)
931    }
932
933    pub fn gas_price(&self) -> CoreBoxFuture<U256> {
934        info!("RPC Request: cfx_gasPrice");
935
936        let light = self.light.clone();
937
938        let fut = async move {
939            Ok(light
940                .gas_price()
941                .await
942                .map_err(|e| e.to_string())
943                .map_err(RpcError::invalid_params)?
944                .unwrap_or(GAS_PRICE_DEFAULT_VALUE.into()))
945        };
946
947        fut.boxed()
948    }
949
950    pub fn interest_rate(
951        &self, epoch: Option<EpochNumber>,
952    ) -> CoreBoxFuture<U256> {
953        let epoch = epoch.unwrap_or(EpochNumber::LatestState).into();
954        info!("RPC Request: cfx_getInterestRate epoch={:?}", epoch);
955
956        // clone to avoid lifetime issues due to capturing `self`
957        let light = self.light.clone();
958
959        let fut = async move {
960            Ok(light
961                .get_interest_rate(epoch)
962                .await
963                .map_err(|e| e.to_string())
964                .map_err(RpcError::invalid_params)?)
965        };
966
967        fut.boxed()
968    }
969
970    pub fn accumulate_interest_rate(
971        &self, epoch: Option<EpochNumber>,
972    ) -> CoreBoxFuture<U256> {
973        let epoch = epoch.unwrap_or(EpochNumber::LatestState).into();
974
975        info!(
976            "RPC Request: cfx_getAccumulateInterestRate epoch={:?}",
977            epoch
978        );
979
980        // clone to avoid lifetime issues due to capturing `self`
981        let light = self.light.clone();
982
983        let fut = async move {
984            Ok(light
985                .get_accumulate_interest_rate(epoch)
986                .await
987                .map_err(|e| e.to_string())
988                .map_err(RpcError::invalid_params)?)
989        };
990
991        fut.boxed()
992    }
993
994    pub fn pos_economics(
995        &self, epoch: Option<EpochNumber>,
996    ) -> CoreBoxFuture<PoSEconomics> {
997        let epoch = epoch.unwrap_or(EpochNumber::LatestState).into();
998
999        info!("RPC Request: cfx_getPoSEconomics epoch={:?}", epoch);
1000
1001        // clone to avoid lifetime issues due to capturing `self`
1002        let light = self.light.clone();
1003
1004        let fut = async move {
1005            Ok(light
1006                .get_pos_economics(epoch)
1007                .await
1008                .map(|ans| PoSEconomics {
1009                    total_pos_staking_tokens: ans[0],
1010                    distributable_pos_interest: ans[1],
1011                    last_distribute_block: ans[2].as_u64().into(),
1012                })
1013                .map_err(|e| e.to_string())
1014                .map_err(RpcError::invalid_params)?)
1015        };
1016
1017        fut.boxed()
1018    }
1019
1020    fn check_balance_against_transaction(
1021        &self, account_addr: RpcAddress, contract_addr: RpcAddress,
1022        gas_limit: U256, gas_price: U256, storage_limit: U256,
1023        epoch: Option<EpochNumber>,
1024    ) -> CoreBoxFuture<CheckBalanceAgainstTransactionResponse> {
1025        let epoch: primitives::EpochNumber =
1026            epoch.unwrap_or(EpochNumber::LatestState).into();
1027
1028        info!(
1029            "RPC Request: cfx_checkBalanceAgainstTransaction account_addr={:?} contract_addr={:?} gas_limit={:?} gas_price={:?} storage_limit={:?} epoch={:?}",
1030            account_addr, contract_addr, gas_limit, gas_price, storage_limit, epoch
1031        );
1032
1033        // clone to avoid lifetime issues due to capturing `self`
1034        let light = self.light.clone();
1035
1036        let fut = async move {
1037            Self::check_address_network(account_addr.network, &light)?;
1038            Self::check_address_network(contract_addr.network, &light)?;
1039
1040            let account_addr: H160 = account_addr.into();
1041            let contract_addr: H160 = contract_addr.into();
1042
1043            if storage_limit > U256::from(std::u64::MAX) {
1044                bail!(RpcError::invalid_params(format!("storage_limit has to be within the range of u64 but {} supplied!", storage_limit)));
1045            }
1046
1047            // retrieve accounts and sponsor info in parallel
1048            let (user_account, contract_account, is_sponsored) =
1049                future::try_join3(
1050                    light.get_account(epoch.clone(), account_addr),
1051                    light.get_account(epoch.clone(), contract_addr),
1052                    light.is_user_sponsored(epoch, contract_addr, account_addr),
1053                )
1054                .await?;
1055
1056            Ok(common::check_balance_against_transaction(
1057                user_account,
1058                contract_account,
1059                is_sponsored,
1060                gas_limit,
1061                gas_price,
1062                storage_limit,
1063            ))
1064        };
1065
1066        fut.boxed()
1067    }
1068
1069    fn fee_history(
1070        &self, mut block_count: HexU64, newest_block: EpochNumber,
1071        reward_percentiles: Option<Vec<f64>>,
1072    ) -> CoreBoxFuture<CfxFeeHistory> {
1073        info!(
1074            "RPC Request: cfx_feeHistory: block_count={}, newest_block={:?}, reward_percentiles={:?}",
1075            block_count, newest_block, reward_percentiles
1076        );
1077
1078        if block_count.as_u64() == 0 {
1079            return async { Ok(FeeHistory::new().into()) }.boxed();
1080        }
1081
1082        if block_count.as_u64() > MAX_FEE_HISTORY_CACHE_BLOCK_COUNT {
1083            block_count = HexU64::from(MAX_FEE_HISTORY_CACHE_BLOCK_COUNT);
1084        }
1085
1086        // clone to avoid lifetime issues due to capturing `self`
1087        let consensus_graph = self.consensus.clone();
1088        let light = self.light.clone();
1089        let reward_percentiles = reward_percentiles.unwrap_or_default();
1090
1091        let fut = async move {
1092            let start_height: u64 = light
1093                .get_height_from_epoch_number(newest_block.into())
1094                .map_err(|e| e.to_string())
1095                .map_err(RpcError::invalid_params)?;
1096
1097            let mut current_height = start_height;
1098
1099            let mut fee_history = FeeHistory::new();
1100
1101            while current_height
1102                >= start_height.saturating_sub(block_count.as_u64() - 1)
1103            {
1104                let block = fetch_block_for_fee_history(
1105                    consensus_graph.clone(),
1106                    light.clone(),
1107                    current_height,
1108                )
1109                .await?;
1110
1111                let transactions = block
1112                    .transactions
1113                    .iter()
1114                    .filter(|tx| tx.space() == Space::Native)
1115                    .map(|x| &**x);
1116                // Internal error happens only if the fetch header has
1117                // inconsistent block height
1118                fee_history
1119                    .push_front_block(
1120                        Space::Native,
1121                        &reward_percentiles,
1122                        &block.block_header,
1123                        transactions,
1124                    )
1125                    .map_err(|_| RpcError::internal_error())?;
1126
1127                if current_height == 0 {
1128                    break;
1129                } else {
1130                    current_height -= 1;
1131                }
1132            }
1133
1134            let block = fetch_block_for_fee_history(
1135                consensus_graph.clone(),
1136                light.clone(),
1137                start_height + 1,
1138            )
1139            .await?;
1140            let oldest_block = if current_height == 0 {
1141                0
1142            } else {
1143                current_height + 1
1144            };
1145            fee_history.finish(
1146                oldest_block,
1147                block.block_header.base_price().as_ref(),
1148                Space::Native,
1149            );
1150            Ok(fee_history.into())
1151        };
1152
1153        fut.boxed()
1154    }
1155}
1156
1157async fn fetch_block_for_fee_history(
1158    consensus_graph: Arc<ConsensusGraph>, light: Arc<QueryService>, height: u64,
1159) -> cfxcore::errors::Result<primitives::Block> {
1160    let hash = consensus_graph
1161        .inner
1162        .read()
1163        .get_pivot_hash_from_epoch_number(height)
1164        .map_err(RpcError::invalid_params)?;
1165
1166    match light.retrieve_block(hash).await? {
1167        None => Err(RpcError::internal_error().into()),
1168        Some(b) => Ok(b),
1169    }
1170}
1171
1172pub struct CfxHandler {
1173    common: Arc<CommonImpl>,
1174    rpc_impl: Arc<RpcImpl>,
1175}
1176
1177impl CfxHandler {
1178    pub fn new(common: Arc<CommonImpl>, rpc_impl: Arc<RpcImpl>) -> Self {
1179        CfxHandler { common, rpc_impl }
1180    }
1181}
1182
1183impl Cfx for CfxHandler {
1184    delegate! {
1185        to self.common {
1186            fn best_block_hash(&self) -> JsonRpcResult<H256>;
1187            fn confirmation_risk_by_hash(&self, block_hash: H256) -> JsonRpcResult<Option<U256>>;
1188            fn get_client_version(&self) -> JsonRpcResult<String>;
1189            fn get_status(&self) -> JsonRpcResult<RpcStatus>;
1190            fn skipped_blocks_by_epoch(&self, num: EpochNumber) -> JsonRpcResult<Vec<H256>>;
1191            fn account_pending_info(&self, addr: RpcAddress) -> BoxFuture<JsonRpcResult<Option<AccountPendingInfo>>>;
1192        }
1193
1194        to self.rpc_impl {
1195            fn account(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<RpcAccount>>;
1196            fn accumulate_interest_rate(&self, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<U256>>;
1197            fn admin(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<Option<RpcAddress>>>;
1198            fn balance(&self, address: RpcAddress, block_hash_or_epoch_number: Option<BlockHashOrEpochNumber>) -> BoxFuture<JsonRpcResult<U256>>;
1199            fn block_by_epoch_number(&self, epoch_num: EpochNumber, include_txs: bool) -> BoxFuture<JsonRpcResult<Option<RpcBlock>>>;
1200            fn block_by_hash_with_pivot_assumption(&self, block_hash: H256, pivot_hash: H256, epoch_number: U64) -> BoxFuture<JsonRpcResult<RpcBlock>>;
1201            fn block_by_hash(&self, hash: H256, include_txs: bool) -> BoxFuture<JsonRpcResult<Option<RpcBlock>>>;
1202            fn blocks_by_epoch(&self, num: EpochNumber) -> JsonRpcResult<Vec<H256>>;
1203            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>>;
1204            fn code(&self, address: RpcAddress, block_hash_or_epoch_num: Option<BlockHashOrEpochNumber>) -> BoxFuture<JsonRpcResult<Bytes>>;
1205            fn collateral_for_storage(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<U256>>;
1206            fn deposit_list(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<Vec<DepositInfo>>>;
1207            fn epoch_number(&self, epoch_num: Option<EpochNumber>) -> JsonRpcResult<U256>;
1208            fn gas_price(&self) -> BoxFuture<JsonRpcResult<U256>>;
1209            fn get_logs(&self, filter: CfxRpcLogFilter) -> BoxFuture<JsonRpcResult<Vec<RpcLog>>>;
1210            fn interest_rate(&self, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<U256>>;
1211            fn next_nonce(&self, address: RpcAddress, num: Option<BlockHashOrEpochNumber>) -> BoxFuture<JsonRpcResult<U256>>;
1212            fn pos_economics(&self, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<PoSEconomics>>;
1213            fn send_raw_transaction(&self, raw: Bytes) -> JsonRpcResult<H256>;
1214            fn sponsor_info(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<SponsorInfo>>;
1215            fn staking_balance(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<U256>>;
1216            fn storage_at(&self, addr: RpcAddress, pos: U256, block_hash_or_epoch_number: Option<BlockHashOrEpochNumber>) -> BoxFuture<JsonRpcResult<Option<H256>>>;
1217            fn storage_root(&self, address: RpcAddress, epoch_num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<Option<StorageRoot>>>;
1218            fn transaction_by_hash(&self, hash: H256) -> BoxFuture<JsonRpcResult<Option<RpcTransaction>>>;
1219            fn transaction_receipt(&self, tx_hash: H256) -> BoxFuture<JsonRpcResult<Option<RpcReceipt>>>;
1220            fn vote_list(&self, address: RpcAddress, num: Option<EpochNumber>) -> BoxFuture<JsonRpcResult<Vec<VoteStakeInfo>>>;
1221            fn fee_history(&self, block_count: HexU64, newest_block: EpochNumber, reward_percentiles: Option<Vec<f64>>) -> BoxFuture<JsonRpcResult<CfxFeeHistory>>;
1222        }
1223    }
1224
1225    // TODO(thegaram): add support for these
1226    not_supported! {
1227        fn account_pending_transactions(&self, address: RpcAddress, maybe_start_nonce: Option<U256>, maybe_limit: Option<U64>) -> BoxFuture<JsonRpcResult<AccountPendingTransactions>>;
1228        fn block_by_block_number(&self, block_number: U64, include_txs: bool) -> BoxFuture<JsonRpcResult<Option<RpcBlock>>>;
1229        fn call(&self, request: TransactionRequest, block_hash_or_epoch_number: Option<BlockHashOrEpochNumber>) -> JsonRpcResult<Bytes>;
1230        fn estimate_gas_and_collateral(&self, request: TransactionRequest, epoch_num: Option<EpochNumber>) -> JsonRpcResult<EstimateGasAndCollateralResponse>;
1231        fn get_block_reward_info(&self, num: EpochNumber) -> JsonRpcResult<Vec<RpcRewardInfo>>;
1232        fn get_supply_info(&self, epoch_num: Option<EpochNumber>) -> JsonRpcResult<TokenSupplyInfo>;
1233        fn get_collateral_info(&self, epoch_num: Option<EpochNumber>) -> JsonRpcResult<StorageCollateralInfo>;
1234        fn get_vote_params(&self, epoch_num: Option<EpochNumber>) -> JsonRpcResult<VoteParamsInfo>;
1235        fn get_pos_reward_by_epoch(&self, epoch: EpochNumber) -> JsonRpcResult<Option<PoSEpochReward>>;
1236        fn get_fee_burnt(&self, epoch: Option<EpochNumber>) -> JsonRpcResult<U256>;
1237        fn max_priority_fee_per_gas(&self) -> BoxFuture<JsonRpcResult<U256>>;
1238    }
1239}
1240
1241pub struct TestRpcImpl {
1242    common: Arc<CommonImpl>,
1243    // rpc_impl: Arc<RpcImpl>,
1244}
1245
1246impl TestRpcImpl {
1247    pub fn new(common: Arc<CommonImpl>, _rpc_impl: Arc<RpcImpl>) -> Self {
1248        TestRpcImpl {
1249            common, /* , rpc_impl */
1250        }
1251    }
1252}
1253
1254impl TestRpc for TestRpcImpl {
1255    delegate! {
1256        to self.common {
1257            fn add_latency(&self, id: NodeId, latency_ms: f64) -> JsonRpcResult<()>;
1258            fn add_peer(&self, node_id: NodeId, address: SocketAddr) -> JsonRpcResult<()>;
1259            fn chain(&self) -> JsonRpcResult<Vec<RpcBlock>>;
1260            fn drop_peer(&self, node_id: NodeId, address: SocketAddr) -> JsonRpcResult<()>;
1261            fn get_block_count(&self) -> JsonRpcResult<u64>;
1262            fn get_goodput(&self) -> JsonRpcResult<String>;
1263            fn get_nodeid(&self, challenge: Vec<u8>) -> JsonRpcResult<Vec<u8>>;
1264            fn get_peer_info(&self) -> JsonRpcResult<Vec<PeerInfo>>;
1265            fn save_node_db(&self) -> JsonRpcResult<()>;
1266            fn say_hello(&self) -> JsonRpcResult<String>;
1267            fn stop(&self) -> JsonRpcResult<()>;
1268            fn pos_register(&self, voting_power: U64, version: Option<u8>) -> JsonRpcResult<(Bytes, AccountAddress)>;
1269            fn pos_update_voting_power(
1270                &self, pos_account: AccountAddress, increased_voting_power: U64,
1271            ) -> JsonRpcResult<()>;
1272            fn pos_stop_election(&self) -> JsonRpcResult<Option<u64>>;
1273            fn pos_start_voting(&self, initialize: bool) -> JsonRpcResult<()>;
1274            fn pos_stop_voting(&self) -> JsonRpcResult<()>;
1275            fn pos_voting_status(&self) -> JsonRpcResult<bool>;
1276            fn pos_start(&self) -> JsonRpcResult<()>;
1277            fn pos_force_vote_proposal(&self, block_id: H256) -> JsonRpcResult<()>;
1278            fn pos_force_propose(&self, round: U64, parent_block_id: H256, payload: Vec<TransactionPayload>) -> JsonRpcResult<()>;
1279            fn pos_trigger_timeout(&self, timeout_type: String) -> JsonRpcResult<()>;
1280            fn pos_force_sign_pivot_decision(&self, block_hash: H256, height: U64) -> JsonRpcResult<()>;
1281            fn pos_get_chosen_proposal(&self) -> JsonRpcResult<Option<PosBlock>>;
1282        }
1283    }
1284
1285    not_supported! {
1286        fn expire_block_gc(&self, timeout: u64) -> JsonRpcResult<()>;
1287        fn generate_block_with_blame_info(&self, num_txs: usize, block_size_limit: usize, blame_info: BlameInfo) -> JsonRpcResult<H256>;
1288        fn generate_block_with_fake_txs(&self, raw_txs_without_data: Bytes, adaptive: Option<bool>, tx_data_len: Option<usize>) -> JsonRpcResult<H256>;
1289        fn generate_block_with_nonce_and_timestamp(&self, parent: H256, referees: Vec<H256>, raw: Bytes, nonce: U256, timestamp: u64, adaptive: bool) -> JsonRpcResult<H256>;
1290        fn generate_custom_block(&self, parent_hash: H256, referee: Vec<H256>, raw_txs: Bytes, adaptive: Option<bool>, custom: Option<Vec<Bytes>>) -> JsonRpcResult<H256>;
1291        fn generate_empty_blocks(&self, num_blocks: usize) -> JsonRpcResult<Vec<H256>>;
1292        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>;
1293        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>;
1294        fn generate_one_block(&self, num_txs: usize, block_size_limit: usize) -> JsonRpcResult<H256>;
1295        fn get_block_status(&self, block_hash: H256) -> JsonRpcResult<(u8, bool)>;
1296        fn get_executed_info(&self, block_hash: H256) -> JsonRpcResult<(H256, H256)> ;
1297        fn get_pivot_chain_and_weight(&self, height_range: Option<(u64, u64)>) -> JsonRpcResult<Vec<(H256, U256)>>;
1298        fn send_usable_genesis_accounts(&self, account_start_index: usize) -> JsonRpcResult<Bytes>;
1299        fn set_db_crash(&self, crash_probability: f64, crash_exit_code: i32) -> JsonRpcResult<()>;
1300    }
1301}
1302
1303pub struct DebugRpcImpl {
1304    common: Arc<CommonImpl>,
1305    rpc_impl: Arc<RpcImpl>,
1306}
1307
1308impl DebugRpcImpl {
1309    pub fn new(common: Arc<CommonImpl>, rpc_impl: Arc<RpcImpl>) -> Self {
1310        DebugRpcImpl { common, rpc_impl }
1311    }
1312}
1313
1314impl LocalRpc for DebugRpcImpl {
1315    delegate! {
1316        to self.common {
1317            fn txpool_content(&self, address: Option<RpcAddress>) -> JsonRpcResult<
1318                BTreeMap<String, BTreeMap<String, BTreeMap<usize, Vec<RpcTransaction>>>>>;
1319            fn txpool_inspect(&self, address: Option<RpcAddress>) -> JsonRpcResult<
1320                BTreeMap<String, BTreeMap<String, BTreeMap<usize, Vec<String>>>>>;
1321            fn txpool_get_account_transactions(&self, address: RpcAddress) -> JsonRpcResult<Vec<RpcTransaction>>;
1322            fn txpool_clear(&self) -> JsonRpcResult<()>;
1323            fn accounts(&self) -> JsonRpcResult<Vec<RpcAddress>>;
1324            fn lock_account(&self, address: RpcAddress) -> JsonRpcResult<bool>;
1325            fn net_disconnect_node(&self, id: NodeId, op: Option<UpdateNodeOperation>) -> JsonRpcResult<bool>;
1326            fn net_node(&self, id: NodeId) -> JsonRpcResult<Option<(String, Node)>>;
1327            fn net_sessions(&self, node_id: Option<NodeId>) -> JsonRpcResult<Vec<SessionDetails>>;
1328            fn net_throttling(&self) -> JsonRpcResult<throttling::Service>;
1329            fn new_account(&self, password: String) -> JsonRpcResult<RpcAddress>;
1330            fn sign(&self, data: Bytes, address: RpcAddress, password: Option<String>) -> JsonRpcResult<H520>;
1331            fn unlock_account(&self, address: RpcAddress, password: String, duration: Option<U128>) -> JsonRpcResult<bool>;
1332        }
1333
1334        to self.rpc_impl {
1335            fn send_transaction(&self, tx: TransactionRequest, password: Option<String>) -> BoxFuture<JsonRpcResult<H256>>;
1336        }
1337    }
1338
1339    not_supported! {
1340        fn consensus_graph_state(&self) -> JsonRpcResult<ConsensusGraphStates>;
1341        fn current_sync_phase(&self) -> JsonRpcResult<String>;
1342        fn epoch_receipts(&self, epoch: BlockHashOrEpochNumber, include_eth_recepits: Option<bool>) -> JsonRpcResult<Option<Vec<Vec<RpcReceipt>>>>;
1343        fn epoch_receipt_proof_by_transaction(&self, tx_hash: H256) -> JsonRpcResult<Option<EpochReceiptProof>>;
1344        fn stat_on_gas_load(&self, epoch: EpochNumber, time_window: U64) -> JsonRpcResult<Option<StatOnGasLoad>>;
1345        fn sign_transaction(&self, tx: TransactionRequest, password: Option<String>) -> JsonRpcResult<String>;
1346        fn sync_graph_state(&self) -> JsonRpcResult<SyncGraphStates>;
1347        fn transactions_by_epoch(&self, epoch_number: U64) -> JsonRpcResult<Vec<WrapTransaction>>;
1348        fn transactions_by_block(&self, block_hash: H256) -> JsonRpcResult<Vec<WrapTransaction>>;
1349    }
1350}