Skip to main content

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