ckb_rpc/module/chain.rs
1use crate::error::RPCError;
2use crate::util::FeeRateCollector;
3use async_trait::async_trait;
4use ckb_jsonrpc_types::{
5 BlockEconomicState, BlockFilter, BlockNumber, BlockResponse, BlockView, CellWithStatus,
6 Consensus, EpochNumber, EpochView, EstimateCycles, FeeRateStatistics, HeaderView, OutPoint,
7 ResponseFormat, ResponseFormatInnerType, Timestamp, Transaction, TransactionAndWitnessProof,
8 TransactionProof, TransactionWithStatusResponse, Uint32, Uint64,
9};
10use ckb_logger::error;
11use ckb_reward_calculator::RewardCalculator;
12use ckb_shared::{Snapshot, shared::Shared};
13use ckb_store::{ChainStore, data_loader_wrapper::AsDataLoader};
14use ckb_traits::HeaderFieldsProvider;
15use ckb_types::core::tx_pool::TransactionWithStatus;
16use ckb_types::{
17 H256,
18 core::{
19 self,
20 cell::{CellProvider, CellStatus, HeaderChecker, resolve_transaction},
21 error::OutPointError,
22 },
23 packed,
24 prelude::*,
25 utilities::{CBMT, MerkleProof, merkle_root},
26};
27use ckb_verification::ScriptVerifier;
28use ckb_verification::TxVerifyEnv;
29use jsonrpc_core::Result;
30use jsonrpc_utils::rpc;
31use std::collections::HashSet;
32use std::sync::Arc;
33
34/// RPC Module Chain for methods related to the canonical chain.
35///
36/// This module queries information about the canonical chain.
37///
38/// ## Canonical Chain
39///
40/// A canonical chain is the one with the most accumulated work. The accumulated work is
41/// the sum of difficulties of all the blocks in the chain.
42///
43/// ## Chain Reorganization
44///
45/// Chain Reorganization happens when CKB found a chain that has accumulated more work than the
46/// canonical chain. The reorganization revert the blocks in the current canonical chain if needed,
47/// and switch the canonical chain to that better chain.
48///
49/// ## Live Cell
50///
51/// A cell is live if
52///
53/// * it is found as an output in any transaction in the [canonical chain](#canonical-chain),
54/// and
55/// * it is not found as an input in any transaction in the canonical chain.
56#[rpc(openrpc)]
57#[async_trait]
58pub trait ChainRpc {
59 /// Returns the information about a block by hash.
60 ///
61 /// ## Params
62 ///
63 /// * `block_hash` - the block hash.
64 /// * `verbosity` - result format which allows 0 and 2. (**Optional**, the default is 2.)
65 /// * `with_cycles` - whether the return cycles of block transactions. (**Optional**, default false.)
66 ///
67 /// ## Returns
68 ///
69 /// The RPC returns a block or null. When the RPC returns a block, the block hash must equal to
70 /// the parameter `block_hash`.
71 ///
72 /// If the block is in the [canonical chain](#canonical-chain), the RPC must return the block
73 /// information. Otherwise, the behavior is undefined. The RPC may return blocks found in local
74 /// storage or simply returns null for all blocks that are not in the canonical chain. And
75 /// because of [chain reorganization](#chain-reorganization), for the same `block_hash`, the
76 /// RPC may sometimes return null and sometimes return the block.
77 ///
78 /// When `verbosity` is 2, it returns a JSON object as the `result`. See `BlockView` for the
79 /// schema.
80 ///
81 /// When `verbosity` is 0, it returns a 0x-prefixed hex string as the `result`. The string
82 /// encodes the block serialized by molecule using schema `table Block`.
83 ///
84 /// ## Examples
85 ///
86 /// Request
87 ///
88 /// ```json
89 /// {
90 /// "id": 42,
91 /// "jsonrpc": "2.0",
92 /// "method": "get_block",
93 /// "params": [
94 /// "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40"
95 /// ]
96 /// }
97 /// ```
98 ///
99 /// Response
100 ///
101 /// ```json
102 /// {
103 /// "id": 42,
104 /// "jsonrpc": "2.0",
105 /// "result": {
106 /// "header": {
107 /// "compact_target": "0x1e083126",
108 /// "dao": "0xb5a3e047474401001bc476b9ee573000c0c387962a38000000febffacf030000",
109 /// "epoch": "0x7080018000001",
110 /// "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
111 /// "hash": "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40",
112 /// "nonce": "0x0",
113 /// "number": "0x400",
114 /// "parent_hash": "0xae003585fa15309b30b31aed3dcf385e9472c3c3e93746a6c4540629a6a1ed2d",
115 /// "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
116 /// "timestamp": "0x5cd2b117",
117 /// "transactions_root": "0xc47d5b78b3c4c4c853e2a32810818940d0ee403423bea9ec7b8e566d9595206c",
118 /// "version": "0x0"
119 /// },
120 /// "proposals": [],
121 /// "transactions": [
122 /// {
123 /// "cell_deps": [],
124 /// "hash": "0x365698b50ca0da75dca2c87f9e7b563811d3b5813736b8cc62cc3b106faceb17",
125 /// "header_deps": [],
126 /// "inputs": [
127 /// {
128 /// "previous_output": {
129 /// "index": "0xffffffff",
130 /// "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000"
131 /// },
132 /// "since": "0x400"
133 /// }
134 /// ],
135 /// "outputs": [
136 /// {
137 /// "capacity": "0x18e64b61cf",
138 /// "lock": {
139 /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5",
140 /// "hash_type": "data",
141 /// "args": "0x"
142 /// },
143 /// "type": null
144 /// }
145 /// ],
146 /// "outputs_data": [
147 /// "0x"
148 /// ],
149 /// "version": "0x0",
150 /// "witnesses": [
151 /// "0x450000000c000000410000003500000010000000300000003100000028e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5000000000000000000"
152 /// ]
153 /// }
154 /// ],
155 /// "uncles": []
156 /// }
157 /// }
158 /// ```
159 ///
160 /// The response looks like below when `verbosity` is 0.
161 ///
162 /// ```text
163 /// {
164 /// "id": 42,
165 /// "jsonrpc": "2.0",
166 /// "result": "0x..."
167 /// }
168 /// ```
169 ///
170 /// When specifying with_cycles, the response object will be different like below:
171 ///
172 /// ```text
173 /// {
174 /// "id": 42,
175 /// "jsonrpc": "2.0",
176 /// "result": {
177 /// "block": <Object> or "0x...",
178 /// "cycles": []
179 /// }
180 /// }
181 /// ```
182 #[rpc(name = "get_block")]
183 fn get_block(
184 &self,
185 block_hash: H256,
186 verbosity: Option<Uint32>,
187 with_cycles: Option<bool>,
188 ) -> Result<Option<BlockResponse>>;
189
190 /// Returns the block in the [canonical chain](#canonical-chain) with the specific block number.
191 ///
192 /// ## Params
193 ///
194 /// * `block_number` - the block number.
195 /// * `verbosity` - result format which allows 0 and 2. (**Optional**, the default is 2.)
196 /// * `with_cycles` - whether the return cycles of block transactions. (**Optional**, default false.)
197 ///
198 /// ## Returns
199 ///
200 /// The RPC returns the block when `block_number` is less than or equal to the tip block
201 /// number returned by [`get_tip_block_number`](#tymethod.get_tip_block_number) and returns
202 /// null otherwise.
203 ///
204 /// Because of [chain reorganization](#chain-reorganization), the RPC may return null or even
205 /// different blocks in different invocations with the same `block_number`.
206 ///
207 /// When `verbosity` is 2, it returns a JSON object as the `result`. See `BlockView` for the
208 /// schema.
209 ///
210 /// When `verbosity` is 0, it returns a 0x-prefixed hex string as the `result`. The string
211 /// encodes the block serialized by molecule using schema `table Block`.
212 ///
213 /// ## Errors
214 ///
215 /// * [`ChainIndexIsInconsistent (-201)`](../enum.RPCError.html#variant.ChainIndexIsInconsistent) - The index is inconsistent. It says a block hash is in the main chain, but cannot read it from the database.
216 /// * [`DatabaseIsCorrupt (-202)`](../enum.RPCError.html#variant.DatabaseIsCorrupt) - The data read from database is dirty. Please report it as a bug.
217 ///
218 /// ## Examples
219 ///
220 /// Request
221 ///
222 /// ```json
223 /// {
224 /// "id": 42,
225 /// "jsonrpc": "2.0",
226 /// "method": "get_block_by_number",
227 /// "params": [
228 /// "0x400"
229 /// ]
230 /// }
231 /// ```
232 ///
233 /// Response
234 ///
235 /// ```json
236 /// {
237 /// "id": 42,
238 /// "jsonrpc": "2.0",
239 /// "result": {
240 /// "header": {
241 /// "compact_target": "0x1e083126",
242 /// "dao": "0xb5a3e047474401001bc476b9ee573000c0c387962a38000000febffacf030000",
243 /// "epoch": "0x7080018000001",
244 /// "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
245 /// "hash": "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40",
246 /// "nonce": "0x0",
247 /// "number": "0x400",
248 /// "parent_hash": "0xae003585fa15309b30b31aed3dcf385e9472c3c3e93746a6c4540629a6a1ed2d",
249 /// "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
250 /// "timestamp": "0x5cd2b117",
251 /// "transactions_root": "0xc47d5b78b3c4c4c853e2a32810818940d0ee403423bea9ec7b8e566d9595206c",
252 /// "version": "0x0"
253 /// },
254 /// "proposals": [],
255 /// "transactions": [
256 /// {
257 /// "cell_deps": [],
258 /// "hash": "0x365698b50ca0da75dca2c87f9e7b563811d3b5813736b8cc62cc3b106faceb17",
259 /// "header_deps": [],
260 /// "inputs": [
261 /// {
262 /// "previous_output": {
263 /// "index": "0xffffffff",
264 /// "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000"
265 /// },
266 /// "since": "0x400"
267 /// }
268 /// ],
269 /// "outputs": [
270 /// {
271 /// "capacity": "0x18e64b61cf",
272 /// "lock": {
273 /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5",
274 /// "hash_type": "data",
275 /// "args": "0x"
276 /// },
277 /// "type": null
278 /// }
279 /// ],
280 /// "outputs_data": [
281 /// "0x"
282 /// ],
283 /// "version": "0x0",
284 /// "witnesses": [
285 /// "0x450000000c000000410000003500000010000000300000003100000028e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5000000000000000000"
286 /// ]
287 /// }
288 /// ],
289 /// "uncles": []
290 /// }
291 /// }
292 /// ```
293 ///
294 /// The response looks like below when `verbosity` is 0.
295 ///
296 /// ```text
297 /// {
298 /// "id": 42,
299 /// "jsonrpc": "2.0",
300 /// "result": "0x..."
301 /// }
302 /// ```
303 ///
304 /// When specifying with_cycles, the response object will be different like below:
305 ///
306 /// ```text
307 /// {
308 /// "id": 42,
309 /// "jsonrpc": "2.0",
310 /// "result": {
311 /// "block": <Object> or "0x...",
312 /// "cycles": []
313 /// }
314 /// }
315 /// ```
316 #[rpc(name = "get_block_by_number")]
317 fn get_block_by_number(
318 &self,
319 block_number: BlockNumber,
320 verbosity: Option<Uint32>,
321 with_cycles: Option<bool>,
322 ) -> Result<Option<BlockResponse>>;
323
324 /// Returns the information about a block header by hash.
325 ///
326 /// ## Params
327 ///
328 /// * `block_hash` - the block hash.
329 /// * `verbosity` - result format which allows 0 and 1. (**Optional**, the default is 1.)
330 ///
331 /// ## Returns
332 ///
333 /// The RPC returns a header or null. When the RPC returns a header, the block hash must equal to
334 /// the parameter `block_hash`.
335 ///
336 /// If the block is in the [canonical chain](#canonical-chain), the RPC must return the header
337 /// information. Otherwise, the behavior is undefined. The RPC may return blocks found in local
338 /// storage or simply returns null for all blocks that are not in the canonical chain. And
339 /// because of [chain reorganization](#chain-reorganization), for the same `block_hash`, the
340 /// RPC may sometimes return null and sometimes return the block header.
341 ///
342 /// When `verbosity` is 1, it returns a JSON object as the `result`. See `HeaderView` for the
343 /// schema.
344 ///
345 /// When `verbosity` is 0, it returns a 0x-prefixed hex string as the `result`. The string
346 /// encodes the block header serialized by molecule using schema `table Header`.
347 ///
348 /// ## Examples
349 ///
350 /// Request
351 ///
352 /// ```json
353 /// {
354 /// "id": 42,
355 /// "jsonrpc": "2.0",
356 /// "method": "get_header",
357 /// "params": [
358 /// "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40"
359 /// ]
360 /// }
361 /// ```
362 ///
363 /// Response
364 ///
365 /// ```json
366 /// {
367 /// "id": 42,
368 /// "jsonrpc": "2.0",
369 /// "result": {
370 /// "compact_target": "0x1e083126",
371 /// "dao": "0xb5a3e047474401001bc476b9ee573000c0c387962a38000000febffacf030000",
372 /// "epoch": "0x7080018000001",
373 /// "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
374 /// "hash": "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40",
375 /// "nonce": "0x0",
376 /// "number": "0x400",
377 /// "parent_hash": "0xae003585fa15309b30b31aed3dcf385e9472c3c3e93746a6c4540629a6a1ed2d",
378 /// "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
379 /// "timestamp": "0x5cd2b117",
380 /// "transactions_root": "0xc47d5b78b3c4c4c853e2a32810818940d0ee403423bea9ec7b8e566d9595206c",
381 /// "version": "0x0"
382 /// }
383 /// }
384 /// ```
385 ///
386 /// The response looks like below when `verbosity` is 0.
387 ///
388 /// ```text
389 /// {
390 /// "id": 42,
391 /// "jsonrpc": "2.0",
392 /// "result": "0x..."
393 /// }
394 /// ```
395 #[rpc(name = "get_header")]
396 fn get_header(
397 &self,
398 block_hash: H256,
399 verbosity: Option<Uint32>,
400 ) -> Result<Option<ResponseFormat<HeaderView>>>;
401
402 /// Returns the block header in the [canonical chain](#canonical-chain) with the specific block
403 /// number.
404 ///
405 /// ## Params
406 ///
407 /// * `block_number` - Number of a block
408 /// * `verbosity` - result format which allows 0 and 1. (**Optional**, the default is 1.)
409 ///
410 /// ## Returns
411 ///
412 /// The RPC returns the block header when `block_number` is less than or equal to the tip block
413 /// number returned by [`get_tip_block_number`](#tymethod.get_tip_block_number) and returns
414 /// null otherwise.
415 ///
416 /// Because of [chain reorganization](#chain-reorganization), the RPC may return null or even
417 /// different block headers in different invocations with the same `block_number`.
418 ///
419 /// When `verbosity` is 1, it returns a JSON object as the `result`. See `HeaderView` for the
420 /// schema.
421 ///
422 /// When `verbosity` is 0, it returns a 0x-prefixed hex string as the `result`. The string
423 /// encodes the block header serialized by molecule using schema `table Header`.
424 ///
425 /// ## Errors
426 ///
427 /// * [`ChainIndexIsInconsistent (-201)`](../enum.RPCError.html#variant.ChainIndexIsInconsistent) - The index is inconsistent. It says a block hash is in the main chain, but cannot read it from the database.
428 ///
429 /// ## Examples
430 ///
431 /// Request
432 ///
433 /// ```json
434 /// {
435 /// "id": 42,
436 /// "jsonrpc": "2.0",
437 /// "method": "get_header_by_number",
438 /// "params": [
439 /// "0x400"
440 /// ]
441 /// }
442 /// ```
443 ///
444 /// Response
445 ///
446 /// ```json
447 /// {
448 /// "id": 42,
449 /// "jsonrpc": "2.0",
450 /// "result": {
451 /// "compact_target": "0x1e083126",
452 /// "dao": "0xb5a3e047474401001bc476b9ee573000c0c387962a38000000febffacf030000",
453 /// "epoch": "0x7080018000001",
454 /// "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
455 /// "hash": "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40",
456 /// "nonce": "0x0",
457 /// "number": "0x400",
458 /// "parent_hash": "0xae003585fa15309b30b31aed3dcf385e9472c3c3e93746a6c4540629a6a1ed2d",
459 /// "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
460 /// "timestamp": "0x5cd2b117",
461 /// "transactions_root": "0xc47d5b78b3c4c4c853e2a32810818940d0ee403423bea9ec7b8e566d9595206c",
462 /// "version": "0x0"
463 /// }
464 /// }
465 /// ```
466 ///
467 /// The response looks like below when `verbosity` is 0.
468 ///
469 /// ```text
470 /// {
471 /// "id": 42,
472 /// "jsonrpc": "2.0",
473 /// "result": "0x..."
474 /// }
475 /// ```
476 #[rpc(name = "get_header_by_number")]
477 fn get_header_by_number(
478 &self,
479 block_number: BlockNumber,
480 verbosity: Option<Uint32>,
481 ) -> Result<Option<ResponseFormat<HeaderView>>>;
482
483 /// Returns the block filter by block hash.
484 ///
485 /// ## Params
486 ///
487 /// * `block_hash` - the block hash.
488 ///
489 /// ## Returns
490 ///
491 /// The block filter data
492 ///
493 /// ## Examples
494 ///
495 /// Request
496 ///
497 /// ```json
498 /// {
499 /// "id": 42,
500 /// "jsonrpc": "2.0",
501 /// "method": "get_block_filter",
502 /// "params": [
503 /// "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40"
504 /// ]
505 /// }
506 /// ```
507 ///
508 /// Response
509 ///
510 /// ```json
511 /// {
512 /// "id": 42,
513 /// "jsonrpc": "2.0",
514 /// "result": null
515 /// }
516 /// ```
517 ///
518 /// The response looks like below when the block have block filter.
519 ///
520 /// ```text
521 /// {
522 /// "id": 42,
523 /// "jsonrpc": "2.0",
524 /// "result": {
525 /// "data": "0x...",
526 /// "hash": "0x..."
527 /// }
528 /// }
529 /// ```
530 #[rpc(name = "get_block_filter")]
531 fn get_block_filter(&self, block_hash: H256) -> Result<Option<BlockFilter>>;
532
533 /// Returns the information about a transaction requested by transaction hash.
534 ///
535 /// ## Returns
536 ///
537 /// This RPC returns `null` if the transaction is not committed in the
538 /// [canonical chain](#canonical-chain) nor the transaction memory pool.
539 ///
540 /// If the transaction is in the chain, the block hash is also returned.
541 ///
542 /// ## Params
543 ///
544 /// * `tx_hash` - Hash of a transaction
545 /// * `verbosity` - result format which allows 0, 1 and 2. (**Optional**, the defaults to 2.)
546 /// * `only_committed` - whether to query committed transaction only. (**Optional**, if not set, it will query all status of transactions.)
547 ///
548 /// ## Returns
549 ///
550 /// When verbosity=0, it's response value is as same as verbosity=2, but it
551 /// return a 0x-prefixed hex encoded molecule packed::Transaction on `transaction` field
552 ///
553 /// When verbosity is 1: The RPC does not return the transaction content and the field transaction must be null.
554 ///
555 /// When verbosity is 2: if tx_status.status is pending, proposed, or committed,
556 /// the RPC returns the transaction content as field transaction, otherwise the field is null.
557 ///
558 /// ## Examples
559 ///
560 /// Request
561 ///
562 /// ```json
563 /// {
564 /// "id": 42,
565 /// "jsonrpc": "2.0",
566 /// "method": "get_transaction",
567 /// "params": [
568 /// "0xa0ef4eb5f4ceeb08a4c8524d84c5da95dce2f608e0ca2ec8091191b0f330c6e3"
569 /// ]
570 /// }
571 /// ```
572 ///
573 /// Response
574 ///
575 /// ```json
576 /// {
577 /// "id": 42,
578 /// "jsonrpc": "2.0",
579 /// "result": {
580 /// "transaction": {
581 /// "cell_deps": [
582 /// {
583 /// "dep_type": "code",
584 /// "out_point": {
585 /// "index": "0x0",
586 /// "tx_hash": "0xa4037a893eb48e18ed4ef61034ce26eba9c585f15c9cee102ae58505565eccc3"
587 /// }
588 /// }
589 /// ],
590 /// "hash": "0xa0ef4eb5f4ceeb08a4c8524d84c5da95dce2f608e0ca2ec8091191b0f330c6e3",
591 /// "header_deps": [
592 /// "0x7978ec7ce5b507cfb52e149e36b1a23f6062ed150503c85bbf825da3599095ed"
593 /// ],
594 /// "inputs": [
595 /// {
596 /// "previous_output": {
597 /// "index": "0x0",
598 /// "tx_hash": "0x365698b50ca0da75dca2c87f9e7b563811d3b5813736b8cc62cc3b106faceb17"
599 /// },
600 /// "since": "0x0"
601 /// }
602 /// ],
603 /// "outputs": [
604 /// {
605 /// "capacity": "0x2540be400",
606 /// "lock": {
607 /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5",
608 /// "hash_type": "data",
609 /// "args": "0x"
610 /// },
611 /// "type": null
612 /// }
613 /// ],
614 /// "outputs_data": [
615 /// "0x"
616 /// ],
617 /// "version": "0x0",
618 /// "witnesses": []
619 /// },
620 /// "cycles": "0x219",
621 /// "time_added_to_pool" : "0x187b3d137a1",
622 /// "fee": "0x16923f7dcf",
623 /// "min_replace_fee": "0x16923f7f6a",
624 /// "tx_status": {
625 /// "block_hash": null,
626 /// "block_number": null,
627 /// "status": "pending",
628 /// "tx_index": null,
629 /// "reason": null
630 /// }
631 /// }
632 /// }
633 /// ```
634 ///
635 ///
636 /// The response looks like below when `verbosity` is 0.
637 ///
638 /// ```text
639 /// {
640 /// "id": 42,
641 /// "jsonrpc": "2.0",
642 /// "result": {
643 /// "transaction": "0x.....",
644 /// "cycles": "0x219",
645 /// "tx_status": {
646 /// "block_hash": null,
647 /// "block_number": null,
648 /// "status": "pending",
649 /// "tx_index": null,
650 /// "reason": null
651 /// }
652 /// }
653 /// }
654 /// ```
655 ///
656 #[rpc(name = "get_transaction")]
657 fn get_transaction(
658 &self,
659 tx_hash: H256,
660 verbosity: Option<Uint32>,
661 only_committed: Option<bool>,
662 ) -> Result<TransactionWithStatusResponse>;
663
664 /// Returns the hash of a block in the [canonical chain](#canonical-chain) with the specified
665 /// `block_number`.
666 ///
667 /// ## Params
668 ///
669 /// * `block_number` - Block number
670 ///
671 /// ## Returns
672 ///
673 /// The RPC returns the block hash when `block_number` is less than or equal to the tip block
674 /// number returned by [`get_tip_block_number`](#tymethod.get_tip_block_number) and returns
675 /// null otherwise.
676 ///
677 /// Because of [chain reorganization](#chain-reorganization), the RPC may return null or even
678 /// different block hashes in different invocations with the same `block_number`.
679 ///
680 /// ## Examples
681 ///
682 /// Request
683 ///
684 /// ```json
685 /// {
686 /// "id": 42,
687 /// "jsonrpc": "2.0",
688 /// "method": "get_block_hash",
689 /// "params": [
690 /// "0x400"
691 /// ]
692 /// }
693 /// ```
694 ///
695 /// Response
696 ///
697 /// ```json
698 /// {
699 /// "id": 42,
700 /// "jsonrpc": "2.0",
701 /// "result": "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40"
702 /// }
703 /// ```
704 #[rpc(name = "get_block_hash")]
705 fn get_block_hash(&self, block_number: BlockNumber) -> Result<Option<H256>>;
706
707 /// Returns the header with the highest block number in the [canonical chain](#canonical-chain).
708 ///
709 /// Because of [chain reorganization](#chain-reorganization), the block number returned can be
710 /// less than previous invocations and different invocations may return different block headers
711 /// with the same block number.
712 ///
713 /// ## Params
714 ///
715 /// * `verbosity` - result format which allows 0 and 1. (**Optional**, the default is 1.)
716 ///
717 /// ## Returns
718 ///
719 /// When `verbosity` is 1, the RPC returns a JSON object as the `result`. See HeaderView for the
720 /// schema.
721 ///
722 /// When `verbosity` is 0, it returns a 0x-prefixed hex string as the `result`. The string
723 /// encodes the header serialized by molecule using schema `table Header`.
724 ///
725 /// ## Examples
726 ///
727 /// Request
728 ///
729 /// ```json
730 /// {
731 /// "id": 42,
732 /// "jsonrpc": "2.0",
733 /// "method": "get_tip_header",
734 /// "params": []
735 /// }
736 /// ```
737 ///
738 /// Response
739 ///
740 /// ```json
741 /// {
742 /// "jsonrpc": "2.0",
743 /// "result": {
744 /// "compact_target": "0x1e083126",
745 /// "dao": "0xb5a3e047474401001bc476b9ee573000c0c387962a38000000febffacf030000",
746 /// "epoch": "0x7080018000001",
747 /// "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
748 /// "hash": "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40",
749 /// "nonce": "0x0",
750 /// "number": "0x400",
751 /// "parent_hash": "0xae003585fa15309b30b31aed3dcf385e9472c3c3e93746a6c4540629a6a1ed2d",
752 /// "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
753 /// "timestamp": "0x5cd2b117",
754 /// "transactions_root": "0xc47d5b78b3c4c4c853e2a32810818940d0ee403423bea9ec7b8e566d9595206c",
755 /// "version": "0x0"
756 /// },
757 /// "id": 42
758 /// }
759 /// ```
760 ///
761 /// The response looks like below when `verbosity` is 0.
762 ///
763 /// ```text
764 /// {
765 /// "id": 42,
766 /// "jsonrpc": "2.0",
767 /// "result": "0x..."
768 /// }
769 /// ```
770 #[rpc(name = "get_tip_header")]
771 fn get_tip_header(&self, verbosity: Option<Uint32>) -> Result<ResponseFormat<HeaderView>>;
772
773 /// Returns the status of a cell. The RPC returns extra information if it is a [live cell](#live-cell).
774 ///
775 /// ## Returns
776 ///
777 /// This RPC tells whether a cell is live or not.
778 ///
779 /// If the cell is live, the RPC will return details about the cell. Otherwise, the field `cell` is
780 /// null in the result.
781 ///
782 /// If the cell is live and `with_data` is set to `false`, the field `cell.data` is null in the
783 /// result.
784 ///
785 /// ## Params
786 ///
787 /// * `out_point` - Reference to the cell by transaction hash and output index.
788 /// * `with_data` - Whether the RPC should return cell data. Cell data can be huge, if the client
789 /// does not need the data, it should set this to `false` to save bandwidth.
790 /// * `include_tx_pool` - Whether the RPC check live cell in TxPool, default is false.
791 ///
792 /// ## Examples
793 ///
794 /// Request
795 ///
796 /// ```json
797 /// {
798 /// "id": 42,
799 /// "jsonrpc": "2.0",
800 /// "method": "get_live_cell",
801 /// "params": [
802 /// {
803 /// "index": "0x0",
804 /// "tx_hash": "0xa4037a893eb48e18ed4ef61034ce26eba9c585f15c9cee102ae58505565eccc3"
805 /// },
806 /// true
807 /// ]
808 /// }
809 /// ```
810 ///
811 /// Response
812 ///
813 /// ```json
814 /// {
815 /// "id": 42,
816 /// "jsonrpc": "2.0",
817 /// "result": {
818 /// "cell": {
819 /// "data": {
820 /// "content": "0x7f454c460201010000000000000000000200f3000100000078000100000000004000000000000000980000000000000005000000400038000100400003000200010000000500000000000000000000000000010000000000000001000000000082000000000000008200000000000000001000000000000001459308d00573000000002e7368737472746162002e74657874000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000010000000600000000000000780001000000000078000000000000000a0000000000000000000000000000000200000000000000000000000000000001000000030000000000000000000000000000000000000082000000000000001100000000000000000000000000000001000000000000000000000000000000",
821 /// "hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5"
822 /// },
823 /// "output": {
824 /// "capacity": "0x802665800",
825 /// "lock": {
826 /// "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
827 /// "hash_type": "data",
828 /// "args": "0x"
829 /// },
830 /// "type": null
831 /// }
832 /// },
833 /// "status": "live"
834 /// }
835 /// }
836 /// ```
837 #[rpc(name = "get_live_cell")]
838 fn get_live_cell(
839 &self,
840 out_point: OutPoint,
841 with_data: bool,
842 include_tx_pool: Option<bool>,
843 ) -> Result<CellWithStatus>;
844
845 /// Returns the highest block number in the [canonical chain](#canonical-chain).
846 ///
847 /// Because of [chain reorganization](#chain-reorganization), the returned block number may be
848 /// less than a value returned in the previous invocation.
849 ///
850 /// ## Examples
851 ///
852 /// Request
853 ///
854 /// ```json
855 /// {
856 /// "id": 42,
857 /// "jsonrpc": "2.0",
858 /// "method": "get_tip_block_number",
859 /// "params": []
860 /// }
861 /// ```
862 ///
863 /// Response
864 ///
865 /// ```json
866 /// {
867 /// "id": 42,
868 /// "jsonrpc": "2.0",
869 /// "result": "0x400"
870 /// }
871 /// ```
872 #[rpc(name = "get_tip_block_number")]
873 fn get_tip_block_number(&self) -> Result<BlockNumber>;
874
875 /// Returns the epoch with the highest number in the [canonical chain](#canonical-chain).
876 ///
877 /// Pay attention that like blocks with the specific block number may change because of [chain
878 /// reorganization](#chain-reorganization), This RPC may return different epochs which have
879 /// the same epoch number.
880 ///
881 /// ## Examples
882 ///
883 /// Request
884 ///
885 /// ```json
886 /// {
887 /// "id": 42,
888 /// "jsonrpc": "2.0",
889 /// "method": "get_current_epoch",
890 /// "params": []
891 /// }
892 /// ```
893 ///
894 /// Response
895 ///
896 /// ```json
897 /// {
898 /// "id": 42,
899 /// "jsonrpc": "2.0",
900 /// "result": {
901 /// "compact_target": "0x1e083126",
902 /// "length": "0x708",
903 /// "number": "0x1",
904 /// "start_number": "0x3e8"
905 /// }
906 /// }
907 /// ```
908 #[rpc(name = "get_current_epoch")]
909 fn get_current_epoch(&self) -> Result<EpochView>;
910
911 /// Returns the epoch in the [canonical chain](#canonical-chain) with the specific epoch number.
912 ///
913 /// ## Params
914 ///
915 /// * `epoch_number` - Epoch number
916 ///
917 /// ## Returns
918 ///
919 /// The RPC returns the epoch when `epoch_number` is less than or equal to the current epoch number
920 /// returned by [`get_current_epoch`](#tymethod.get_current_epoch) and returns null otherwise.
921 ///
922 /// Because of [chain reorganization](#chain-reorganization), for the same `epoch_number`, this
923 /// RPC may return null or different epochs in different invocations.
924 ///
925 /// ## Examples
926 ///
927 /// Request
928 ///
929 /// ```json
930 /// {
931 /// "id": 42,
932 /// "jsonrpc": "2.0",
933 /// "method": "get_epoch_by_number",
934 /// "params": [
935 /// "0x0"
936 /// ]
937 /// }
938 /// ```
939 ///
940 /// Response
941 ///
942 /// ```json
943 /// {
944 /// "id": 42,
945 /// "jsonrpc": "2.0",
946 /// "result": {
947 /// "compact_target": "0x20010000",
948 /// "length": "0x3e8",
949 /// "number": "0x0",
950 /// "start_number": "0x0"
951 /// }
952 /// }
953 /// ```
954 #[rpc(name = "get_epoch_by_number")]
955 fn get_epoch_by_number(&self, epoch_number: EpochNumber) -> Result<Option<EpochView>>;
956
957 /// Returns increased issuance, miner reward, and the total transaction fee of a block.
958 ///
959 /// This RPC returns null if the block is not in the [canonical chain](#canonical-chain).
960 ///
961 /// CKB delays CKB creation for miners. The output cells in the cellbase of block N are for the
962 /// miner creating block `N - 1 - ProposalWindow.farthest`.
963 ///
964 /// In mainnet, `ProposalWindow.farthest` is 10, so the outputs in block 100 are rewards for
965 /// miner creating block 89.
966 ///
967 /// Because of the delay, this RPC returns null if the block rewards are not finalized yet. For
968 /// example, the economic state for block 89 is only available when the number returned by
969 /// [`get_tip_block_number`](#tymethod.get_tip_block_number) is greater than or equal to 100.
970 ///
971 /// ## Params
972 ///
973 /// * `block_hash` - Specifies the block hash which rewards should be analyzed.
974 ///
975 /// ## Returns
976 ///
977 /// If the block with the hash `block_hash` is in the [canonical chain](#canonical-chain) and
978 /// its rewards have been finalized, return the block rewards analysis for this block. A special
979 /// case is that the return value for genesis block is null.
980 ///
981 /// ## Examples
982 ///
983 /// Request
984 ///
985 /// ```json
986 /// {
987 /// "id": 42,
988 /// "jsonrpc": "2.0",
989 /// "method": "get_block_economic_state",
990 /// "params": [
991 /// "0x02530b25ad0ff677acc365cb73de3e8cc09c7ddd58272e879252e199d08df83b"
992 /// ]
993 /// }
994 /// ```
995 ///
996 /// Response
997 ///
998 /// ```json
999 /// {
1000 /// "id": 42,
1001 /// "jsonrpc": "2.0",
1002 /// "result": {
1003 /// "finalized_at": "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40",
1004 /// "issuance": {
1005 /// "primary": "0x18ce922bca",
1006 /// "secondary": "0x7f02ec655"
1007 /// },
1008 /// "miner_reward": {
1009 /// "committed": "0x0",
1010 /// "primary": "0x18ce922bca",
1011 /// "proposal": "0x0",
1012 /// "secondary": "0x17b93605"
1013 /// },
1014 /// "txs_fee": "0x0"
1015 /// }
1016 /// }
1017 /// ```
1018 #[rpc(name = "get_block_economic_state")]
1019 fn get_block_economic_state(&self, block_hash: H256) -> Result<Option<BlockEconomicState>>;
1020
1021 /// Returns a Merkle proof that transactions are included in a block.
1022 ///
1023 /// ## Params
1024 ///
1025 /// * `tx_hashes` - Transaction hashes, all transactions must be in the same block
1026 /// * `block_hash` - An optional parameter, if specified, looks for transactions in the block with this hash
1027 ///
1028 /// ## Examples
1029 ///
1030 /// Request
1031 ///
1032 /// ```json
1033 /// {
1034 /// "id": 42,
1035 /// "jsonrpc": "2.0",
1036 /// "method": "get_transaction_proof",
1037 /// "params": [
1038 /// [ "0xa4037a893eb48e18ed4ef61034ce26eba9c585f15c9cee102ae58505565eccc3" ]
1039 /// ]
1040 /// }
1041 /// ```
1042 ///
1043 /// Response
1044 ///
1045 /// ```json
1046 /// {
1047 /// "id": 42,
1048 /// "jsonrpc": "2.0",
1049 /// "result": {
1050 /// "block_hash": "0x7978ec7ce5b507cfb52e149e36b1a23f6062ed150503c85bbf825da3599095ed",
1051 /// "proof": {
1052 /// "indices": [ "0x0" ],
1053 /// "lemmas": []
1054 /// },
1055 /// "witnesses_root": "0x2bb631f4a251ec39d943cc238fc1e39c7f0e99776e8a1e7be28a03c70c4f4853"
1056 /// }
1057 /// }
1058 /// ```
1059 #[rpc(name = "get_transaction_proof")]
1060 fn get_transaction_proof(
1061 &self,
1062 tx_hashes: Vec<H256>,
1063 block_hash: Option<H256>,
1064 ) -> Result<TransactionProof>;
1065
1066 /// Verifies that a proof points to transactions in a block, returning the transaction hashes it commits to.
1067 ///
1068 /// ## Parameters
1069 ///
1070 /// * `transaction_proof` - proof generated by [`get_transaction_proof`](#tymethod.get_transaction_proof).
1071 ///
1072 /// ## Examples
1073 ///
1074 /// Request
1075 ///
1076 /// ```json
1077 /// {
1078 /// "id": 42,
1079 /// "jsonrpc": "2.0",
1080 /// "method": "verify_transaction_proof",
1081 /// "params": [
1082 /// {
1083 /// "block_hash": "0x7978ec7ce5b507cfb52e149e36b1a23f6062ed150503c85bbf825da3599095ed",
1084 /// "proof": {
1085 /// "indices": [ "0x0" ],
1086 /// "lemmas": []
1087 /// },
1088 /// "witnesses_root": "0x2bb631f4a251ec39d943cc238fc1e39c7f0e99776e8a1e7be28a03c70c4f4853"
1089 /// }
1090 /// ]
1091 /// }
1092 /// ```
1093 ///
1094 /// Response
1095 ///
1096 /// ```json
1097 /// {
1098 /// "id": 42,
1099 /// "jsonrpc": "2.0",
1100 /// "result": [
1101 /// "0xa4037a893eb48e18ed4ef61034ce26eba9c585f15c9cee102ae58505565eccc3"
1102 /// ]
1103 /// }
1104 /// ```
1105 #[rpc(name = "verify_transaction_proof")]
1106 fn verify_transaction_proof(&self, tx_proof: TransactionProof) -> Result<Vec<H256>>;
1107
1108 /// Returns a Merkle proof of transactions' witness included in a block.
1109 ///
1110 /// ## Params
1111 ///
1112 /// * `tx_hashes` - Transaction hashes, all transactions must be in the same block
1113 /// * `block_hash` - An optional parameter, if specified, looks for transactions in the block with this hash
1114 ///
1115 /// ## Examples
1116 ///
1117 /// Request
1118 ///
1119 /// ```json
1120 /// {
1121 /// "id": 42,
1122 /// "jsonrpc": "2.0",
1123 /// "method": "get_transaction_and_witness_proof",
1124 /// "params": [
1125 /// [ "0xa4037a893eb48e18ed4ef61034ce26eba9c585f15c9cee102ae58505565eccc3" ]
1126 /// ]
1127 /// }
1128 /// ```
1129 ///
1130 /// Response
1131 ///
1132 /// ```json
1133 /// {
1134 /// "jsonrpc": "2.0",
1135 /// "result": {
1136 /// "block_hash": "0x7978ec7ce5b507cfb52e149e36b1a23f6062ed150503c85bbf825da3599095ed",
1137 /// "transactions_proof": {
1138 /// "indices": [ "0x0" ],
1139 /// "lemmas": []
1140 /// },
1141 /// "witnesses_proof": {
1142 /// "indices": [
1143 /// "0x0"
1144 /// ],
1145 /// "lemmas": []
1146 /// }
1147 /// },
1148 /// "id": 42
1149 /// }
1150 /// ```
1151 #[rpc(name = "get_transaction_and_witness_proof")]
1152 fn get_transaction_and_witness_proof(
1153 &self,
1154 tx_hashes: Vec<H256>,
1155 block_hash: Option<H256>,
1156 ) -> Result<TransactionAndWitnessProof>;
1157
1158 /// Verifies that a proof points to transactions in a block, returning the transaction hashes it commits to.
1159 ///
1160 /// ## Parameters
1161 ///
1162 /// * `tx_proof` - proof generated by [`get_transaction_and_witness_proof`](#tymethod.get_transaction_and_witness_proof).
1163 ///
1164 /// ## Examples
1165 ///
1166 /// Request
1167 ///
1168 /// ```json
1169 /// {
1170 /// "id": 42,
1171 /// "jsonrpc": "2.0",
1172 /// "method": "verify_transaction_and_witness_proof",
1173 /// "params": [
1174 /// {
1175 /// "block_hash": "0x7978ec7ce5b507cfb52e149e36b1a23f6062ed150503c85bbf825da3599095ed",
1176 /// "transactions_proof": {
1177 /// "indices": [ "0x0" ],
1178 /// "lemmas": []
1179 /// },
1180 /// "witnesses_proof": {
1181 /// "indices": [
1182 /// "0x0"
1183 /// ],
1184 /// "lemmas": []
1185 /// }
1186 /// }
1187 /// ]
1188 /// }
1189 /// ```
1190 ///
1191 /// Response
1192 ///
1193 /// ```json
1194 /// {
1195 /// "id": 42,
1196 /// "jsonrpc": "2.0",
1197 /// "result": [
1198 /// "0xa4037a893eb48e18ed4ef61034ce26eba9c585f15c9cee102ae58505565eccc3"
1199 /// ]
1200 /// }
1201 /// ```
1202 #[rpc(name = "verify_transaction_and_witness_proof")]
1203 fn verify_transaction_and_witness_proof(
1204 &self,
1205 tx_proof: TransactionAndWitnessProof,
1206 ) -> Result<Vec<H256>>;
1207
1208 /// Returns the information about a fork block by hash.
1209 ///
1210 /// ## Params
1211 ///
1212 /// * `block_hash` - the fork block hash.
1213 /// * `verbosity` - result format which allows 0 and 2. (**Optional**, the default is 2.)
1214 ///
1215 /// ## Returns
1216 ///
1217 /// The RPC returns a fork block or null. When the RPC returns a block, the block hash must equal to
1218 /// the parameter `block_hash`.
1219 ///
1220 /// Please note that due to the technical nature of the peer to peer sync, the RPC may return null or a fork block
1221 /// result on different nodes with same `block_hash` even they are fully synced to the [canonical chain](#canonical-chain).
1222 /// And because of [chain reorganization](#chain-reorganization), for the same `block_hash`, the
1223 /// RPC may sometimes return null and sometimes return the fork block.
1224 ///
1225 /// When `verbosity` is 2, it returns a JSON object as the `result`. See `BlockView` for the
1226 /// schema.
1227 ///
1228 /// When `verbosity` is 0, it returns a 0x-prefixed hex string as the `result`. The string
1229 /// encodes the block serialized by molecule using schema `table Block`.
1230 ///
1231 /// ## Examples
1232 ///
1233 /// Request
1234 ///
1235 /// ```json
1236 /// {
1237 /// "id": 42,
1238 /// "jsonrpc": "2.0",
1239 /// "method": "get_fork_block",
1240 /// "params": [
1241 /// "0xdca341a42890536551f99357612cef7148ed471e3b6419d0844a4e400be6ee94"
1242 /// ]
1243 /// }
1244 /// ```
1245 ///
1246 /// Response
1247 ///
1248 /// ```json
1249 /// {
1250 /// "id": 42,
1251 /// "jsonrpc": "2.0",
1252 /// "result": {
1253 /// "header": {
1254 /// "compact_target": "0x1e083126",
1255 /// "dao": "0xb5a3e047474401001bc476b9ee573000c0c387962a38000000febffacf030000",
1256 /// "epoch": "0x7080018000001",
1257 /// "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1258 /// "hash": "0xdca341a42890536551f99357612cef7148ed471e3b6419d0844a4e400be6ee94",
1259 /// "nonce": "0x0",
1260 /// "number": "0x400",
1261 /// "parent_hash": "0xae003585fa15309b30b31aed3dcf385e9472c3c3e93746a6c4540629a6a1ed2d",
1262 /// "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1263 /// "timestamp": "0x5cd2b118",
1264 /// "transactions_root": "0xc47d5b78b3c4c4c853e2a32810818940d0ee403423bea9ec7b8e566d9595206c",
1265 /// "version": "0x0"
1266 /// },
1267 /// "proposals": [],
1268 /// "transactions": [
1269 /// {
1270 /// "cell_deps": [],
1271 /// "hash": "0x365698b50ca0da75dca2c87f9e7b563811d3b5813736b8cc62cc3b106faceb17",
1272 /// "header_deps": [],
1273 /// "inputs": [
1274 /// {
1275 /// "previous_output": {
1276 /// "index": "0xffffffff",
1277 /// "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000"
1278 /// },
1279 /// "since": "0x400"
1280 /// }
1281 /// ],
1282 /// "outputs": [
1283 /// {
1284 /// "capacity": "0x18e64b61cf",
1285 /// "lock": {
1286 /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5",
1287 /// "hash_type": "data",
1288 /// "args": "0x"
1289 /// },
1290 /// "type": null
1291 /// }
1292 /// ],
1293 /// "outputs_data": [
1294 /// "0x"
1295 /// ],
1296 /// "version": "0x0",
1297 /// "witnesses": [
1298 /// "0x450000000c000000410000003500000010000000300000003100000028e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5000000000000000000"
1299 /// ]
1300 /// }
1301 /// ],
1302 /// "uncles": []
1303 /// }
1304 /// }
1305 /// ```
1306 ///
1307 /// The response looks like below when `verbosity` is 0.
1308 ///
1309 /// ```text
1310 /// {
1311 /// "id": 42,
1312 /// "jsonrpc": "2.0",
1313 /// "result": "0x..."
1314 /// }
1315 /// ```
1316 #[rpc(name = "get_fork_block")]
1317 fn get_fork_block(
1318 &self,
1319 block_hash: H256,
1320 verbosity: Option<Uint32>,
1321 ) -> Result<Option<ResponseFormat<BlockView>>>;
1322
1323 /// Return various consensus parameters.
1324 ///
1325 /// ## Returns
1326 ///
1327 /// If any hardfork feature has `epoch=null`, it means the feature will never be activated.
1328 ///
1329 /// ## Examples
1330 ///
1331 /// Request
1332 ///
1333 /// ```json
1334 /// {
1335 /// "id": 42,
1336 /// "jsonrpc": "2.0",
1337 /// "method": "get_consensus",
1338 /// "params": []
1339 /// }
1340 /// ```
1341 ///
1342 /// Response
1343 ///
1344 /// ```json
1345 /// {
1346 /// "id": 42,
1347 /// "jsonrpc": "2.0",
1348 /// "result": {
1349 /// "block_version": "0x0",
1350 /// "cellbase_maturity": "0x10000000000",
1351 /// "dao_type_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1352 /// "epoch_duration_target": "0x3840",
1353 /// "genesis_hash": "0x7978ec7ce5b507cfb52e149e36b1a23f6062ed150503c85bbf825da3599095ed",
1354 /// "hardfork_features": [
1355 /// { "rfc": "0028", "epoch_number": "0x1526" },
1356 /// { "rfc": "0029", "epoch_number": "0x0" },
1357 /// { "rfc": "0030", "epoch_number": "0x0" },
1358 /// { "rfc": "0031", "epoch_number": "0x0" },
1359 /// { "rfc": "0032", "epoch_number": "0x1526" },
1360 /// { "rfc": "0036", "epoch_number": "0x0" },
1361 /// { "rfc": "0038", "epoch_number": "0x0" },
1362 /// { "rfc": "0048", "epoch_number": "0x3005" },
1363 /// { "rfc": "0049", "epoch_number": "0x3005" }
1364 /// ],
1365 /// "id": "main",
1366 /// "initial_primary_epoch_reward": "0x71afd498d000",
1367 /// "max_block_bytes": "0x91c08",
1368 /// "max_block_cycles": "0xd09dc300",
1369 /// "max_block_proposals_limit": "0x5dc",
1370 /// "max_uncles_num": "0x2",
1371 /// "median_time_block_count": "0x25",
1372 /// "orphan_rate_target": {
1373 /// "denom": "0x28",
1374 /// "numer": "0x1"
1375 /// },
1376 /// "permanent_difficulty_in_dummy": false,
1377 /// "primary_epoch_reward_halving_interval": "0x2238",
1378 /// "proposer_reward_ratio": {
1379 /// "denom": "0xa",
1380 /// "numer": "0x4"
1381 /// },
1382 /// "secondary_epoch_reward": "0x37d0c8e28542",
1383 /// "secp256k1_blake160_multisig_all_type_hash": null,
1384 /// "secp256k1_blake160_sighash_all_type_hash": null,
1385 /// "softforks": {
1386 /// "testdummy": {
1387 /// "status": "rfc0043",
1388 /// "rfc0043": {
1389 /// "bit": 1,
1390 /// "min_activation_epoch": "0x0",
1391 /// "period": "0xa",
1392 /// "start": "0x0",
1393 /// "threshold": {
1394 /// "denom": "0x4",
1395 /// "numer": "0x3"
1396 /// },
1397 /// "timeout": "0x0"
1398 /// }
1399 /// }
1400 /// },
1401 /// "tx_proposal_window": {
1402 /// "closest": "0x2",
1403 /// "farthest": "0xa"
1404 /// },
1405 /// "tx_version": "0x0",
1406 /// "type_id_code_hash": "0x00000000000000000000000000000000000000000000000000545950455f4944"
1407 /// }
1408 /// }
1409 /// ```
1410 #[rpc(name = "get_consensus")]
1411 fn get_consensus(&self) -> Result<Consensus>;
1412
1413 /// Returns the past median time by block hash.
1414 ///
1415 /// ## Params
1416 ///
1417 /// * `block_hash` - A median time is calculated for a consecutive block sequence. `block_hash` indicates the highest block of the sequence.
1418 ///
1419 /// ## Returns
1420 ///
1421 /// When the given block hash is not on the current canonical chain, this RPC returns null;
1422 /// otherwise returns the median time of the consecutive 37 blocks where the given block_hash has the highest height.
1423 ///
1424 /// Note that the given block is included in the median time. The included block number range is `[MAX(block - 36, 0), block]`.
1425 ///
1426 /// ## Examples
1427 ///
1428 /// Request
1429 ///
1430 /// ```json
1431 /// {
1432 /// "id": 42,
1433 /// "jsonrpc": "2.0",
1434 /// "method": "get_block_median_time",
1435 /// "params": [
1436 /// "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40"
1437 /// ]
1438 /// }
1439 /// ```
1440 ///
1441 /// Response
1442 ///
1443 /// ```json
1444 /// {
1445 /// "id": 42,
1446 /// "jsonrpc": "2.0",
1447 /// "result": "0x5cd2b105"
1448 /// }
1449 /// ```
1450 #[rpc(name = "get_block_median_time")]
1451 fn get_block_median_time(&self, block_hash: H256) -> Result<Option<Timestamp>>;
1452
1453 /// `estimate_cycles` run a transaction and return the execution consumed cycles.
1454 ///
1455 /// This method will not check the transaction validity, but only run the lock script
1456 /// and type script and then return the execution cycles.
1457 ///
1458 /// It is used to estimate how many cycles the scripts consume.
1459 ///
1460 /// ## Errors
1461 ///
1462 /// * [`TransactionFailedToResolve (-301)`](../enum.RPCError.html#variant.TransactionFailedToResolve) - Failed to resolve the referenced cells and headers used in the transaction, as inputs or dependencies.
1463 /// * [`TransactionFailedToVerify (-302)`](../enum.RPCError.html#variant.TransactionFailedToVerify) - There is a script returns with an error.
1464 ///
1465 /// ## Examples
1466 ///
1467 /// Request
1468 ///
1469 /// ```json
1470 /// {
1471 /// "id": 42,
1472 /// "jsonrpc": "2.0",
1473 /// "method": "estimate_cycles",
1474 /// "params": [
1475 /// {
1476 /// "cell_deps": [
1477 /// {
1478 /// "dep_type": "code",
1479 /// "out_point": {
1480 /// "index": "0x0",
1481 /// "tx_hash": "0xa4037a893eb48e18ed4ef61034ce26eba9c585f15c9cee102ae58505565eccc3"
1482 /// }
1483 /// }
1484 /// ],
1485 /// "header_deps": [
1486 /// "0x7978ec7ce5b507cfb52e149e36b1a23f6062ed150503c85bbf825da3599095ed"
1487 /// ],
1488 /// "inputs": [
1489 /// {
1490 /// "previous_output": {
1491 /// "index": "0x0",
1492 /// "tx_hash": "0x365698b50ca0da75dca2c87f9e7b563811d3b5813736b8cc62cc3b106faceb17"
1493 /// },
1494 /// "since": "0x0"
1495 /// }
1496 /// ],
1497 /// "outputs": [
1498 /// {
1499 /// "capacity": "0x2540be400",
1500 /// "lock": {
1501 /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5",
1502 /// "hash_type": "data",
1503 /// "args": "0x"
1504 /// },
1505 /// "type": null
1506 /// }
1507 /// ],
1508 /// "outputs_data": [
1509 /// "0x"
1510 /// ],
1511 /// "version": "0x0",
1512 /// "witnesses": []
1513 /// }
1514 /// ]
1515 /// }
1516 /// ```
1517 ///
1518 /// Response
1519 ///
1520 /// ```json
1521 /// {
1522 /// "id": 42,
1523 /// "jsonrpc": "2.0",
1524 /// "result": {
1525 /// "cycles": "0x219"
1526 /// }
1527 /// }
1528 /// ```
1529 #[rpc(name = "estimate_cycles")]
1530 fn estimate_cycles(&self, tx: Transaction) -> Result<EstimateCycles>;
1531
1532 /// Returns the fee_rate statistics of confirmed blocks on the chain
1533 ///
1534 /// ## Params
1535 ///
1536 /// * `target` - Specify the number (1 - 101) of confirmed blocks to be counted.
1537 /// If the number is even, automatically add one. If not specified, defaults to 21
1538 ///
1539 /// ## Returns
1540 ///
1541 /// If the query finds the corresponding historical data,
1542 /// the corresponding statistics are returned,
1543 /// containing the mean and median, in shannons per kilo-weight.
1544 /// If not, it returns null.
1545 ///
1546 /// ## Examples
1547 ///
1548 /// Request
1549 ///
1550 /// ```json
1551 /// {
1552 /// "id": 42,
1553 /// "jsonrpc": "2.0",
1554 /// "method": "get_fee_rate_statics",
1555 /// "params": []
1556 /// }
1557 /// ```
1558 ///
1559 /// Response
1560 ///
1561 /// ```json
1562 /// {
1563 /// "id": 42,
1564 /// "jsonrpc": "2.0",
1565 /// "result": {
1566 /// "mean": "0xe79d",
1567 /// "median": "0x14a8"
1568 /// }
1569 /// }
1570 /// ```
1571 #[deprecated(
1572 since = "0.109.0",
1573 note = "Please use the RPC method [`get_fee_rate_statistics`](#chain-get_fee_rate_statistics) instead"
1574 )]
1575 #[rpc(name = "get_fee_rate_statics")]
1576 fn get_fee_rate_statics(&self, target: Option<Uint64>) -> Result<Option<FeeRateStatistics>>;
1577
1578 /// Returns the fee_rate statistics of confirmed blocks on the chain
1579 ///
1580 /// ## Params
1581 ///
1582 /// * `target` - Specify the number (1 - 101) of confirmed blocks to be counted.
1583 /// If the number is even, automatically add one. If not specified, defaults to 21
1584 ///
1585 /// ## Returns
1586 ///
1587 /// If the query finds the corresponding historical data,
1588 /// the corresponding statistics are returned,
1589 /// containing the mean and median, in shannons per kilo-weight.
1590 /// If not, it returns null.
1591 ///
1592 /// ## Examples
1593 ///
1594 /// Request
1595 ///
1596 /// ```json
1597 /// {
1598 /// "id": 42,
1599 /// "jsonrpc": "2.0",
1600 /// "method": "get_fee_rate_statistics",
1601 /// "params": []
1602 /// }
1603 /// ```
1604 ///
1605 /// Response
1606 ///
1607 /// ```json
1608 /// {
1609 /// "id": 42,
1610 /// "jsonrpc": "2.0",
1611 /// "result": {
1612 /// "mean": "0xe79d",
1613 /// "median": "0x14a8"
1614 /// }
1615 /// }
1616 /// ```
1617 #[rpc(name = "get_fee_rate_statistics")]
1618 fn get_fee_rate_statistics(&self, target: Option<Uint64>) -> Result<Option<FeeRateStatistics>>;
1619}
1620
1621#[derive(Clone)]
1622pub(crate) struct ChainRpcImpl {
1623 pub shared: Shared,
1624}
1625
1626const DEFAULT_BLOCK_VERBOSITY_LEVEL: u32 = 2;
1627const DEFAULT_HEADER_VERBOSITY_LEVEL: u32 = 1;
1628const DEFAULT_GET_TRANSACTION_VERBOSITY_LEVEL: u32 = 2;
1629
1630#[async_trait]
1631impl ChainRpc for ChainRpcImpl {
1632 fn get_block(
1633 &self,
1634 block_hash: H256,
1635 verbosity: Option<Uint32>,
1636 with_cycles: Option<bool>,
1637 ) -> Result<Option<BlockResponse>> {
1638 let snapshot = self.shared.snapshot();
1639 let block_hash = block_hash.into();
1640
1641 self.get_block_by_hash(&snapshot, &block_hash, verbosity, with_cycles)
1642 }
1643
1644 fn get_block_by_number(
1645 &self,
1646 block_number: BlockNumber,
1647 verbosity: Option<Uint32>,
1648 with_cycles: Option<bool>,
1649 ) -> Result<Option<BlockResponse>> {
1650 let snapshot = self.shared.snapshot();
1651 let block_hash = match snapshot.get_block_hash(block_number.into()) {
1652 Some(block_hash) => block_hash,
1653 None => return Ok(None),
1654 };
1655
1656 let ret = self.get_block_by_hash(&snapshot, &block_hash, verbosity, with_cycles);
1657 if ret == Ok(None) {
1658 let message = format!(
1659 "Chain Index says block #{block_number} is {block_hash:#x}, but that block is not in the database"
1660 );
1661 error!("{message}");
1662 return Err(RPCError::custom(
1663 RPCError::ChainIndexIsInconsistent,
1664 message,
1665 ));
1666 }
1667 ret
1668 }
1669
1670 fn get_header(
1671 &self,
1672 block_hash: H256,
1673 verbosity: Option<Uint32>,
1674 ) -> Result<Option<ResponseFormat<HeaderView>>> {
1675 let snapshot = self.shared.snapshot();
1676 let block_hash = block_hash.into();
1677 if !snapshot.is_main_chain(&block_hash) {
1678 return Ok(None);
1679 }
1680
1681 let verbosity = verbosity
1682 .map(|v| v.value())
1683 .unwrap_or(DEFAULT_HEADER_VERBOSITY_LEVEL);
1684 if verbosity == 1 {
1685 Ok(snapshot
1686 .get_block_header(&block_hash)
1687 .map(|header| ResponseFormat::json(header.into())))
1688 } else if verbosity == 0 {
1689 Ok(snapshot
1690 .get_packed_block_header(&block_hash)
1691 .map(|packed| ResponseFormat::hex(packed.as_bytes())))
1692 } else {
1693 Err(RPCError::invalid_params("invalid verbosity level"))
1694 }
1695 }
1696
1697 fn get_header_by_number(
1698 &self,
1699 block_number: BlockNumber,
1700 verbosity: Option<Uint32>,
1701 ) -> Result<Option<ResponseFormat<HeaderView>>> {
1702 let snapshot = self.shared.snapshot();
1703 let block_hash = match snapshot.get_block_hash(block_number.into()) {
1704 Some(block_hash) => block_hash,
1705 None => return Ok(None),
1706 };
1707
1708 let verbosity = verbosity
1709 .map(|v| v.value())
1710 .unwrap_or(DEFAULT_HEADER_VERBOSITY_LEVEL);
1711 let result = if verbosity == 1 {
1712 snapshot
1713 .get_block_header(&block_hash)
1714 .map(|header| Some(ResponseFormat::json(header.into())))
1715 } else if verbosity == 0 {
1716 snapshot
1717 .get_packed_block_header(&block_hash)
1718 .map(|header| Some(ResponseFormat::hex(header.as_bytes())))
1719 } else {
1720 return Err(RPCError::invalid_params("invalid verbosity level"));
1721 };
1722
1723 result.ok_or_else(|| {
1724 let message = format!(
1725 "Chain Index says block #{block_number} is {block_hash:#x}, but that block is not in the database"
1726 );
1727 error!("{message}");
1728 RPCError::custom(RPCError::ChainIndexIsInconsistent, message)
1729 })
1730 }
1731
1732 fn get_block_filter(&self, block_hash: H256) -> Result<Option<BlockFilter>> {
1733 let store = self.shared.store();
1734 let block_hash = block_hash.into();
1735 if !store.is_main_chain(&block_hash) {
1736 return Ok(None);
1737 }
1738 Ok(store.get_block_filter(&block_hash).map(|data| {
1739 let hash = store
1740 .get_block_filter_hash(&block_hash)
1741 .expect("stored filter hash");
1742 BlockFilter {
1743 data: data.into(),
1744 hash: hash.into(),
1745 }
1746 }))
1747 }
1748
1749 fn get_transaction(
1750 &self,
1751 tx_hash: H256,
1752 verbosity: Option<Uint32>,
1753 only_committed: Option<bool>,
1754 ) -> Result<TransactionWithStatusResponse> {
1755 let tx_hash = tx_hash.into();
1756 let verbosity = verbosity
1757 .map(|v| v.value())
1758 .unwrap_or(DEFAULT_GET_TRANSACTION_VERBOSITY_LEVEL);
1759
1760 let only_committed: bool = only_committed.unwrap_or(false);
1761
1762 if verbosity == 0 {
1763 // when verbosity=0, it's response value is as same as verbosity=2, but it
1764 // return a 0x-prefixed hex encoded molecule packed::Transaction` on `transaction` field
1765 self.get_transaction_verbosity2(tx_hash, only_committed)
1766 .map(|tws| TransactionWithStatusResponse::from(tws, ResponseFormatInnerType::Hex))
1767 } else if verbosity == 1 {
1768 // The RPC does not return the transaction content and the field transaction must be null.
1769 self.get_transaction_verbosity1(tx_hash, only_committed)
1770 .map(|tws| TransactionWithStatusResponse::from(tws, ResponseFormatInnerType::Json))
1771 } else if verbosity == 2 {
1772 // if tx_status.status is pending, proposed, or committed,
1773 // the RPC returns the transaction content as field transaction,
1774 // otherwise the field is null.
1775 self.get_transaction_verbosity2(tx_hash, only_committed)
1776 .map(|tws| TransactionWithStatusResponse::from(tws, ResponseFormatInnerType::Json))
1777 } else {
1778 Err(RPCError::invalid_params("invalid verbosity level"))
1779 }
1780 }
1781
1782 fn get_block_hash(&self, block_number: BlockNumber) -> Result<Option<H256>> {
1783 Ok(self
1784 .shared
1785 .snapshot()
1786 .get_block_hash(block_number.into())
1787 .map(|h| h.into()))
1788 }
1789
1790 fn get_tip_header(&self, verbosity: Option<Uint32>) -> Result<ResponseFormat<HeaderView>> {
1791 let verbosity = verbosity
1792 .map(|v| v.value())
1793 .unwrap_or(DEFAULT_HEADER_VERBOSITY_LEVEL);
1794 if verbosity == 1 {
1795 Ok(ResponseFormat::json(
1796 self.shared.snapshot().tip_header().clone().into(),
1797 ))
1798 } else if verbosity == 0 {
1799 Ok(ResponseFormat::hex(
1800 self.shared.snapshot().tip_header().data().as_bytes(),
1801 ))
1802 } else {
1803 Err(RPCError::invalid_params("invalid verbosity level"))
1804 }
1805 }
1806
1807 fn get_current_epoch(&self) -> Result<EpochView> {
1808 Ok(EpochView::from_ext(
1809 self.shared.snapshot().epoch_ext().into(),
1810 ))
1811 }
1812
1813 fn get_epoch_by_number(&self, epoch_number: EpochNumber) -> Result<Option<EpochView>> {
1814 let snapshot = self.shared.snapshot();
1815 Ok(snapshot
1816 .get_epoch_index(epoch_number.into())
1817 .and_then(|hash| {
1818 snapshot
1819 .get_epoch_ext(&hash)
1820 .map(|ext| EpochView::from_ext(ext.into()))
1821 }))
1822 }
1823
1824 fn get_live_cell(
1825 &self,
1826 out_point: OutPoint,
1827 with_data: bool,
1828 include_tx_pool: Option<bool>,
1829 ) -> Result<CellWithStatus> {
1830 let cell_status: CellStatus = if include_tx_pool.unwrap_or_default() {
1831 self.shared
1832 .tx_pool_controller()
1833 .get_live_cell(out_point.into(), with_data)
1834 .map_err(|err| RPCError::custom(RPCError::CKBInternalError, err.to_string()))?
1835 } else {
1836 self.shared
1837 .snapshot()
1838 .as_ref()
1839 .cell(&out_point.into(), with_data)
1840 };
1841 Ok(cell_status.into())
1842 }
1843
1844 fn get_tip_block_number(&self) -> Result<BlockNumber> {
1845 Ok(self.shared.snapshot().tip_header().number().into())
1846 }
1847
1848 fn get_block_economic_state(&self, block_hash: H256) -> Result<Option<BlockEconomicState>> {
1849 let snapshot = self.shared.snapshot();
1850
1851 let block_number =
1852 if let Some(block_number) = snapshot.get_block_number(&(&block_hash).into()) {
1853 block_number
1854 } else {
1855 return Ok(None);
1856 };
1857
1858 let delay_length = snapshot.consensus().finalization_delay_length();
1859 let finalized_at_number = block_number + delay_length;
1860 if block_number == 0 || snapshot.tip_number() < finalized_at_number {
1861 return Ok(None);
1862 }
1863
1864 let block_hash = (&block_hash).into();
1865 let finalized_at = if let Some(block_hash) = snapshot.get_block_hash(finalized_at_number) {
1866 block_hash
1867 } else {
1868 return Ok(None);
1869 };
1870
1871 let issuance = if let Some(issuance) = snapshot
1872 .get_block_epoch_index(&block_hash)
1873 .and_then(|index| snapshot.get_epoch_ext(&index))
1874 .and_then(|epoch_ext| {
1875 let primary = epoch_ext.block_reward(block_number).ok()?;
1876 let secondary = epoch_ext
1877 .secondary_block_issuance(
1878 block_number,
1879 snapshot.consensus().secondary_epoch_reward(),
1880 )
1881 .ok()?;
1882 Some(core::BlockIssuance { primary, secondary })
1883 }) {
1884 issuance
1885 } else {
1886 return Ok(None);
1887 };
1888
1889 let txs_fee = if let Some(txs_fee) =
1890 snapshot.get_block_ext(&block_hash).and_then(|block_ext| {
1891 block_ext
1892 .txs_fees
1893 .iter()
1894 .try_fold(core::Capacity::zero(), |acc, tx_fee| acc.safe_add(*tx_fee))
1895 .ok()
1896 }) {
1897 txs_fee
1898 } else {
1899 return Ok(None);
1900 };
1901
1902 Ok(snapshot.get_block_header(&block_hash).and_then(|header| {
1903 RewardCalculator::new(snapshot.consensus(), snapshot.as_ref())
1904 .block_reward_for_target(&header)
1905 .ok()
1906 .map(|(_, block_reward)| core::BlockEconomicState {
1907 issuance,
1908 miner_reward: block_reward.into(),
1909 txs_fee,
1910 finalized_at,
1911 })
1912 .map(Into::into)
1913 }))
1914 }
1915
1916 fn get_transaction_proof(
1917 &self,
1918 tx_hashes: Vec<H256>,
1919 block_hash: Option<H256>,
1920 ) -> Result<TransactionProof> {
1921 let (block, leaf_indices) = self.get_tx_indices(tx_hashes, block_hash)?;
1922 Ok(TransactionProof {
1923 block_hash: block.hash().into(),
1924 witnesses_root: block.calc_witnesses_root().into(),
1925 proof: CBMT::build_merkle_proof(
1926 &block
1927 .transactions()
1928 .iter()
1929 .map(|tx| tx.hash())
1930 .collect::<Vec<_>>(),
1931 &leaf_indices,
1932 )
1933 .expect("build proof with verified inputs should be OK")
1934 .into(),
1935 })
1936 }
1937
1938 fn verify_transaction_proof(&self, tx_proof: TransactionProof) -> Result<Vec<H256>> {
1939 let snapshot = self.shared.snapshot();
1940
1941 snapshot
1942 .get_block(&(&tx_proof.block_hash).into())
1943 .ok_or_else(|| {
1944 RPCError::invalid_params(format!("Cannot find block {:#x}", tx_proof.block_hash))
1945 })
1946 .and_then(|block| {
1947 let witnesses_root = tx_proof.witnesses_root.into();
1948 let merkle_proof = MerkleProof::new(
1949 tx_proof
1950 .proof
1951 .indices
1952 .into_iter()
1953 .map(|index| index.value())
1954 .collect(),
1955 tx_proof
1956 .proof
1957 .lemmas
1958 .into_iter()
1959 .map(|lemma| lemma.into())
1960 .collect(),
1961 );
1962
1963 CBMT::retrieve_leaves(block.tx_hashes(), &merkle_proof)
1964 .and_then(|tx_hashes| {
1965 merkle_proof
1966 .root(&tx_hashes)
1967 .and_then(|raw_transactions_root| {
1968 if block.transactions_root()
1969 == merkle_root(&[raw_transactions_root, witnesses_root])
1970 {
1971 Some(tx_hashes.iter().map(|hash| hash.into()).collect())
1972 } else {
1973 None
1974 }
1975 })
1976 })
1977 .ok_or_else(|| RPCError::invalid_params("Invalid transaction proof"))
1978 })
1979 }
1980
1981 fn get_transaction_and_witness_proof(
1982 &self,
1983 tx_hashes: Vec<H256>,
1984 block_hash: Option<H256>,
1985 ) -> Result<TransactionAndWitnessProof> {
1986 let (block, leaf_indices) = self.get_tx_indices(tx_hashes, block_hash)?;
1987 Ok(TransactionAndWitnessProof {
1988 block_hash: block.hash().into(),
1989 transactions_proof: CBMT::build_merkle_proof(
1990 &block
1991 .transactions()
1992 .iter()
1993 .map(|tx| tx.hash())
1994 .collect::<Vec<_>>(),
1995 &leaf_indices,
1996 )
1997 .expect("build proof with verified inputs should be OK")
1998 .into(),
1999 witnesses_proof: CBMT::build_merkle_proof(block.tx_witness_hashes(), &leaf_indices)
2000 .expect("build proof with verified inputs should be OK")
2001 .into(),
2002 })
2003 }
2004
2005 fn verify_transaction_and_witness_proof(
2006 &self,
2007 tx_proof: TransactionAndWitnessProof,
2008 ) -> Result<Vec<H256>> {
2009 let snapshot = self.shared.snapshot();
2010 snapshot
2011 .get_block(&(&tx_proof.block_hash).into())
2012 .ok_or_else(|| {
2013 RPCError::invalid_params(format!("Cannot find block {:#x}", tx_proof.block_hash))
2014 })
2015 .and_then(|block| {
2016 let transactions_merkle_proof = MerkleProof::new(
2017 tx_proof
2018 .transactions_proof
2019 .indices
2020 .into_iter()
2021 .map(|index| index.value())
2022 .collect(),
2023 tx_proof
2024 .transactions_proof
2025 .lemmas
2026 .into_iter()
2027 .map(|lemma| lemma.into())
2028 .collect(),
2029 );
2030 let witnesses_merkle_proof = MerkleProof::new(
2031 tx_proof
2032 .witnesses_proof
2033 .indices
2034 .into_iter()
2035 .map(|index| index.value())
2036 .collect(),
2037 tx_proof
2038 .witnesses_proof
2039 .lemmas
2040 .into_iter()
2041 .map(|lemma| lemma.into())
2042 .collect(),
2043 );
2044
2045 CBMT::retrieve_leaves(block.tx_witness_hashes(), &witnesses_merkle_proof)
2046 .and_then(|witnesses_hashes| witnesses_merkle_proof.root(&witnesses_hashes))
2047 .and_then(|witnesses_proof_root| {
2048 CBMT::retrieve_leaves(block.tx_hashes(), &transactions_merkle_proof)
2049 .and_then(|tx_hashes| {
2050 transactions_merkle_proof.root(&tx_hashes).and_then(
2051 |raw_transactions_root| {
2052 if block.transactions_root()
2053 == merkle_root(&[
2054 raw_transactions_root,
2055 witnesses_proof_root,
2056 ])
2057 {
2058 Some(tx_hashes.iter().map(|hash| hash.into()).collect())
2059 } else {
2060 None
2061 }
2062 },
2063 )
2064 })
2065 })
2066 .ok_or_else(|| {
2067 RPCError::invalid_params("Invalid transaction_and_witness proof")
2068 })
2069 })
2070 }
2071
2072 fn get_fork_block(
2073 &self,
2074 block_hash: H256,
2075 verbosity: Option<Uint32>,
2076 ) -> Result<Option<ResponseFormat<BlockView>>> {
2077 let snapshot = self.shared.snapshot();
2078 let block_hash = block_hash.into();
2079 if snapshot.is_main_chain(&block_hash) {
2080 return Ok(None);
2081 }
2082
2083 let verbosity = verbosity
2084 .map(|v| v.value())
2085 .unwrap_or(DEFAULT_BLOCK_VERBOSITY_LEVEL);
2086 // TODO: verbosity level == 1, output block only contains tx_hash in JSON format
2087 if verbosity == 2 {
2088 Ok(snapshot
2089 .get_block(&block_hash)
2090 .map(|block| ResponseFormat::json(block.into())))
2091 } else if verbosity == 0 {
2092 Ok(snapshot
2093 .get_packed_block(&block_hash)
2094 .map(|packed| ResponseFormat::hex(packed.as_bytes())))
2095 } else {
2096 Err(RPCError::invalid_params("invalid verbosity level"))
2097 }
2098 }
2099
2100 fn get_consensus(&self) -> Result<Consensus> {
2101 let consensus = self.shared.consensus().clone();
2102 Ok(consensus.into())
2103 }
2104
2105 fn get_block_median_time(&self, block_hash: H256) -> Result<Option<Timestamp>> {
2106 let block_hash = block_hash.into();
2107 let snapshot = self.shared.snapshot();
2108 if !snapshot.is_main_chain(&block_hash) {
2109 return Ok(None);
2110 }
2111
2112 let median_time = snapshot.block_median_time(
2113 &block_hash,
2114 self.shared.consensus().median_time_block_count(),
2115 );
2116 Ok(Some(median_time.into()))
2117 }
2118
2119 fn estimate_cycles(&self, tx: Transaction) -> Result<EstimateCycles> {
2120 let tx: packed::Transaction = tx.into();
2121 CyclesEstimator::new(&self.shared).run(tx)
2122 }
2123
2124 fn get_fee_rate_statics(&self, target: Option<Uint64>) -> Result<Option<FeeRateStatistics>> {
2125 Ok(FeeRateCollector::new(self.shared.snapshot().as_ref())
2126 .statistics(target.map(Into::into)))
2127 }
2128
2129 fn get_fee_rate_statistics(&self, target: Option<Uint64>) -> Result<Option<FeeRateStatistics>> {
2130 Ok(FeeRateCollector::new(self.shared.snapshot().as_ref())
2131 .statistics(target.map(Into::into)))
2132 }
2133}
2134
2135impl ChainRpcImpl {
2136 fn get_transaction_verbosity1(
2137 &self,
2138 tx_hash: packed::Byte32,
2139 only_committed: bool,
2140 ) -> Result<TransactionWithStatus> {
2141 let snapshot = self.shared.snapshot();
2142
2143 if let Some(tx_info) = snapshot.get_transaction_info(&tx_hash) {
2144 let cycles = if tx_info.is_cellbase() {
2145 None
2146 } else {
2147 snapshot
2148 .get_block_ext(&tx_info.block_hash)
2149 .and_then(|block_ext| {
2150 block_ext
2151 .cycles
2152 .and_then(|v| v.get(tx_info.index.saturating_sub(1)).copied())
2153 })
2154 };
2155 return Ok(TransactionWithStatus::with_committed(
2156 None,
2157 tx_info.block_number,
2158 tx_info.block_hash.into(),
2159 tx_info.index as u32,
2160 cycles,
2161 None,
2162 ));
2163 }
2164
2165 if only_committed {
2166 return Ok(TransactionWithStatus::with_unknown());
2167 }
2168
2169 let tx_pool = self.shared.tx_pool_controller();
2170 let tx_status = tx_pool.get_tx_status(tx_hash);
2171 if let Err(e) = tx_status {
2172 error!("Send get_tx_status request error {}", e);
2173 return Err(RPCError::ckb_internal_error(e));
2174 };
2175 let tx_status = tx_status.unwrap();
2176
2177 if let Err(e) = tx_status {
2178 error!("get_tx_status from db error {}", e);
2179 return Err(RPCError::ckb_internal_error(e));
2180 };
2181 let (tx_status, cycles) = tx_status.unwrap();
2182 Ok(TransactionWithStatus::omit_transaction(tx_status, cycles))
2183 }
2184
2185 fn get_transaction_verbosity2(
2186 &self,
2187 tx_hash: packed::Byte32,
2188 only_committed: bool,
2189 ) -> Result<TransactionWithStatus> {
2190 let snapshot = self.shared.snapshot();
2191 if let Some((tx, tx_info)) = snapshot.get_transaction_with_info(&tx_hash) {
2192 let cycles = if tx_info.is_cellbase() {
2193 None
2194 } else {
2195 snapshot
2196 .get_block_ext(&tx_info.block_hash)
2197 .and_then(|block_ext| {
2198 block_ext
2199 .cycles
2200 .and_then(|v| v.get(tx_info.index.saturating_sub(1)).copied())
2201 })
2202 };
2203
2204 return Ok(TransactionWithStatus::with_committed(
2205 Some(tx),
2206 tx_info.block_number,
2207 tx_info.block_hash.into(),
2208 tx_info.index as u32,
2209 cycles,
2210 None,
2211 ));
2212 }
2213
2214 if only_committed {
2215 return Ok(TransactionWithStatus::with_unknown());
2216 }
2217
2218 let tx_pool = self.shared.tx_pool_controller();
2219 let transaction_with_status = tx_pool.get_transaction_with_status(tx_hash);
2220 if let Err(e) = transaction_with_status {
2221 error!("Send get_transaction_with_status request error {}", e);
2222 return Err(RPCError::ckb_internal_error(e));
2223 };
2224 let transaction_with_status = transaction_with_status.unwrap();
2225
2226 if let Err(e) = transaction_with_status {
2227 error!("Get transaction_with_status from db error {}", e);
2228 return Err(RPCError::ckb_internal_error(e));
2229 };
2230 let transaction_with_status = transaction_with_status.unwrap();
2231 Ok(transaction_with_status)
2232 }
2233
2234 fn get_block_by_hash(
2235 &self,
2236 snapshot: &Snapshot,
2237 block_hash: &packed::Byte32,
2238 verbosity: Option<Uint32>,
2239 with_cycles: Option<bool>,
2240 ) -> Result<Option<BlockResponse>> {
2241 if !snapshot.is_main_chain(block_hash) {
2242 return Ok(None);
2243 }
2244
2245 let verbosity = verbosity
2246 .map(|v| v.value())
2247 .unwrap_or(DEFAULT_BLOCK_VERBOSITY_LEVEL);
2248
2249 // default false
2250 let with_cycles = with_cycles.unwrap_or(false);
2251
2252 // TODO: verbosity level == 1, output block only contains tx_hash in JSON format
2253 let block_view = if verbosity == 2 {
2254 snapshot
2255 .get_block(block_hash)
2256 .map(|block| ResponseFormat::json(block.into()))
2257 } else if verbosity == 0 {
2258 snapshot
2259 .get_packed_block(block_hash)
2260 .map(|packed| ResponseFormat::hex(packed.as_bytes()))
2261 } else {
2262 return Err(RPCError::invalid_params("invalid verbosity level"));
2263 };
2264
2265 Ok(block_view.map(|block| {
2266 if with_cycles {
2267 let cycles = snapshot
2268 .get_block_ext(block_hash)
2269 .and_then(|ext| ext.cycles);
2270
2271 BlockResponse::with_cycles(
2272 block,
2273 cycles.map(|c| c.into_iter().map(Into::into).collect()),
2274 )
2275 } else {
2276 BlockResponse::regular(block)
2277 }
2278 }))
2279 }
2280
2281 fn get_tx_indices(
2282 &self,
2283 tx_hashes: Vec<H256>,
2284 block_hash: Option<H256>,
2285 ) -> Result<(core::BlockView, Vec<u32>)> {
2286 if tx_hashes.is_empty() {
2287 return Err(RPCError::invalid_params("Empty transaction hashes"));
2288 }
2289 let snapshot = self.shared.snapshot();
2290
2291 let mut retrieved_block_hash = None;
2292 let mut tx_indices = HashSet::new();
2293 for tx_hash in tx_hashes {
2294 match snapshot.get_transaction_info(&(&tx_hash).into()) {
2295 Some(tx_info) => {
2296 if retrieved_block_hash.is_none() {
2297 retrieved_block_hash = Some(tx_info.block_hash);
2298 } else if Some(tx_info.block_hash) != retrieved_block_hash {
2299 return Err(RPCError::invalid_params(
2300 "Not all transactions found in retrieved block",
2301 ));
2302 }
2303
2304 if !tx_indices.insert(tx_info.index as u32) {
2305 return Err(RPCError::invalid_params(format!(
2306 "Duplicated tx_hash {tx_hash:#x}"
2307 )));
2308 }
2309 }
2310 None => {
2311 return Err(RPCError::invalid_params(format!(
2312 "Transaction {tx_hash:#x} not yet in block"
2313 )));
2314 }
2315 }
2316 }
2317
2318 let retrieved_block_hash = retrieved_block_hash.expect("checked len");
2319 if let Some(specified_block_hash) = block_hash
2320 && !retrieved_block_hash.eq(&specified_block_hash.into())
2321 {
2322 return Err(RPCError::invalid_params(
2323 "Not all transactions found in specified block",
2324 ));
2325 }
2326
2327 snapshot
2328 .get_block(&retrieved_block_hash)
2329 .ok_or_else(|| {
2330 let message = format!(
2331 "Chain TransactionInfo says block {retrieved_block_hash:#x} existing, but that block is not in the database"
2332 );
2333 error!("{}", message);
2334 RPCError::custom(RPCError::ChainIndexIsInconsistent, message)
2335 })
2336 .map(|block| {
2337 (block, tx_indices.into_iter().collect::<Vec<_>>())
2338 })
2339 }
2340}
2341
2342// CyclesEstimator run given transaction, and return the result, including execution cycles.
2343pub(crate) struct CyclesEstimator<'a> {
2344 shared: &'a Shared,
2345}
2346
2347impl<'a> CellProvider for CyclesEstimator<'a> {
2348 fn cell(&self, out_point: &packed::OutPoint, eager_load: bool) -> CellStatus {
2349 let snapshot = self.shared.snapshot();
2350 snapshot
2351 .get_cell(out_point)
2352 .map(|mut cell_meta| {
2353 if eager_load
2354 && let Some((data, data_hash)) = snapshot.get_cell_data(out_point) {
2355 cell_meta.mem_cell_data = Some(data);
2356 cell_meta.mem_cell_data_hash = Some(data_hash);
2357 }
2358 CellStatus::live_cell(cell_meta)
2359 }) // treat as live cell, regardless of live or dead
2360 .unwrap_or(CellStatus::Unknown)
2361 }
2362}
2363
2364impl<'a> HeaderChecker for CyclesEstimator<'a> {
2365 fn check_valid(&self, block_hash: &packed::Byte32) -> std::result::Result<(), OutPointError> {
2366 self.shared.snapshot().check_valid(block_hash)
2367 }
2368}
2369
2370impl<'a> CyclesEstimator<'a> {
2371 pub(crate) fn new(shared: &'a Shared) -> Self {
2372 Self { shared }
2373 }
2374
2375 pub(crate) fn run(&self, tx: packed::Transaction) -> Result<EstimateCycles> {
2376 let snapshot = self.shared.cloned_snapshot();
2377 let consensus = snapshot.cloned_consensus();
2378 match resolve_transaction(tx.into_view(), &mut HashSet::new(), self, self) {
2379 Ok(resolved) => {
2380 let max_cycles = consensus.max_block_cycles;
2381 let tip_header = snapshot.tip_header();
2382 let tx_env = TxVerifyEnv::new_submit(tip_header);
2383 match ScriptVerifier::new(
2384 Arc::new(resolved),
2385 snapshot.as_data_loader(),
2386 consensus,
2387 Arc::new(tx_env),
2388 )
2389 .verify(max_cycles)
2390 {
2391 Ok(cycles) => Ok(EstimateCycles {
2392 cycles: cycles.into(),
2393 }),
2394 Err(err) => Err(RPCError::custom_with_error(
2395 RPCError::TransactionFailedToVerify,
2396 err,
2397 )),
2398 }
2399 }
2400 Err(err) => Err(RPCError::custom_with_error(
2401 RPCError::TransactionFailedToResolve,
2402 err,
2403 )),
2404 }
2405 }
2406}