github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/store_last_events.go (about) 1 package gossip 2 3 import ( 4 "bytes" 5 "sort" 6 7 "github.com/unicornultrafoundation/go-helios/hash" 8 "github.com/unicornultrafoundation/go-helios/native/idx" 9 10 "github.com/unicornultrafoundation/go-u2u/utils/concurrent" 11 ) 12 13 type sortedLastEvent []byte 14 15 func (es *epochStore) getCachedLastEvents() (*concurrent.ValidatorEventsSet, bool) { 16 cache := es.cache.LastEvents.Load() 17 if cache != nil { 18 return cache.(*concurrent.ValidatorEventsSet), true 19 } 20 return nil, false 21 } 22 23 func (es *epochStore) loadLastEvents() *concurrent.ValidatorEventsSet { 24 res := make(map[idx.ValidatorID]hash.Event, 100) 25 26 b, err := es.table.LastEvents.Get([]byte{}) 27 if err != nil { 28 es.Log.Crit("Failed to get key-value", "err", err) 29 } 30 if b == nil { 31 return concurrent.WrapValidatorEventsSet(res) 32 } 33 for i := 0; i < len(b); i += 32 + 4 { 34 res[idx.BytesToValidatorID(b[i:i+4])] = hash.BytesToEvent(b[i+4 : i+4+32]) 35 } 36 37 return concurrent.WrapValidatorEventsSet(res) 38 } 39 40 func (es *epochStore) GetLastEvents() *concurrent.ValidatorEventsSet { 41 cached, ok := es.getCachedLastEvents() 42 if ok { 43 return cached 44 } 45 heads := es.loadLastEvents() 46 if heads == nil { 47 heads = &concurrent.ValidatorEventsSet{} 48 } 49 es.cache.LastEvents.Store(heads) 50 return heads 51 } 52 53 func (es *epochStore) SetLastEvents(ids *concurrent.ValidatorEventsSet) { 54 es.cache.LastEvents.Store(ids) 55 } 56 57 func (es *epochStore) FlushLastEvents() { 58 lasts, ok := es.getCachedLastEvents() 59 if !ok { 60 return 61 } 62 63 // sort values for determinism 64 sortedLastEvents := make([]sortedLastEvent, 0, len(lasts.Val)) 65 for vid, val := range lasts.Val { 66 b := append(vid.Bytes(), val.Bytes()...) 67 sortedLastEvents = append(sortedLastEvents, b) 68 } 69 sort.Slice(sortedLastEvents, func(i, j int) bool { 70 a, b := sortedLastEvents[i], sortedLastEvents[j] 71 return bytes.Compare(a, b) < 0 72 }) 73 74 b := make([]byte, 0, len(sortedLastEvents)*(32+4)) 75 for _, head := range sortedLastEvents { 76 b = append(b, head...) 77 } 78 79 if err := es.table.LastEvents.Put([]byte{}, b); err != nil { 80 es.Log.Crit("Failed to put key-value", "err", err) 81 } 82 } 83 84 // GetLastEvents returns latest connected epoch events from each validator 85 func (s *Store) GetLastEvents(epoch idx.Epoch) *concurrent.ValidatorEventsSet { 86 es := s.getEpochStore(epoch) 87 if es == nil { 88 return nil 89 } 90 91 return es.GetLastEvents() 92 } 93 94 // GetLastEvent returns latest connected epoch event from specified validator 95 func (s *Store) GetLastEvent(epoch idx.Epoch, vid idx.ValidatorID) *hash.Event { 96 es := s.getEpochStore(epoch) 97 if es == nil { 98 return nil 99 } 100 101 lasts := s.GetLastEvents(epoch) 102 lasts.RLock() 103 defer lasts.RUnlock() 104 last, ok := lasts.Val[vid] 105 if !ok { 106 return nil 107 } 108 return &last 109 } 110 111 func (s *Store) SetLastEvents(epoch idx.Epoch, ids *concurrent.ValidatorEventsSet) { 112 es := s.getEpochStore(epoch) 113 if es == nil { 114 return 115 } 116 117 es.SetLastEvents(ids) 118 }