forest/fil_cns/
mod.rs

1// Copyright 2019-2026 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3use std::{fmt::Debug, sync::Arc};
4
5use crate::beacon::BeaconSchedule;
6use crate::blocks::{Block, Tipset};
7use crate::chain::{Error as ChainStoreError, Weight};
8use crate::state_manager::{Error as StateManagerError, StateManager};
9use anyhow::anyhow;
10use fvm_ipld_blockstore::Blockstore;
11use fvm_ipld_encoding::Error as ForestEncodingError;
12use nunny::Vec as NonEmpty;
13use thiserror::Error;
14
15mod validation;
16mod weight;
17
18#[derive(Debug, Error)]
19pub enum FilecoinConsensusError {
20    #[error("Block must have an election proof included in tipset")]
21    BlockWithoutElectionProof,
22    #[error("Block without ticket")]
23    BlockWithoutTicket,
24    #[error("Block height {current} not greater than parent height {parent}")]
25    BlockHeightNotGreaterThanParentHeight { current: i64, parent: i64 },
26    #[error("Block had the wrong timestamp: {0} != {1}")]
27    UnequalBlockTimestamps(u64, u64),
28    #[error("Tipset without ticket to verify")]
29    TipsetWithoutTicket,
30    #[error("Block is not claiming to be a winner")]
31    NotClaimingWin,
32    #[error("Block miner was slashed or is invalid")]
33    InvalidOrSlashedMiner,
34    #[error("Miner power not available for miner address")]
35    MinerPowerNotAvailable,
36    #[error("Miner claimed wrong number of wins: miner = {0}, computed = {1}")]
37    MinerWinClaimsIncorrect(i64, i64),
38    #[error("Drawing chain randomness failed: {0}")]
39    DrawingChainRandomness(String),
40    #[error("Miner isn't elligible to mine")]
41    MinerNotEligibleToMine,
42    #[error("Querying miner power failed: {0}")]
43    MinerPowerUnavailable(String),
44    #[error("Power actor not found")]
45    PowerActorUnavailable,
46    #[error("Verifying VRF failed: {0}")]
47    VrfValidation(String),
48    #[error("Failed to validate blocks random beacon values: {0}")]
49    BeaconValidation(String),
50    #[error("Failed to verify winning PoSt: {0}")]
51    WinningPoStValidation(String),
52    #[error("Chain store error: {0}")]
53    ChainStore(#[from] ChainStoreError),
54    #[error("StateManager error: {0}")]
55    StateManager(#[from] StateManagerError),
56    #[error("Encoding error: {0}")]
57    ForestEncoding(#[from] ForestEncodingError),
58}
59
60#[derive(derive_more::Constructor)]
61pub struct FilecoinConsensus {
62    /// `Drand` randomness beacon
63    ///
64    /// NOTE: The `StateManager` makes available a beacon as well,
65    /// but it potentially has a different type.
66    /// Not sure where this is utilized.
67    beacon: Arc<BeaconSchedule>,
68}
69
70impl FilecoinConsensus {
71    pub async fn validate_block<DB: Blockstore + Sync + Send + 'static>(
72        &self,
73        state_manager: Arc<StateManager<DB>>,
74        block: Arc<Block>,
75    ) -> Result<(), NonEmpty<FilecoinConsensusError>> {
76        validation::validate_block::<_>(state_manager, self.beacon.clone(), block).await
77    }
78}
79
80impl Debug for FilecoinConsensus {
81    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82        f.debug_struct("FilecoinConsensus")
83            .field("beacon", &self.beacon.0.len())
84            .finish()
85    }
86}
87
88pub fn weight<DB>(db: &DB, ts: &Tipset) -> Result<Weight, anyhow::Error>
89where
90    DB: Blockstore,
91{
92    weight::weight(&Arc::new(db), ts).map_err(|s| anyhow!(s))
93}