7
7
ValidatorSetHbbftMock ,
8
8
StakingHbbftCoinsMock ,
9
9
KeyGenHistory ,
10
- IStakingHbbft
10
+ IStakingHbbft ,
11
11
} from "../src/types" ;
12
12
13
13
import fp from 'lodash/fp' ;
@@ -131,6 +131,7 @@ describe('BlockRewardHbbft', () => {
131
131
// The IP addresses are irrelevant for these unit test, just initialize them to 0.
132
132
initialValidatorsIpAddresses = [ '0x00000000000000000000000000000000' , '0x00000000000000000000000000000000' , '0x00000000000000000000000000000000' ] ;
133
133
134
+ await validatorSetHbbft . setCurrentTimestamp ( ( await ethers . provider . getBlock ( await ethers . provider . getBlockNumber ( ) ) ) . timestamp )
134
135
135
136
// Initialize ValidatorSetHbbft
136
137
await validatorSetHbbft . initialize (
@@ -181,6 +182,7 @@ describe('BlockRewardHbbft', () => {
181
182
[ [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 145 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 4 , 239 , 1 , 112 , 13 , 13 , 251 , 103 , 186 , 212 , 78 , 44 , 47 , 250 , 221 , 84 , 118 , 88 , 7 , 64 , 206 , 186 , 11 , 2 , 8 , 204 , 140 , 106 , 179 , 52 , 251 , 237 , 19 , 53 , 74 , 187 , 217 , 134 , 94 , 66 , 68 , 89 , 42 , 85 , 207 , 155 , 220 , 101 , 223 , 51 , 199 , 37 , 38 , 203 , 132 , 13 , 77 , 78 , 114 , 53 , 219 , 114 , 93 , 21 , 25 , 164 , 12 , 43 , 252 , 160 , 16 , 23 , 111 , 79 , 230 , 121 , 95 , 223 , 174 , 211 , 172 , 231 , 0 , 52 , 25 , 49 , 152 , 79 , 128 , 39 , 117 , 216 , 85 , 201 , 237 , 242 , 151 , 219 , 149 , 214 , 77 , 233 , 145 , 47 , 10 , 184 , 175 , 162 , 174 , 237 , 177 , 131 , 45 , 126 , 231 , 32 , 147 , 227 , 170 , 125 , 133 , 36 , 123 , 164 , 232 , 129 , 135 , 196 , 136 , 186 , 45 , 73 , 226 , 179 , 169 , 147 , 42 , 41 , 140 , 202 , 191 , 12 , 73 , 146 , 2 ] ] ,
182
183
[ [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 145 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 4 , 239 , 1 , 112 , 13 , 13 , 251 , 103 , 186 , 212 , 78 , 44 , 47 , 250 , 221 , 84 , 118 , 88 , 7 , 64 , 206 , 186 , 11 , 2 , 8 , 204 , 140 , 106 , 179 , 52 , 251 , 237 , 19 , 53 , 74 , 187 , 217 , 134 , 94 , 66 , 68 , 89 , 42 , 85 , 207 , 155 , 220 , 101 , 223 , 51 , 199 , 37 , 38 , 203 , 132 , 13 , 77 , 78 , 114 , 53 , 219 , 114 , 93 , 21 , 25 , 164 , 12 , 43 , 252 , 160 , 16 , 23 , 111 , 79 , 230 , 121 , 95 , 223 , 174 , 211 , 172 , 231 , 0 , 52 , 25 , 49 , 152 , 79 , 128 , 39 , 117 , 216 , 85 , 201 , 237 , 242 , 151 , 219 , 149 , 214 , 77 , 233 , 145 , 47 , 10 , 184 , 175 , 162 , 174 , 237 , 177 , 131 , 45 , 126 , 231 , 32 , 147 , 227 , 170 , 125 , 133 , 36 , 123 , 164 , 232 , 129 , 135 , 196 , 136 , 186 , 45 , 73 , 226 , 179 , 169 , 147 , 42 , 41 , 140 , 202 , 191 , 12 , 73 , 146 , 2 ] ] ]
183
184
)
185
+
184
186
} ) ;
185
187
186
188
it ( 'staking epoch #0 finished' , async ( ) => {
@@ -454,6 +456,63 @@ describe('BlockRewardHbbft', () => {
454
456
455
457
actualValidatorReward . should . be . closeTo ( expectedValidatorReward , expectedValidatorReward . div ( 100000 ) ) ;
456
458
} )
459
+
460
+ describe ( "Upscaling tests" , async ( ) => {
461
+ it ( "Add multiple validator pools and upscale if needed." , async ( ) => {
462
+ const accountAddresses = accounts . map ( item => item . address ) ;
463
+ const additionalValidators = accountAddresses . slice ( 7 , 52 + 1 ) ; // accounts[7...32]
464
+ const additionalStakingAddresses = accountAddresses . slice ( 53 , 99 + 1 ) ; // accounts[33...59]
465
+
466
+ additionalValidators . length . should . be . equal ( 46 ) ;
467
+ additionalStakingAddresses . length . should . be . equal ( 46 ) ;
468
+
469
+ await network . provider . send ( "evm_setIntervalMining" , [ 8 ] ) ;
470
+
471
+ for ( let i = 0 ; i < additionalValidators . length ; i ++ ) {
472
+ let stakingAddress = await ethers . getSigner ( additionalStakingAddresses [ i ] ) ;
473
+ let miningAddress = await ethers . getSigner ( additionalValidators [ i ] ) ;
474
+
475
+ await stakingHbbft . connect ( stakingAddress ) . addPool ( miningAddress . address , '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' ,
476
+ '0x00000000000000000000000000000000' , { value : MIN_STAKE } ) ;
477
+ await announceAvailability ( miningAddress . address ) ;
478
+ await mine ( ) ;
479
+
480
+ let toBeElected = ( await stakingHbbft . getPoolsToBeElected ( ) ) . length ;
481
+ let pendingValidators = ( await validatorSetHbbft . getPendingValidators ( ) ) . length
482
+ if ( toBeElected > 4 && toBeElected <= 19 && pendingValidators == 0 ) {
483
+ ( await validatorSetHbbft . getValidatorCountSweetSpot ( ( await stakingHbbft . getPoolsToBeElected ( ) ) . length ) ) . should . be . equal ( ( await validatorSetHbbft . getValidators ( ) ) . length ) ;
484
+ }
485
+ }
486
+
487
+ await timeTravelToTransition ( ) ;
488
+ await timeTravelToEndEpoch ( ) ;
489
+ // after epoch was finalized successfully, validator set length is healthy
490
+ ( await validatorSetHbbft . getValidators ( ) ) . length . should . be . eq ( 25 ) ;
491
+ ( await stakingHbbft . getPoolsToBeElected ( ) ) . length . should . be . eq ( 49 ) ;
492
+ } )
493
+
494
+ it ( "banning validator up to 16" , async ( ) => {
495
+ await validatorSetHbbft . setSystemAddress ( owner . address ) ;
496
+ while ( ( await validatorSetHbbft . getValidators ( ) ) . length > 16 ) {
497
+ await mine ( ) ;
498
+ await validatorSetHbbft . connect ( owner ) . removeMaliciousValidators ( [ ( await validatorSetHbbft . getValidators ( ) ) [ 13 ] ] ) ;
499
+ }
500
+ ( await validatorSetHbbft . getValidators ( ) ) . length . should . be . eq ( 16 ) ;
501
+ } )
502
+ it ( "mining twice shouldn't change pending validator set" , async ( ) => {
503
+ await callReward ( false ) ;
504
+ ( await validatorSetHbbft . getPendingValidators ( ) ) . length . should . be . eq ( 25 ) ;
505
+ let pendingValidators = await validatorSetHbbft . getPendingValidators ( ) ;
506
+ await callReward ( false ) ;
507
+ sortedEqual ( pendingValidators , await validatorSetHbbft . getPendingValidators ( ) ) ;
508
+ } )
509
+ it ( "set is scaled to 25" , async ( ) => {
510
+ await mine ( ) ;
511
+ ( await validatorSetHbbft . getValidators ( ) ) . length . should . be . eq ( 25 ) ;
512
+ ( await validatorSetHbbft . getPendingValidators ( ) ) . length . should . be . eq ( 0 ) ;
513
+ await network . provider . send ( "evm_setIntervalMining" , [ 0 ] ) ;
514
+ } )
515
+ } )
457
516
} ) ;
458
517
459
518
function sortedEqual < T > ( arr1 : T [ ] , arr2 : T [ ] ) : void {
@@ -490,6 +549,8 @@ async function increaseTime(time: number) {
490
549
491
550
const currentTimestamp = await validatorSetHbbft . getCurrentTimestamp ( ) ;
492
551
const futureTimestamp = currentTimestamp . add ( BigNumber . from ( time ) ) ;
552
+ await network . provider . send ( "evm_setNextBlockTimestamp" , [ futureTimestamp . toNumber ( ) ] ) ;
553
+ await network . provider . send ( "evm_mine" ) ;
493
554
await validatorSetHbbft . setCurrentTimestamp ( futureTimestamp ) ;
494
555
const currentTimestampAfter = await validatorSetHbbft . getCurrentTimestamp ( ) ;
495
556
futureTimestamp . should . be . equal ( currentTimestampAfter ) ;
@@ -501,6 +562,9 @@ async function increaseTime(time: number) {
501
562
async function timeTravelToTransition ( ) {
502
563
let startTimeOfNextPhaseTransition = await stakingHbbft . startTimeOfNextPhaseTransition ( ) ;
503
564
565
+ await network . provider . send ( "evm_setNextBlockTimestamp" , [ startTimeOfNextPhaseTransition . toNumber ( ) ] ) ;
566
+ await network . provider . send ( "evm_mine" ) ;
567
+
504
568
await validatorSetHbbft . setCurrentTimestamp ( startTimeOfNextPhaseTransition ) ;
505
569
const currentTS = await validatorSetHbbft . getCurrentTimestamp ( ) ;
506
570
currentTS . should . be . equal ( startTimeOfNextPhaseTransition ) ;
@@ -510,14 +574,78 @@ async function timeTravelToTransition() {
510
574
async function timeTravelToEndEpoch ( ) {
511
575
512
576
const endTimeOfCurrentEpoch = await stakingHbbft . stakingFixedEpochEndTime ( ) ;
577
+ await network . provider . send ( "evm_setNextBlockTimestamp" , [ endTimeOfCurrentEpoch . toNumber ( ) ] ) ;
578
+ await network . provider . send ( "evm_mine" ) ;
513
579
await validatorSetHbbft . setCurrentTimestamp ( endTimeOfCurrentEpoch ) ;
514
580
await callReward ( true ) ;
515
581
}
516
582
517
583
async function finishEpochPrelim ( _percentage : BigNumber ) {
518
584
const epochDuration = ( await stakingHbbft . stakingFixedEpochEndTime ( ) ) . sub ( ( await stakingHbbft . stakingEpochStartTime ( ) ) ) . mul ( _percentage ) . div ( 100 ) . add ( 1 ) ;
519
585
const endTimeOfCurrentEpoch = ( await stakingHbbft . stakingEpochStartTime ( ) ) . add ( epochDuration ) ;
586
+ await network . provider . send ( "evm_setNextBlockTimestamp" , [ endTimeOfCurrentEpoch . toNumber ( ) ] ) ;
587
+ await network . provider . send ( "evm_mine" ) ;
520
588
await validatorSetHbbft . setCurrentTimestamp ( endTimeOfCurrentEpoch ) ;
521
- _percentage = await blockRewardHbbft . epochPercentage ( ) ;
589
+ // _percentage = await blockRewardHbbft.epochPercentage();
522
590
await callReward ( true ) ;
523
591
}
592
+
593
+ async function announceAvailability ( pool : string ) {
594
+ const blockNumber = await ethers . provider . getBlockNumber ( )
595
+ const block = await ethers . provider . getBlock ( blockNumber ) ;
596
+ const asEncoded = validatorSetHbbft . interface . encodeFunctionData ( "announceAvailability" , [ blockNumber , block . hash ] ) ;
597
+
598
+ // we know now, that this call is allowed.
599
+ // so we can execute it.
600
+ await ( await ethers . getSigner ( pool ) ) . sendTransaction ( { to : validatorSetHbbft . address , data : asEncoded } ) ;
601
+ }
602
+
603
+ async function mine ( ) {
604
+ let expectedEpochDuration = ( await stakingHbbft
605
+ . stakingFixedEpochEndTime ( ) ) . sub ( await stakingHbbft . stakingEpochStartTime ( ) ) ;
606
+ let blocktime = expectedEpochDuration . mul ( 5 ) . div ( 100 ) . add ( 1 ) ; //5% of the epoch
607
+ // let blocksPerEpoch = 60 * 60 * 12 / blocktime;
608
+ await network . provider . send ( "evm_increaseTime" , [ blocktime . toNumber ( ) ] ) ;
609
+ await validatorSetHbbft . setCurrentTimestamp ( ( await validatorSetHbbft . getCurrentTimestamp ( ) ) . add ( blocktime ) ) ;
610
+ if ( ( await validatorSetHbbft . getPendingValidators ( ) ) . length > 0 ) {
611
+ const currentValidators = await validatorSetHbbft . getValidators ( ) ;
612
+ const maxValidators = await validatorSetHbbft . maxValidators ( ) ;
613
+ stakingEpoch = await stakingHbbft . stakingEpoch ( ) ;
614
+
615
+ const initialGovernancePotBalance = await getCurrentGovernancePotValue ( ) ;
616
+ let deltaPotValue = await blockRewardHbbft . deltaPot ( ) ;
617
+ let reinsertPotValue = await blockRewardHbbft . reinsertPot ( ) ;
618
+ let _epochPercentage = await blockRewardHbbft . epochPercentage ( ) ;
619
+
620
+ await callReward ( true ) ;
621
+
622
+ const currentGovernancePotBalance = await getCurrentGovernancePotValue ( ) ;
623
+ const governancePotIncrease = currentGovernancePotBalance . sub ( initialGovernancePotBalance ) ;
624
+
625
+
626
+ const deltaPotShare = deltaPotValue . mul ( BigNumber . from ( currentValidators . length ) ) . mul ( _epochPercentage ) . div ( BigNumber . from ( '6000' ) ) . div ( maxValidators ) . div ( 100 ) ;
627
+ const reinsertPotShare = reinsertPotValue . mul ( BigNumber . from ( currentValidators . length ) ) . mul ( _epochPercentage ) . div ( BigNumber . from ( '6000' ) ) . div ( maxValidators ) . div ( 100 ) ;
628
+ const nativeRewardUndistributed = await blockRewardHbbft . nativeRewardUndistributed ( ) ;
629
+
630
+ const totalReward = deltaPotShare . add ( reinsertPotShare ) . add ( nativeRewardUndistributed ) ;
631
+ const expectedDAOShare = totalReward . div ( BigNumber . from ( '10' ) ) ;
632
+
633
+ // we expect 1 wei difference, since the reward combination from 2 pots results in that.
634
+ //expectedDAOShare.sub(governancePotIncrease).should.to.be.bignumber.lte(BigNumber.from('1'));
635
+ governancePotIncrease . should . to . be . closeTo ( expectedDAOShare , expectedDAOShare . div ( 10000 ) ) ;
636
+
637
+ //since there are a lot of delegators, we need to calc it on a basis that pays out the validator min reward.
638
+ let minValidatorSharePercent = 100 ;
639
+ ///first 4 validators have delegators so they receive less DMD
640
+ if ( currentValidators . length < 4 ) {
641
+ minValidatorSharePercent = 30 ;
642
+ }
643
+
644
+ const expectedValidatorReward = totalReward . sub ( expectedDAOShare ) . div ( BigNumber . from ( currentValidators . length ) ) . mul ( minValidatorSharePercent ) . div ( BigNumber . from ( '100' ) ) ;
645
+ const actualValidatorReward = await blockRewardHbbft . getValidatorReward ( stakingEpoch , currentValidators [ currentValidators . length - 1 ] ) ;
646
+
647
+ actualValidatorReward . should . be . closeTo ( expectedValidatorReward , expectedValidatorReward . div ( 10000 ) ) ;
648
+ } else {
649
+ await callReward ( false ) ;
650
+ }
651
+ }
0 commit comments