Skip to main content

snarkvm_ledger_block/header/metadata/
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 bytes;
17mod genesis;
18mod serialize;
19mod string;
20mod to_bits;
21mod to_hash;
22mod verify;
23
24use console::{network::prelude::*, types::Field};
25
26use anyhow::Context;
27use core::marker::PhantomData;
28
29#[derive(Copy, Clone, PartialEq, Eq, Hash)]
30pub struct Metadata<N: Network> {
31    /// The network ID of the block.
32    network: u16,
33    /// The round that produced this block - 8 bytes.
34    round: u64,
35    /// The height of this block - 4 bytes.
36    height: u32,
37    /// The cumulative weight for this block - 16 bytes.
38    cumulative_weight: u128,
39    /// The cumulative proof target for this block - 16 bytes.
40    cumulative_proof_target: u128,
41    /// The coinbase target for this block - 8 bytes.
42    coinbase_target: u64,
43    /// The proof target for this block - 8 bytes.
44    proof_target: u64,
45    /// The coinbase target for the last coinbase - 8 bytes.
46    last_coinbase_target: u64,
47    /// The Unix timestamp (UTC) for the last coinbase - 8 bytes.
48    last_coinbase_timestamp: i64,
49    /// The Unix timestamp (UTC) for this block - 8 bytes.
50    timestamp: i64,
51    /// PhantomData.
52    _phantom: PhantomData<N>,
53}
54
55impl<N: Network> Metadata<N> {
56    /// Initializes a new metadata with the given inputs.
57    #[allow(clippy::too_many_arguments)]
58    pub fn new(
59        network: u16,
60        round: u64,
61        height: u32,
62        cumulative_weight: u128,
63        cumulative_proof_target: u128,
64        coinbase_target: u64,
65        proof_target: u64,
66        last_coinbase_target: u64,
67        last_coinbase_timestamp: i64,
68        timestamp: i64,
69    ) -> Result<Self> {
70        // Construct a new metadata.
71        let metadata = Self {
72            network,
73            round,
74            height,
75            cumulative_weight,
76            cumulative_proof_target,
77            coinbase_target,
78            proof_target,
79            last_coinbase_target,
80            last_coinbase_timestamp,
81            timestamp,
82            _phantom: PhantomData,
83        };
84
85        // Ensure the header is valid.
86        metadata.check_validity().with_context(|| "Invalid block metadata")?;
87
88        Ok(metadata)
89    }
90
91    /// Returns `true` if the block metadata is well-formed.
92    ///
93    /// Consider using [`Self::check_validity`] to get more information on invalid block metadata.
94    pub fn is_valid(&self) -> bool {
95        self.check_validity().is_ok()
96    }
97
98    /// Returns `Ok(())` if the block metadata is well-formed, and error describing (one of) the problem(s) in the block header.
99    pub fn check_validity(&self) -> Result<()> {
100        if self.height == 0u32 {
101            // [`Self::is_genesis`] performs its own validity checks.
102            if !self.is_genesis().with_context(|| "Genesis block check failed")? {
103                bail!("Block at height 0 is not a genesis block");
104            }
105            return Ok(());
106        }
107
108        // Ensure the network ID is correct.
109        ensure!(self.network == N::ID, "Invalid network ID");
110        ensure!(self.round > 0u64, "Invalid round");
111        ensure!(self.round >= self.height as u64, "Round must be greater or equal to height");
112        ensure!(self.proof_target >= N::GENESIS_PROOF_TARGET, "Invalid proof target");
113
114        ensure!(self.last_coinbase_timestamp >= N::GENESIS_TIMESTAMP, "Ensure last coinbase timestamp");
115        ensure!(self.timestamp > N::GENESIS_TIMESTAMP, "Invalid timeestamp");
116
117        if self.coinbase_target < N::GENESIS_COINBASE_TARGET {
118            bail!(
119                "Invalid coinbase target: Was {actual} but expected {min} or greater.",
120                actual = self.coinbase_target,
121                min = N::GENESIS_COINBASE_TARGET,
122            );
123        }
124
125        if self.proof_target < N::GENESIS_PROOF_TARGET {
126            bail!(
127                "Invalid proof target: Was {actual} but expected {min} or greater.",
128                actual = self.proof_target,
129                min = N::GENESIS_PROOF_TARGET,
130            );
131        }
132
133        ensure!(self.coinbase_target > self.proof_target, "Invalid coinbase target: must be greater than proof target");
134        Ok(())
135    }
136}
137
138impl<N: Network> Metadata<N> {
139    /// Returns the network ID of the block.
140    pub const fn network(&self) -> u16 {
141        self.network
142    }
143
144    /// Returns the round number of the block.
145    pub const fn round(&self) -> u64 {
146        self.round
147    }
148
149    /// Returns the height of the block.
150    pub const fn height(&self) -> u32 {
151        self.height
152    }
153
154    /// Returns the cumulative weight for this block.
155    pub const fn cumulative_weight(&self) -> u128 {
156        self.cumulative_weight
157    }
158
159    /// Returns the cumulative proof target for this block.
160    pub const fn cumulative_proof_target(&self) -> u128 {
161        self.cumulative_proof_target
162    }
163
164    /// Returns the coinbase target for this block.
165    pub const fn coinbase_target(&self) -> u64 {
166        self.coinbase_target
167    }
168
169    /// Returns the proof target for this block.
170    pub const fn proof_target(&self) -> u64 {
171        self.proof_target
172    }
173
174    /// Returns the coinbase target of the last coinbase.
175    pub const fn last_coinbase_target(&self) -> u64 {
176        self.last_coinbase_target
177    }
178
179    /// Returns the block timestamp of the last coinbase.
180    pub const fn last_coinbase_timestamp(&self) -> i64 {
181        self.last_coinbase_timestamp
182    }
183
184    /// Returns the Unix timestamp (UTC) for this block.
185    pub const fn timestamp(&self) -> i64 {
186        self.timestamp
187    }
188}
189
190#[cfg(test)]
191pub mod test_helpers {
192    use super::*;
193
194    type CurrentNetwork = console::network::MainnetV0;
195
196    /// Samples a block metadata.
197    pub(crate) fn sample_block_metadata(rng: &mut TestRng) -> Metadata<CurrentNetwork> {
198        *crate::test_helpers::sample_genesis_block(rng).metadata()
199    }
200}