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  }