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 }