@@ -4,7 +4,7 @@ use std::{
44 ops:: { Add , Div , Mul , Rem , Sub } ,
55} ;
66
7- use witnet_data_structures:: { staking:: prelude:: * , wit:: PrecisionLoss } ;
7+ use witnet_data_structures:: { chain :: Hash , staking:: prelude:: * , wit:: PrecisionLoss } ;
88
99const MINING_REPLICATION_FACTOR : usize = 4 ;
1010const WITNESSING_MAX_ROUNDS : usize = 4 ;
7171 epoch : Epoch ,
7272 witnesses : u16 ,
7373 round : u16 ,
74- ) -> StakesResult < Eligible , Address , Coins , Epoch >
74+ ) -> StakesResult < ( Eligible , Hash , f64 ) , Address , Coins , Epoch >
7575 where
7676 ISK : Into < Address > ;
7777
@@ -87,10 +87,10 @@ where
8787 where
8888 ISK : Into < Address > ,
8989 {
90- matches ! (
91- self . witnessing_eligibility ( validator , epoch , witnesses , round ) ,
92- Ok ( Eligible :: Yes )
93- )
90+ match self . witnessing_eligibility ( validator , epoch , witnesses , round ) {
91+ Ok ( ( eligible , _ , _ ) ) => matches ! ( eligible , Eligible :: Yes ) ,
92+ Err ( _ ) => false ,
93+ }
9494 }
9595}
9696
@@ -139,7 +139,7 @@ where
139139 + From < u64 >
140140 + Sum
141141 + Display ,
142- u64 : From < Coins > + From < Power > ,
142+ u64 : From < Coins > + From < Power > + Mul < Power , Output = u64 > + Div < Power , Output = u64 > ,
143143{
144144 fn mining_eligibility < ISK > (
145145 & self ,
@@ -180,7 +180,7 @@ where
180180 epoch : Epoch ,
181181 witnesses : u16 ,
182182 round : u16 ,
183- ) -> StakesResult < Eligible , Address , Coins , Epoch >
183+ ) -> StakesResult < ( Eligible , Hash , f64 ) , Address , Coins , Epoch >
184184 where
185185 ISK : Into < Address > ,
186186 {
@@ -189,44 +189,51 @@ where
189189 Err ( e) => {
190190 // Early exit if the stake key does not exist
191191 return match e {
192- StakesError :: EntryNotFound { .. } => Ok ( IneligibilityReason :: NotStaking . into ( ) ) ,
192+ StakesError :: EntryNotFound { .. } => {
193+ Ok ( ( IneligibilityReason :: NotStaking . into ( ) , Hash :: min ( ) , 0.0 ) )
194+ }
193195 e => Err ( e) ,
194196 } ;
195197 }
196198 } ;
197199
198- let mut rank = self . rank ( Capability :: Mining , epoch) ;
199- let rf = 2usize . pow ( u32 :: from ( round ) ) * witnesses as usize ;
200+ let mut rank = self . rank ( Capability :: Witnessing , epoch) ;
201+ let ( _ , max_power ) = rank . next ( ) . unwrap_or_default ( ) ;
200202
201203 // Requirement no. 2 from the WIP:
202- // "the witnessing power of the block proposer is in the `rf / stakers`th quantile among the witnessing powers
203- // of all the stakers"
204- let stakers = self . stakes_count ( ) ;
205- let quantile = stakers / MINING_REPLICATION_FACTOR ;
206- // TODO: verify if defaulting to 0 makes sense
207- let ( _, threshold) = rank. nth ( quantile) . unwrap_or_default ( ) ;
208- if power <= threshold {
209- return Ok ( IneligibilityReason :: InsufficientPower . into ( ) ) ;
204+ // "the mining power of the block proposer is in the `rf / stakers`th quantile among the witnessing powers of all
205+ // the stakers"
206+ let rf = 2usize . pow ( u32:: from ( round) ) * witnesses as usize ;
207+ let ( _, threshold_power) = rank. nth ( rf - 2 ) . unwrap_or_default ( ) ;
208+ if power <= threshold_power {
209+ return Ok ( (
210+ IneligibilityReason :: InsufficientPower . into ( ) ,
211+ Hash :: min ( ) ,
212+ 0.0 ,
213+ ) ) ;
210214 }
211215
212216 // Requirement no. 3 from the WIP:
213217 // "the big-endian value of the VRF output is less than
214- // `max_rounds * own_power / (max_power * (rf - max_rounds) - rf * threshold_power)`"
215- // TODO: verify if defaulting to 0 makes sense
216- let ( _, max_power) = rank. next ( ) . unwrap_or_default ( ) ;
217- let stakers = self . stakes_count ( ) ;
218- let quantile = stakers / rf;
219- // TODO: verify if defaulting to 0 makes sense
220- let ( _, threshold_power) = rank. nth ( quantile) . unwrap_or_default ( ) ;
218+ // `max_rounds * own_power / (max_power * (rf - max_rounds) - rf * threshold_power)`"
221219 let dividend = Power :: from ( WITNESSING_MAX_ROUNDS as u64 ) * power;
222220 let divisor = max_power * Power :: from ( ( rf - WITNESSING_MAX_ROUNDS ) as u64 )
223221 - Power :: from ( rf as u64 ) * threshold_power;
224- let threshold = dividend / divisor;
225- if power <= threshold {
226- return Ok ( IneligibilityReason :: InsufficientPower . into ( ) ) ;
227- }
222+ let target_hash = if divisor == Power :: from ( 0 ) {
223+ Hash :: with_first_u32 ( u32:: MAX )
224+ } else {
225+ Hash :: with_first_u32 (
226+ ( ( ( u64:: MAX / divisor) . saturating_mul ( dividend. into ( ) ) ) >> 32 )
227+ . try_into ( )
228+ . unwrap ( ) ,
229+ )
230+ } ;
228231
229- Ok ( Eligible :: Yes )
232+ Ok ( (
233+ Eligible :: Yes ,
234+ target_hash,
235+ ( u64:: from ( dividend) / divisor) as f64 ,
236+ ) )
230237 }
231238}
232239
@@ -274,16 +281,20 @@ mod tests {
274281 let stakes = <Stakes < String , _ , _ , _ > >:: with_minimum ( 100u64 ) ;
275282 let isk = "validator" ;
276283
277- assert_eq ! (
278- stakes. witnessing_eligibility( isk, 0 , 10 , 0 ) ,
279- Ok ( Eligible :: No ( IneligibilityReason :: NotStaking ) )
280- ) ;
284+ match stakes. witnessing_eligibility ( isk, 0 , 10 , 0 ) {
285+ Ok ( ( eligible, _, _) ) => {
286+ assert_eq ! ( eligible, Eligible :: No ( IneligibilityReason :: NotStaking ) ) ;
287+ }
288+ Err ( _) => assert ! ( false ) ,
289+ }
281290 assert ! ( !stakes. witnessing_eligibility_bool( isk, 0 , 10 , 0 ) ) ;
282291
283- assert_eq ! (
284- stakes. witnessing_eligibility( isk, 100 , 10 , 0 ) ,
285- Ok ( Eligible :: No ( IneligibilityReason :: NotStaking ) )
286- ) ;
292+ match stakes. witnessing_eligibility ( isk, 100 , 10 , 0 ) {
293+ Ok ( ( eligible, _, _) ) => {
294+ assert_eq ! ( eligible, Eligible :: No ( IneligibilityReason :: NotStaking ) ) ;
295+ }
296+ Err ( _) => assert ! ( false ) ,
297+ }
287298 assert ! ( !stakes. witnessing_eligibility_bool( isk, 100 , 10 , 0 ) ) ;
288299 }
289300
@@ -294,16 +305,58 @@ mod tests {
294305
295306 stakes. add_stake ( isk, 1_000 , 0 ) . unwrap ( ) ;
296307
297- assert_eq ! (
298- stakes. witnessing_eligibility( isk, 0 , 10 , 0 ) ,
299- Ok ( Eligible :: No ( IneligibilityReason :: InsufficientPower ) )
300- ) ;
308+ match stakes. witnessing_eligibility ( isk, 0 , 10 , 0 ) {
309+ Ok ( ( eligible, _, _) ) => {
310+ assert_eq ! (
311+ eligible,
312+ Eligible :: No ( IneligibilityReason :: InsufficientPower )
313+ ) ;
314+ }
315+ Err ( _) => assert ! ( false ) ,
316+ }
301317 assert ! ( !stakes. witnessing_eligibility_bool( isk, 0 , 10 , 0 ) ) ;
302318
303- assert_eq ! (
304- stakes. witnessing_eligibility( isk, 100 , 10 , 0 ) ,
305- Ok ( Eligible :: Yes )
306- ) ;
319+ match stakes. witnessing_eligibility ( isk, 100 , 10 , 0 ) {
320+ Ok ( ( eligible, _, _) ) => {
321+ assert_eq ! ( eligible, Eligible :: Yes ) ;
322+ }
323+ Err ( _) => assert ! ( false ) ,
324+ }
307325 assert ! ( stakes. witnessing_eligibility_bool( isk, 100 , 10 , 0 ) ) ;
308326 }
327+
328+ #[ test]
329+ fn test_witnessing_eligibility_target_hash ( ) {
330+ let mut stakes = <Stakes < String , _ , _ , _ > >:: with_minimum ( 100u64 ) ;
331+ let isk_1 = "validator_1" ;
332+ let isk_2 = "validator_2" ;
333+ let isk_3 = "validator_3" ;
334+ let isk_4 = "validator_4" ;
335+
336+ stakes. add_stake ( isk_1, 10_000_000_000 , 0 ) . unwrap ( ) ;
337+ stakes. add_stake ( isk_2, 20_000_000_000 , 0 ) . unwrap ( ) ;
338+ stakes. add_stake ( isk_3, 30_000_000_000 , 0 ) . unwrap ( ) ;
339+ stakes. add_stake ( isk_4, 40_000_000_000 , 0 ) . unwrap ( ) ;
340+
341+ match stakes. witnessing_eligibility ( isk_1, 0 , 2 , 0 ) {
342+ // TODO: verify target hash
343+ Ok ( ( eligible, _target_hash, _) ) => {
344+ assert_eq ! (
345+ eligible,
346+ Eligible :: No ( IneligibilityReason :: InsufficientPower )
347+ ) ;
348+ }
349+ Err ( _) => assert ! ( false ) ,
350+ }
351+ assert ! ( !stakes. witnessing_eligibility_bool( isk_1, 0 , 10 , 0 ) ) ;
352+
353+ match stakes. witnessing_eligibility ( isk_1, 100 , 2 , 0 ) {
354+ // TODO: verify target hash
355+ Ok ( ( eligible, _target_hash, _) ) => {
356+ assert_eq ! ( eligible, Eligible :: No ( IneligibilityReason :: InsufficientPower ) ) ;
357+ }
358+ Err ( _) => assert ! ( false ) ,
359+ }
360+ assert ! ( stakes. witnessing_eligibility_bool( isk_1, 100 , 10 , 0 ) ) ;
361+ }
309362}
0 commit comments