Skip to main content

snarkvm_ledger_block/header/
mod.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16mod metadata;
17pub use metadata::*;
18
19mod bytes;
20mod genesis;
21mod merkle;
22mod serialize;
23mod string;
24mod verify;
25
26use crate::{Ratifications, Transactions};
27use console::{
28    network::prelude::*,
29    program::{HEADER_DEPTH, HeaderLeaf, HeaderPath, HeaderTree},
30    types::Field,
31};
32use snarkvm_synthesizer_program::FinalizeOperation;
33
34use anyhow::Context;
35
36/// The header for the block contains metadata that uniquely identifies the block.
37#[derive(Copy, Clone, PartialEq, Eq, Hash)]
38pub struct Header<N: Network> {
39    /// The Merkle root representing the blocks in the ledger up to the previous block.
40    previous_state_root: N::StateRoot,
41    /// The Merkle root representing the transactions in the block.
42    transactions_root: Field<N>,
43    /// The Merkle root representing the on-chain finalize including the current block.
44    finalize_root: Field<N>,
45    /// The Merkle root representing the ratifications in the block.
46    ratifications_root: Field<N>,
47    /// The solutions root of the puzzle.
48    solutions_root: Field<N>,
49    /// The subdag Merkle root of the authority.
50    subdag_root: Field<N>,
51    /// The metadata of the block.
52    metadata: Metadata<N>,
53}
54
55impl<N: Network> Header<N> {
56    /// Initializes a new block header with the given inputs.
57    pub fn from(
58        previous_state_root: N::StateRoot,
59        transactions_root: Field<N>,
60        finalize_root: Field<N>,
61        ratifications_root: Field<N>,
62        solutions_root: Field<N>,
63        subdag_root: Field<N>,
64        metadata: Metadata<N>,
65    ) -> Result<Self> {
66        // Construct a new block header.
67        let header = Self {
68            previous_state_root,
69            transactions_root,
70            finalize_root,
71            ratifications_root,
72            solutions_root,
73            subdag_root,
74            metadata,
75        };
76        // Ensure the header is valid.
77        header.check_validity().with_context(|| "Invalid block header")?;
78        Ok(header)
79    }
80
81    /// Returns `true` if the block header is well-formed.
82    ///
83    /// Consider using [`Self::check_validity`] to get more information on invalid block headers.
84    pub fn is_valid(&self) -> bool {
85        self.check_validity().is_ok()
86    }
87
88    /// Returns `Ok(())` if the block header is well-formed, and error describing (one of) the problem(s) in the block header.
89    pub fn check_validity(&self) -> Result<()> {
90        if self.height() == 0u32 {
91            if !self.is_genesis()? {
92                bail!("Block at height 0 is not a gensis block");
93            }
94            return Ok(());
95        }
96
97        self.metadata.check_validity().with_context(|| "Invalid metadata")?;
98
99        ensure!(*self.previous_state_root != Field::zero(), "Previous state root cannot be zero");
100        ensure!(self.transactions_root != Field::zero(), "Transactions root cannot be zero");
101        ensure!(self.finalize_root != Field::zero(), "Finalize root cannot be zero");
102        ensure!(self.ratifications_root != Field::zero(), "Ratifications root cannot be zero");
103
104        Ok(())
105    }
106
107    /// Returns the previous state root from the block header.
108    pub const fn previous_state_root(&self) -> N::StateRoot {
109        self.previous_state_root
110    }
111
112    /// Returns the transactions root in the block header.
113    pub const fn transactions_root(&self) -> Field<N> {
114        self.transactions_root
115    }
116
117    /// Returns the finalize root in the block header.
118    pub const fn finalize_root(&self) -> Field<N> {
119        self.finalize_root
120    }
121
122    /// Returns the ratifications root in the block header.
123    pub const fn ratifications_root(&self) -> Field<N> {
124        self.ratifications_root
125    }
126
127    /// Returns the solutions root in the block header.
128    pub const fn solutions_root(&self) -> Field<N> {
129        self.solutions_root
130    }
131
132    /// Returns the subdag root in the block header.
133    pub const fn subdag_root(&self) -> Field<N> {
134        self.subdag_root
135    }
136
137    /// Returns the metadata in the block header.
138    pub const fn metadata(&self) -> &Metadata<N> {
139        &self.metadata
140    }
141
142    /// Returns the network ID of the block.
143    pub const fn network(&self) -> u16 {
144        self.metadata.network()
145    }
146
147    /// Returns the round number of the block.
148    pub const fn round(&self) -> u64 {
149        self.metadata.round()
150    }
151
152    /// Returns the height of the block.
153    pub const fn height(&self) -> u32 {
154        self.metadata.height()
155    }
156
157    /// Returns the cumulative weight for this block.
158    pub const fn cumulative_weight(&self) -> u128 {
159        self.metadata.cumulative_weight()
160    }
161
162    /// Returns the cumulative proof target for this block.
163    pub const fn cumulative_proof_target(&self) -> u128 {
164        self.metadata.cumulative_proof_target()
165    }
166
167    /// Returns the coinbase target for this block.
168    pub const fn coinbase_target(&self) -> u64 {
169        self.metadata.coinbase_target()
170    }
171
172    /// Returns the proof target for this block.
173    pub const fn proof_target(&self) -> u64 {
174        self.metadata.proof_target()
175    }
176
177    /// Returns the coinbase target of the last coinbase.
178    pub const fn last_coinbase_target(&self) -> u64 {
179        self.metadata.last_coinbase_target()
180    }
181
182    /// Returns the Unix timestamp (UTC) of the last coinbase.
183    pub const fn last_coinbase_timestamp(&self) -> i64 {
184        self.metadata.last_coinbase_timestamp()
185    }
186
187    /// Returns the Unix timestamp (UTC) for this block.
188    pub const fn timestamp(&self) -> i64 {
189        self.metadata.timestamp()
190    }
191}
192
193#[cfg(test)]
194pub mod test_helpers {
195    use super::*;
196
197    type CurrentNetwork = console::network::MainnetV0;
198
199    /// Samples a block header.
200    pub(crate) fn sample_block_header(rng: &mut TestRng) -> Header<CurrentNetwork> {
201        *crate::test_helpers::sample_genesis_block(rng).header()
202    }
203}