github.com/lino-network/lino@v0.6.11/x/validator/manager/manager.go (about) 1 package manager 2 3 import ( 4 "fmt" 5 "math" 6 "reflect" 7 8 codec "github.com/cosmos/cosmos-sdk/codec" 9 sdk "github.com/cosmos/cosmos-sdk/types" 10 abci "github.com/tendermint/tendermint/abci/types" 11 crypto "github.com/tendermint/tendermint/crypto" 12 tmtypes "github.com/tendermint/tendermint/types" 13 14 "github.com/lino-network/lino/param" 15 linotypes "github.com/lino-network/lino/types" 16 "github.com/lino-network/lino/utils" 17 acc "github.com/lino-network/lino/x/account" 18 "github.com/lino-network/lino/x/global" 19 "github.com/lino-network/lino/x/validator/model" 20 "github.com/lino-network/lino/x/validator/types" 21 "github.com/lino-network/lino/x/vote" 22 votetypes "github.com/lino-network/lino/x/vote/types" 23 ) 24 25 const ( 26 exportVersion = 1 27 importVersion = 1 28 ) 29 30 // ValidatorManager - validator manager 31 type ValidatorManager struct { 32 storage model.ValidatorStorage 33 34 // deps 35 paramHolder param.ParamKeeper 36 vote vote.VoteKeeper 37 global global.GlobalKeeper 38 acc acc.AccountKeeper 39 } 40 41 func NewValidatorManager(key sdk.StoreKey, holder param.ParamKeeper, vote vote.VoteKeeper, 42 global global.GlobalKeeper, acc acc.AccountKeeper) ValidatorManager { 43 return ValidatorManager{ 44 storage: model.NewValidatorStorage(key), 45 paramHolder: holder, 46 vote: vote, 47 global: global, 48 acc: acc, 49 } 50 } 51 52 // InitGenesis - initialize KVStore 53 func (vm ValidatorManager) InitGenesis(ctx sdk.Context) { 54 lst := &model.ValidatorList{ 55 LowestOncallVotes: linotypes.NewCoinFromInt64(0), 56 LowestStandbyVotes: linotypes.NewCoinFromInt64(0), 57 } 58 vm.storage.SetValidatorList(ctx, lst) 59 } 60 61 func (vm ValidatorManager) OnBeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { 62 // update preblock validators 63 validatorList := vm.GetValidatorList(ctx) 64 vals := vm.GetCommittingValidators(ctx) 65 validatorList.PreBlockValidators = vals 66 vm.SetValidatorList(ctx, validatorList) 67 68 // update signing stats. 69 updateErr := vm.updateSigningStats(ctx, req.LastCommitInfo.Votes) 70 if updateErr != nil { 71 panic(updateErr) 72 } 73 74 if err := vm.fireIncompetentValidator(ctx, req.ByzantineValidators); err != nil { 75 panic(err) 76 } 77 78 // grant free votes to lino validators for migration. 79 if ctx.BlockHeight() == linotypes.Upgrade5Update2 { 80 vm.grantFreeVotes(ctx) 81 } 82 } 83 84 func (vm ValidatorManager) grantFreeVotes(ctx sdk.Context) { 85 valNames := []linotypes.AccountKey{ 86 "validator1", 87 "validator2", 88 "validator3", 89 "validator5", 90 "validator7", 91 } 92 votes := make([]*model.ElectionVote, 0) 93 for _, name := range valNames { 94 votes = append(votes, &model.ElectionVote{ 95 ValidatorName: name, 96 Vote: linotypes.NewCoinFromInt64(50 * 1000 * 1000 * linotypes.Decimals), 97 }) 98 } 99 err := vm.updateValidatorReceivedVotes(ctx, votes) 100 if err != nil { 101 ctx.Logger().Error(err.Error()) 102 } 103 } 104 105 func (vm ValidatorManager) UpdateValidator(ctx sdk.Context, username linotypes.AccountKey, link string) sdk.Error { 106 val, err := vm.storage.GetValidator(ctx, username) 107 if err != nil { 108 return err 109 } 110 val.Link = link 111 vm.storage.SetValidator(ctx, username, val) 112 return nil 113 } 114 115 // RegisterValidator - register a validator. 116 func (vm ValidatorManager) RegisterValidator(ctx sdk.Context, username linotypes.AccountKey, valPubKey crypto.PubKey, link string) sdk.Error { 117 lst := vm.storage.GetValidatorList(ctx) 118 if linotypes.FindAccountInList(username, lst.Jail) != -1 { 119 return vm.rejoinFromJail(ctx, username) 120 } 121 122 if vm.IsLegalValidator(ctx, username) { 123 return types.ErrValidatorAlreadyExist() 124 } 125 126 // must be voter duty 127 if duty, err := vm.vote.GetVoterDuty(ctx, username); err != nil || duty != votetypes.DutyVoter { 128 return types.ErrInvalidVoterDuty() 129 } 130 131 param := vm.paramHolder.GetValidatorParam(ctx) 132 133 // assign validator duty in vote 134 if err := vm.vote.AssignDuty(ctx, username, votetypes.DutyValidator, param.ValidatorMinDeposit); err != nil { 135 return err 136 } 137 138 if err := vm.checkDupPubKey(ctx, valPubKey); err != nil { 139 return err 140 } 141 142 // recover data if was revoked: inherite the votes. 143 prevVotes := vm.getPrevVotes(ctx, username) 144 validator := &model.Validator{ 145 ABCIValidator: abci.Validator{ 146 Address: valPubKey.Address(), 147 Power: 0, 148 }, 149 ReceivedVotes: prevVotes, 150 PubKey: valPubKey, 151 Username: username, 152 Link: link, 153 } 154 vm.storage.SetValidator(ctx, username, validator) 155 156 // join as candidate validator first and vote itself 157 if err := vm.addValidatortToCandidateList(ctx, username); err != nil { 158 return err 159 } 160 if err := vm.onCandidateVotesInc(ctx, username); err != nil { 161 return err 162 } 163 if err := vm.VoteValidator(ctx, username, []linotypes.AccountKey{username}); err != nil { 164 return err 165 } 166 167 return nil 168 } 169 170 func (vm ValidatorManager) RevokeValidator(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 171 if !vm.IsLegalValidator(ctx, username) { 172 return types.ErrInvalidValidator() 173 } 174 175 me, err := vm.storage.GetValidator(ctx, username) 176 if err != nil { 177 return err 178 } 179 180 me.HasRevoked = true 181 vm.storage.SetValidator(ctx, username, me) 182 183 if err := vm.removeValidatorFromAllLists(ctx, username); err != nil { 184 return err 185 } 186 if err := vm.balanceValidatorList(ctx); err != nil { 187 return err 188 } 189 190 param := vm.paramHolder.GetValidatorParam(ctx) 191 if err = vm.vote.UnassignDuty(ctx, username, param.ValidatorRevokePendingSec); err != nil { 192 return err 193 } 194 195 return nil 196 } 197 198 func (vm ValidatorManager) VoteValidator(ctx sdk.Context, username linotypes.AccountKey, 199 votedValidators []linotypes.AccountKey) sdk.Error { 200 param := vm.paramHolder.GetValidatorParam(ctx) 201 if int64(len(votedValidators)) > param.MaxVotedValidators { 202 return types.ErrInvalidVotedValidators() 203 } 204 // check if voted validators exist 205 for _, valName := range votedValidators { 206 if !vm.IsLegalValidator(ctx, valName) { 207 return types.ErrValidatorNotFound(valName) 208 } 209 } 210 211 updates, err := vm.getElectionVoteListUpdates(ctx, username, votedValidators) 212 if err != nil { 213 return err 214 } 215 216 if err := vm.updateValidatorReceivedVotes(ctx, updates); err != nil { 217 return err 218 } 219 220 if err := vm.setNewElectionVoteList(ctx, username, votedValidators); err != nil { 221 return err 222 } 223 224 if err := vm.vote.ClaimInterest(ctx, username); err != nil { 225 return err 226 } 227 return nil 228 } 229 230 func (vm ValidatorManager) DistributeInflationToValidator(ctx sdk.Context) sdk.Error { 231 coin, err := vm.acc.GetPool(ctx, linotypes.InflationValidatorPool) 232 if err != nil { 233 return err 234 } 235 param := vm.paramHolder.GetValidatorParam(ctx) 236 lst := vm.storage.GetValidatorList(ctx) 237 totalWeight := int64(len(lst.Oncall))*param.OncallInflationWeight + 238 int64(len(lst.Standby))*param.StandbyInflationWeight 239 index := int64(0) 240 // give inflation to each validator according it's weight 241 for _, oncall := range lst.Oncall { 242 ratPerOncall := coin.ToDec().Mul(sdk.NewDec(param.OncallInflationWeight)).Quo(sdk.NewDec(totalWeight - index)) 243 err := vm.acc.MoveFromPool(ctx, linotypes.InflationValidatorPool, 244 linotypes.NewAccOrAddrFromAcc(oncall), 245 linotypes.DecToCoin(ratPerOncall)) 246 if err != nil { 247 return err 248 } 249 coin = coin.Minus(linotypes.DecToCoin(ratPerOncall)) 250 index += param.OncallInflationWeight 251 } 252 253 for _, standby := range lst.Standby { 254 ratPerStandby := coin.ToDec().Mul(sdk.NewDec(param.StandbyInflationWeight)).Quo(sdk.NewDec(totalWeight - index)) 255 err := vm.acc.MoveFromPool(ctx, linotypes.InflationValidatorPool, 256 linotypes.NewAccOrAddrFromAcc(standby), 257 linotypes.DecToCoin(ratPerStandby)) 258 if err != nil { 259 return err 260 } 261 coin = coin.Minus(linotypes.DecToCoin(ratPerStandby)) 262 index += param.StandbyInflationWeight 263 } 264 return nil 265 } 266 267 func (vm ValidatorManager) rejoinFromJail(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 268 param := vm.paramHolder.GetValidatorParam(ctx) 269 totalStake, err := vm.vote.GetLinoStake(ctx, username) 270 if err != nil { 271 return err 272 } 273 274 if !totalStake.IsGTE(param.ValidatorMinDeposit) { 275 return types.ErrInsufficientDeposit() 276 } 277 278 vm.removeValidatorFromJailList(ctx, username) 279 if err := vm.addValidatortToCandidateList(ctx, username); err != nil { 280 return err 281 } 282 if err := vm.onCandidateVotesInc(ctx, username); err != nil { 283 return err 284 } 285 return nil 286 } 287 288 // calculate the changed votes between current election votes and previous election votes 289 // negative number means the corresponding validator need to decrease it's received votes 290 // positive number means the corresponding validator need to increase it's received votes 291 func (vm ValidatorManager) getElectionVoteListUpdates(ctx sdk.Context, username linotypes.AccountKey, 292 votedValidators []linotypes.AccountKey) ([]*model.ElectionVote, sdk.Error) { 293 res := []*model.ElectionVote{} 294 prevList := vm.storage.GetElectionVoteList(ctx, username) 295 totalStake, err := vm.vote.GetLinoStake(ctx, username) 296 if err != nil { 297 return nil, err 298 } 299 300 if len(prevList.ElectionVotes) == 0 && len(votedValidators) == 0 { 301 return nil, nil 302 } 303 if len(votedValidators) == 0 { 304 return nil, types.ErrInvalidVotedValidators() 305 } 306 307 voteStake := linotypes.DecToCoin( 308 totalStake.ToDec().Quo(sdk.NewDec(int64(len(votedValidators))))) 309 310 // add all old votes into res set first and default all votes are negative (not in the new list) 311 for _, oldVote := range prevList.ElectionVotes { 312 changeDec := oldVote.Vote.Neg() 313 res = append(res, &model.ElectionVote{ 314 ValidatorName: oldVote.ValidatorName, 315 Vote: changeDec, 316 }) 317 } 318 319 // a helper function to return the pointer to the matching ElectionVote. 320 findInPrev := func(valName linotypes.AccountKey) *model.ElectionVote { 321 for _, oldVote := range res { 322 if oldVote.ValidatorName == valName { 323 return oldVote 324 } 325 } 326 return nil 327 } 328 329 for _, validatorName := range votedValidators { 330 if prev := findInPrev(validatorName); prev != nil { 331 prev.Vote = prev.Vote.Plus(voteStake) 332 } else { 333 res = append(res, &model.ElectionVote{ 334 ValidatorName: validatorName, 335 Vote: voteStake, 336 }) 337 } 338 } 339 return res, nil 340 } 341 342 func (vm ValidatorManager) updateValidatorReceivedVotes(ctx sdk.Context, updates []*model.ElectionVote) sdk.Error { 343 for _, update := range updates { 344 lst := vm.storage.GetValidatorList(ctx) 345 if update.Vote.IsZero() { 346 continue 347 } 348 349 // revoked validator's record will still be in kv. 350 validator, err := vm.storage.GetValidator(ctx, update.ValidatorName) 351 if err != nil { 352 return err 353 } 354 validator.ReceivedVotes = validator.ReceivedVotes.Plus(update.Vote) 355 vm.storage.SetValidator(ctx, update.ValidatorName, validator) 356 357 // the corresponding validator's received votes increase 358 if update.Vote.IsPositive() { 359 if linotypes.FindAccountInList(update.ValidatorName, lst.Oncall) != -1 { 360 if err := vm.onOncallVotesInc(ctx, update.ValidatorName); err != nil { 361 return err 362 } 363 } 364 if linotypes.FindAccountInList(update.ValidatorName, lst.Standby) != -1 { 365 if err := vm.onStandbyVotesInc(ctx, update.ValidatorName); err != nil { 366 return err 367 } 368 } 369 if linotypes.FindAccountInList(update.ValidatorName, lst.Candidates) != -1 { 370 if err := vm.onCandidateVotesInc(ctx, update.ValidatorName); err != nil { 371 return err 372 } 373 } 374 } else { 375 // the corresponding validator's received votes decrease 376 if linotypes.FindAccountInList(update.ValidatorName, lst.Oncall) != -1 { 377 if err := vm.onOncallVotesDec(ctx, update.ValidatorName); err != nil { 378 return err 379 } 380 } 381 if linotypes.FindAccountInList(update.ValidatorName, lst.Standby) != -1 { 382 if err := vm.onStandbyVotesDec(ctx, update.ValidatorName); err != nil { 383 return err 384 } 385 } 386 } 387 } 388 389 return nil 390 } 391 392 func (vm ValidatorManager) setNewElectionVoteList(ctx sdk.Context, username linotypes.AccountKey, 393 votedValidators []linotypes.AccountKey) sdk.Error { 394 if len(votedValidators) == 0 { 395 return nil 396 } 397 lst := &model.ElectionVoteList{} 398 totalStake, err := vm.vote.GetLinoStake(ctx, username) 399 if err != nil { 400 return err 401 } 402 403 voteStakeDec := totalStake.ToDec().Quo(sdk.NewDec(int64(len(votedValidators)))) 404 for _, validatorName := range votedValidators { 405 electionVote := model.ElectionVote{ 406 ValidatorName: validatorName, 407 Vote: linotypes.DecToCoin(voteStakeDec), 408 } 409 lst.ElectionVotes = append(lst.ElectionVotes, electionVote) 410 } 411 412 vm.storage.SetElectionVoteList(ctx, username, lst) 413 return nil 414 } 415 416 // IsLegalValidator - check if the validator is a validator and not revoked. 417 func (vm ValidatorManager) IsLegalValidator(ctx sdk.Context, accKey linotypes.AccountKey) bool { 418 val, err := vm.storage.GetValidator(ctx, accKey) 419 if err != nil { 420 return false 421 } 422 return !val.HasRevoked 423 } 424 425 // GetInitValidators return all validators in state. 426 // XXX(yumin): This is intended to be used only in initChainer 427 func (vm ValidatorManager) GetInitValidators(ctx sdk.Context) ([]abci.ValidatorUpdate, sdk.Error) { 428 committingValidators := vm.GetCommittingValidators(ctx) 429 updates := []abci.ValidatorUpdate{} 430 for _, curValidator := range committingValidators { 431 validator, err := vm.storage.GetValidator(ctx, curValidator) 432 if err != nil { 433 return nil, err 434 } 435 updates = append(updates, abci.ValidatorUpdate{ 436 PubKey: tmtypes.TM2PB.PubKey(validator.PubKey), 437 Power: validator.ABCIValidator.Power, 438 }) 439 } 440 return updates, nil 441 } 442 443 // GetValidatorUpdates - after a block, compare updated validator set with 444 // recorded validator set before block execution 445 func (vm ValidatorManager) GetValidatorUpdates(ctx sdk.Context) ([]abci.ValidatorUpdate, sdk.Error) { 446 validatorList := vm.storage.GetValidatorList(ctx) 447 updates := []abci.ValidatorUpdate{} 448 committingValidators := vm.GetCommittingValidators(ctx) 449 committingSet := linotypes.AccountListToSet(committingValidators) 450 451 for _, preValidator := range validatorList.PreBlockValidators { 452 // set power to 0 if a previous validator not in oncall and standby list anymore 453 if committingSet[preValidator] == false { 454 validator, err := vm.storage.GetValidator(ctx, preValidator) 455 if err != nil { 456 return nil, err 457 } 458 updates = append(updates, abci.ValidatorUpdate{ 459 PubKey: tmtypes.TM2PB.PubKey(validator.PubKey), 460 Power: 0, 461 }) 462 } 463 } 464 465 for _, curValidator := range committingValidators { 466 validator, err := vm.storage.GetValidator(ctx, curValidator) 467 if err != nil { 468 return nil, err 469 } 470 471 updates = append(updates, abci.ValidatorUpdate{ 472 PubKey: tmtypes.TM2PB.PubKey(validator.PubKey), 473 Power: validator.ABCIValidator.Power, 474 }) 475 476 } 477 return updates, nil 478 } 479 480 // UpdateSigningStats - based on info in beginBlocker, record last block singing info 481 func (vm ValidatorManager) updateSigningStats(ctx sdk.Context, voteInfos []abci.VoteInfo) sdk.Error { 482 // map address to whether that validator has signed. 483 addressSigned := make(map[string]bool) 484 for _, voteInfo := range voteInfos { 485 addressSigned[string(voteInfo.Validator.Address)] = voteInfo.SignedLastBlock 486 } 487 488 // go through oncall and standby validator list to get all address and name mapping 489 committingValidators := vm.GetCommittingValidators(ctx) 490 for _, curValidator := range committingValidators { 491 validator, err := vm.storage.GetValidator(ctx, curValidator) 492 if err != nil { 493 return err 494 } 495 signed, exist := addressSigned[string(validator.ABCIValidator.Address)] 496 if !exist || !signed { 497 validator.AbsentCommit++ 498 } else { 499 validator.ProducedBlocks++ 500 if validator.AbsentCommit > 0 { 501 validator.AbsentCommit-- 502 } 503 } 504 vm.storage.SetValidator(ctx, curValidator, validator) 505 } 506 507 return nil 508 } 509 510 // PunishOncallValidator - punish committing validator 511 // if 1) byzantine or 2) missing blocks reach limiation 512 func (vm ValidatorManager) PunishCommittingValidator(ctx sdk.Context, username linotypes.AccountKey, 513 penalty linotypes.Coin, punishType linotypes.PunishType) sdk.Error { 514 // slash and add slashed coin back into validator inflation pool 515 _, err := vm.vote.SlashStake(ctx, username, penalty, linotypes.InflationValidatorPool) 516 if err != nil { 517 return err 518 } 519 validator, err := vm.storage.GetValidator(ctx, username) 520 if err != nil { 521 return err 522 } 523 validator.NumSlash++ 524 // reset absent commit 525 if punishType == linotypes.PunishAbsentCommit { 526 validator.AbsentCommit = 0 527 } 528 vm.storage.SetValidator(ctx, username, validator) 529 530 totalStake, err := vm.vote.GetLinoStake(ctx, username) 531 if err != nil { 532 return err 533 } 534 // remove this validator and put into jail if its remaining stake is not enough 535 // OR, this is byzantine validator 536 // OR, the num of slash exceeds limit 537 param := vm.paramHolder.GetValidatorParam(ctx) 538 if punishType == linotypes.PunishByzantine || 539 !totalStake.IsGTE(param.ValidatorMinDeposit) || 540 validator.NumSlash > param.SlashLimitation { 541 if err := vm.removeValidatorFromAllLists(ctx, username); err != nil { 542 return err 543 } 544 if err := vm.addValidatortToJailList(ctx, username); err != nil { 545 return err 546 } 547 if err := vm.balanceValidatorList(ctx); err != nil { 548 return err 549 } 550 } 551 552 return nil 553 } 554 555 // FireIncompetentValidator - fire oncall validator if 556 // 1. absent commit > absent limitation. 557 // 2. byzantine 558 func (vm ValidatorManager) fireIncompetentValidator(ctx sdk.Context, 559 byzantineValidators []abci.Evidence) sdk.Error { 560 param := vm.paramHolder.GetValidatorParam(ctx) 561 committingValidators := vm.GetCommittingValidators(ctx) 562 563 for _, validatorName := range committingValidators { 564 validator, err := vm.storage.GetValidator(ctx, validatorName) 565 if err != nil { 566 return err 567 } 568 569 for _, evidence := range byzantineValidators { 570 if reflect.DeepEqual(validator.ABCIValidator.Address, evidence.Validator.Address) { 571 if err := vm.PunishCommittingValidator(ctx, validator.Username, param.PenaltyByzantine, 572 linotypes.PunishByzantine); err != nil { 573 return err 574 } 575 break 576 } 577 } 578 579 if validator.AbsentCommit > param.AbsentCommitLimitation { 580 if err := vm.PunishCommittingValidator(ctx, validator.Username, param.PenaltyMissCommit, 581 linotypes.PunishAbsentCommit); err != nil { 582 return err 583 } 584 } 585 } 586 587 return nil 588 } 589 590 func (vm ValidatorManager) checkDupPubKey(ctx sdk.Context, pubKey crypto.PubKey) sdk.Error { 591 // make sure the pub key has not been registered 592 allValidators := vm.GetAllValidators(ctx) 593 for _, validatorName := range allValidators { 594 validator, err := vm.storage.GetValidator(ctx, validatorName) 595 if err != nil { 596 return err 597 } 598 if reflect.DeepEqual(validator.ABCIValidator.Address, pubKey.Address().Bytes()) { 599 return types.ErrValidatorPubKeyAlreadyExist() 600 } 601 } 602 603 return nil 604 } 605 606 func (vm ValidatorManager) onStakeChange(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 607 lst := vm.storage.GetElectionVoteList(ctx, username) 608 oldList := []linotypes.AccountKey{} 609 for _, electionVote := range lst.ElectionVotes { 610 oldList = append(oldList, electionVote.ValidatorName) 611 } 612 613 updates, err := vm.getElectionVoteListUpdates(ctx, username, oldList) 614 if err != nil { 615 return err 616 } 617 618 if err := vm.updateValidatorReceivedVotes(ctx, updates); err != nil { 619 return err 620 } 621 622 if err := vm.setNewElectionVoteList(ctx, username, oldList); err != nil { 623 return err 624 } 625 return nil 626 } 627 628 func (vm ValidatorManager) onCandidateVotesInc(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 629 me, err := vm.GetValidator(ctx, username) 630 if err != nil { 631 return err 632 } 633 634 lst := vm.GetValidatorList(ctx) 635 if me.ReceivedVotes.IsGT(lst.LowestOncallVotes) { 636 // join the oncall validator list 637 vm.removeValidatorFromCandidateList(ctx, username) 638 if err := vm.addValidatortToOncallList(ctx, username); err != nil { 639 return err 640 } 641 } else if me.ReceivedVotes.IsGT(lst.LowestStandbyVotes) { 642 // join the standby validator list 643 vm.removeValidatorFromCandidateList(ctx, username) 644 if err := vm.addValidatortToStandbyList(ctx, username); err != nil { 645 return err 646 } 647 } 648 649 if err := vm.balanceValidatorList(ctx); err != nil { 650 return err 651 } 652 return nil 653 } 654 655 func (vm ValidatorManager) onStandbyVotesInc(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 656 me, err := vm.GetValidator(ctx, username) 657 if err != nil { 658 return err 659 } 660 661 // join the oncall validator list 662 lst := vm.GetValidatorList(ctx) 663 if me.ReceivedVotes.IsGT(lst.LowestOncallVotes) { 664 vm.removeValidatorFromStandbyList(ctx, username) 665 if err := vm.addValidatortToOncallList(ctx, username); err != nil { 666 return err 667 } 668 } 669 if err := vm.balanceValidatorList(ctx); err != nil { 670 return err 671 } 672 return nil 673 } 674 675 func (vm ValidatorManager) onOncallVotesInc(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 676 if err := vm.setOncallValidatorPower(ctx, username); err != nil { 677 return err 678 } 679 if err := vm.balanceValidatorList(ctx); err != nil { 680 return err 681 } 682 return nil 683 } 684 685 func (vm ValidatorManager) onStandbyVotesDec(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 686 lst := vm.GetValidatorList(ctx) 687 validator, err := vm.GetValidator(ctx, username) 688 if err != nil { 689 return err 690 } 691 692 if !validator.ReceivedVotes.IsGTE(lst.LowestStandbyVotes) { 693 vm.removeValidatorFromStandbyList(ctx, username) 694 if err := vm.addValidatortToCandidateList(ctx, username); err != nil { 695 return err 696 } 697 } 698 699 if err := vm.balanceValidatorList(ctx); err != nil { 700 return err 701 } 702 return nil 703 } 704 705 func (vm ValidatorManager) onOncallVotesDec(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 706 if err := vm.setOncallValidatorPower(ctx, username); err != nil { 707 return err 708 } 709 710 lst := vm.GetValidatorList(ctx) 711 validator, err := vm.GetValidator(ctx, username) 712 if err != nil { 713 return err 714 } 715 716 if !validator.ReceivedVotes.IsGTE(lst.LowestStandbyVotes) { 717 // move to the candidate validator list 718 vm.removeValidatorFromOncallList(ctx, username) 719 if err := vm.addValidatortToCandidateList(ctx, username); err != nil { 720 return err 721 } 722 } else if !validator.ReceivedVotes.IsGTE(lst.LowestOncallVotes) { 723 // move to the standby validator list 724 vm.removeValidatorFromOncallList(ctx, username) 725 if err := vm.addValidatortToStandbyList(ctx, username); err != nil { 726 return err 727 } 728 } 729 if err := vm.balanceValidatorList(ctx); err != nil { 730 return err 731 } 732 return nil 733 } 734 735 func (vm ValidatorManager) balanceValidatorList(ctx sdk.Context) sdk.Error { 736 if err := vm.removeExtraOncall(ctx); err != nil { 737 return err 738 } 739 if err := vm.removeExtraStandby(ctx); err != nil { 740 return err 741 } 742 if err := vm.fillEmptyOncall(ctx); err != nil { 743 return err 744 } 745 if err := vm.fillEmptyStandby(ctx); err != nil { 746 return err 747 } 748 if err := vm.updateLowestOncall(ctx); err != nil { 749 return err 750 } 751 if err := vm.updateLowestStandby(ctx); err != nil { 752 return err 753 } 754 return nil 755 } 756 757 // move lowest votes oncall validator to standby list if current oncall size exceeds max 758 func (vm ValidatorManager) removeExtraOncall(ctx sdk.Context) sdk.Error { 759 lst := vm.storage.GetValidatorList(ctx) 760 curLen := int64(len(lst.Oncall)) 761 param := vm.paramHolder.GetValidatorParam(ctx) 762 763 for curLen > param.OncallSize { 764 lst := vm.storage.GetValidatorList(ctx) 765 lowestOncall, _, err := vm.getLowestVotesAndValidator(ctx, lst.Oncall) 766 if err != nil { 767 return err 768 } 769 vm.removeValidatorFromOncallList(ctx, lowestOncall) 770 if err := vm.addValidatortToStandbyList(ctx, lowestOncall); err != nil { 771 return err 772 } 773 curLen-- 774 } 775 return nil 776 } 777 778 // move lowest votes standby validator to candidate list if current standby size exceeds max 779 func (vm ValidatorManager) removeExtraStandby(ctx sdk.Context) sdk.Error { 780 lst := vm.storage.GetValidatorList(ctx) 781 curLen := int64(len(lst.Standby)) 782 param := vm.paramHolder.GetValidatorParam(ctx) 783 for curLen > param.StandbySize { 784 lst := vm.storage.GetValidatorList(ctx) 785 lowestStandby, _, err := vm.getLowestVotesAndValidator(ctx, lst.Standby) 786 if err != nil { 787 return err 788 } 789 vm.removeValidatorFromStandbyList(ctx, lowestStandby) 790 if err := vm.addValidatortToCandidateList(ctx, lowestStandby); err != nil { 791 return err 792 } 793 curLen-- 794 } 795 return nil 796 } 797 798 // move highest votes standby validator to oncall list if current oncall size not full 799 // if standby validator not enough, try move highest votes candidate validator 800 func (vm ValidatorManager) fillEmptyOncall(ctx sdk.Context) sdk.Error { 801 lst := vm.storage.GetValidatorList(ctx) 802 lenOncall := int64(len(lst.Oncall)) 803 lenStandby := int64(len(lst.Standby)) 804 lenCandidate := int64(len(lst.Candidates)) 805 param := vm.paramHolder.GetValidatorParam(ctx) 806 807 for lenOncall < param.OncallSize && lenStandby > 0 { 808 lst := vm.storage.GetValidatorList(ctx) 809 highestStandby, _, err := vm.getHighestVotesAndValidator(ctx, lst.Standby) 810 if err != nil { 811 return err 812 } 813 vm.removeValidatorFromStandbyList(ctx, highestStandby) 814 if err := vm.addValidatortToOncallList(ctx, highestStandby); err != nil { 815 return err 816 } 817 lenOncall++ 818 lenStandby-- 819 } 820 821 for lenOncall < param.OncallSize && lenCandidate > 0 { 822 lst := vm.storage.GetValidatorList(ctx) 823 highestCandidate, _, err := vm.getHighestVotesAndValidator(ctx, lst.Candidates) 824 if err != nil { 825 return err 826 } 827 vm.removeValidatorFromCandidateList(ctx, highestCandidate) 828 if err := vm.addValidatortToOncallList(ctx, highestCandidate); err != nil { 829 return err 830 } 831 lenOncall++ 832 lenCandidate-- 833 } 834 835 return nil 836 } 837 838 // move highest votes candidate validator to standby list if current standby size not full 839 func (vm ValidatorManager) fillEmptyStandby(ctx sdk.Context) sdk.Error { 840 lst := vm.storage.GetValidatorList(ctx) 841 lenStandby := int64(len(lst.Standby)) 842 lenCandidate := int64(len(lst.Candidates)) 843 param := vm.paramHolder.GetValidatorParam(ctx) 844 845 for lenStandby < param.StandbySize && lenCandidate > 0 { 846 lst := vm.storage.GetValidatorList(ctx) 847 highestCandidate, _, err := vm.getHighestVotesAndValidator(ctx, lst.Candidates) 848 if err != nil { 849 return err 850 } 851 vm.removeValidatorFromCandidateList(ctx, highestCandidate) 852 if err := vm.addValidatortToStandbyList(ctx, highestCandidate); err != nil { 853 return err 854 } 855 lenStandby++ 856 lenCandidate-- 857 } 858 return nil 859 } 860 861 func (vm ValidatorManager) removeValidatorFromAllLists(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 862 vm.removeValidatorFromOncallList(ctx, username) 863 vm.removeValidatorFromStandbyList(ctx, username) 864 vm.removeValidatorFromCandidateList(ctx, username) 865 vm.removeValidatorFromJailList(ctx, username) 866 return nil 867 } 868 869 func (vm ValidatorManager) removeValidatorFromOncallList(ctx sdk.Context, username linotypes.AccountKey) { 870 lst := vm.storage.GetValidatorList(ctx) 871 lst.Oncall = removeFromList(username, lst.Oncall) 872 vm.storage.SetValidatorList(ctx, lst) 873 } 874 875 func (vm ValidatorManager) removeValidatorFromStandbyList(ctx sdk.Context, username linotypes.AccountKey) { 876 lst := vm.storage.GetValidatorList(ctx) 877 lst.Standby = removeFromList(username, lst.Standby) 878 vm.storage.SetValidatorList(ctx, lst) 879 } 880 881 func (vm ValidatorManager) removeValidatorFromCandidateList(ctx sdk.Context, username linotypes.AccountKey) { 882 lst := vm.storage.GetValidatorList(ctx) 883 lst.Candidates = removeFromList(username, lst.Candidates) 884 vm.storage.SetValidatorList(ctx, lst) 885 } 886 887 func (vm ValidatorManager) removeValidatorFromJailList(ctx sdk.Context, username linotypes.AccountKey) { 888 lst := vm.storage.GetValidatorList(ctx) 889 lst.Jail = removeFromList(username, lst.Jail) 890 vm.storage.SetValidatorList(ctx, lst) 891 } 892 893 func (vm ValidatorManager) addValidatortToOncallList(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 894 lst := vm.storage.GetValidatorList(ctx) 895 lst.Oncall = append(lst.Oncall, username) 896 if err := vm.setOncallValidatorPower(ctx, username); err != nil { 897 return err 898 } 899 vm.storage.SetValidatorList(ctx, lst) 900 return nil 901 } 902 903 func (vm ValidatorManager) addValidatortToStandbyList(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 904 lst := vm.storage.GetValidatorList(ctx) 905 lst.Standby = append(lst.Standby, username) 906 me, err := vm.storage.GetValidator(ctx, username) 907 if err != nil { 908 return err 909 } 910 911 // set oncall validator committing power equal to 1 912 me.ABCIValidator.Power = 1 913 vm.storage.SetValidator(ctx, username, me) 914 vm.storage.SetValidatorList(ctx, lst) 915 return nil 916 } 917 918 func (vm ValidatorManager) addValidatortToCandidateList(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 919 lst := vm.storage.GetValidatorList(ctx) 920 lst.Candidates = append(lst.Candidates, username) 921 me, err := vm.storage.GetValidator(ctx, username) 922 if err != nil { 923 return err 924 } 925 926 // set oncall validator committing power equal to 0 927 me.ABCIValidator.Power = 0 928 vm.storage.SetValidator(ctx, username, me) 929 vm.storage.SetValidatorList(ctx, lst) 930 return nil 931 } 932 933 func (vm ValidatorManager) addValidatortToJailList(ctx sdk.Context, username linotypes.AccountKey) sdk.Error { 934 lst := vm.storage.GetValidatorList(ctx) 935 lst.Jail = append(lst.Jail, username) 936 me, err := vm.storage.GetValidator(ctx, username) 937 if err != nil { 938 return err 939 } 940 941 // set oncall validator committing power equal to 0 and clear all stats 942 me.ABCIValidator.Power = 0 943 me.AbsentCommit = 0 944 me.NumSlash = 0 945 vm.storage.SetValidator(ctx, username, me) 946 vm.storage.SetValidatorList(ctx, lst) 947 return nil 948 } 949 950 func removeFromList(me linotypes.AccountKey, users []linotypes.AccountKey) []linotypes.AccountKey { 951 for i := 0; i < len(users); i++ { 952 if me == users[i] { 953 return append(users[:i], users[i+1:]...) 954 } 955 } 956 return users 957 } 958 959 func (vm ValidatorManager) getHighestVotesAndValidator(ctx sdk.Context, 960 lst []linotypes.AccountKey) (linotypes.AccountKey, linotypes.Coin, sdk.Error) { 961 highestValdator := linotypes.AccountKey("") 962 highestValdatorVotes := linotypes.NewCoinFromInt64(0) 963 964 for i := range lst { 965 validator, err := vm.storage.GetValidator(ctx, lst[i]) 966 if err != nil { 967 return highestValdator, linotypes.NewCoinFromInt64(0), err 968 } 969 if validator.ReceivedVotes.IsGTE(highestValdatorVotes) { 970 highestValdator = validator.Username 971 highestValdatorVotes = validator.ReceivedVotes 972 } 973 } 974 return highestValdator, highestValdatorVotes, nil 975 } 976 977 func (vm ValidatorManager) getLowestVotesAndValidator(ctx sdk.Context, 978 lst []linotypes.AccountKey) (linotypes.AccountKey, linotypes.Coin, sdk.Error) { 979 lowestValdator := linotypes.AccountKey("") 980 lowestValdatorVotes := linotypes.NewCoinFromInt64(math.MaxInt64) 981 982 for i := range lst { 983 validator, err := vm.storage.GetValidator(ctx, lst[i]) 984 if err != nil { 985 return lowestValdator, linotypes.NewCoinFromInt64(0), err 986 } 987 if lowestValdatorVotes.IsGTE(validator.ReceivedVotes) { 988 lowestValdator = validator.Username 989 lowestValdatorVotes = validator.ReceivedVotes 990 } 991 } 992 return lowestValdator, lowestValdatorVotes, nil 993 } 994 995 func (vm ValidatorManager) updateLowestOncall(ctx sdk.Context) sdk.Error { 996 lst := vm.storage.GetValidatorList(ctx) 997 newLowestVotes := linotypes.NewCoinFromInt64(math.MaxInt64) 998 newLowestValidator := linotypes.AccountKey("") 999 1000 for _, validatorKey := range lst.Oncall { 1001 validator, err := vm.storage.GetValidator(ctx, validatorKey) 1002 if err != nil { 1003 return err 1004 } 1005 1006 if newLowestVotes.IsGT(validator.ReceivedVotes) { 1007 newLowestVotes = validator.ReceivedVotes 1008 newLowestValidator = validator.Username 1009 } 1010 } 1011 1012 // set the new lowest power 1013 if len(lst.Oncall) == 0 { 1014 lst.LowestOncallVotes = linotypes.NewCoinFromInt64(0) 1015 lst.LowestOncall = linotypes.AccountKey("") 1016 } else { 1017 lst.LowestOncallVotes = newLowestVotes 1018 lst.LowestOncall = newLowestValidator 1019 } 1020 1021 vm.storage.SetValidatorList(ctx, lst) 1022 return nil 1023 } 1024 1025 func (vm ValidatorManager) updateLowestStandby(ctx sdk.Context) sdk.Error { 1026 lst := vm.storage.GetValidatorList(ctx) 1027 newLowestVotes := linotypes.NewCoinFromInt64(math.MaxInt64) 1028 newLowestValidator := linotypes.AccountKey("") 1029 1030 for _, validatorKey := range lst.Standby { 1031 validator, err := vm.storage.GetValidator(ctx, validatorKey) 1032 if err != nil { 1033 return err 1034 } 1035 1036 if newLowestVotes.IsGT(validator.ReceivedVotes) { 1037 newLowestVotes = validator.ReceivedVotes 1038 newLowestValidator = validator.Username 1039 } 1040 } 1041 1042 // set the new lowest power 1043 if len(lst.Standby) == 0 { 1044 lst.LowestStandbyVotes = linotypes.NewCoinFromInt64(0) 1045 lst.LowestStandby = linotypes.AccountKey("") 1046 } else { 1047 1048 lst.LowestStandbyVotes = newLowestVotes 1049 lst.LowestStandby = newLowestValidator 1050 } 1051 1052 vm.storage.SetValidatorList(ctx, lst) 1053 return nil 1054 } 1055 1056 func (vm ValidatorManager) setOncallValidatorPower(ctx sdk.Context, 1057 username linotypes.AccountKey) sdk.Error { 1058 me, err := vm.storage.GetValidator(ctx, username) 1059 if err != nil { 1060 return err 1061 } 1062 1063 votesCoinInt64, err := me.ReceivedVotes.ToInt64() 1064 if err != nil { 1065 return err 1066 } 1067 // set oncall validator committing power equal to it's votes (lino) 1068 powerLNO := votesCoinInt64 / linotypes.Decimals 1069 switch { 1070 case powerLNO > linotypes.ValidatorMaxPower: 1071 me.ABCIValidator.Power = linotypes.ValidatorMaxPower 1072 case powerLNO < 1: 1073 me.ABCIValidator.Power = 1 1074 default: 1075 me.ABCIValidator.Power = powerLNO 1076 } 1077 1078 vm.storage.SetValidator(ctx, username, me) 1079 return nil 1080 } 1081 1082 // getter and setter 1083 func (vm ValidatorManager) GetValidator(ctx sdk.Context, accKey linotypes.AccountKey) (*model.Validator, sdk.Error) { 1084 return vm.storage.GetValidator(ctx, accKey) 1085 } 1086 1087 func (vm ValidatorManager) GetAllValidators(ctx sdk.Context) []linotypes.AccountKey { 1088 lst := vm.GetValidatorList(ctx) 1089 tmp := append(lst.Standby, lst.Candidates...) 1090 return append(lst.Oncall, tmp...) 1091 } 1092 1093 func (vm ValidatorManager) GetCommittingValidators(ctx sdk.Context) []linotypes.AccountKey { 1094 lst := vm.GetValidatorList(ctx) 1095 return append(lst.Oncall, lst.Standby...) 1096 } 1097 1098 func (vm ValidatorManager) GetValidatorList(ctx sdk.Context) *model.ValidatorList { 1099 return vm.storage.GetValidatorList(ctx) 1100 } 1101 1102 func (vm ValidatorManager) SetValidatorList(ctx sdk.Context, lst *model.ValidatorList) { 1103 vm.storage.SetValidatorList(ctx, lst) 1104 } 1105 1106 func (vm ValidatorManager) GetElectionVoteList(ctx sdk.Context, 1107 accKey linotypes.AccountKey) *model.ElectionVoteList { 1108 return vm.storage.GetElectionVoteList(ctx, accKey) 1109 } 1110 1111 func (vm ValidatorManager) getPrevVotes(ctx sdk.Context, user linotypes.AccountKey) linotypes.Coin { 1112 val, err := vm.storage.GetValidator(ctx, user) 1113 if err != nil { 1114 return linotypes.NewCoinFromInt64(0) 1115 } 1116 return val.ReceivedVotes 1117 } 1118 1119 func (vm ValidatorManager) GetCommittingValidatorVoteStatus(ctx sdk.Context) []model.ReceivedVotesStatus { 1120 lst := vm.GetCommittingValidators(ctx) 1121 res := []model.ReceivedVotesStatus{} 1122 for _, name := range lst { 1123 val, err := vm.storage.GetValidator(ctx, name) 1124 if err != nil { 1125 panic(err) 1126 } 1127 res = append(res, model.ReceivedVotesStatus{ 1128 ValidatorName: name, 1129 ReceivedVotes: val.ReceivedVotes, 1130 }) 1131 } 1132 return res 1133 } 1134 1135 // ExportToFile - 1136 func (vm ValidatorManager) ExportToFile(ctx sdk.Context, cdc *codec.Codec, filepath string) error { 1137 state := &model.ValidatorTablesIR{ 1138 Version: exportVersion, 1139 } 1140 substores := vm.storage.StoreMap(ctx) 1141 1142 // export validators 1143 substores[string(model.ValidatorSubstore)].Iterate(func(key []byte, val interface{}) bool { 1144 validator := val.(*model.Validator) 1145 state.Validators = append(state.Validators, model.ValidatorIR{ 1146 ABCIValidator: model.ABCIValidatorIR{ 1147 Address: validator.ABCIValidator.Address, 1148 Power: validator.ABCIValidator.Power, 1149 }, 1150 PubKey: model.NewABCIPubKeyIRFromTM(validator.PubKey), 1151 Username: validator.Username, 1152 ReceivedVotes: validator.ReceivedVotes, 1153 HasRevoked: validator.HasRevoked, 1154 AbsentCommit: validator.AbsentCommit, 1155 ProducedBlocks: validator.ProducedBlocks, 1156 Link: validator.Link, 1157 }) 1158 return false 1159 }) 1160 1161 // export votes 1162 substores[string(model.ElectionVoteListSubstore)].Iterate(func(key []byte, val interface{}) bool { 1163 user := linotypes.AccountKey(key) 1164 votelist := val.(*model.ElectionVoteList) 1165 votesIR := make([]model.ElectionVoteIR, 0) 1166 for _, vote := range votelist.ElectionVotes { 1167 votesIR = append(votesIR, model.ElectionVoteIR(vote)) 1168 } 1169 state.Votes = append(state.Votes, model.ElectionVoteListIR{ 1170 Username: user, 1171 ElectionVotes: votesIR, 1172 }) 1173 return false 1174 }) 1175 1176 // export validator list. 1177 substores[string(model.ValidatorListSubstore)].Iterate(func(key []byte, val interface{}) bool { 1178 lst := val.(*model.ValidatorList) 1179 state.List = model.ValidatorListIR(*lst) 1180 return false 1181 }) 1182 1183 return utils.Save(filepath, cdc, state) 1184 } 1185 1186 // ImportFromFile import state from file. 1187 func (vs ValidatorManager) ImportFromFile(ctx sdk.Context, cdc *codec.Codec, filepath string) error { 1188 rst, err := utils.Load(filepath, cdc, func() interface{} { return &model.ValidatorTablesIR{} }) 1189 if err != nil { 1190 return err 1191 } 1192 table := rst.(*model.ValidatorTablesIR) 1193 1194 if table.Version != importVersion { 1195 return fmt.Errorf("unsupported import version: %d", table.Version) 1196 } 1197 1198 // import validators. 1199 for _, val := range table.Validators { 1200 vs.storage.SetValidator(ctx, val.Username, &model.Validator{ 1201 ABCIValidator: abci.Validator{ 1202 Address: val.ABCIValidator.Address, 1203 Power: val.ABCIValidator.Power, 1204 }, 1205 PubKey: val.PubKey.ToTM(), 1206 Username: val.Username, 1207 ReceivedVotes: val.ReceivedVotes, 1208 HasRevoked: val.HasRevoked, 1209 AbsentCommit: val.AbsentCommit, 1210 ProducedBlocks: val.ProducedBlocks, 1211 Link: val.Link, 1212 }) 1213 } 1214 1215 // import votes. 1216 for _, vote := range table.Votes { 1217 votes := make([]model.ElectionVote, 0) 1218 for _, v := range vote.ElectionVotes { 1219 votes = append(votes, model.ElectionVote(v)) 1220 } 1221 vs.storage.SetElectionVoteList(ctx, vote.Username, &model.ElectionVoteList{ 1222 ElectionVotes: votes, 1223 }) 1224 } 1225 1226 // import validator list 1227 validatorList := model.ValidatorList(table.List) 1228 vs.storage.SetValidatorList(ctx, &validatorList) 1229 return nil 1230 }