Skip to main content

zebra_rpc/methods/types/
default_roots.rs

1//! The `DefaultRoots` type is part of the `getblocktemplate` RPC method output.
2
3use std::iter;
4
5use derive_getters::Getters;
6use derive_new::new;
7use zebra_chain::{
8    amount::NegativeOrZero,
9    block::{
10        self,
11        merkle::{self, AuthDataRoot, AUTH_DIGEST_PLACEHOLDER},
12        ChainHistoryBlockTxAuthCommitmentHash, ChainHistoryMmrRootHash, Height,
13    },
14    parameters::{Network, NetworkUpgrade},
15    transaction::VerifiedUnminedTx,
16};
17
18use crate::client::TransactionTemplate;
19
20/// The block header roots for the transactions in a block template.
21///
22/// If the transactions in the block template are modified, these roots must be recalculated
23/// [according to the specification](https://zcash.github.io/rpc/getblocktemplate.html).
24#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, Getters, new)]
25pub struct DefaultRoots {
26    /// The merkle root of the transaction IDs in the block.
27    /// Used in the new block's header.
28    #[serde(rename = "merkleroot")]
29    #[serde(with = "hex")]
30    #[getter(copy)]
31    pub(crate) merkle_root: merkle::Root,
32
33    /// The root of the merkle mountain range of the chain history roots from the last network upgrade to the previous block.
34    /// Unlike the other roots, this not cover any data from this new block, only from previous blocks.
35    #[serde(rename = "chainhistoryroot")]
36    #[serde(with = "hex")]
37    #[getter(copy)]
38    pub(crate) chain_history_root: ChainHistoryMmrRootHash,
39
40    /// The merkle root of the authorizing data hashes of the transactions in the new block.
41    #[serde(rename = "authdataroot")]
42    #[serde(with = "hex")]
43    #[getter(copy)]
44    pub(crate) auth_data_root: AuthDataRoot,
45
46    /// The block commitment for the new block's header.
47    /// This hash covers `chain_history_root` and `auth_data_root`.
48    ///
49    /// `merkle_root` has its own field in the block header.
50    #[serde(rename = "blockcommitmentshash")]
51    #[serde(with = "hex")]
52    #[getter(copy)]
53    pub(crate) block_commitments_hash: ChainHistoryBlockTxAuthCommitmentHash,
54}
55
56impl DefaultRoots {
57    /// Creates a new [`DefaultRoots`] instance from the given coinbase tx template.
58    pub fn from_coinbase(
59        net: &Network,
60        height: Height,
61        coinbase: &TransactionTemplate<NegativeOrZero>,
62        chain_history_root: Option<ChainHistoryMmrRootHash>,
63        mempool_txs: &[VerifiedUnminedTx],
64    ) -> Self {
65        let chain_history_root = chain_history_root
66            .or_else(|| {
67                (NetworkUpgrade::Heartwood.activation_height(net) == Some(height))
68                    .then_some(block::CHAIN_HISTORY_ACTIVATION_RESERVED.into())
69            })
70            .expect("history root is required for block templates");
71
72        // TODO:
73        // Computing `auth_data_root` and `merkle_root` gets more expensive as `mempool_txs` grows.
74        // It might be worth doing it in rayon.
75
76        let auth_data_root = iter::once(coinbase.auth_digest)
77            .chain(mempool_txs.iter().map(|tx| {
78                tx.transaction
79                    .id
80                    .auth_digest()
81                    .unwrap_or(AUTH_DIGEST_PLACEHOLDER)
82            }))
83            .collect();
84
85        Self {
86            merkle_root: iter::once(coinbase.hash)
87                .chain(mempool_txs.iter().map(|tx| tx.transaction.id.mined_id()))
88                .collect(),
89            chain_history_root,
90            auth_data_root,
91            block_commitments_hash: if NetworkUpgrade::current(net, height)
92                == NetworkUpgrade::Heartwood
93                && chain_history_root == block::CHAIN_HISTORY_ACTIVATION_RESERVED.into()
94            {
95                block::CHAIN_HISTORY_ACTIVATION_RESERVED.into()
96            } else {
97                ChainHistoryBlockTxAuthCommitmentHash::from_commitments(
98                    &chain_history_root,
99                    &auth_data_root,
100                )
101            },
102        }
103    }
104}