@@ -43,6 +43,10 @@ func poisonValidationSlot(st *state.State, contract thor.Address, id thor.Addres
4343 st .SetRawStorage (contract , slot , rlp.RawValue {0xFF })
4444}
4545
46+ func poisonQueueSlot (st * state.State , contract thor.Address ) {
47+ st .SetRawStorage (contract , slotQueuedGroupSize , rlp.RawValue {0xFF })
48+ }
49+
4650func TestService_SetGetValidation_RoundTrip (t * testing.T ) {
4751 svc , _ , _ := newSvc ()
4852
@@ -630,3 +634,220 @@ func TestService_GetCompletedPeriods(t *testing.T) {
630634 assert .NoError (t , err )
631635 assert .Equal (t , uint32 (0 ), periods )
632636}
637+
638+ func TestService_GetQueuedAndLeaderGroups (t * testing.T ) {
639+ svc , _ , _ := newSvc ()
640+
641+ a1 := thor .BytesToAddress ([]byte ("a1" ))
642+ a2 := thor .BytesToAddress ([]byte ("a2" ))
643+ a3 := thor .BytesToAddress ([]byte ("a3" ))
644+ for _ , id := range []thor.Address {a1 , a2 , a3 } {
645+ assert .NoError (t , svc .Add (id , id , thor .LowStakingPeriod (), big .NewInt (1 )))
646+ }
647+
648+ queuedCnt , err := svc .QueuedGroupSize ()
649+ assert .NoError (t , err )
650+ assert .Equal (t , big .NewInt (3 ), queuedCnt )
651+
652+ leaderCnt , err := svc .LeaderGroupSize ()
653+ assert .NoError (t , err )
654+ assert .Equal (t , big .NewInt (0 ).String (), leaderCnt .String ())
655+
656+ idPtr , err := svc .NextToActivate (big .NewInt (10 ))
657+ assert .NoError (t , err )
658+ assert .Equal (t , a1 , * idPtr )
659+ _ , err = svc .ActivateValidator (* idPtr , 1 , & delta.Renewal {NewLockedWeight : big .NewInt (0 )})
660+ assert .NoError (t , err )
661+
662+ queuedCnt , err = svc .QueuedGroupSize ()
663+ assert .NoError (t , err )
664+ assert .Equal (t , big .NewInt (2 ), queuedCnt )
665+
666+ leaderCnt , err = svc .LeaderGroupSize ()
667+ assert .NoError (t , err )
668+ assert .Equal (t , big .NewInt (1 ), leaderCnt )
669+
670+ val , err := svc .GetLeaderGroupHead ()
671+ assert .NoError (t , err )
672+ assert .Equal (t , a1 , val .Endorser )
673+ assert .Nil (t , val .Beneficiary )
674+ assert .Equal (t , big .NewInt (1 ), val .LockedVET )
675+ assert .Equal (t , big .NewInt (1 ), val .Weight )
676+ assert .Equal (t , thor .LowStakingPeriod (), val .Period )
677+ assert .Equal (t , uint32 (0 ), val .CompleteIterations )
678+ assert .Equal (t , StatusActive , val .Status )
679+ assert .Equal (t , uint32 (1 ), val .StartBlock )
680+ assert .Nil (t , val .ExitBlock )
681+ assert .Nil (t , val .OfflineBlock )
682+ assert .Equal (t , big .NewInt (0 ), val .PendingUnlockVET )
683+ assert .Equal (t , big .NewInt (0 ), val .QueuedVET )
684+ assert .Equal (t , big .NewInt (0 ), val .CooldownVET )
685+ assert .Equal (t , big .NewInt (0 ), val .WithdrawableVET )
686+ }
687+
688+ func TestService_Add_Error (t * testing.T ) {
689+ svc , addr , st := newSvc ()
690+ id1 := thor .BytesToAddress ([]byte ("id1" ))
691+ id2 := thor .BytesToAddress ([]byte ("id2" ))
692+
693+ assert .ErrorContains (t , svc .Add (id1 , id1 , uint32 (1 ), big .NewInt (1 )), "period is out of boundaries" )
694+ assert .ErrorContains (t , svc .Add (id1 , id1 , thor .LowStakingPeriod (), big .NewInt (0 )), "stake is out of range" )
695+ assert .NoError (t , svc .Add (id1 , id1 , thor .LowStakingPeriod (), big .NewInt (1 )))
696+ assert .ErrorContains (t , svc .Add (id1 , id1 , thor .LowStakingPeriod (), big .NewInt (1 )), "validator already exists" )
697+
698+ poisonValidationSlot (st , addr , id1 )
699+ assert .Error (t , svc .Add (id1 , id1 , thor .LowStakingPeriod (), big .NewInt (1 )))
700+
701+ slot := thor .Blake2b (id1 .Bytes (), slotValidations .Bytes ())
702+ st .SetRawStorage (addr , slot , rlp.RawValue {0x0 })
703+ poisonQueueSlot (st , addr )
704+ assert .Error (t , svc .Add (id2 , id2 , thor .LowStakingPeriod (), big .NewInt (1 )))
705+ }
706+
707+ func TestService_Evict (t * testing.T ) {
708+ svc , addr , st := newSvc ()
709+ id1 := thor .BytesToAddress ([]byte ("id1" ))
710+
711+ assert .NoError (t , svc .Add (id1 , id1 , thor .LowStakingPeriod (), big .NewInt (1 )))
712+
713+ assert .NoError (t , svc .Evict (id1 , 5 ))
714+ val , err := svc .GetValidation (id1 )
715+ assert .NoError (t , err )
716+ expectedExitBlock := uint32 (5 ) + thor .EpochLength ()
717+ assert .Equal (t , & expectedExitBlock , val .ExitBlock )
718+
719+ assert .NoError (t , svc .Evict (id1 , 7 ))
720+ val , err = svc .GetValidation (id1 )
721+ assert .NoError (t , err )
722+ assert .Equal (t , & expectedExitBlock , val .ExitBlock )
723+
724+ poisonExitSlot (st , addr , 7 + thor .EpochLength ())
725+ assert .Error (t , svc .Evict (id1 , 7 ))
726+
727+ poisonValidationSlot (st , addr , id1 )
728+ assert .Error (t , svc .Evict (id1 , 8 ))
729+ }
730+
731+ func TestService_SetBeneficiary (t * testing.T ) {
732+ svc , addr , st := newSvc ()
733+ id1 := thor .BytesToAddress ([]byte ("id1" ))
734+ assert .NoError (t , svc .Add (id1 , id1 , thor .LowStakingPeriod (), big .NewInt (1 )))
735+
736+ val , err := svc .GetValidation (id1 )
737+ assert .NoError (t , err )
738+ assert .Nil (t , val .Beneficiary )
739+
740+ assert .NoError (t , svc .SetBeneficiary (id1 , id1 , id1 ))
741+ val , err = svc .GetValidation (id1 )
742+ assert .NoError (t , err )
743+ assert .Equal (t , & id1 , val .Beneficiary )
744+
745+ assert .NoError (t , svc .SetBeneficiary (id1 , id1 , thor.Address {}))
746+ val , err = svc .GetValidation (id1 )
747+ assert .NoError (t , err )
748+ assert .Nil (t , val .Beneficiary )
749+
750+ assert .ErrorContains (t , svc .SetBeneficiary (id1 , thor.Address {}, id1 ), "invalid endorser" )
751+ assert .NoError (t , svc .Evict (id1 , 2 ))
752+ assert .ErrorContains (t , svc .SetBeneficiary (id1 , id1 , id1 ), "validator has exited or signaled exit, cannot set beneficiary" )
753+
754+ poisonValidationSlot (st , addr , id1 )
755+ assert .Error (t , svc .SetBeneficiary (id1 , id1 , id1 ))
756+ }
757+
758+ func TestService_UpdateOfflineBlock (t * testing.T ) {
759+ svc , _ , _ := newSvc ()
760+
761+ id1 := thor .BytesToAddress ([]byte ("id1" ))
762+ assert .NoError (t , svc .Add (id1 , id1 , thor .LowStakingPeriod (), big .NewInt (1 )))
763+
764+ val , err := svc .GetValidation (id1 )
765+ assert .NoError (t , err )
766+ assert .Nil (t , val .OfflineBlock )
767+
768+ assert .NoError (t , svc .UpdateOfflineBlock (id1 , 2 , false ))
769+
770+ expectedOfflineBlk := uint32 (2 )
771+ val , err = svc .GetValidation (id1 )
772+ assert .NoError (t , err )
773+ assert .Equal (t , & expectedOfflineBlk , val .OfflineBlock )
774+
775+ assert .NoError (t , svc .UpdateOfflineBlock (id1 , 2 , true ))
776+
777+ val , err = svc .GetValidation (id1 )
778+ assert .NoError (t , err )
779+ assert .Nil (t , val .OfflineBlock )
780+ }
781+
782+ func TestService_Renew (t * testing.T ) {
783+ svc , _ , _ := newSvc ()
784+
785+ id1 := thor .BytesToAddress ([]byte ("id1" ))
786+ assert .NoError (t , svc .Add (id1 , id1 , thor .LowStakingPeriod (), big .NewInt (50 )))
787+
788+ err := svc .IncreaseStake (id1 , id1 , big .NewInt (600 ))
789+ assert .NoError (t , err )
790+ _ , err = svc .DecreaseStake (id1 , id1 , big .NewInt (300 ))
791+ assert .NoError (t , err )
792+
793+ val , err := svc .GetValidation (id1 )
794+ assert .NoError (t , err )
795+ assert .Equal (t , big .NewInt (0 ), val .LockedVET )
796+ assert .Equal (t , big .NewInt (0 ), val .Weight )
797+ assert .Equal (t , big .NewInt (0 ), val .PendingUnlockVET )
798+ assert .Equal (t , big .NewInt (350 ), val .QueuedVET )
799+ assert .Equal (t , big .NewInt (0 ), val .CooldownVET )
800+ assert .Equal (t , big .NewInt (300 ), val .WithdrawableVET )
801+
802+ renewal := delta.Renewal {
803+ NewLockedVET : big .NewInt (1000 ),
804+ NewLockedWeight : big .NewInt (1500 ),
805+ QueuedDecrease : big .NewInt (100 ),
806+ QueuedDecreaseWeight : big .NewInt (15 ),
807+ }
808+ delta , err := svc .Renew (id1 , & renewal , false )
809+ assert .NoError (t , err )
810+ assert .Equal (t , big .NewInt (350 ), delta .NewLockedVET )
811+ assert .Equal (t , big .NewInt (350 ), delta .NewLockedWeight )
812+ assert .Equal (t , big .NewInt (350 ), delta .QueuedDecrease )
813+ assert .Equal (t , big .NewInt (350 ), delta .QueuedDecreaseWeight )
814+
815+ val , err = svc .GetValidation (id1 )
816+ assert .NoError (t , err )
817+ assert .Equal (t , big .NewInt (350 ), val .LockedVET )
818+ assert .Equal (t , big .NewInt (1850 ), val .Weight )
819+ assert .Equal (t , big .NewInt (0 ), val .PendingUnlockVET )
820+ assert .Equal (t , big .NewInt (0 ), val .QueuedVET )
821+ assert .Equal (t , big .NewInt (0 ), val .CooldownVET )
822+ assert .Equal (t , big .NewInt (300 ), val .WithdrawableVET )
823+
824+ err = svc .IncreaseStake (id1 , id1 , big .NewInt (400 ))
825+ assert .NoError (t , err )
826+ _ , err = svc .DecreaseStake (id1 , id1 , big .NewInt (200 ))
827+ assert .NoError (t , err )
828+
829+ val , err = svc .GetValidation (id1 )
830+ assert .NoError (t , err )
831+ assert .Equal (t , big .NewInt (350 ), val .LockedVET )
832+ assert .Equal (t , big .NewInt (1850 ), val .Weight )
833+ assert .Equal (t , big .NewInt (0 ), val .PendingUnlockVET )
834+ assert .Equal (t , big .NewInt (200 ), val .QueuedVET )
835+ assert .Equal (t , big .NewInt (0 ), val .CooldownVET )
836+ assert .Equal (t , big .NewInt (500 ), val .WithdrawableVET )
837+
838+ delta , err = svc .Renew (id1 , & renewal , true )
839+ assert .NoError (t , err )
840+ assert .Equal (t , big .NewInt (200 ), delta .NewLockedVET )
841+ assert .Equal (t , big .NewInt (200 ), delta .NewLockedWeight )
842+ assert .Equal (t , big .NewInt (200 ), delta .QueuedDecrease )
843+ assert .Equal (t , big .NewInt (200 ), delta .QueuedDecreaseWeight )
844+
845+ val , err = svc .GetValidation (id1 )
846+ assert .NoError (t , err )
847+ assert .Equal (t , big .NewInt (550 ), val .LockedVET )
848+ assert .Equal (t , big .NewInt (3550 ), val .Weight )
849+ assert .Equal (t , big .NewInt (0 ), val .PendingUnlockVET )
850+ assert .Equal (t , big .NewInt (0 ), val .QueuedVET )
851+ assert .Equal (t , big .NewInt (0 ), val .CooldownVET )
852+ assert .Equal (t , big .NewInt (500 ), val .WithdrawableVET )
853+ }
0 commit comments