snarkvm_ledger_block/header/metadata/
mod.rs1mod 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 network: u16,
33 round: u64,
35 height: u32,
37 cumulative_weight: u128,
39 cumulative_proof_target: u128,
41 coinbase_target: u64,
43 proof_target: u64,
45 last_coinbase_target: u64,
47 last_coinbase_timestamp: i64,
49 timestamp: i64,
51 _phantom: PhantomData<N>,
53}
54
55impl<N: Network> Metadata<N> {
56 #[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 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 metadata.check_validity().with_context(|| "Invalid block metadata")?;
87
88 Ok(metadata)
89 }
90
91 pub fn is_valid(&self) -> bool {
95 self.check_validity().is_ok()
96 }
97
98 pub fn check_validity(&self) -> Result<()> {
100 if self.height == 0u32 {
101 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!(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 pub const fn network(&self) -> u16 {
141 self.network
142 }
143
144 pub const fn round(&self) -> u64 {
146 self.round
147 }
148
149 pub const fn height(&self) -> u32 {
151 self.height
152 }
153
154 pub const fn cumulative_weight(&self) -> u128 {
156 self.cumulative_weight
157 }
158
159 pub const fn cumulative_proof_target(&self) -> u128 {
161 self.cumulative_proof_target
162 }
163
164 pub const fn coinbase_target(&self) -> u64 {
166 self.coinbase_target
167 }
168
169 pub const fn proof_target(&self) -> u64 {
171 self.proof_target
172 }
173
174 pub const fn last_coinbase_target(&self) -> u64 {
176 self.last_coinbase_target
177 }
178
179 pub const fn last_coinbase_timestamp(&self) -> i64 {
181 self.last_coinbase_timestamp
182 }
183
184 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 pub(crate) fn sample_block_metadata(rng: &mut TestRng) -> Metadata<CurrentNetwork> {
198 *crate::test_helpers::sample_genesis_block(rng).metadata()
199 }
200}