github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/emitter/emitter_llr.go (about)

     1  package emitter
     2  
     3  import (
     4  	"math/rand"
     5  
     6  	"github.com/unicornultrafoundation/go-helios/hash"
     7  	"github.com/unicornultrafoundation/go-helios/native/idx"
     8  	"github.com/unicornultrafoundation/go-helios/utils/piecefunc"
     9  
    10  	"github.com/unicornultrafoundation/go-u2u/eventcheck/basiccheck"
    11  	"github.com/unicornultrafoundation/go-u2u/native"
    12  )
    13  
    14  var emptyLlrBlockVotes = native.LlrBlockVotes{
    15  	Votes: []hash.Hash{},
    16  }
    17  
    18  func (em *Emitter) addLlrBlockVotes(e *native.MutableEventPayload) {
    19  	if em.skipLlrBlockVote() || e.Version() == 0 {
    20  		e.SetBlockVotes(emptyLlrBlockVotes)
    21  		return
    22  	}
    23  	start := em.world.GetLowestBlockToDecide()
    24  	prevInDB := em.world.GetLastBV(e.Creator())
    25  	if prevInDB != nil && start < *prevInDB+1 {
    26  		start = *prevInDB + 1
    27  	}
    28  	prevInFile := em.readLastBlockVotes()
    29  	if prevInFile != nil && start < *prevInFile+1 {
    30  		start = *prevInFile + 1
    31  	}
    32  	records := make([]hash.Hash, 0, 16)
    33  	epochEnd := false
    34  	var epoch idx.Epoch
    35  	for b := start; len(records) < basiccheck.MaxBlockVotesPerEvent; b++ {
    36  		record := em.world.GetBlockRecordHash(b)
    37  		if record == nil {
    38  			break
    39  		}
    40  		blockEpoch := em.world.GetBlockEpoch(b)
    41  		if epoch == 0 {
    42  			epoch = blockEpoch
    43  		}
    44  		if epoch != blockEpoch || blockEpoch == 0 {
    45  			epochEnd = true
    46  			break
    47  		}
    48  		records = append(records, *record)
    49  	}
    50  
    51  	waitUntilLongerBatch := !epochEnd && len(records) < basiccheck.MaxBlockVotesPerEvent
    52  	if len(records) == 0 || waitUntilLongerBatch {
    53  		e.SetBlockVotes(emptyLlrBlockVotes)
    54  		return
    55  	}
    56  	e.SetBlockVotes(native.LlrBlockVotes{
    57  		Start: start,
    58  		Epoch: epoch,
    59  		Votes: records,
    60  	})
    61  }
    62  
    63  func (em *Emitter) addLlrEpochVote(e *native.MutableEventPayload) {
    64  	if em.skipLlrEpochVote() || e.Version() == 0 {
    65  		return
    66  	}
    67  	target := em.world.GetLowestEpochToDecide()
    68  	prevInDB := em.world.GetLastEV(e.Creator())
    69  	if prevInDB != nil && target < *prevInDB+1 {
    70  		target = *prevInDB + 1
    71  	}
    72  	prevInFile := em.readLastEpochVote()
    73  	if prevInFile != nil && target < *prevInFile+1 {
    74  		target = *prevInFile + 1
    75  	}
    76  	vote := em.world.GetEpochRecordHash(target)
    77  	if vote == nil {
    78  		return
    79  	}
    80  	e.SetEpochVote(native.LlrEpochVote{
    81  		Epoch: target,
    82  		Vote:  *vote,
    83  	})
    84  }
    85  
    86  func (em *Emitter) neverSkipLlrVote() bool {
    87  	return em.stakeRatio[em.config.Validator.ID] <= uint64(piecefunc.DecimalUnit)/3+1
    88  }
    89  
    90  func (em *Emitter) skipLlrBlockVote() bool {
    91  	if em.neverSkipLlrVote() {
    92  		return false
    93  	}
    94  	// poor validators vote only if we have a long batch of non-decided blocks
    95  	return em.world.GetLatestBlockIndex() < em.world.GetLowestBlockToDecide()+basiccheck.MaxBlockVotesPerEvent*3
    96  }
    97  
    98  func (em *Emitter) skipLlrEpochVote() bool {
    99  	if em.neverSkipLlrVote() {
   100  		return false
   101  	}
   102  	// poor validators vote if we have a long batch of non-decided epochs
   103  	if em.epoch > em.world.GetLowestEpochToDecide()+2 {
   104  		return false
   105  	}
   106  	// otherwise, poor validators have a small chance to vote
   107  	return rand.Intn(30) != 0
   108  }