1use 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};
32use 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
62macro_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 accounts: Arc<AccountProvider>,
88
89 consensus: SharedConsensusGraph,
91
92 data_man: Arc<BlockDataManager>,
94
95 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 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(), &U256::zero(), )),
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 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 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 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 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 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 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 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 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 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 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 let light = self.light.clone();
460
461 let fut = async move {
462 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()) .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 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 match 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 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 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 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 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 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()) .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 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()) .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 let light = self.light.clone();
678 let data_man = self.data_man.clone();
679
680 let fut = async move {
681 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 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 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 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 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 consensus_graph
837 .inner
838 .read()
839 .check_block_pivot_assumption(&pivot_hash, epoch_number)
840 .map_err(RpcError::invalid_params)?;
841
842 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 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 let hash = consensus_graph
885 .inner
886 .read()
887 .get_pivot_hash_from_epoch_number(epoch)
888 .map_err(RpcError::invalid_params)?;
889
890 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 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 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 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 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 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 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 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 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 }
1244
1245impl TestRpcImpl {
1246 pub fn new(common: Arc<CommonImpl>, _rpc_impl: Arc<RpcImpl>) -> Self {
1247 TestRpcImpl {
1248 common, }
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}