mod bytes;
mod genesis;
mod serialize;
mod string;
mod to_bits;
mod to_hash;
mod verify;
use console::{network::prelude::*, types::Field};
use anyhow::Context;
use core::marker::PhantomData;
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Metadata<N: Network> {
network: u16,
round: u64,
height: u32,
cumulative_weight: u128,
cumulative_proof_target: u128,
coinbase_target: u64,
proof_target: u64,
last_coinbase_target: u64,
last_coinbase_timestamp: i64,
timestamp: i64,
_phantom: PhantomData<N>,
}
impl<N: Network> Metadata<N> {
#[allow(clippy::too_many_arguments)]
pub fn new(
network: u16,
round: u64,
height: u32,
cumulative_weight: u128,
cumulative_proof_target: u128,
coinbase_target: u64,
proof_target: u64,
last_coinbase_target: u64,
last_coinbase_timestamp: i64,
timestamp: i64,
) -> Result<Self> {
let metadata = Self {
network,
round,
height,
cumulative_weight,
cumulative_proof_target,
coinbase_target,
proof_target,
last_coinbase_target,
last_coinbase_timestamp,
timestamp,
_phantom: PhantomData,
};
metadata.check_validity().with_context(|| "Invalid block metadata")?;
Ok(metadata)
}
pub fn is_valid(&self) -> bool {
self.check_validity().is_ok()
}
pub fn check_validity(&self) -> Result<()> {
if self.height == 0u32 {
if !self.is_genesis().with_context(|| "Genesis block check failed")? {
bail!("Block at height 0 is not a genesis block");
}
return Ok(());
}
ensure!(self.network == N::ID, "Invalid network ID");
ensure!(self.round > 0u64, "Invalid round");
ensure!(self.round >= self.height as u64, "Round must be greater or equal to height");
ensure!(self.proof_target >= N::GENESIS_PROOF_TARGET, "Invalid proof target");
ensure!(self.last_coinbase_timestamp >= N::GENESIS_TIMESTAMP, "Ensure last coinbase timestamp");
ensure!(self.timestamp > N::GENESIS_TIMESTAMP, "Invalid timeestamp");
if self.coinbase_target < N::GENESIS_COINBASE_TARGET {
bail!(
"Invalid coinbase target: Was {actual} but expected {min} or greater.",
actual = self.coinbase_target,
min = N::GENESIS_COINBASE_TARGET,
);
}
if self.proof_target < N::GENESIS_PROOF_TARGET {
bail!(
"Invalid proof target: Was {actual} but expected {min} or greater.",
actual = self.proof_target,
min = N::GENESIS_PROOF_TARGET,
);
}
ensure!(self.coinbase_target > self.proof_target, "Invalid coinbase target: must be greater than proof target");
Ok(())
}
}
impl<N: Network> Metadata<N> {
pub const fn network(&self) -> u16 {
self.network
}
pub const fn round(&self) -> u64 {
self.round
}
pub const fn height(&self) -> u32 {
self.height
}
pub const fn cumulative_weight(&self) -> u128 {
self.cumulative_weight
}
pub const fn cumulative_proof_target(&self) -> u128 {
self.cumulative_proof_target
}
pub const fn coinbase_target(&self) -> u64 {
self.coinbase_target
}
pub const fn proof_target(&self) -> u64 {
self.proof_target
}
pub const fn last_coinbase_target(&self) -> u64 {
self.last_coinbase_target
}
pub const fn last_coinbase_timestamp(&self) -> i64 {
self.last_coinbase_timestamp
}
pub const fn timestamp(&self) -> i64 {
self.timestamp
}
}
#[cfg(test)]
pub mod test_helpers {
use super::*;
type CurrentNetwork = console::network::MainnetV0;
pub(crate) fn sample_block_metadata(rng: &mut TestRng) -> Metadata<CurrentNetwork> {
*crate::test_helpers::sample_genesis_block(rng).metadata()
}
}