ckb_jsonrpc_types/blockchain.rs
1use crate::bytes::JsonBytes;
2use crate::{
3 BlockNumber, Byte32, Capacity, Cycle, DeploymentPos, EpochNumber, EpochNumberWithFraction,
4 ProposalShortId, ResponseFormat, ResponseFormatInnerType, Timestamp, Uint32, Uint64, Uint128,
5 Version,
6};
7use ckb_types::core::tx_pool;
8use ckb_types::utilities::MerkleProof as RawMerkleProof;
9use ckb_types::{H256, core, packed, prelude::*};
10use schemars::JsonSchema;
11use seq_macro::seq;
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14use std::fmt;
15
16seq!(N in 3..=127 {
17 /// Specifies how the script `code_hash` is used to match the script code and how to run the code.
18 ///
19 /// Allowed kinds: "data", "type", "data1" and "data2"
20 ///
21 /// Refer to the section [Code Locating](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#code-locating)
22 /// and [Upgradable Script](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#upgradable-script)
23 /// in the RFC *CKB Transaction Structure*.
24 ///
25 /// The hash type is split into the high 7 bits and the low 1 bit,
26 /// when the low 1 bit is 1, it indicates the type,
27 /// when the low 1 bit is 0, it indicates the data,
28 /// and then it relies on the high 7 bits to indicate
29 /// that the data actually corresponds to the version.
30 #[derive(Default, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
31 #[serde(rename_all = "snake_case")]
32 #[repr(u8)]
33 pub enum ScriptHashType {
34 /// Type "data" matches script code via cell data hash, and run the script code in v0 CKB VM.
35 #[default]
36 Data = 0,
37 /// Type "type" matches script code via cell type script hash.
38 Type = 1,
39 /// Type "data1" matches script code via cell data hash, and run the script code in v1 CKB VM.
40 Data1 = 2,
41 /// Type "data2" matches script code via cell data hash, and run the script code in v2 CKB VM.
42 Data2 = 4,
43 #(
44 #[doc = concat!("Type \"data", stringify!(N), "\" matches script code via cell data hash, and runs the script code in v", stringify!(N), " CKB VM.")]
45 Data~N = N << 1,
46 )*
47 }
48});
49
50impl From<ScriptHashType> for core::ScriptHashType {
51 fn from(json: ScriptHashType) -> Self {
52 seq!(N in 1..=127 {
53 match json {
54 ScriptHashType::Data => core::ScriptHashType::Data,
55 ScriptHashType::Type => core::ScriptHashType::Type,
56 #(
57 ScriptHashType::Data~N => core::ScriptHashType::Data~N,
58 )*
59 }
60 })
61 }
62}
63
64impl From<core::ScriptHashType> for ScriptHashType {
65 fn from(core: core::ScriptHashType) -> ScriptHashType {
66 seq!(N in 1..=127 {
67 match core {
68 core::ScriptHashType::Data => ScriptHashType::Data,
69 core::ScriptHashType::Type => ScriptHashType::Type,
70 #(
71 core::ScriptHashType::Data~N => ScriptHashType::Data~N,
72 )*
73 }
74 })
75 }
76}
77
78impl fmt::Display for ScriptHashType {
79 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
80 seq!(N in 1..=127 {
81 match self {
82 Self::Data => write!(f, "data"),
83 Self::Type => write!(f, "type"),
84 #(
85 Self::Data~N => write!(f, "data{}", N),
86 )*
87 }
88 })
89 }
90}
91
92/// Describes the lock script and type script for a cell.
93///
94/// ## Examples
95///
96/// ```
97/// # serde_json::from_str::<ckb_jsonrpc_types::Script>(r#"
98/// {
99/// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5",
100/// "hash_type": "data",
101/// "args": "0x"
102/// }
103/// # "#).unwrap();
104/// ```
105#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
106#[serde(deny_unknown_fields)]
107pub struct Script {
108 /// The hash used to match the script code.
109 pub code_hash: H256,
110 /// Specifies how to use the `code_hash` to match the script code.
111 pub hash_type: ScriptHashType,
112 /// Arguments for script.
113 pub args: JsonBytes,
114}
115
116impl From<Script> for packed::Script {
117 fn from(json: Script) -> Self {
118 let Script {
119 args,
120 code_hash,
121 hash_type,
122 } = json;
123 let hash_type: core::ScriptHashType = hash_type.into();
124 packed::Script::new_builder()
125 .args(args.into_bytes())
126 .code_hash(code_hash)
127 .hash_type(hash_type)
128 .build()
129 }
130}
131
132impl From<packed::Script> for Script {
133 fn from(input: packed::Script) -> Script {
134 Script {
135 code_hash: input.code_hash().into(),
136 args: JsonBytes::from_vec(input.args().into()),
137 hash_type: core::ScriptHashType::try_from(input.hash_type())
138 .expect("checked data")
139 .into(),
140 }
141 }
142}
143
144/// The fields of an output cell except the cell data.
145///
146/// ## Examples
147///
148/// ```
149/// # serde_json::from_str::<ckb_jsonrpc_types::CellOutput>(r#"
150/// {
151/// "capacity": "0x2540be400",
152/// "lock": {
153/// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5",
154/// "hash_type": "data",
155/// "args": "0x"
156/// },
157/// "type": null
158/// }
159/// # "#).unwrap();
160/// ```
161#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
162#[serde(deny_unknown_fields)]
163pub struct CellOutput {
164 /// The cell capacity.
165 ///
166 /// The capacity of a cell is the value of the cell in Shannons. It is also the upper limit of
167 /// the cell occupied storage size where every 100,000,000 Shannons give 1-byte storage.
168 pub capacity: Capacity,
169 /// The lock script.
170 pub lock: Script,
171 /// The optional type script.
172 ///
173 /// The JSON field name is "type".
174 #[serde(rename = "type")]
175 pub type_: Option<Script>,
176}
177
178impl From<packed::CellOutput> for CellOutput {
179 fn from(input: packed::CellOutput) -> CellOutput {
180 CellOutput {
181 capacity: input.capacity().into(),
182 lock: input.lock().into(),
183 type_: input.type_().to_opt().map(Into::into),
184 }
185 }
186}
187
188impl From<CellOutput> for packed::CellOutput {
189 fn from(json: CellOutput) -> Self {
190 let CellOutput {
191 capacity,
192 lock,
193 type_,
194 } = json;
195 let type_builder = packed::ScriptOpt::new_builder();
196 let type_ = match type_ {
197 Some(type_) => type_builder.set(Some(type_.into())),
198 None => type_builder,
199 }
200 .build();
201 packed::CellOutput::new_builder()
202 .capacity(capacity)
203 .lock(lock)
204 .type_(type_)
205 .build()
206 }
207}
208
209/// Reference to a cell via transaction hash and output index.
210///
211/// ## Examples
212///
213/// ```
214/// # serde_json::from_str::<ckb_jsonrpc_types::OutPoint>(r#"
215/// {
216/// "index": "0x0",
217/// "tx_hash": "0x365698b50ca0da75dca2c87f9e7b563811d3b5813736b8cc62cc3b106faceb17"
218/// }
219/// # "#).unwrap();
220/// ```
221#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
222#[serde(deny_unknown_fields)]
223pub struct OutPoint {
224 /// Transaction hash in which the cell is an output.
225 pub tx_hash: H256,
226 /// The output index of the cell in the transaction specified by `tx_hash`.
227 pub index: Uint32,
228}
229
230impl From<packed::OutPoint> for OutPoint {
231 fn from(input: packed::OutPoint) -> OutPoint {
232 let index: u32 = input.index().into();
233 OutPoint {
234 tx_hash: input.tx_hash().into(),
235 index: index.into(),
236 }
237 }
238}
239
240impl From<OutPoint> for packed::OutPoint {
241 fn from(json: OutPoint) -> Self {
242 let OutPoint { tx_hash, index } = json;
243 let index = index.value();
244 packed::OutPoint::new_builder()
245 .tx_hash(tx_hash)
246 .index(index)
247 .build()
248 }
249}
250
251/// The input cell of a transaction.
252///
253/// ## Examples
254///
255/// ```
256/// # serde_json::from_str::<ckb_jsonrpc_types::CellInput>(r#"
257/// {
258/// "previous_output": {
259/// "index": "0x0",
260/// "tx_hash": "0x365698b50ca0da75dca2c87f9e7b563811d3b5813736b8cc62cc3b106faceb17"
261/// },
262/// "since": "0x0"
263/// }
264/// # "#).unwrap();
265/// ```
266#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
267#[serde(deny_unknown_fields)]
268pub struct CellInput {
269 /// Restrict when the transaction can be committed into the chain.
270 ///
271 /// See the RFC [Transaction valid since](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0017-tx-valid-since/0017-tx-valid-since.md).
272 pub since: Uint64,
273 /// Reference to the input cell.
274 pub previous_output: OutPoint,
275}
276
277impl From<packed::CellInput> for CellInput {
278 fn from(input: packed::CellInput) -> CellInput {
279 CellInput {
280 previous_output: input.previous_output().into(),
281 since: input.since().into(),
282 }
283 }
284}
285
286impl From<CellInput> for packed::CellInput {
287 fn from(json: CellInput) -> Self {
288 let CellInput {
289 previous_output,
290 since,
291 } = json;
292 packed::CellInput::new_builder()
293 .previous_output(previous_output)
294 .since(since)
295 .build()
296 }
297}
298
299/// The dep cell type. Allowed values: "code" and "dep_group".
300#[derive(Default, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
301#[serde(rename_all = "snake_case")]
302pub enum DepType {
303 /// Type "code".
304 ///
305 /// Use the cell itself as the dep cell.
306 #[default]
307 Code,
308 /// Type "dep_group".
309 ///
310 /// The cell is a dep group which members are cells. These members are used as dep cells
311 /// instead of the group itself.
312 ///
313 /// The dep group stores the array of `OutPoint`s serialized via molecule in the cell data.
314 /// Each `OutPoint` points to one cell member.
315 DepGroup,
316}
317
318impl From<DepType> for core::DepType {
319 fn from(json: DepType) -> Self {
320 match json {
321 DepType::Code => core::DepType::Code,
322 DepType::DepGroup => core::DepType::DepGroup,
323 }
324 }
325}
326
327impl From<core::DepType> for DepType {
328 fn from(core: core::DepType) -> DepType {
329 match core {
330 core::DepType::Code => DepType::Code,
331 core::DepType::DepGroup => DepType::DepGroup,
332 }
333 }
334}
335
336/// The cell dependency of a transaction.
337///
338/// ## Examples
339///
340/// ```
341/// # serde_json::from_str::<ckb_jsonrpc_types::CellDep>(r#"
342/// {
343/// "dep_type": "code",
344/// "out_point": {
345/// "index": "0x0",
346/// "tx_hash": "0xa4037a893eb48e18ed4ef61034ce26eba9c585f15c9cee102ae58505565eccc3"
347/// }
348/// }
349/// # "#).unwrap();
350/// ```
351#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
352#[serde(deny_unknown_fields)]
353pub struct CellDep {
354 /// Reference to the cell.
355 pub out_point: OutPoint,
356 /// Dependency type.
357 pub dep_type: DepType,
358}
359
360impl From<packed::CellDep> for CellDep {
361 fn from(input: packed::CellDep) -> Self {
362 CellDep {
363 out_point: input.out_point().into(),
364 dep_type: core::DepType::try_from(input.dep_type())
365 .expect("checked data")
366 .into(),
367 }
368 }
369}
370
371impl From<CellDep> for packed::CellDep {
372 fn from(json: CellDep) -> Self {
373 let CellDep {
374 out_point,
375 dep_type,
376 } = json;
377 let dep_type: core::DepType = dep_type.into();
378 packed::CellDep::new_builder()
379 .out_point(out_point)
380 .dep_type(dep_type)
381 .build()
382 }
383}
384
385/// The transaction.
386///
387/// Refer to RFC [CKB Transaction Structure](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md).
388#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
389#[serde(deny_unknown_fields)]
390pub struct Transaction {
391 /// Reserved for future usage. It must equal 0 in current version.
392 pub version: Version,
393 /// An array of cell deps.
394 ///
395 /// CKB locates lock script and type script code via cell deps. The script also can use syscalls
396 /// to read the cells here.
397 ///
398 /// Unlike inputs, the live cells can be used as cell deps in multiple transactions.
399 pub cell_deps: Vec<CellDep>,
400 /// An array of header deps.
401 ///
402 /// The block must already be in the canonical chain.
403 ///
404 /// Lock script and type script can read the header information of blocks listed here.
405 pub header_deps: Vec<H256>,
406 /// An array of input cells.
407 ///
408 /// In the canonical chain, any cell can only appear as an input once.
409 pub inputs: Vec<CellInput>,
410 /// An array of output cells.
411 pub outputs: Vec<CellOutput>,
412 /// Output cells data.
413 ///
414 /// This is a parallel array of outputs. The cell capacity, lock, and type of the output i is
415 /// `outputs[i]` and its data is `outputs_data[i]`.
416 pub outputs_data: Vec<JsonBytes>,
417 /// An array of variable-length binaries.
418 ///
419 /// Lock script and type script can read data here to verify the transaction.
420 ///
421 /// For example, the bundled secp256k1 lock script requires storing the signature in
422 /// `witnesses`.
423 pub witnesses: Vec<JsonBytes>,
424}
425
426/// The JSON view of a Transaction.
427///
428/// This structure is serialized into a JSON object with field `hash` and all the fields in
429/// [`Transaction`](struct.Transaction.html).
430///
431/// ## Examples
432///
433/// ```
434/// # serde_json::from_str::<ckb_jsonrpc_types::TransactionView>(r#"
435/// {
436/// "cell_deps": [
437/// {
438/// "dep_type": "code",
439/// "out_point": {
440/// "index": "0x0",
441/// "tx_hash": "0xa4037a893eb48e18ed4ef61034ce26eba9c585f15c9cee102ae58505565eccc3"
442/// }
443/// }
444/// ],
445/// "hash": "0xa0ef4eb5f4ceeb08a4c8524d84c5da95dce2f608e0ca2ec8091191b0f330c6e3",
446/// "header_deps": [
447/// "0x7978ec7ce5b507cfb52e149e36b1a23f6062ed150503c85bbf825da3599095ed"
448/// ],
449/// "inputs": [
450/// {
451/// "previous_output": {
452/// "index": "0x0",
453/// "tx_hash": "0x365698b50ca0da75dca2c87f9e7b563811d3b5813736b8cc62cc3b106faceb17"
454/// },
455/// "since": "0x0"
456/// }
457/// ],
458/// "outputs": [
459/// {
460/// "capacity": "0x2540be400",
461/// "lock": {
462/// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5",
463/// "hash_type": "data",
464/// "args": "0x"
465/// },
466/// "type": null
467/// }
468/// ],
469/// "outputs_data": [
470/// "0x"
471/// ],
472/// "version": "0x0",
473/// "witnesses": []
474/// }
475/// # "#).unwrap();
476/// ```
477#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
478pub struct TransactionView {
479 /// All the fields in `Transaction` are included in `TransactionView` in JSON.
480 #[serde(flatten)]
481 pub inner: Transaction,
482 /// The transaction hash.
483 pub hash: H256,
484}
485
486impl From<packed::Transaction> for Transaction {
487 fn from(input: packed::Transaction) -> Self {
488 let raw = input.raw();
489 Self {
490 version: raw.version().into(),
491 cell_deps: raw.cell_deps().into_iter().map(Into::into).collect(),
492 header_deps: raw
493 .header_deps()
494 .into_iter()
495 .map(|d| Into::<H256>::into(&d))
496 .collect(),
497 inputs: raw.inputs().into_iter().map(Into::into).collect(),
498 outputs: raw.outputs().into_iter().map(Into::into).collect(),
499 outputs_data: raw.outputs_data().into_iter().map(Into::into).collect(),
500 witnesses: input.witnesses().into_iter().map(Into::into).collect(),
501 }
502 }
503}
504
505impl From<core::TransactionView> for TransactionView {
506 fn from(input: core::TransactionView) -> Self {
507 Self {
508 inner: input.data().into(),
509 hash: input.hash().into(),
510 }
511 }
512}
513
514impl From<Transaction> for packed::Transaction {
515 fn from(json: Transaction) -> Self {
516 let Transaction {
517 version,
518 cell_deps,
519 header_deps,
520 inputs,
521 outputs,
522 witnesses,
523 outputs_data,
524 } = json;
525 let raw = packed::RawTransaction::new_builder()
526 .version(version)
527 .cell_deps(
528 cell_deps
529 .into_iter()
530 .map(Into::into)
531 .collect::<Vec<packed::CellDep>>(),
532 )
533 .header_deps(
534 header_deps
535 .iter()
536 .map(Into::into)
537 .collect::<Vec<packed::Byte32>>(),
538 )
539 .inputs(
540 inputs
541 .into_iter()
542 .map(Into::into)
543 .collect::<Vec<packed::CellInput>>(),
544 )
545 .outputs(
546 outputs
547 .into_iter()
548 .map(Into::into)
549 .collect::<Vec<packed::CellOutput>>(),
550 )
551 .outputs_data(
552 outputs_data
553 .into_iter()
554 .map(Into::into)
555 .collect::<Vec<packed::Bytes>>(),
556 )
557 .build();
558 packed::Transaction::new_builder()
559 .raw(raw)
560 .witnesses(
561 witnesses
562 .into_iter()
563 .map(Into::into)
564 .collect::<Vec<packed::Bytes>>(),
565 )
566 .build()
567 }
568}
569
570/// The JSON view of a transaction as well as its status.
571#[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
572pub struct TransactionWithStatusResponse {
573 /// The transaction.
574 pub transaction: Option<ResponseFormat<TransactionView>>,
575 /// The transaction consumed cycles.
576 pub cycles: Option<Cycle>,
577 /// If the transaction is in tx-pool, `time_added_to_pool` represent when it enters the tx-pool. unit: Millisecond
578 pub time_added_to_pool: Option<Uint64>,
579 /// The Transaction status.
580 pub tx_status: TxStatus,
581 /// The transaction fee of the transaction
582 pub fee: Option<Capacity>,
583 /// The minimal fee required to replace this transaction
584 pub min_replace_fee: Option<Capacity>,
585}
586
587impl TransactionWithStatusResponse {
588 /// Transpose `tx_pool::TransactionWithStatus` to `TransactionWithStatusResponse`
589 /// according to the type of inner_type
590 pub fn from(t: tx_pool::TransactionWithStatus, inner_type: ResponseFormatInnerType) -> Self {
591 match inner_type {
592 ResponseFormatInnerType::Hex => TransactionWithStatusResponse {
593 transaction: t
594 .transaction
595 .map(|tx| ResponseFormat::hex(tx.data().as_bytes())),
596 tx_status: t.tx_status.into(),
597 cycles: t.cycles.map(Into::into),
598 time_added_to_pool: t.time_added_to_pool.map(Into::into),
599 fee: t.fee.map(Into::into),
600 min_replace_fee: t.min_replace_fee.map(Into::into),
601 },
602 ResponseFormatInnerType::Json => TransactionWithStatusResponse {
603 transaction: t
604 .transaction
605 .map(|tx| ResponseFormat::json(TransactionView::from(tx))),
606 tx_status: t.tx_status.into(),
607 cycles: t.cycles.map(Into::into),
608 time_added_to_pool: t.time_added_to_pool.map(Into::into),
609 fee: t.fee.map(Into::into),
610 min_replace_fee: t.min_replace_fee.map(Into::into),
611 },
612 }
613 }
614}
615
616/// Status for transaction
617#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
618#[serde(rename_all = "lowercase")]
619pub enum Status {
620 /// Status "pending". The transaction is in the pool, and not proposed yet.
621 Pending,
622 /// Status "proposed". The transaction is in the pool and has been proposed.
623 Proposed,
624 /// Status "committed". The transaction has been committed to the canonical chain.
625 Committed,
626 /// Status "unknown". The node has not seen the transaction,
627 /// or it should be rejected but was cleared due to storage limitations.
628 Unknown,
629 /// Status "rejected". The transaction has been recently removed from the pool.
630 /// Due to storage limitations, the node can only hold the most recently removed transactions.
631 Rejected,
632}
633
634/// Transaction status and the block hash if it is committed.
635#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
636pub struct TxStatus {
637 /// The transaction status, allowed values: "pending", "proposed" "committed" "unknown" and "rejected".
638 pub status: Status,
639 /// The block number of the block which has committed this transaction in the canonical chain.
640 pub block_number: Option<BlockNumber>,
641 /// The block hash of the block which has committed this transaction in the canonical chain.
642 pub block_hash: Option<H256>,
643 /// The transaction index in the block.
644 pub tx_index: Option<Uint32>,
645 /// The reason why the transaction is rejected
646 pub reason: Option<String>,
647}
648
649impl From<tx_pool::TxStatus> for TxStatus {
650 fn from(tx_pool_status: core::tx_pool::TxStatus) -> Self {
651 match tx_pool_status {
652 tx_pool::TxStatus::Pending => TxStatus::pending(),
653 tx_pool::TxStatus::Proposed => TxStatus::proposed(),
654 tx_pool::TxStatus::Committed(number, hash, tx_index) => {
655 TxStatus::committed(number.into(), hash, tx_index.into())
656 }
657 tx_pool::TxStatus::Rejected(reason) => TxStatus::rejected(reason),
658 tx_pool::TxStatus::Unknown => TxStatus::unknown(),
659 }
660 }
661}
662
663impl TxStatus {
664 /// Pending transaction which is in the memory pool and must be proposed first.
665 pub fn pending() -> Self {
666 Self {
667 status: Status::Pending,
668 block_number: None,
669 block_hash: None,
670 tx_index: None,
671 reason: None,
672 }
673 }
674
675 /// Transaction which has been proposed but not committed yet.
676 pub fn proposed() -> Self {
677 Self {
678 status: Status::Proposed,
679 block_number: None,
680 block_hash: None,
681 tx_index: None,
682 reason: None,
683 }
684 }
685
686 /// Transaction which has already been committed.
687 ///
688 /// ## Params
689 ///
690 /// * `hash` - the block hash in which the transaction is committed.
691 pub fn committed(number: BlockNumber, hash: H256, tx_index: Uint32) -> Self {
692 Self {
693 status: Status::Committed,
694 block_number: Some(number),
695 block_hash: Some(hash),
696 tx_index: Some(tx_index),
697 reason: None,
698 }
699 }
700
701 /// Transaction which has already been rejected recently.
702 ///
703 /// ## Params
704 ///
705 /// * `reason` - the reason why the transaction is rejected.
706 pub fn rejected(reason: String) -> Self {
707 Self {
708 status: Status::Rejected,
709 block_number: None,
710 block_hash: None,
711 tx_index: None,
712 reason: Some(reason),
713 }
714 }
715
716 /// The node has not seen the transaction,
717 pub fn unknown() -> Self {
718 Self {
719 status: Status::Unknown,
720 block_number: None,
721 block_hash: None,
722 tx_index: None,
723 reason: None,
724 }
725 }
726
727 /// Returns true if the status is Unknown.
728 pub fn is_unknown(&self) -> bool {
729 matches!(self.status, Status::Unknown)
730 }
731}
732
733/// The block header.
734///
735/// Refer to RFC [CKB Block Structure](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0027-block-structure/0027-block-structure.md).
736#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
737#[serde(deny_unknown_fields)]
738pub struct Header {
739 /// The block version.
740 ///
741 /// It must equal to 0 now and is reserved for future upgrades.
742 pub version: Version,
743 /// The block difficulty target.
744 ///
745 /// It can be converted to a 256-bit target. Miners must ensure the Eaglesong of the header is
746 /// within the target.
747 pub compact_target: Uint32,
748 /// The block timestamp.
749 ///
750 /// It is a Unix timestamp in milliseconds (1 second = 1000 milliseconds).
751 ///
752 /// Miners should put the time when the block is created in the header, however, the precision
753 /// is not guaranteed. A block with a higher block number may even have a smaller timestamp.
754 pub timestamp: Timestamp,
755 /// The consecutive block number starting from 0.
756 pub number: BlockNumber,
757 /// The epoch information of this block.
758 ///
759 /// See `EpochNumberWithFraction` for details.
760 pub epoch: EpochNumberWithFraction,
761 /// The header hash of the parent block.
762 pub parent_hash: H256,
763 /// The commitment to all the transactions in the block.
764 ///
765 /// It is a hash on two Merkle Tree roots:
766 ///
767 /// * The root of a CKB Merkle Tree, which items are the transaction hashes of all the transactions in the block.
768 /// * The root of a CKB Merkle Tree, but the items are the transaction witness hashes of all the transactions in the block.
769 pub transactions_root: H256,
770 /// The hash on `proposals` in the block body.
771 ///
772 /// It is all zeros when `proposals` is empty, or the hash on all the bytes concatenated together.
773 pub proposals_hash: H256,
774 /// The hash on `uncles` and extension in the block body.
775 ///
776 /// The uncles hash is all zeros when `uncles` is empty, or the hash on all the uncle header hashes concatenated together.
777 /// The extension hash is the hash of the extension.
778 /// The extra hash is the hash on uncles hash and extension hash concatenated together.
779 ///
780 /// **Notice**
781 ///
782 /// This field is renamed from `uncles_hash` since 0.100.0.
783 /// More details can be found in [CKB RFC 0031].
784 ///
785 /// [CKB RFC 0031]: https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0031-variable-length-header-field/0031-variable-length-header-field.md
786 pub extra_hash: H256,
787 /// DAO fields.
788 ///
789 /// See RFC [Deposit and Withdraw in Nervos DAO](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md#calculation).
790 pub dao: Byte32,
791 /// Miner can modify this field to find a proper value such that the Eaglesong of the header is
792 /// within the target encoded from `compact_target`.
793 pub nonce: Uint128,
794}
795
796/// The JSON view of a Header.
797///
798/// This structure is serialized into a JSON object with field `hash` and all the fields in
799/// [`Header`](struct.Header.html).
800///
801/// ## Examples
802///
803/// ```
804/// # serde_json::from_str::<ckb_jsonrpc_types::HeaderView>(r#"
805/// {
806/// "compact_target": "0x1e083126",
807/// "dao": "0xb5a3e047474401001bc476b9ee573000c0c387962a38000000febffacf030000",
808/// "epoch": "0x7080018000001",
809/// "hash": "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40",
810/// "nonce": "0x0",
811/// "number": "0x400",
812/// "parent_hash": "0xae003585fa15309b30b31aed3dcf385e9472c3c3e93746a6c4540629a6a1ed2d",
813/// "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
814/// "timestamp": "0x5cd2b117",
815/// "transactions_root": "0xc47d5b78b3c4c4c853e2a32810818940d0ee403423bea9ec7b8e566d9595206c",
816/// "extra_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
817/// "version": "0x0"
818/// }
819/// # "#).unwrap();
820/// ```
821#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
822pub struct HeaderView {
823 /// All the fields in `Header` are included in `HeaderView` in JSON.
824 #[serde(flatten)]
825 pub inner: Header,
826 /// The header hash. It is also called the block hash.
827 pub hash: H256,
828}
829
830impl From<packed::Header> for Header {
831 fn from(input: packed::Header) -> Self {
832 let raw = input.raw();
833 Self {
834 version: raw.version().into(),
835 parent_hash: raw.parent_hash().into(),
836 timestamp: raw.timestamp().into(),
837 number: raw.number().into(),
838 epoch: raw.epoch().into(),
839 transactions_root: raw.transactions_root().into(),
840 proposals_hash: raw.proposals_hash().into(),
841 compact_target: raw.compact_target().into(),
842 extra_hash: raw.extra_hash().into(),
843 dao: raw.dao().into(),
844 nonce: input.nonce().into(),
845 }
846 }
847}
848
849impl From<core::HeaderView> for HeaderView {
850 fn from(input: core::HeaderView) -> Self {
851 Self {
852 inner: input.data().into(),
853 hash: input.hash().into(),
854 }
855 }
856}
857
858impl From<HeaderView> for core::HeaderView {
859 fn from(input: HeaderView) -> Self {
860 let header: packed::Header = input.inner.into();
861 header.into_view()
862 }
863}
864
865impl From<Header> for packed::Header {
866 fn from(json: Header) -> Self {
867 let Header {
868 version,
869 parent_hash,
870 timestamp,
871 number,
872 epoch,
873 transactions_root,
874 proposals_hash,
875 compact_target,
876 extra_hash,
877 dao,
878 nonce,
879 } = json;
880 let raw = packed::RawHeader::new_builder()
881 .version(version)
882 .parent_hash(parent_hash)
883 .timestamp(timestamp)
884 .number(number)
885 .epoch(epoch)
886 .transactions_root(transactions_root)
887 .proposals_hash(proposals_hash)
888 .compact_target(compact_target)
889 .extra_hash(extra_hash)
890 .dao(dao)
891 .build();
892 packed::Header::new_builder().raw(raw).nonce(nonce).build()
893 }
894}
895
896/// The uncle block used as a parameter in the RPC.
897///
898/// The chain stores only the uncle block header and proposal IDs. The header ensures the block is
899/// covered by PoW and can pass the consensus rules on uncle blocks. Proposal IDs are there because
900/// a block can commit transactions proposed in an uncle.
901///
902/// A block B1 is considered to be the uncle of another block B2 if all the following conditions are met:
903///
904/// 1. They are in the same epoch, sharing the same difficulty;
905/// 2. B2 block number is larger than B1;
906/// 3. B1's parent is either B2's ancestor or an uncle embedded in B2 or any of B2's ancestors.
907/// 4. B2 is the first block in its chain to refer to B1.
908#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
909#[serde(deny_unknown_fields)]
910pub struct UncleBlock {
911 /// The uncle block header.
912 pub header: Header,
913 /// Proposal IDs in the uncle block body.
914 pub proposals: Vec<ProposalShortId>,
915}
916
917/// The uncle block.
918///
919/// The chain stores only the uncle block header and proposal IDs. The header ensures the block is
920/// covered by PoW and can pass the consensus rules on uncle blocks. Proposal IDs are there because
921/// a block can commit transactions proposed in an uncle.
922///
923/// A block B1 is considered to be the uncle of another block B2 if all the following conditions are met:
924///
925/// 1. They are in the same epoch, sharing the same difficulty;
926/// 2. B2 block number is larger than B1;
927/// 3. B1's parent is either B2's ancestor or an uncle embedded in B2 or any of B2's ancestors.
928/// 4. B2 is the first block in its chain to refer to B1.
929#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
930pub struct UncleBlockView {
931 /// The uncle block header.
932 pub header: HeaderView,
933 /// Proposal IDs in the uncle block body.
934 pub proposals: Vec<ProposalShortId>,
935}
936
937impl From<packed::UncleBlock> for UncleBlock {
938 fn from(input: packed::UncleBlock) -> Self {
939 Self {
940 header: input.header().into(),
941 proposals: input.proposals().into_iter().map(Into::into).collect(),
942 }
943 }
944}
945
946impl From<core::UncleBlockView> for UncleBlockView {
947 fn from(input: core::UncleBlockView) -> Self {
948 let header = HeaderView {
949 inner: input.data().header().into(),
950 hash: input.hash().into(),
951 };
952 Self {
953 header,
954 proposals: input
955 .data()
956 .proposals()
957 .into_iter()
958 .map(Into::into)
959 .collect(),
960 }
961 }
962}
963
964impl From<UncleBlock> for packed::UncleBlock {
965 fn from(json: UncleBlock) -> Self {
966 let UncleBlock { header, proposals } = json;
967 packed::UncleBlock::new_builder()
968 .header(header)
969 .proposals(
970 proposals
971 .into_iter()
972 .map(Into::into)
973 .collect::<Vec<packed::ProposalShortId>>(),
974 )
975 .build()
976 }
977}
978
979/// The JSON view of a Block used as a parameter in the RPC.
980#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
981#[serde(deny_unknown_fields)]
982pub struct Block {
983 /// The block header.
984 pub header: Header,
985 /// The uncles blocks in the block body.
986 pub uncles: Vec<UncleBlock>,
987 /// The transactions in the block body.
988 pub transactions: Vec<Transaction>,
989 /// The proposal IDs in the block body.
990 pub proposals: Vec<ProposalShortId>,
991 /// The extension in the block body.
992 ///
993 /// This is a field introduced in [CKB RFC 0031]. Since the activation of [CKB RFC 0044], this
994 /// field is at least 32 bytes, and at most 96 bytes. The consensus rule of first 32 bytes is
995 /// defined in the RFC 0044.
996 ///
997 /// [CKB RFC 0031]: https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0031-variable-length-header-field/0031-variable-length-header-field.md
998 /// [CKB RFC 0044]: https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0044-ckb-light-client/0044-ckb-light-client.md
999 #[serde(default, skip_serializing_if = "Option::is_none")]
1000 pub extension: Option<JsonBytes>,
1001}
1002
1003/// The wrapper represent response of `get_block` | `get_block_by_number`, return a Block with cycles.
1004#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
1005#[serde(untagged)]
1006pub enum BlockResponse {
1007 /// The block response regular format
1008 ///
1009 /// [`BlockView`] | [\`SerializedBlock\`](#type-serializedblock) - The block structure
1010 Regular(ResponseFormat<BlockView>),
1011 /// The block with cycles response format
1012 ///
1013 /// A JSON object with the following fields:
1014 /// * `block`: [`BlockView`] | [\`SerializedBlock\`](#type-serializedblock) - The block structure
1015 /// * `cycles`: `Array<` [`Cycle`](#type-cycle) `>` `|` `null` - The block transactions consumed cycles.
1016 WithCycles(BlockWithCyclesResponse),
1017}
1018
1019impl BlockResponse {
1020 /// Wrap regular block response
1021 pub fn regular(block: ResponseFormat<BlockView>) -> Self {
1022 BlockResponse::Regular(block)
1023 }
1024
1025 /// Wrap with cycles block response
1026 pub fn with_cycles(block: ResponseFormat<BlockView>, cycles: Option<Vec<Cycle>>) -> Self {
1027 BlockResponse::WithCycles(BlockWithCyclesResponse { block, cycles })
1028 }
1029}
1030
1031/// BlockResponse with cycles format wrapper
1032#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
1033pub struct BlockWithCyclesResponse {
1034 /// The block structure
1035 pub block: ResponseFormat<BlockView>,
1036 /// The block transactions consumed cycles.
1037 #[serde(default)]
1038 pub cycles: Option<Vec<Cycle>>,
1039}
1040
1041/// The JSON view of a Block including header and body.
1042#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
1043pub struct BlockView {
1044 /// The block header.
1045 pub header: HeaderView,
1046 /// The uncles blocks in the block body.
1047 pub uncles: Vec<UncleBlockView>,
1048 /// The transactions in the block body.
1049 pub transactions: Vec<TransactionView>,
1050 /// The proposal IDs in the block body.
1051 pub proposals: Vec<ProposalShortId>,
1052 /// The extension in the block body.
1053 ///
1054 /// This is a field introduced in [CKB RFC 0031]. Since the activation of [CKB RFC 0044], this
1055 /// field is at least 32 bytes, and at most 96 bytes. The consensus rule of first 32 bytes is
1056 /// defined in the RFC 0044.
1057 ///
1058 /// [CKB RFC 0031]: https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0031-variable-length-header-field/0031-variable-length-header-field.md
1059 /// [CKB RFC 0044]: https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0044-ckb-light-client/0044-ckb-light-client.md
1060 #[serde(default, skip_serializing_if = "Option::is_none")]
1061 pub extension: Option<JsonBytes>,
1062}
1063
1064impl From<packed::Block> for Block {
1065 fn from(input: packed::Block) -> Self {
1066 Self {
1067 header: input.header().into(),
1068 uncles: input.uncles().into_iter().map(Into::into).collect(),
1069 transactions: input.transactions().into_iter().map(Into::into).collect(),
1070 proposals: input.proposals().into_iter().map(Into::into).collect(),
1071 extension: input.extension().map(Into::into),
1072 }
1073 }
1074}
1075
1076impl From<core::BlockView> for BlockView {
1077 fn from(input: core::BlockView) -> Self {
1078 let block = input.data();
1079 let header = HeaderView {
1080 inner: block.header().into(),
1081 hash: input.hash().into(),
1082 };
1083 let uncles = block
1084 .uncles()
1085 .into_iter()
1086 .zip(input.uncle_hashes())
1087 .map(|(uncle, hash)| {
1088 let header = HeaderView {
1089 inner: uncle.header().into(),
1090 hash: hash.into(),
1091 };
1092 UncleBlockView {
1093 header,
1094 proposals: uncle.proposals().into_iter().map(Into::into).collect(),
1095 }
1096 })
1097 .collect();
1098 let transactions = block
1099 .transactions()
1100 .into_iter()
1101 .zip(input.tx_hashes().iter())
1102 .map(|(tx, hash)| TransactionView {
1103 inner: tx.into(),
1104 hash: hash.into(),
1105 })
1106 .collect();
1107 Self {
1108 header,
1109 uncles,
1110 transactions,
1111 proposals: block.proposals().into_iter().map(Into::into).collect(),
1112 extension: block.extension().map(Into::into),
1113 }
1114 }
1115}
1116
1117impl From<Block> for packed::Block {
1118 fn from(json: Block) -> Self {
1119 let Block {
1120 header,
1121 uncles,
1122 transactions,
1123 proposals,
1124 extension,
1125 } = json;
1126 if let Some(extension) = extension {
1127 let extension: packed::Bytes = extension.into();
1128 packed::BlockV1::new_builder()
1129 .header(header)
1130 .uncles(
1131 uncles
1132 .into_iter()
1133 .map(Into::into)
1134 .collect::<Vec<packed::UncleBlock>>(),
1135 )
1136 .transactions(
1137 transactions
1138 .into_iter()
1139 .map(Into::into)
1140 .collect::<Vec<packed::Transaction>>(),
1141 )
1142 .proposals(
1143 proposals
1144 .into_iter()
1145 .map(Into::into)
1146 .collect::<Vec<packed::ProposalShortId>>(),
1147 )
1148 .extension(extension)
1149 .build()
1150 .as_v0()
1151 } else {
1152 packed::Block::new_builder()
1153 .header(header)
1154 .uncles(
1155 uncles
1156 .into_iter()
1157 .map(Into::into)
1158 .collect::<Vec<packed::UncleBlock>>(),
1159 )
1160 .transactions(
1161 transactions
1162 .into_iter()
1163 .map(Into::into)
1164 .collect::<Vec<packed::Transaction>>(),
1165 )
1166 .proposals(
1167 proposals
1168 .into_iter()
1169 .map(Into::into)
1170 .collect::<Vec<packed::ProposalShortId>>(),
1171 )
1172 .build()
1173 }
1174 }
1175}
1176
1177impl From<BlockView> for core::BlockView {
1178 fn from(input: BlockView) -> Self {
1179 let BlockView {
1180 header,
1181 uncles,
1182 transactions,
1183 proposals,
1184 extension,
1185 } = input;
1186 let block = Block {
1187 header: header.inner,
1188 uncles: uncles
1189 .into_iter()
1190 .map(|u| {
1191 let UncleBlockView { header, proposals } = u;
1192 UncleBlock {
1193 header: header.inner,
1194 proposals,
1195 }
1196 })
1197 .collect(),
1198 transactions: transactions.into_iter().map(|tx| tx.inner).collect(),
1199 proposals,
1200 extension,
1201 };
1202 let block: packed::Block = block.into();
1203 block.into_view()
1204 }
1205}
1206
1207/// JSON view of an epoch.
1208///
1209/// CKB adjusts difficulty based on epochs.
1210///
1211/// ## Examples
1212///
1213/// ```
1214/// # serde_json::from_str::<ckb_jsonrpc_types::EpochView>(r#"
1215/// {
1216/// "compact_target": "0x1e083126",
1217/// "length": "0x708",
1218/// "number": "0x1",
1219/// "start_number": "0x3e8"
1220/// }
1221/// # "#).unwrap();
1222/// ```
1223#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
1224pub struct EpochView {
1225 /// Consecutive epoch number starting from 0.
1226 pub number: EpochNumber,
1227 /// The block number of the first block in the epoch.
1228 ///
1229 /// It also equals the total count of blocks in all the epochs which epoch number is
1230 /// less than this epoch.
1231 pub start_number: BlockNumber,
1232 /// The number of blocks in this epoch.
1233 pub length: BlockNumber,
1234 /// The difficulty target for any block in this epoch.
1235 pub compact_target: Uint32,
1236}
1237
1238impl EpochView {
1239 /// Creates the view from the stored ext.
1240 pub fn from_ext(ext: packed::EpochExt) -> EpochView {
1241 EpochView {
1242 number: ext.number().into(),
1243 start_number: ext.start_number().into(),
1244 length: ext.length().into(),
1245 compact_target: ext.compact_target().into(),
1246 }
1247 }
1248}
1249
1250/// Block base rewards.
1251#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
1252pub struct BlockIssuance {
1253 /// The primary base rewards.
1254 pub primary: Capacity,
1255 /// The secondary base rewards.
1256 pub secondary: Capacity,
1257}
1258
1259impl From<core::BlockIssuance> for BlockIssuance {
1260 fn from(core: core::BlockIssuance) -> Self {
1261 Self {
1262 primary: core.primary.into(),
1263 secondary: core.secondary.into(),
1264 }
1265 }
1266}
1267
1268impl From<BlockIssuance> for core::BlockIssuance {
1269 fn from(json: BlockIssuance) -> Self {
1270 Self {
1271 primary: json.primary.into(),
1272 secondary: json.secondary.into(),
1273 }
1274 }
1275}
1276
1277/// Block rewards for miners.
1278#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
1279pub struct MinerReward {
1280 /// The primary base block reward allocated to miners.
1281 pub primary: Capacity,
1282 /// The secondary base block reward allocated to miners.
1283 pub secondary: Capacity,
1284 /// The transaction fees that are rewarded to miners because the transaction is committed in the block.
1285 ///
1286 /// Miners get 60% of the transaction fee for each transaction committed in the block.
1287 pub committed: Capacity,
1288 /// The transaction fees that are rewarded to miners because the transaction is proposed in the block or
1289 /// its uncles.
1290 ///
1291 /// Miners get 40% of the transaction fee for each transaction proposed in the block and
1292 /// committed later in its active commit window.
1293 pub proposal: Capacity,
1294}
1295
1296impl From<core::MinerReward> for MinerReward {
1297 fn from(core: core::MinerReward) -> Self {
1298 Self {
1299 primary: core.primary.into(),
1300 secondary: core.secondary.into(),
1301 committed: core.committed.into(),
1302 proposal: core.proposal.into(),
1303 }
1304 }
1305}
1306
1307impl From<MinerReward> for core::MinerReward {
1308 fn from(json: MinerReward) -> Self {
1309 Self {
1310 primary: json.primary.into(),
1311 secondary: json.secondary.into(),
1312 committed: json.committed.into(),
1313 proposal: json.proposal.into(),
1314 }
1315 }
1316}
1317
1318/// Block Economic State.
1319///
1320/// It includes the rewards details and when it is finalized.
1321#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
1322pub struct BlockEconomicState {
1323 /// Block base rewards.
1324 pub issuance: BlockIssuance,
1325 /// Block rewards for miners.
1326 pub miner_reward: MinerReward,
1327 /// The total fees of all transactions committed in the block.
1328 pub txs_fee: Capacity,
1329 /// The block hash of the block which creates the rewards as cells in its cellbase transaction.
1330 pub finalized_at: H256,
1331}
1332
1333impl From<core::BlockEconomicState> for BlockEconomicState {
1334 fn from(core: core::BlockEconomicState) -> Self {
1335 Self {
1336 issuance: core.issuance.into(),
1337 miner_reward: core.miner_reward.into(),
1338 txs_fee: core.txs_fee.into(),
1339 finalized_at: core.finalized_at.into(),
1340 }
1341 }
1342}
1343
1344impl From<BlockEconomicState> for core::BlockEconomicState {
1345 fn from(json: BlockEconomicState) -> Self {
1346 Self {
1347 issuance: json.issuance.into(),
1348 miner_reward: json.miner_reward.into(),
1349 txs_fee: json.txs_fee.into(),
1350 finalized_at: json.finalized_at.into(),
1351 }
1352 }
1353}
1354
1355/// Merkle proof for transactions in a block.
1356#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
1357pub struct TransactionProof {
1358 /// Block hash
1359 pub block_hash: H256,
1360 /// Merkle root of all transactions' witness hash
1361 pub witnesses_root: H256,
1362 /// Merkle proof of all transactions' hash
1363 pub proof: MerkleProof,
1364}
1365
1366/// Merkle proof for transactions' witnesses in a block.
1367#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
1368pub struct TransactionAndWitnessProof {
1369 /// Block hash
1370 pub block_hash: H256,
1371 /// Merkle proof of all transactions' hash
1372 pub transactions_proof: MerkleProof,
1373 /// Merkle proof of transactions' witnesses
1374 pub witnesses_proof: MerkleProof,
1375}
1376
1377/// Proof of CKB Merkle Tree.
1378///
1379/// CKB Merkle Tree is a [CBMT](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0006-merkle-tree/0006-merkle-tree.md) using CKB blake2b hash as the merge function.
1380#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
1381pub struct MerkleProof {
1382 /// Leaves indices in the CBMT that are proved present in the block.
1383 ///
1384 /// These are indices in the CBMT tree not the transaction indices in the block.
1385 pub indices: Vec<Uint32>,
1386 /// Hashes of all siblings along the paths to root.
1387 pub lemmas: Vec<H256>,
1388}
1389
1390impl From<RawMerkleProof> for MerkleProof {
1391 fn from(proof: RawMerkleProof) -> Self {
1392 MerkleProof {
1393 indices: proof
1394 .indices()
1395 .iter()
1396 .map(|index| (*index).into())
1397 .collect(),
1398 lemmas: proof.lemmas().iter().map(Unpack::<H256>::unpack).collect(),
1399 }
1400 }
1401}
1402
1403/// Block filter data and hash.
1404#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
1405pub struct BlockFilter {
1406 /// The hex-encoded filter data of the block
1407 pub data: JsonBytes,
1408 /// The filter hash, blake2b hash of the parent block filter hash and the filter data, blake2b(parent_block_filter_hash | current_block_filter_data)
1409 pub hash: Byte32,
1410}
1411
1412/// Two protocol parameters `closest` and `farthest` define the closest
1413/// and farthest on-chain distance between a transaction's proposal
1414/// and commitment.
1415///
1416/// A non-cellbase transaction is committed at height h_c if all of the following conditions are met:
1417/// 1) it is proposed at height h_p of the same chain, where w_close <= h_c − h_p <= w_far ;
1418/// 2) it is in the commitment zone of the main chain block with height h_c ;
1419///
1420/// ```text
1421/// ProposalWindow { closest: 2, farthest: 10 }
1422/// propose
1423/// \
1424/// \
1425/// 13 14 [15 16 17 18 19 20 21 22 23]
1426/// \_______________________/
1427/// \
1428/// commit
1429/// ```
1430#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug, JsonSchema)]
1431pub struct ProposalWindow {
1432 /// The closest distance between the proposal and the commitment.
1433 pub closest: BlockNumber,
1434 /// The farthest distance between the proposal and the commitment.
1435 pub farthest: BlockNumber,
1436}
1437
1438/// Consensus defines various parameters that influence chain consensus
1439#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
1440pub struct Consensus {
1441 /// Names the network.
1442 pub id: String,
1443 /// The genesis block hash
1444 pub genesis_hash: H256,
1445 /// The dao type hash
1446 pub dao_type_hash: H256,
1447 /// The secp256k1_blake160_sighash_all_type_hash
1448 pub secp256k1_blake160_sighash_all_type_hash: Option<H256>,
1449 /// The secp256k1_blake160_multisig_all_type_hash
1450 pub secp256k1_blake160_multisig_all_type_hash: Option<H256>,
1451 /// The initial primary_epoch_reward
1452 pub initial_primary_epoch_reward: Capacity,
1453 /// The secondary primary_epoch_reward
1454 pub secondary_epoch_reward: Capacity,
1455 /// The maximum amount of uncles allowed for a block
1456 pub max_uncles_num: Uint64,
1457 /// The expected orphan_rate
1458 #[schemars(schema_with = "crate::json_schema::rational_u256")]
1459 pub orphan_rate_target: core::RationalU256,
1460 /// The expected epoch_duration
1461 pub epoch_duration_target: Uint64,
1462 /// The two-step-transaction-confirmation proposal window
1463 pub tx_proposal_window: ProposalWindow,
1464 /// The two-step-transaction-confirmation proposer reward ratio
1465 #[schemars(schema_with = "crate::json_schema::rational_u256")]
1466 pub proposer_reward_ratio: core::RationalU256,
1467 /// The Cellbase maturity
1468 pub cellbase_maturity: EpochNumberWithFraction,
1469 /// This parameter indicates the count of past blocks used in the median time calculation
1470 pub median_time_block_count: Uint64,
1471 /// Maximum cycles that all the scripts in all the commit transactions can take
1472 pub max_block_cycles: Cycle,
1473 /// Maximum number of bytes to use for the entire block
1474 pub max_block_bytes: Uint64,
1475 /// The block version number supported
1476 pub block_version: Version,
1477 /// The tx version number supported
1478 pub tx_version: Version,
1479 /// The "TYPE_ID" in hex
1480 pub type_id_code_hash: H256,
1481 /// The Limit to the number of proposals per block
1482 pub max_block_proposals_limit: Uint64,
1483 /// Primary reward is cut in half every halving_interval epoch
1484 pub primary_epoch_reward_halving_interval: Uint64,
1485 /// Keep difficulty be permanent if the pow is dummy
1486 pub permanent_difficulty_in_dummy: bool,
1487 /// Hardfork features
1488 pub hardfork_features: HardForks,
1489 /// `HashMap<DeploymentPos, SoftFork>` - Softforks
1490 pub softforks: HashMap<DeploymentPos, SoftFork>,
1491}
1492
1493/// Hardfork information
1494#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
1495#[serde(transparent)]
1496pub struct HardForks {
1497 inner: Vec<HardForkFeature>,
1498}
1499
1500impl HardForks {
1501 /// Returns a list of hardfork features from a hardfork switch.
1502 pub fn new(hardforks: &core::hardfork::HardForks) -> Self {
1503 HardForks {
1504 inner: vec![
1505 HardForkFeature::new("0028", convert(hardforks.ckb2021.rfc_0028())),
1506 HardForkFeature::new("0029", convert(hardforks.ckb2021.rfc_0029())),
1507 HardForkFeature::new("0030", convert(hardforks.ckb2021.rfc_0030())),
1508 HardForkFeature::new("0031", convert(hardforks.ckb2021.rfc_0031())),
1509 HardForkFeature::new("0032", convert(hardforks.ckb2021.rfc_0032())),
1510 HardForkFeature::new("0036", convert(hardforks.ckb2021.rfc_0036())),
1511 HardForkFeature::new("0038", convert(hardforks.ckb2021.rfc_0038())),
1512 HardForkFeature::new("0048", convert(hardforks.ckb2023.rfc_0048())),
1513 HardForkFeature::new("0049", convert(hardforks.ckb2023.rfc_0049())),
1514 ],
1515 }
1516 }
1517}
1518
1519/// The information about one hardfork feature.
1520#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
1521pub struct HardForkFeature {
1522 /// The related RFC ID.
1523 pub rfc: String,
1524 /// The first epoch when the feature is enabled, `null` indicates that the RFC has never been enabled.
1525 pub epoch_number: Option<EpochNumber>,
1526}
1527
1528/// SoftForkStatus which is either `buried` (for soft fork deployments where the activation epoch is
1529/// hard-coded into the client implementation), or `rfc0043` (for soft fork deployments
1530/// where activation is controlled by rfc0043 signaling).
1531#[derive(Clone, Copy, Serialize, Deserialize, Debug, JsonSchema)]
1532#[serde(rename_all = "snake_case")]
1533pub enum SoftForkStatus {
1534 /// the activation epoch is hard-coded into the client implementation
1535 Buried,
1536 /// the activation is controlled by rfc0043 signaling
1537 Rfc0043,
1538}
1539
1540/// SoftFork information
1541#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
1542#[serde(untagged)]
1543pub enum SoftFork {
1544 /// buried - the activation epoch is hard-coded into the client implementation
1545 Buried(Buried),
1546 /// rfc0043 - the activation is controlled by rfc0043 signaling
1547 Rfc0043(Rfc0043),
1548}
1549
1550impl SoftFork {
1551 /// Construct new rfc0043
1552 pub fn new_rfc0043(deployment: Deployment) -> SoftFork {
1553 SoftFork::Rfc0043(Rfc0043 {
1554 status: SoftForkStatus::Rfc0043,
1555 rfc0043: deployment,
1556 })
1557 }
1558
1559 /// Construct new buried
1560 pub fn new_buried(active: bool, epoch: EpochNumber) -> SoftFork {
1561 SoftFork::Buried(Buried {
1562 active,
1563 epoch,
1564 status: SoftForkStatus::Buried,
1565 })
1566 }
1567}
1568
1569/// Represent soft fork deployments where the activation epoch is
1570/// hard-coded into the client implementation
1571#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
1572pub struct Buried {
1573 /// SoftFork status
1574 pub status: SoftForkStatus,
1575 /// Whether the rules are active
1576 pub active: bool,
1577 /// The first epoch which the rules will be enforced
1578 pub epoch: EpochNumber,
1579}
1580
1581/// Represent soft fork deployments
1582/// where activation is controlled by rfc0043 signaling
1583#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
1584pub struct Rfc0043 {
1585 /// SoftFork status
1586 pub status: SoftForkStatus,
1587 /// RFC0043 deployment params
1588 pub rfc0043: Deployment,
1589}
1590
1591/// Represents the ratio `numerator / denominator`, where `numerator` and `denominator` are both
1592/// unsigned 64-bit integers.
1593#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
1594pub struct Ratio {
1595 /// Numerator.
1596 pub numer: Uint64,
1597 /// Denominator.
1598 pub denom: Uint64,
1599}
1600
1601impl From<core::Ratio> for Ratio {
1602 fn from(value: core::Ratio) -> Self {
1603 Ratio {
1604 numer: value.numer().into(),
1605 denom: value.denom().into(),
1606 }
1607 }
1608}
1609
1610/// RFC0043 deployment params
1611#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
1612pub struct Deployment {
1613 /// Determines which bit in the `version` field of the block is to be used to signal the softfork lock-in and activation.
1614 /// It is chosen from the set {0,1,2,...,28}.
1615 pub bit: u8,
1616 /// Specifies the first epoch in which the bit gains meaning.
1617 pub start: EpochNumber,
1618 /// Specifies an epoch at which the miner signaling ends.
1619 /// Once this epoch has been reached, if the softfork has not yet locked_in (excluding this epoch block's bit state),
1620 /// the deployment is considered failed on all descendants of the block.
1621 pub timeout: EpochNumber,
1622 /// Specifies the epoch at which the softfork is allowed to become active.
1623 pub min_activation_epoch: EpochNumber,
1624 /// Specifies length of epochs of the signalling period.
1625 pub period: EpochNumber,
1626 /// Specifies the minimum ratio of block per `period`,
1627 /// which indicate the locked_in of the softfork during the `period`.
1628 pub threshold: Ratio,
1629}
1630
1631fn convert(number: core::EpochNumber) -> Option<EpochNumber> {
1632 if number == core::EpochNumber::MAX {
1633 None
1634 } else {
1635 Some(number.into())
1636 }
1637}
1638
1639impl HardForkFeature {
1640 /// Creates a new struct.
1641 pub fn new(rfc: &str, epoch_number: Option<EpochNumber>) -> Self {
1642 Self {
1643 rfc: rfc.to_owned(),
1644 epoch_number,
1645 }
1646 }
1647}
1648
1649/// The fee_rate statistics information, includes mean and median, unit: shannons per kilo-weight
1650#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, JsonSchema)]
1651pub struct FeeRateStatistics {
1652 /// mean
1653 pub mean: Uint64,
1654 /// median
1655 pub median: Uint64,
1656}