1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
pub use chain_impl_mockchain::{
    block::{builder as block_builder, Block},
    chaineval::HeaderContentEvalContext,
    chaintypes::ConsensusVersion,
    config::{self, Block0Date, ConfigParam},
    fragment::{ConfigParams, Contents, ContentsBuilder, Fragment, FragmentId},
    header::{
        BlockDate, BlockVersion, ChainLength, Epoch, Header, HeaderBft, HeaderBftBuilder,
        HeaderBuilder, HeaderBuilderNew, HeaderDesc, HeaderGenesisPraos, HeaderGenesisPraosBuilder,
        HeaderId, HeaderSetConsensusSignature, SlotId,
    },
    leadership::{BftLeader, GenesisLeader, Leader, LeaderOutput, Leadership},
    ledger::{
        ApplyBlockLedger, EpochRewardsInfo, Ledger, LedgerStaticParameters, RewardsInfoParameters,
    },
    multiverse::Multiverse,
    value::{Value, ValueError},
};
pub use chain_network::data::gossip::Gossip;
use std::time::{Duration, SystemTime};
use thiserror::Error;

pub type HeaderHash = HeaderId;

#[derive(Debug, Error)]
pub enum Block0Error {
    #[error("Block0 Initial settings: {0}")]
    CannotParseEntity(#[from] config::Error),
    #[error("Block0 is invalid or malformed: {0}")]
    Malformed(#[from] Block0Malformed),
}

#[derive(Debug, Error)]
pub enum Block0Malformed {
    #[error("missing its initial settings")]
    NoInitialSettings,
    #[error("missing `block0-start' value in the block0")]
    NoStartTime,
    #[error("missing `discrimination' value in the block0")]
    NoDiscrimination,
    #[error("missing `slot_duration' value in the block0")]
    NoSlotDuration,
    #[error("missing `slots_per_epoch' value in the block0")]
    NoSlotsPerEpoch,
}

pub trait Block0DataSource {
    fn slot_duration(&self) -> Result<Duration, Block0Error>;
    fn slots_per_epoch(&self) -> Result<u32, Block0Error>;
    fn start_time(&self) -> Result<SystemTime, Block0Error>;
}

impl Block0DataSource for Block {
    fn slot_duration(&self) -> Result<Duration, Block0Error> {
        for config in initial(self)?.iter() {
            if let ConfigParam::SlotDuration(duration) = config {
                return Ok(Duration::from_secs(*duration as u64));
            }
        }
        Err(Block0Malformed::NoSlotDuration.into())
    }

    fn slots_per_epoch(&self) -> Result<u32, Block0Error> {
        for config in initial(self)?.iter() {
            if let ConfigParam::SlotsPerEpoch(slots) = config {
                return Ok(*slots);
            }
        }
        Err(Block0Malformed::NoSlotsPerEpoch.into())
    }

    fn start_time(&self) -> Result<SystemTime, Block0Error> {
        for config in initial(self)?.iter() {
            if let ConfigParam::Block0Date(date) = config {
                return Ok(SystemTime::UNIX_EPOCH + Duration::from_secs(date.0));
            }
        }
        Err(Block0Malformed::NoStartTime.into())
    }
}

fn initial(block: &Block) -> Result<&ConfigParams, Block0Malformed> {
    for fragment in block.fragments() {
        if let Fragment::Initial(init) = fragment {
            return Ok(init);
        }
    }
    Err(Block0Malformed::NoInitialSettings)
}