forest/state_manager/
mining.rs1use super::chain_rand::draw_randomness;
5use super::*;
6use crate::beacon::BeaconEntry;
7use crate::rpc::types::MiningBaseInfo;
8use crate::shim::randomness::Randomness;
9use crate::shim::runtime::Policy;
10use anyhow::Context as _;
11use fil_actors_shared::v12::runtime::DomainSeparationTag;
12use fvm_ipld_encoding::to_vec;
13use num::BigInt;
14use num_traits::identities::Zero;
15
16impl StateManager {
17 pub fn eligible_to_mine(
20 &self,
21 address: &Address,
22 base_tipset: &Tipset,
23 lookback_tipset: &Tipset,
24 ) -> anyhow::Result<bool, Error> {
25 let hmp =
26 self.miner_has_min_power(&self.chain_config().policy, address, lookback_tipset)?;
27 let version = self.get_network_version(base_tipset.epoch());
28
29 if version <= NetworkVersion::V3 {
30 return Ok(hmp);
31 }
32
33 if !hmp {
34 return Ok(false);
35 }
36
37 let actor = self
38 .get_actor(&Address::POWER_ACTOR, *base_tipset.parent_state())?
39 .ok_or_else(|| Error::state("Power actor address could not be resolved"))?;
40
41 let power_state = power::State::load(self.db(), actor.code, actor.state)?;
42
43 let actor = self
44 .get_actor(address, *base_tipset.parent_state())?
45 .ok_or_else(|| Error::state("Miner actor address could not be resolved"))?;
46
47 let miner_state = miner::State::load(self.db(), actor.code, actor.state)?;
48
49 let claim = power_state
51 .miner_power(self.db(), address)?
52 .ok_or_else(|| Error::Other("Could not get claim".to_string()))?;
53 if claim.quality_adj_power <= BigInt::zero() {
54 return Ok(false);
55 }
56
57 if !miner_state.fee_debt().is_zero() {
59 return Ok(false);
60 }
61
62 let info = miner_state.info(self.db())?;
64 if base_tipset.epoch() <= info.consensus_fault_elapsed {
65 return Ok(false);
66 }
67
68 Ok(true)
69 }
70
71 pub async fn miner_get_base_info(
72 &self,
73 beacon_schedule: &BeaconSchedule,
74 tipset: Tipset,
75 addr: Address,
76 epoch: ChainEpoch,
77 ) -> anyhow::Result<Option<MiningBaseInfo>> {
78 let prev_beacon = self
79 .chain_store()
80 .chain_index()
81 .latest_beacon_entry(tipset.clone())?;
82
83 let entries: Vec<BeaconEntry> = beacon_schedule
84 .beacon_entries_for_block(
85 self.chain_config().network_version(epoch),
86 epoch,
87 tipset.epoch(),
88 &prev_beacon,
89 )
90 .await?;
91
92 let base = entries.last().unwrap_or(&prev_beacon);
93
94 let (lb_tipset, lb_state_root) = ChainStore::get_lookback_tipset_for_round(
95 self.chain_index().shallow_clone(),
96 self.chain_config().shallow_clone(),
97 tipset.shallow_clone(),
98 epoch,
99 )
100 .await?;
101
102 let actor = self.get_required_actor(&addr, *tipset.parent_state())?;
107 if self.get_actor(&addr, lb_state_root)?.is_none() {
108 return Ok(None);
109 }
110
111 let miner_state = miner::State::load(self.db(), actor.code, actor.state)?;
112
113 let addr_buf = to_vec(&addr)?;
114 let rand = draw_randomness(
115 base.signature(),
116 DomainSeparationTag::WinningPoStChallengeSeed as i64,
117 epoch,
118 &addr_buf,
119 )?;
120
121 let network_version = self.chain_config().network_version(tipset.epoch());
122 let sectors = self.get_sectors_for_winning_post(
123 &lb_state_root,
124 network_version,
125 &addr,
126 Randomness::new(rand.to_vec()),
127 )?;
128
129 if sectors.is_empty() {
130 return Ok(None);
131 }
132
133 let (miner_power, total_power) = self
134 .get_power(&lb_state_root, Some(&addr))?
135 .context("failed to get power")?;
136
137 let info = miner_state.info(self.db())?;
138
139 let worker_key = self
140 .resolve_to_deterministic_address(info.worker, &tipset)
141 .await?;
142 let eligible = self.eligible_to_mine(&addr, &tipset, &lb_tipset)?;
143
144 Ok(Some(MiningBaseInfo {
145 miner_power: miner_power.quality_adj_power,
146 network_power: total_power.quality_adj_power,
147 sectors,
148 worker_key,
149 sector_size: info.sector_size,
150 prev_beacon_entry: prev_beacon,
151 beacon_entries: entries,
152 eligible_for_mining: eligible,
153 }))
154 }
155
156 pub fn miner_has_min_power(
159 &self,
160 policy: &Policy,
161 addr: &Address,
162 ts: &Tipset,
163 ) -> anyhow::Result<bool> {
164 let actor = self
165 .get_actor(&Address::POWER_ACTOR, *ts.parent_state())?
166 .ok_or_else(|| Error::state("Power actor address could not be resolved"))?;
167 let ps = power::State::load(self.db(), actor.code, actor.state)?;
168
169 ps.miner_nominal_power_meets_consensus_minimum(policy, self.db(), addr)
170 }
171}