1use 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
60pub struct FilecoinConsensus {
61 beacon: Arc<BeaconSchedule>,
67}
68
69impl FilecoinConsensus {
70 pub fn new(beacon: Arc<BeaconSchedule>) -> Self {
71 Self { beacon }
72 }
73
74 pub async fn validate_block<DB: Blockstore + Sync + Send + 'static>(
75 &self,
76 state_manager: Arc<StateManager<DB>>,
77 block: Arc<Block>,
78 ) -> Result<(), NonEmpty<FilecoinConsensusError>> {
79 validation::validate_block::<_>(state_manager, self.beacon.clone(), block).await
80 }
81}
82
83impl Debug for FilecoinConsensus {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 f.debug_struct("FilecoinConsensus")
86 .field("beacon", &self.beacon.0.len())
87 .finish()
88 }
89}
90
91pub fn weight<DB>(db: &DB, ts: &Tipset) -> Result<Weight, anyhow::Error>
92where
93 DB: Blockstore,
94{
95 weight::weight(&Arc::new(db), ts).map_err(|s| anyhow!(s))
96}