github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/consensus/neatcon/epoch/epoch.go (about) 1 package epoch 2 3 import ( 4 "errors" 5 "fmt" 6 7 dbm "github.com/neatio-net/db-go" 8 ncTypes "github.com/neatio-net/neatio/chain/consensus/neatcon/types" 9 "github.com/neatio-net/neatio/chain/core/state" 10 "github.com/neatio-net/neatio/chain/log" 11 "github.com/neatio-net/neatio/utilities/common" 12 "github.com/neatio-net/wire-go" 13 14 "math/big" 15 "sort" 16 "strconv" 17 "sync" 18 "time" 19 ) 20 21 var NextEpochNotExist = errors.New("next epoch parameters do not exist, fatal error") 22 var NextEpochNotEXPECTED = errors.New("next epoch parameters are not excepted, fatal error") 23 24 const ( 25 EPOCH_NOT_EXIST = iota 26 EPOCH_PROPOSED_NOT_VOTED 27 EPOCH_VOTED_NOT_SAVED 28 EPOCH_SAVED 29 30 MinimumValidatorsSize = 1 31 MaximumValidatorsSize = 100 32 33 epochKey = "Epoch:%v" 34 latestEpochKey = "LatestEpoch" 35 ) 36 37 type Epoch struct { 38 mtx sync.Mutex 39 db dbm.DB 40 41 Number uint64 42 RewardPerBlock *big.Int 43 StartBlock uint64 44 EndBlock uint64 45 StartTime time.Time 46 EndTime time.Time 47 BlockGenerated int 48 Status int 49 Validators *ncTypes.ValidatorSet 50 51 validatorVoteSet *EpochValidatorVoteSet 52 rs *RewardScheme 53 previousEpoch *Epoch 54 nextEpoch *Epoch 55 56 logger log.Logger 57 } 58 59 func calcEpochKeyWithHeight(number uint64) []byte { 60 return []byte(fmt.Sprintf(epochKey, number)) 61 } 62 63 func InitEpoch(db dbm.DB, genDoc *ncTypes.GenesisDoc, logger log.Logger) *Epoch { 64 65 epochNumber := db.Get([]byte(latestEpochKey)) 66 if epochNumber == nil { 67 rewardScheme := MakeRewardScheme(db, &genDoc.RewardScheme) 68 rewardScheme.Save() 69 70 ep := MakeOneEpoch(db, &genDoc.CurrentEpoch, logger) 71 ep.Save() 72 73 ep.SetRewardScheme(rewardScheme) 74 return ep 75 } else { 76 epNo, _ := strconv.ParseUint(string(epochNumber), 10, 64) 77 return LoadOneEpoch(db, epNo, logger) 78 } 79 } 80 81 func LoadOneEpoch(db dbm.DB, epochNumber uint64, logger log.Logger) *Epoch { 82 epoch := loadOneEpoch(db, epochNumber, logger) 83 rewardscheme := LoadRewardScheme(db) 84 epoch.rs = rewardscheme 85 epoch.validatorVoteSet = LoadEpochVoteSet(db, epochNumber) 86 if epochNumber > 0 { 87 epoch.previousEpoch = loadOneEpoch(db, epochNumber-1, logger) 88 if epoch.previousEpoch != nil { 89 epoch.previousEpoch.rs = rewardscheme 90 } 91 } 92 epoch.nextEpoch = loadOneEpoch(db, epochNumber+1, logger) 93 if epoch.nextEpoch != nil { 94 epoch.nextEpoch.rs = rewardscheme 95 epoch.nextEpoch.validatorVoteSet = LoadEpochVoteSet(db, epochNumber+1) 96 } 97 98 return epoch 99 } 100 101 func loadOneEpoch(db dbm.DB, epochNumber uint64, logger log.Logger) *Epoch { 102 103 buf := db.Get(calcEpochKeyWithHeight(epochNumber)) 104 ep := FromBytes(buf) 105 if ep != nil { 106 ep.db = db 107 ep.logger = logger 108 } 109 return ep 110 } 111 112 func MakeOneEpoch(db dbm.DB, oneEpoch *ncTypes.OneEpochDoc, logger log.Logger) *Epoch { 113 114 validators := make([]*ncTypes.Validator, len(oneEpoch.Validators)) 115 for i, val := range oneEpoch.Validators { 116 validators[i] = &ncTypes.Validator{ 117 Address: val.EthAccount.Bytes(), 118 PubKey: val.PubKey, 119 VotingPower: val.Amount, 120 RemainingEpoch: val.RemainingEpoch, 121 } 122 } 123 124 te := &Epoch{ 125 db: db, 126 127 Number: oneEpoch.Number, 128 RewardPerBlock: oneEpoch.RewardPerBlock, 129 StartBlock: oneEpoch.StartBlock, 130 EndBlock: oneEpoch.EndBlock, 131 StartTime: time.Now(), 132 EndTime: time.Unix(0, 0), 133 Status: oneEpoch.Status, 134 Validators: ncTypes.NewValidatorSet(validators), 135 logger: logger, 136 } 137 138 return te 139 } 140 141 func (epoch *Epoch) GetDB() dbm.DB { 142 return epoch.db 143 } 144 145 func (epoch *Epoch) GetEpochValidatorVoteSet() *EpochValidatorVoteSet { 146 if epoch.validatorVoteSet == nil { 147 epoch.validatorVoteSet = LoadEpochVoteSet(epoch.db, epoch.Number) 148 } 149 return epoch.validatorVoteSet 150 } 151 152 func (epoch *Epoch) GetRewardScheme() *RewardScheme { 153 return epoch.rs 154 } 155 156 func (epoch *Epoch) SetRewardScheme(rs *RewardScheme) { 157 epoch.rs = rs 158 } 159 160 func (epoch *Epoch) Save() { 161 epoch.mtx.Lock() 162 defer epoch.mtx.Unlock() 163 epoch.db.SetSync(calcEpochKeyWithHeight(epoch.Number), epoch.Bytes()) 164 epoch.db.SetSync([]byte(latestEpochKey), []byte(strconv.FormatUint(epoch.Number, 10))) 165 166 if epoch.nextEpoch != nil && epoch.nextEpoch.Status == EPOCH_VOTED_NOT_SAVED { 167 epoch.nextEpoch.Status = EPOCH_SAVED 168 epoch.db.SetSync(calcEpochKeyWithHeight(epoch.nextEpoch.Number), epoch.nextEpoch.Bytes()) 169 } 170 171 } 172 173 func FromBytes(buf []byte) *Epoch { 174 175 if len(buf) == 0 { 176 return nil 177 } else { 178 ep := &Epoch{} 179 err := wire.ReadBinaryBytes(buf, ep) 180 if err != nil { 181 log.Errorf("Load Epoch from Bytes Failed, error: %v", err) 182 return nil 183 } 184 return ep 185 } 186 } 187 188 func (epoch *Epoch) Bytes() []byte { 189 return wire.BinaryBytes(*epoch) 190 } 191 192 func (epoch *Epoch) ValidateNextEpoch(next *Epoch, lastHeight uint64, lastBlockTime time.Time) error { 193 194 myNextEpoch := epoch.ProposeNextEpoch(lastHeight, lastBlockTime) 195 196 if !myNextEpoch.Equals(next, false) { 197 log.Warnf("next epoch parameters are not expected, epoch propose next epoch: %v, next %v", myNextEpoch.String(), next.String()) 198 return NextEpochNotEXPECTED 199 } 200 201 return nil 202 } 203 204 func (epoch *Epoch) ShouldProposeNextEpoch(curBlockHeight uint64) bool { 205 206 fmt.Printf("\n") 207 fmt.Printf("-------- Next Epoch Info --------\n") 208 fmt.Printf("Next epoch proposed: %v", epoch.nextEpoch) 209 210 if epoch.nextEpoch != nil { 211 212 return false 213 } 214 215 shouldPropose := curBlockHeight > (epoch.StartBlock+1) && curBlockHeight != epoch.EndBlock 216 return shouldPropose 217 } 218 219 func (epoch *Epoch) ProposeNextEpoch(lastBlockHeight uint64, lastBlockTime time.Time) *Epoch { 220 221 if epoch != nil { 222 223 rewardPerBlock, blocks := epoch.estimateForNextEpoch(lastBlockHeight, lastBlockTime) 224 225 next := &Epoch{ 226 mtx: epoch.mtx, 227 db: epoch.db, 228 229 Number: epoch.Number + 1, 230 RewardPerBlock: rewardPerBlock, 231 StartBlock: epoch.EndBlock + 1, 232 EndBlock: epoch.EndBlock + blocks, 233 BlockGenerated: 0, 234 Status: EPOCH_PROPOSED_NOT_VOTED, 235 Validators: epoch.Validators.Copy(), 236 237 logger: epoch.logger, 238 } 239 240 return next 241 } 242 return nil 243 } 244 245 func (epoch *Epoch) GetNextEpoch() *Epoch { 246 if epoch.nextEpoch == nil { 247 epoch.nextEpoch = loadOneEpoch(epoch.db, epoch.Number+1, epoch.logger) 248 if epoch.nextEpoch != nil { 249 epoch.nextEpoch.rs = epoch.rs 250 epoch.nextEpoch.validatorVoteSet = LoadEpochVoteSet(epoch.db, epoch.Number+1) 251 } 252 } 253 return epoch.nextEpoch 254 } 255 256 func (epoch *Epoch) SetNextEpoch(next *Epoch) { 257 if next != nil { 258 next.db = epoch.db 259 next.rs = epoch.rs 260 next.logger = epoch.logger 261 } 262 epoch.nextEpoch = next 263 } 264 265 func (epoch *Epoch) GetPreviousEpoch() *Epoch { 266 return epoch.previousEpoch 267 } 268 269 func (epoch *Epoch) ShouldEnterNewEpoch(height uint64, state *state.StateDB) (bool, *ncTypes.ValidatorSet, error) { 270 271 if height == epoch.EndBlock { 272 epoch.nextEpoch = epoch.GetNextEpoch() 273 if epoch.nextEpoch != nil { 274 275 for refundAddress := range state.GetDelegateAddressRefundSet() { 276 state.ForEachProxied(refundAddress, func(key common.Address, proxiedBalance, depositProxiedBalance, pendingRefundBalance *big.Int) bool { 277 if pendingRefundBalance.Sign() > 0 { 278 state.SubDepositProxiedBalanceByUser(refundAddress, key, pendingRefundBalance) 279 state.SubPendingRefundBalanceByUser(refundAddress, key, pendingRefundBalance) 280 state.SubDelegateBalance(key, pendingRefundBalance) 281 state.AddBalance(key, pendingRefundBalance) 282 } 283 return true 284 }) 285 if !state.IsCandidate(refundAddress) { 286 state.ClearCommission(refundAddress) 287 } 288 } 289 state.ClearDelegateRefundSet() 290 291 var ( 292 refunds []*ncTypes.RefundValidatorAmount 293 ) 294 295 newValidators := epoch.Validators.Copy() 296 297 nextEpochVoteSet := epoch.nextEpoch.validatorVoteSet.Copy() 298 299 if nextEpochVoteSet == nil { 300 nextEpochVoteSet = NewEpochValidatorVoteSet() 301 epoch.logger.Debugf("Should enter new epoch, next epoch vote set is nil, %v", nextEpochVoteSet) 302 } 303 304 for i := 0; i < len(newValidators.Validators); i++ { 305 v := newValidators.Validators[i] 306 vAddr := common.BytesToAddress(v.Address) 307 308 totalProxiedBalance := new(big.Int).Add(state.GetTotalProxiedBalance(vAddr), state.GetTotalDepositProxiedBalance(vAddr)) 309 newVotingPower := new(big.Int).Add(totalProxiedBalance, state.GetDepositBalance(vAddr)) 310 if newVotingPower.Sign() == 0 { 311 newValidators.Remove(v.Address) 312 313 i-- 314 } else { 315 v.VotingPower = newVotingPower 316 } 317 318 } 319 320 refundsUpdate, err := updateEpochValidatorSet(newValidators, nextEpochVoteSet) 321 322 if err != nil { 323 epoch.logger.Warn("Error changing validator set", "error", err) 324 return false, nil, err 325 } 326 refunds = append(refunds, refundsUpdate...) 327 328 for _, v := range newValidators.Validators { 329 vAddr := common.BytesToAddress(v.Address) 330 if state.IsCandidate(vAddr) && state.GetTotalProxiedBalance(vAddr).Sign() > 0 { 331 state.ForEachProxied(vAddr, func(key common.Address, proxiedBalance, depositProxiedBalance, pendingRefundBalance *big.Int) bool { 332 if proxiedBalance.Sign() > 0 { 333 state.SubProxiedBalanceByUser(vAddr, key, proxiedBalance) 334 state.AddDepositProxiedBalanceByUser(vAddr, key, proxiedBalance) 335 } 336 return true 337 }) 338 } 339 } 340 341 for _, r := range refunds { 342 if !r.Voteout { 343 state.SubDepositBalance(r.Address, r.Amount) 344 state.AddBalance(r.Address, r.Amount) 345 } else { 346 if state.IsCandidate(r.Address) { 347 state.ForEachProxied(r.Address, func(key common.Address, proxiedBalance, depositProxiedBalance, pendingRefundBalance *big.Int) bool { 348 if depositProxiedBalance.Sign() > 0 { 349 state.SubDepositProxiedBalanceByUser(r.Address, key, depositProxiedBalance) 350 state.AddProxiedBalanceByUser(r.Address, key, depositProxiedBalance) 351 } 352 return true 353 }) 354 } 355 depositBalance := state.GetDepositBalance(r.Address) 356 state.SubDepositBalance(r.Address, depositBalance) 357 state.AddBalance(r.Address, depositBalance) 358 } 359 } 360 361 return true, newValidators, nil 362 } else { 363 return false, nil, NextEpochNotExist 364 } 365 } 366 return false, nil, nil 367 } 368 369 func compareAddress(addrA, addrB []byte) bool { 370 if addrA[0] == addrB[0] { 371 return compareAddress(addrA[1:], addrB[1:]) 372 } else { 373 return addrA[0] > addrB[0] 374 } 375 } 376 377 func (epoch *Epoch) EnterNewEpoch(newValidators *ncTypes.ValidatorSet) (*Epoch, error) { 378 if epoch.nextEpoch != nil { 379 now := time.Now() 380 381 epoch.EndTime = now 382 epoch.Save() 383 epoch.logger.Infof("Epoch %v reach to his end", epoch.Number) 384 385 nextEpoch := epoch.nextEpoch 386 nextEpoch.previousEpoch = &Epoch{Validators: epoch.Validators} 387 388 nextEpoch.StartTime = now 389 nextEpoch.Validators = newValidators 390 391 nextEpoch.nextEpoch = nil 392 nextEpoch.Save() 393 epoch.logger.Infof("Enter into New Epoch %v", nextEpoch) 394 return nextEpoch, nil 395 } else { 396 return nil, NextEpochNotExist 397 } 398 } 399 400 func DryRunUpdateEpochValidatorSet(state *state.StateDB, validators *ncTypes.ValidatorSet, voteSet *EpochValidatorVoteSet) error { 401 for i := 0; i < len(validators.Validators); i++ { 402 v := validators.Validators[i] 403 vAddr := common.BytesToAddress(v.Address) 404 405 totalProxiedBalance := new(big.Int).Add(state.GetTotalProxiedBalance(vAddr), state.GetTotalDepositProxiedBalance(vAddr)) 406 totalProxiedBalance.Sub(totalProxiedBalance, state.GetTotalPendingRefundBalance(vAddr)) 407 408 newVotingPower := new(big.Int).Add(totalProxiedBalance, state.GetDepositBalance(vAddr)) 409 if newVotingPower.Sign() == 0 { 410 validators.Remove(v.Address) 411 i-- 412 } else { 413 v.VotingPower = newVotingPower 414 } 415 } 416 417 if voteSet == nil { 418 fmt.Printf("DryRunUpdateEpochValidatorSet, voteSet is nil %v\n", voteSet) 419 voteSet = NewEpochValidatorVoteSet() 420 } 421 422 _, err := updateEpochValidatorSet(validators, voteSet) 423 return err 424 } 425 426 func updateEpochValidatorSet(validators *ncTypes.ValidatorSet, voteSet *EpochValidatorVoteSet) ([]*ncTypes.RefundValidatorAmount, error) { 427 428 var refund []*ncTypes.RefundValidatorAmount 429 oldValSize, newValSize := validators.Size(), 0 430 fmt.Printf("updateEpochValidatorSet, validators: %v\n, voteSet: %v\n", validators, voteSet) 431 432 if !voteSet.IsEmpty() { 433 for _, v := range voteSet.Votes { 434 if v.Amount == nil || v.Salt == "" || v.PubKey == nil { 435 continue 436 } 437 _, validator := validators.GetByAddress(v.Address[:]) 438 if validator == nil { 439 added := validators.Add(ncTypes.NewValidator(v.Address[:], v.PubKey, v.Amount)) 440 if !added { 441 fmt.Print(fmt.Errorf("Failed to add new validator %v with voting power %d", v.Address, v.Amount)) 442 } else { 443 newValSize++ 444 } 445 } else { 446 if v.Amount.Sign() == 0 { 447 fmt.Printf("updateEpochValidatorSet amount is zero\n") 448 _, removed := validators.Remove(validator.Address) 449 if !removed { 450 fmt.Print(fmt.Errorf("Failed to remove validator %v", validator.Address)) 451 } else { 452 refund = append(refund, &ncTypes.RefundValidatorAmount{Address: v.Address, Amount: validator.VotingPower, Voteout: false}) 453 } 454 } else { 455 if v.Amount.Cmp(validator.VotingPower) == -1 { 456 fmt.Printf("updateEpochValidatorSet amount less than the voting power, amount: %v, votingPower: %v\n", v.Amount, validator.VotingPower) 457 refundAmount := new(big.Int).Sub(validator.VotingPower, v.Amount) 458 refund = append(refund, &ncTypes.RefundValidatorAmount{Address: v.Address, Amount: refundAmount, Voteout: false}) 459 } 460 461 validator.VotingPower = v.Amount 462 updated := validators.Update(validator) 463 if !updated { 464 fmt.Print(fmt.Errorf("Failed to update validator %v with voting power %d", validator.Address, v.Amount)) 465 } 466 } 467 } 468 } 469 } 470 471 valSize := oldValSize + newValSize 472 473 if valSize > MaximumValidatorsSize { 474 valSize = MaximumValidatorsSize 475 } else if valSize < MinimumValidatorsSize { 476 valSize = MinimumValidatorsSize 477 } 478 479 for _, v := range validators.Validators { 480 if v.RemainingEpoch > 0 { 481 v.RemainingEpoch-- 482 } 483 } 484 485 if validators.Size() > valSize { 486 sort.Slice(validators.Validators, func(i, j int) bool { 487 if validators.Validators[i].RemainingEpoch == validators.Validators[j].RemainingEpoch { 488 return validators.Validators[i].VotingPower.Cmp(validators.Validators[j].VotingPower) == 1 489 } else { 490 return validators.Validators[i].RemainingEpoch > validators.Validators[j].RemainingEpoch 491 } 492 }) 493 knockout := validators.Validators[valSize:] 494 for _, k := range knockout { 495 refund = append(refund, &ncTypes.RefundValidatorAmount{Address: common.BytesToAddress(k.Address), Amount: nil, Voteout: true}) 496 } 497 498 validators.Validators = validators.Validators[:valSize] 499 } 500 501 return refund, nil 502 } 503 504 func (epoch *Epoch) GetEpochByBlockNumber(blockNumber uint64) *Epoch { 505 if blockNumber >= epoch.StartBlock && blockNumber <= epoch.EndBlock { 506 return epoch 507 } 508 509 for number := epoch.Number - 1; number >= 0; number-- { 510 511 ep := loadOneEpoch(epoch.db, number, epoch.logger) 512 if ep == nil { 513 return nil 514 } 515 516 if blockNumber >= ep.StartBlock && blockNumber <= ep.EndBlock { 517 return ep 518 } 519 } 520 521 return nil 522 } 523 524 func (epoch *Epoch) Copy() *Epoch { 525 return epoch.copy(true) 526 } 527 528 func (epoch *Epoch) copy(copyPrevNext bool) *Epoch { 529 530 var previousEpoch, nextEpoch *Epoch 531 if copyPrevNext { 532 if epoch.previousEpoch != nil { 533 previousEpoch = epoch.previousEpoch.copy(false) 534 } 535 536 if epoch.nextEpoch != nil { 537 nextEpoch = epoch.nextEpoch.copy(false) 538 } 539 } 540 541 return &Epoch{ 542 mtx: epoch.mtx, 543 db: epoch.db, 544 logger: epoch.logger, 545 546 rs: epoch.rs, 547 548 Number: epoch.Number, 549 RewardPerBlock: new(big.Int).Set(epoch.RewardPerBlock), 550 StartBlock: epoch.StartBlock, 551 EndBlock: epoch.EndBlock, 552 StartTime: epoch.StartTime, 553 EndTime: epoch.EndTime, 554 BlockGenerated: epoch.BlockGenerated, 555 Status: epoch.Status, 556 Validators: epoch.Validators.Copy(), 557 validatorVoteSet: epoch.validatorVoteSet.Copy(), 558 559 previousEpoch: previousEpoch, 560 nextEpoch: nextEpoch, 561 } 562 } 563 564 func (epoch *Epoch) estimateForNextEpoch(lastBlockHeight uint64, lastBlockTime time.Time) (rewardPerBlock *big.Int, nextEpochBlocks uint64) { 565 566 var rewardFirstYear = epoch.rs.RewardFirstYear 567 var epochNumberPerYear = epoch.rs.EpochNumberPerYear 568 var totalYear = epoch.rs.TotalMintingYears 569 var timePerBlockOfEpoch int64 570 571 const EMERGENCY_BLOCKS_OF_NEXT_EPOCH_LOWER uint64 = 15000 572 const EMERGENCY_BLOCKS_OF_NEXT_EPOCH_UPPER uint64 = 20000 573 574 const DEFAULT_TIME_PER_BLOCK_OF_EPOCH int64 = 5000000000 575 576 zeroEpoch := loadOneEpoch(epoch.db, 0, epoch.logger) 577 initStartTime := zeroEpoch.StartTime 578 579 thisYear := epoch.Number / epochNumberPerYear 580 nextYear := thisYear + 1 581 582 timePerBlockOfEpoch = lastBlockTime.Sub(epoch.StartTime).Nanoseconds() / int64(lastBlockHeight-epoch.StartBlock) 583 584 if timePerBlockOfEpoch <= 0 { 585 log.Debugf("estimateForNextEpoch, timePerBlockOfEpoch is %v", timePerBlockOfEpoch) 586 timePerBlockOfEpoch = DEFAULT_TIME_PER_BLOCK_OF_EPOCH 587 } 588 589 epochLeftThisYear := epochNumberPerYear - epoch.Number%epochNumberPerYear - 1 590 591 nextEpochBlocks = 0 592 593 // log.Info("estimateForNextEpoch", 594 // "epochLeftThisYear", epochLeftThisYear, 595 // "timePerBlockOfEpoch", timePerBlockOfEpoch) 596 597 if epochLeftThisYear == 0 { 598 599 nextYearStartTime := initStartTime.AddDate(int(nextYear), 0, 0) 600 601 nextYearEndTime := nextYearStartTime.AddDate(1, 0, 0) 602 603 timeLeftNextYear := nextYearEndTime.Sub(nextYearStartTime) 604 605 epochLeftNextYear := epochNumberPerYear 606 607 epochTimePerEpochLeftNextYear := timeLeftNextYear.Nanoseconds() / int64(epochLeftNextYear) 608 609 nextEpochBlocks = uint64(epochTimePerEpochLeftNextYear / timePerBlockOfEpoch) 610 611 // log.Info("estimateForNextEpoch 0", 612 // "timePerBlockOfEpoch", timePerBlockOfEpoch, 613 // "nextYearStartTime", nextYearStartTime, 614 // "timeLeftNextYear", timeLeftNextYear, 615 // "epochLeftNextYear", epochLeftNextYear, 616 // "epochTimePerEpochLeftNextYear", epochTimePerEpochLeftNextYear, 617 // "nextEpochBlocks", nextEpochBlocks) 618 619 if nextEpochBlocks <= EMERGENCY_BLOCKS_OF_NEXT_EPOCH_LOWER { 620 nextEpochBlocks = EMERGENCY_BLOCKS_OF_NEXT_EPOCH_LOWER 621 epoch.logger.Warn("EstimateForNextEpoch warning: You should probably take a look at 'epoch_no_per_year' setup in genesis") 622 } 623 if nextEpochBlocks >= EMERGENCY_BLOCKS_OF_NEXT_EPOCH_UPPER { 624 nextEpochBlocks = EMERGENCY_BLOCKS_OF_NEXT_EPOCH_UPPER 625 epoch.logger.Warn("EstimateForNextEpoch warning: You should probably take a look at 'epoch_no_per_year' setup in genesis") 626 } 627 628 rewardPerEpochNextYear := calculateRewardPerEpochByYear(rewardFirstYear, int64(nextYear), int64(totalYear), int64(epochNumberPerYear)) 629 630 rewardPerBlock = new(big.Int).Div(rewardPerEpochNextYear, big.NewInt(int64(nextEpochBlocks))) 631 632 } else { 633 634 nextYearStartTime := initStartTime.AddDate(int(nextYear), 0, 0) 635 636 timeLeftThisYear := nextYearStartTime.Sub(lastBlockTime) 637 638 if timeLeftThisYear > 0 { 639 640 epochTimePerEpochLeftThisYear := timeLeftThisYear.Nanoseconds() / int64(epochLeftThisYear) 641 642 nextEpochBlocks = uint64(epochTimePerEpochLeftThisYear / timePerBlockOfEpoch) 643 644 } 645 646 if nextEpochBlocks <= EMERGENCY_BLOCKS_OF_NEXT_EPOCH_LOWER { 647 nextEpochBlocks = EMERGENCY_BLOCKS_OF_NEXT_EPOCH_LOWER 648 epoch.logger.Warn("EstimateForNextEpoch warning: You should probably take a look at 'epoch_no_per_year' setup in genesis") 649 } 650 if nextEpochBlocks > EMERGENCY_BLOCKS_OF_NEXT_EPOCH_UPPER { 651 nextEpochBlocks = EMERGENCY_BLOCKS_OF_NEXT_EPOCH_UPPER 652 epoch.logger.Warn("EstimateForNextEpoch warning: You should probably take a look at 'epoch_no_per_year' setup in genesis") 653 } 654 655 rewardPerEpochThisYear := calculateRewardPerEpochByYear(rewardFirstYear, int64(thisYear), int64(totalYear), int64(epochNumberPerYear)) 656 657 rewardPerBlock = new(big.Int).Div(rewardPerEpochThisYear, big.NewInt(int64(nextEpochBlocks))) 658 659 } 660 return rewardPerBlock, nextEpochBlocks 661 } 662 663 func calculateRewardPerEpochByYear(rewardFirstYear *big.Int, year, totalYear, epochNumberPerYear int64) *big.Int { 664 if year > totalYear { 665 return big.NewInt(0) 666 } 667 668 return new(big.Int).Div(rewardFirstYear, big.NewInt(epochNumberPerYear)) 669 } 670 671 func (epoch *Epoch) Equals(other *Epoch, checkPrevNext bool) bool { 672 673 if (epoch == nil && other != nil) || (epoch != nil && other == nil) { 674 return false 675 } 676 677 if epoch == nil && other == nil { 678 // log.Debugf("Epoch equals epoch %v, other %v", epoch, other) 679 return true 680 } 681 682 if !(epoch.Number == other.Number && epoch.RewardPerBlock.Cmp(other.RewardPerBlock) == 0 && 683 epoch.StartBlock == other.StartBlock && epoch.EndBlock == other.EndBlock && 684 epoch.Validators.Equals(other.Validators)) { 685 return false 686 } 687 688 if checkPrevNext { 689 if !epoch.previousEpoch.Equals(other.previousEpoch, false) || 690 !epoch.nextEpoch.Equals(other.nextEpoch, false) { 691 return false 692 } 693 } 694 log.Debugf("Epoch equals end, no matching") 695 return true 696 } 697 698 func (epoch *Epoch) String() string { 699 erpb := epoch.RewardPerBlock 700 intToFloat := new(big.Float).SetInt(erpb) 701 floatToBigFloat := new(big.Float).SetFloat64(1e18) 702 var blockReward = new(big.Float).Quo(intToFloat, floatToBigFloat) 703 704 return fmt.Sprintf( 705 "Number %v,\n"+ 706 "Reward / block: %v "+"NIO"+",\n"+ 707 "Next epoch is starting at block: %v,\n"+ 708 "The epoch will last until block: %v,\n", 709 epoch.Number, 710 blockReward, 711 epoch.StartBlock, 712 epoch.EndBlock, 713 ) 714 } 715 716 func UpdateEpochEndTime(db dbm.DB, epNumber uint64, endTime time.Time) { 717 ep := loadOneEpoch(db, epNumber, nil) 718 if ep != nil { 719 ep.mtx.Lock() 720 defer ep.mtx.Unlock() 721 ep.EndTime = endTime 722 db.SetSync(calcEpochKeyWithHeight(epNumber), ep.Bytes()) 723 } 724 }