github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/c_llr_callbacks.go (about) 1 package gossip 2 3 import ( 4 "errors" 5 6 "github.com/unicornultrafoundation/go-helios/hash" 7 "github.com/unicornultrafoundation/go-helios/native/idx" 8 "github.com/unicornultrafoundation/go-helios/native/pos" 9 "github.com/unicornultrafoundation/go-u2u/common" 10 "github.com/unicornultrafoundation/go-u2u/core/types" 11 12 "github.com/unicornultrafoundation/go-u2u/eventcheck" 13 "github.com/unicornultrafoundation/go-u2u/gossip/evmstore" 14 "github.com/unicornultrafoundation/go-u2u/native" 15 "github.com/unicornultrafoundation/go-u2u/native/iblockproc" 16 "github.com/unicornultrafoundation/go-u2u/native/ibr" 17 "github.com/unicornultrafoundation/go-u2u/native/ier" 18 "github.com/unicornultrafoundation/go-u2u/u2u" 19 ) 20 21 var errValidatorNotExist = errors.New("validator does not exist") 22 23 func actualizeLowestIndex(current, upd uint64, exists func(uint64) bool) uint64 { 24 if current == upd { 25 current++ 26 for exists(current) { 27 current++ 28 } 29 } 30 return current 31 } 32 33 func (s *Service) processBlockVote(block idx.Block, epoch idx.Epoch, bv hash.Hash, val idx.Validator, vals *pos.Validators, llrs *LlrState) { 34 newWeight := s.store.AddLlrBlockVoteWeight(block, epoch, bv, val, vals.Len(), vals.GetWeightByIdx(val)) 35 if newWeight >= vals.TotalWeight()/3+1 { 36 wonBr := s.store.GetLlrBlockResult(block) 37 if wonBr == nil { 38 s.store.SetLlrBlockResult(block, bv) 39 llrs.LowestBlockToDecide = idx.Block(actualizeLowestIndex(uint64(llrs.LowestBlockToDecide), uint64(block), func(u uint64) bool { 40 return s.store.GetLlrBlockResult(idx.Block(u)) != nil 41 })) 42 } else if *wonBr != bv { 43 s.Log.Error("LLR voting doublesign is met", "block", block) 44 } 45 } 46 } 47 48 func (s *Service) processBlockVotes(bvs native.LlrSignedBlockVotes) error { 49 // engineMu should be locked here 50 if len(bvs.Val.Votes) == 0 { 51 // short circuit if no records 52 return nil 53 } 54 if s.store.HasBlockVotes(bvs.Val.Epoch, bvs.Val.LastBlock(), bvs.Signed.Locator.ID()) { 55 return eventcheck.ErrAlreadyProcessedBVs 56 } 57 done := s.procLogger.BlockVotesConnectionStarted(bvs) 58 defer done() 59 vid := bvs.Signed.Locator.Creator 60 61 // get the validators group 62 epoch := bvs.Signed.Locator.Epoch 63 es := s.store.GetHistoryEpochState(epoch) 64 if es == nil { 65 return eventcheck.ErrUnknownEpochBVs 66 } 67 68 if !es.Validators.Exists(vid) { 69 return errValidatorNotExist 70 } 71 72 s.store.ModifyLlrState(func(llrs *LlrState) { 73 b := bvs.Val.Start 74 for _, bv := range bvs.Val.Votes { 75 s.processBlockVote(b, bvs.Val.Epoch, bv, es.Validators.GetIdx(vid), es.Validators, llrs) 76 b++ 77 } 78 }) 79 s.store.SetBlockVotes(bvs) 80 lBVs := s.store.GetLastBVs() 81 lBVs.Lock() 82 if bvs.Val.LastBlock() > lBVs.Val[vid] { 83 lBVs.Val[vid] = bvs.Val.LastBlock() 84 s.store.SetLastBVs(lBVs) 85 } 86 lBVs.Unlock() 87 88 return nil 89 } 90 91 func (s *Service) ProcessBlockVotes(bvs native.LlrSignedBlockVotes) error { 92 s.engineMu.Lock() 93 defer s.engineMu.Unlock() 94 95 err := s.processBlockVotes(bvs) 96 if err == nil { 97 s.mayCommit(false) 98 } 99 return err 100 } 101 102 func indexRawReceipts(s *Store, receiptsForStorage []*types.ReceiptForStorage, txs types.Transactions, blockIdx idx.Block, atropos hash.Event) { 103 s.evm.SetRawReceipts(blockIdx, receiptsForStorage) 104 receipts, _ := evmstore.UnwrapStorageReceipts(receiptsForStorage, blockIdx, nil, common.Hash(atropos), txs) 105 for _, r := range receipts { 106 s.evm.IndexLogs(r.Logs...) 107 } 108 } 109 110 func (s *Store) WriteFullBlockRecord(br ibr.LlrIdxFullBlockRecord) { 111 txHashes := make([]common.Hash, 0, len(br.Txs)) 112 for _, tx := range br.Txs { 113 txHashes = append(txHashes, tx.Hash()) 114 s.EvmStore().SetTx(tx.Hash(), tx) 115 } 116 117 if len(br.Receipts) != 0 { 118 // Note: it's possible for receipts to get indexed twice by BR and block processing 119 indexRawReceipts(s, br.Receipts, br.Txs, br.Idx, br.Atropos) 120 } 121 for i, tx := range br.Txs { 122 s.EvmStore().SetTx(tx.Hash(), tx) 123 s.EvmStore().SetTxPosition(tx.Hash(), evmstore.TxPosition{ 124 Block: br.Idx, 125 BlockOffset: uint32(i), 126 }) 127 } 128 s.SetBlock(br.Idx, &native.Block{ 129 Time: br.Time, 130 Atropos: br.Atropos, 131 Events: hash.Events{}, 132 Txs: txHashes, 133 InternalTxs: []common.Hash{}, 134 SkippedTxs: []uint32{}, 135 GasUsed: br.GasUsed, 136 Root: br.Root, 137 }) 138 s.SetBlockIndex(br.Atropos, br.Idx) 139 } 140 141 func (s *Service) ProcessFullBlockRecord(br ibr.LlrIdxFullBlockRecord) error { 142 // engineMu should NOT be locked here 143 if s.store.HasBlock(br.Idx) { 144 return eventcheck.ErrAlreadyProcessedBR 145 } 146 done := s.procLogger.BlockRecordConnectionStarted(br) 147 defer done() 148 res := s.store.GetLlrBlockResult(br.Idx) 149 if res == nil { 150 return eventcheck.ErrUndecidedBR 151 } 152 153 if br.Hash() != *res { 154 return errors.New("block record hash mismatch") 155 } 156 157 s.store.WriteFullBlockRecord(br) 158 s.engineMu.Lock() 159 defer s.engineMu.Unlock() 160 if s.verWatcher != nil { 161 // Note: it's possible for logs to get indexed twice by BR and block processing 162 for _, r := range br.Receipts { 163 for _, l := range r.Logs { 164 s.verWatcher.OnNewLog(l) 165 } 166 } 167 } 168 updateLowestBlockToFill(br.Idx, s.store) 169 s.mayCommit(false) 170 171 return nil 172 } 173 174 func (s *Service) processRawEpochVote(epoch idx.Epoch, ev hash.Hash, val idx.Validator, vals *pos.Validators, llrs *LlrState) { 175 newWeight := s.store.AddLlrEpochVoteWeight(epoch, ev, val, vals.Len(), vals.GetWeightByIdx(val)) 176 if newWeight >= vals.TotalWeight()/3+1 { 177 wonEr := s.store.GetLlrEpochResult(epoch) 178 if wonEr == nil { 179 s.store.SetLlrEpochResult(epoch, ev) 180 llrs.LowestEpochToDecide = idx.Epoch(actualizeLowestIndex(uint64(llrs.LowestEpochToDecide), uint64(epoch), func(u uint64) bool { 181 return s.store.GetLlrEpochResult(idx.Epoch(u)) != nil 182 })) 183 } else if *wonEr != ev { 184 s.Log.Error("LLR voting doublesign is met", "epoch", epoch) 185 } 186 } 187 } 188 189 func (s *Service) processEpochVote(ev native.LlrSignedEpochVote) error { 190 // engineMu should be locked here 191 if ev.Val.Epoch == 0 { 192 // short circuit if no records 193 return nil 194 } 195 if s.store.HasEpochVote(ev.Val.Epoch, ev.Signed.Locator.ID()) { 196 return eventcheck.ErrAlreadyProcessedEV 197 } 198 done := s.procLogger.EpochVoteConnectionStarted(ev) 199 defer done() 200 vid := ev.Signed.Locator.Creator 201 202 // get the validators group 203 es := s.store.GetHistoryEpochState(ev.Val.Epoch - 1) 204 if es == nil { 205 return eventcheck.ErrUnknownEpochEV 206 } 207 208 if !es.Validators.Exists(vid) { 209 return errValidatorNotExist 210 } 211 212 s.store.ModifyLlrState(func(llrs *LlrState) { 213 s.processRawEpochVote(ev.Val.Epoch, ev.Val.Vote, es.Validators.GetIdx(vid), es.Validators, llrs) 214 }) 215 s.store.SetEpochVote(ev) 216 lEVs := s.store.GetLastEVs() 217 lEVs.Lock() 218 if ev.Val.Epoch > lEVs.Val[vid] { 219 lEVs.Val[vid] = ev.Val.Epoch 220 s.store.SetLastEVs(lEVs) 221 } 222 lEVs.Unlock() 223 224 return nil 225 } 226 227 func (s *Service) ProcessEpochVote(ev native.LlrSignedEpochVote) error { 228 s.engineMu.Lock() 229 defer s.engineMu.Unlock() 230 231 err := s.processEpochVote(ev) 232 if err == nil { 233 s.mayCommit(false) 234 } 235 return err 236 } 237 238 func (s *Store) WriteFullEpochRecord(er ier.LlrIdxFullEpochRecord) { 239 s.SetHistoryBlockEpochState(er.Idx, er.BlockState, er.EpochState) 240 s.SetEpochBlock(er.BlockState.LastBlock.Idx+1, er.Idx) 241 } 242 243 func (s *Store) WriteUpgradeHeight(bs iblockproc.BlockState, es iblockproc.EpochState, prevEs *iblockproc.EpochState) { 244 if prevEs == nil || es.Rules.Upgrades != prevEs.Rules.Upgrades { 245 s.AddUpgradeHeight(u2u.UpgradeHeight{ 246 Upgrades: es.Rules.Upgrades, 247 Height: bs.LastBlock.Idx + 1, 248 }) 249 } 250 } 251 252 func (s *Service) ProcessFullEpochRecord(er ier.LlrIdxFullEpochRecord) error { 253 // engineMu should NOT be locked here 254 if s.store.HasHistoryBlockEpochState(er.Idx) { 255 return eventcheck.ErrAlreadyProcessedER 256 } 257 done := s.procLogger.EpochRecordConnectionStarted(er) 258 defer done() 259 260 res := s.store.GetLlrEpochResult(er.Idx) 261 if res == nil { 262 return eventcheck.ErrUndecidedER 263 } 264 265 if er.Hash() != *res { 266 return errors.New("epoch record hash mismatch") 267 } 268 269 s.store.WriteFullEpochRecord(er) 270 s.store.WriteUpgradeHeight(er.BlockState, er.EpochState, s.store.GetHistoryEpochState(er.EpochState.Epoch-1)) 271 s.engineMu.Lock() 272 defer s.engineMu.Unlock() 273 updateLowestEpochToFill(er.Idx, s.store) 274 s.mayCommit(false) 275 276 return nil 277 } 278 279 func updateLowestBlockToFill(block idx.Block, store *Store) { 280 store.ModifyLlrState(func(llrs *LlrState) { 281 llrs.LowestBlockToFill = idx.Block(actualizeLowestIndex(uint64(llrs.LowestBlockToFill), uint64(block), func(u uint64) bool { 282 return store.GetBlock(idx.Block(u)) != nil 283 })) 284 }) 285 } 286 287 func updateLowestEpochToFill(epoch idx.Epoch, store *Store) { 288 store.ModifyLlrState(func(llrs *LlrState) { 289 llrs.LowestEpochToFill = idx.Epoch(actualizeLowestIndex(uint64(llrs.LowestEpochToFill), uint64(epoch), func(u uint64) bool { 290 return store.HasHistoryBlockEpochState(idx.Epoch(u)) 291 })) 292 }) 293 }