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  }