forest/blocks/
election_proof.rs1use crate::blocks::VRFProof;
5use crate::shim::clock::BLOCKS_PER_EPOCH;
6use crate::utils::encoding::blake2b_256;
7use fvm_ipld_encoding::tuple::*;
8use get_size2::GetSize;
9use num::{
10 BigInt, Integer,
11 bigint::{ParseBigIntError, Sign},
12};
13use std::sync::LazyLock;
14
15const PRECISION: u64 = 256;
16const MAX_WIN_COUNT: i64 = 3 * BLOCKS_PER_EPOCH as i64;
17
18fn parse(strings: &[&str]) -> Result<Vec<BigInt>, ParseBigIntError> {
19 strings
20 .iter()
21 .map(|s| {
22 let i: BigInt = s.parse()?;
23 Ok(i << (PRECISION - 128))
25 })
26 .collect()
27}
28
29static EXP_NUM_COEF: LazyLock<Vec<BigInt>> = LazyLock::new(|| {
30 parse(&[
31 "-648770010757830093818553637600",
32 "67469480939593786226847644286976",
33 "-3197587544499098424029388939001856",
34 "89244641121992890118377641805348864",
35 "-1579656163641440567800982336819953664",
36 "17685496037279256458459817590917169152",
37 "-115682590513835356866803355398940131328",
38 "340282366920938463463374607431768211456",
39 ])
40 .unwrap()
41});
42static EXP_DENO_COEF: LazyLock<Vec<BigInt>> = LazyLock::new(|| {
43 parse(&[
44 "1225524182432722209606361",
45 "114095592300906098243859450",
46 "5665570424063336070530214243",
47 "194450132448609991765137938448",
48 "5068267641632683791026134915072",
49 "104716890604972796896895427629056",
50 "1748338658439454459487681798864896",
51 "23704654329841312470660182937960448",
52 "259380097567996910282699886670381056",
53 "2250336698853390384720606936038375424",
54 "14978272436876548034486263159246028800",
55 "72144088983913131323343765784380833792",
56 "224599776407103106596571252037123047424",
57 "340282366920938463463374607431768211456",
58 ])
59 .unwrap()
60});
61
62fn expneg(x: &BigInt) -> BigInt {
67 let num = poly_val(&EXP_NUM_COEF, x);
68 let deno = poly_val(&EXP_DENO_COEF, x);
69
70 (num << PRECISION).div_floor(&deno)
71}
72
73fn poly_val(poly: &[BigInt], x: &BigInt) -> BigInt {
78 let mut poly_iter = poly.iter();
79 let mut res = poly_iter.next().cloned().unwrap_or_default();
80
81 for coeff in poly_iter {
82 res = ((res * x) >> PRECISION) + coeff;
83 }
84 res
85}
86
87#[inline]
89fn lambda(power: &BigInt, total_power: &BigInt) -> BigInt {
90 ((power * BLOCKS_PER_EPOCH) << PRECISION).div_floor(total_power)
91}
92
93struct Poiss {
96 lam: BigInt,
97 pmf: BigInt,
98 icdf: BigInt,
99
100 k: u64,
101}
102
103impl Poiss {
104 fn new(lambda: BigInt) -> Self {
105 let pmf = expneg(&lambda);
108
109 let icdf = (BigInt::from(1) << PRECISION) - &pmf;
110
111 Self {
112 lam: lambda,
113 pmf,
114 icdf,
115 k: 0,
116 }
117 }
118 fn next(&mut self) -> &BigInt {
119 self.k += 1;
122
123 self.pmf = self.pmf.div_floor(&BigInt::from(self.k));
125 self.pmf = (&self.pmf * &self.lam) >> PRECISION;
126
127 self.icdf -= &self.pmf;
130 &self.icdf
131 }
132}
133
134#[derive(
138 Clone,
139 Debug,
140 PartialEq,
141 PartialOrd,
142 Eq,
143 Default,
144 Ord,
145 Serialize_tuple,
146 Deserialize_tuple,
147 Hash,
148 GetSize,
149)]
150pub struct ElectionProof {
151 pub win_count: i64,
152 pub vrfproof: VRFProof,
153}
154
155impl ElectionProof {
156 pub fn compute_win_count(&self, power: &BigInt, total_power: &BigInt) -> i64 {
160 let h = blake2b_256(self.vrfproof.as_bytes());
161 let lhs = BigInt::from_bytes_be(Sign::Plus, &h);
162
163 let lam = lambda(power, total_power);
175 let mut p = Poiss::new(lam);
176 let mut rhs = &p.icdf;
177
178 let mut j: i64 = 0;
179 while &lhs < rhs && j < MAX_WIN_COUNT {
180 rhs = p.next();
181 j += 1;
182 }
183
184 j
185 }
186}
187
188#[cfg(test)]
189impl quickcheck::Arbitrary for ElectionProof {
190 fn arbitrary(g: &mut quickcheck::Gen) -> Self {
191 let fmt_str = format!("===={}=====", u64::arbitrary(g));
192 let vrfproof = VRFProof::new(fmt_str.into_bytes());
193 Self {
194 win_count: i64::arbitrary(g),
195 vrfproof,
196 }
197 }
198}