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

     1  package emitter
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math/rand"
     7  	"os"
     8  	"strings"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/unicornultrafoundation/go-helios/emitter/ancestor"
    13  	"github.com/unicornultrafoundation/go-helios/hash"
    14  	"github.com/unicornultrafoundation/go-helios/native/idx"
    15  	"github.com/unicornultrafoundation/go-helios/native/pos"
    16  	"github.com/unicornultrafoundation/go-helios/utils/piecefunc"
    17  	"github.com/unicornultrafoundation/go-u2u/core/types"
    18  
    19  	"github.com/unicornultrafoundation/go-u2u/gossip/emitter/originatedtxs"
    20  	"github.com/unicornultrafoundation/go-u2u/logger"
    21  	"github.com/unicornultrafoundation/go-u2u/native"
    22  	"github.com/unicornultrafoundation/go-u2u/tracing"
    23  	"github.com/unicornultrafoundation/go-u2u/utils/errlock"
    24  	"github.com/unicornultrafoundation/go-u2u/utils/rate"
    25  )
    26  
    27  const (
    28  	SenderCountBufferSize = 20000
    29  	PayloadIndexerSize    = 5000
    30  )
    31  
    32  type Emitter struct {
    33  	config Config
    34  
    35  	world World
    36  
    37  	syncStatus syncStatus
    38  
    39  	prevIdleTime       time.Time
    40  	prevEmittedAtTime  time.Time
    41  	prevEmittedAtBlock idx.Block
    42  	originatedTxs      *originatedtxs.Buffer
    43  	pendingGas         uint64
    44  
    45  	// note: track validators and epoch internally to avoid referring to
    46  	// validators of a future epoch inside OnEventConnected of last epoch event
    47  	validators *pos.Validators
    48  	epoch      idx.Epoch
    49  
    50  	// challenges is deadlines when each validator should emit an event
    51  	challenges map[idx.ValidatorID]time.Time
    52  	// offlineValidators is a map of validators which are likely to be offline
    53  	// This map may be different on different instances
    54  	offlineValidators     map[idx.ValidatorID]bool
    55  	expectedEmitIntervals map[idx.ValidatorID]time.Duration
    56  	stakeRatio            map[idx.ValidatorID]uint64
    57  
    58  	prevRecheckedChallenges time.Time
    59  
    60  	quorumIndexer  *ancestor.QuorumIndexer
    61  	fcIndexer      *ancestor.FCIndexer
    62  	payloadIndexer *ancestor.PayloadIndexer
    63  
    64  	intervals                EmitIntervals
    65  	globalConfirmingInterval time.Duration
    66  
    67  	done chan struct{}
    68  	wg   sync.WaitGroup
    69  
    70  	maxParents idx.Event
    71  
    72  	cache struct {
    73  		sortedTxs *types.TransactionsByPriceAndNonce
    74  		poolTime  time.Time
    75  		poolBlock idx.Block
    76  		poolCount int
    77  	}
    78  
    79  	emittedEventFile *os.File
    80  	emittedBvsFile   *os.File
    81  	emittedEvFile    *os.File
    82  	busyRate         *rate.Gauge
    83  
    84  	switchToFCIndexer bool
    85  	validatorVersions map[idx.ValidatorID]uint64
    86  
    87  	logger.Periodic
    88  }
    89  
    90  // NewEmitter creation.
    91  func NewEmitter(
    92  	config Config,
    93  	world World,
    94  ) *Emitter {
    95  	// Randomize event time to decrease chance of 2 parallel instances emitting event at the same time
    96  	// It increases the chance of detecting parallel instances
    97  	r := rand.New(rand.NewSource(time.Now().UnixNano()))
    98  	config.EmitIntervals = config.EmitIntervals.RandomizeEmitTime(r)
    99  
   100  	return &Emitter{
   101  		config:            config,
   102  		world:             world,
   103  		originatedTxs:     originatedtxs.New(SenderCountBufferSize),
   104  		intervals:         config.EmitIntervals,
   105  		Periodic:          logger.Periodic{Instance: logger.New()},
   106  		validatorVersions: make(map[idx.ValidatorID]uint64),
   107  	}
   108  }
   109  
   110  // init emitter without starting events emission
   111  func (em *Emitter) init() {
   112  	em.syncStatus.startup = time.Now()
   113  	em.syncStatus.lastConnected = time.Now()
   114  	em.syncStatus.p2pSynced = time.Now()
   115  	validators, epoch := em.world.GetEpochValidators()
   116  	em.OnNewEpoch(validators, epoch)
   117  
   118  	if len(em.config.PrevEmittedEventFile.Path) != 0 {
   119  		em.emittedEventFile = openPrevActionFile(em.config.PrevEmittedEventFile.Path, em.config.PrevEmittedEventFile.SyncMode)
   120  	}
   121  	if len(em.config.PrevBlockVotesFile.Path) != 0 {
   122  		em.emittedBvsFile = openPrevActionFile(em.config.PrevBlockVotesFile.Path, em.config.PrevBlockVotesFile.SyncMode)
   123  	}
   124  	if len(em.config.PrevEpochVoteFile.Path) != 0 {
   125  		em.emittedEvFile = openPrevActionFile(em.config.PrevEpochVoteFile.Path, em.config.PrevEpochVoteFile.SyncMode)
   126  	}
   127  	em.busyRate = rate.NewGauge()
   128  }
   129  
   130  // Start starts event emission.
   131  func (em *Emitter) Start() {
   132  	if em.config.Validator.ID == 0 {
   133  		// short circuit if not a validator
   134  		return
   135  	}
   136  	if em.done != nil {
   137  		return
   138  	}
   139  	em.init()
   140  	em.done = make(chan struct{})
   141  
   142  	done := em.done
   143  	if em.config.EmitIntervals.Min == 0 {
   144  		return
   145  	}
   146  	em.wg.Add(1)
   147  	go func() {
   148  		defer em.wg.Done()
   149  		tick := 11 * time.Millisecond
   150  		timer := time.NewTimer(tick)
   151  		defer timer.Stop()
   152  		for {
   153  			select {
   154  			case <-timer.C:
   155  				em.tick()
   156  			case <-done:
   157  				return
   158  			}
   159  			timer.Reset(tick)
   160  		}
   161  	}()
   162  }
   163  
   164  // Stop stops event emission.
   165  func (em *Emitter) Stop() {
   166  	if em.done == nil {
   167  		return
   168  	}
   169  
   170  	close(em.done)
   171  	em.done = nil
   172  	em.wg.Wait()
   173  	em.busyRate.Stop()
   174  }
   175  
   176  func (em *Emitter) tick() {
   177  	// track synced time
   178  	if em.world.PeersNum() == 0 {
   179  		// connected time ~= last time when it's true that "not connected yet"
   180  		em.syncStatus.lastConnected = time.Now()
   181  	}
   182  	if !em.world.IsSynced() {
   183  		// synced time ~= last time when it's true that "not synced yet"
   184  		em.syncStatus.p2pSynced = time.Now()
   185  	}
   186  	if em.idle() {
   187  		em.busyRate.Mark(0)
   188  	} else {
   189  		em.busyRate.Mark(1)
   190  	}
   191  	if em.world.IsBusy() {
   192  		return
   193  	}
   194  
   195  	em.recheckChallenges()
   196  	em.recheckIdleTime()
   197  	if time.Since(em.prevEmittedAtTime) >= em.intervals.Min {
   198  		_, _ = em.EmitEvent()
   199  	}
   200  }
   201  
   202  func (em *Emitter) getSortedTxs() *types.TransactionsByPriceAndNonce {
   203  	// Short circuit if pool wasn't updated since the cache was built
   204  	poolCount := em.world.TxPool.Count()
   205  	if em.cache.sortedTxs != nil &&
   206  		em.cache.poolBlock == em.world.GetLatestBlockIndex() &&
   207  		em.cache.poolCount == poolCount &&
   208  		time.Since(em.cache.poolTime) < em.config.TxsCacheInvalidation {
   209  		return em.cache.sortedTxs.Copy()
   210  	}
   211  	// Build the cache
   212  	pendingTxs, err := em.world.TxPool.Pending(true)
   213  	if err != nil {
   214  		em.Log.Error("Tx pool transactions fetching error", "err", err)
   215  		return nil
   216  	}
   217  	for from, txs := range pendingTxs {
   218  		// Filter the excessive transactions from each sender
   219  		if len(txs) > em.config.MaxTxsPerAddress {
   220  			pendingTxs[from] = txs[:em.config.MaxTxsPerAddress]
   221  		}
   222  	}
   223  	sortedTxs := types.NewTransactionsByPriceAndNonce(em.world.TxSigner, pendingTxs, em.world.GetRules().Economy.MinGasPrice)
   224  	em.cache.sortedTxs = sortedTxs
   225  	em.cache.poolCount = poolCount
   226  	em.cache.poolBlock = em.world.GetLatestBlockIndex()
   227  	em.cache.poolTime = time.Now()
   228  	return sortedTxs.Copy()
   229  }
   230  
   231  func (em *Emitter) EmitEvent() (*native.EventPayload, error) {
   232  	if em.config.Validator.ID == 0 {
   233  		// short circuit if not a validator
   234  		return nil, nil
   235  	}
   236  	sortedTxs := em.getSortedTxs()
   237  
   238  	if em.world.IsBusy() {
   239  		return nil, nil
   240  	}
   241  	em.world.Lock()
   242  	defer em.world.Unlock()
   243  
   244  	e, err := em.createEvent(sortedTxs)
   245  	if e == nil || err != nil {
   246  		return nil, err
   247  	}
   248  	em.syncStatus.prevLocalEmittedID = e.ID()
   249  
   250  	err = em.world.Process(e)
   251  	if err != nil {
   252  		em.Log.Error("Self-event connection failed", "err", err.Error())
   253  		return nil, err
   254  	}
   255  	// write event ID to avoid doublesigning in future after a crash
   256  	em.writeLastEmittedEventID(e.ID())
   257  	if e.EpochVote().Epoch != 0 {
   258  		em.writeLastEmittedEpochVote(e.EpochVote().Epoch)
   259  	}
   260  	if len(e.BlockVotes().Votes) != 0 {
   261  		em.writeLastEmittedBlockVotes(e.BlockVotes().LastBlock())
   262  	}
   263  	// broadcast the event
   264  	em.world.Broadcast(e)
   265  
   266  	em.prevEmittedAtTime = time.Now() // record time after connecting, to add the event processing time"
   267  	em.prevEmittedAtBlock = em.world.GetLatestBlockIndex()
   268  
   269  	// metrics
   270  	if tracing.Enabled() {
   271  		for _, t := range e.Txs() {
   272  			span := tracing.CheckTx(t.Hash(), "Emitter.EmitEvent()")
   273  			defer span.Finish()
   274  		}
   275  	}
   276  
   277  	return e, nil
   278  }
   279  
   280  func (em *Emitter) loadPrevEmitTime() time.Time {
   281  	prevEventID := em.world.GetLastEvent(em.epoch, em.config.Validator.ID)
   282  	if prevEventID == nil {
   283  		return em.prevEmittedAtTime
   284  	}
   285  	prevEvent := em.world.GetEvent(*prevEventID)
   286  	if prevEvent == nil {
   287  		return em.prevEmittedAtTime
   288  	}
   289  	return prevEvent.CreationTime().Time()
   290  }
   291  
   292  // createEvent is not safe for concurrent use.
   293  func (em *Emitter) createEvent(sortedTxs *types.TransactionsByPriceAndNonce) (*native.EventPayload, error) {
   294  	if !em.isValidator() {
   295  		return nil, nil
   296  	}
   297  
   298  	if synced := em.logSyncStatus(em.isSyncedToEmit()); !synced {
   299  		// I'm reindexing my old events, so don't create events until connect all the existing self-events
   300  		return nil, nil
   301  	}
   302  
   303  	var (
   304  		selfParentSeq  idx.Event
   305  		selfParentTime native.Timestamp
   306  		parents        hash.Events
   307  		maxLamport     idx.Lamport
   308  	)
   309  
   310  	// Find parents
   311  	selfParent, parents, ok := em.chooseParents(em.epoch, em.config.Validator.ID)
   312  	if !ok {
   313  		return nil, nil
   314  	}
   315  	prevEmitted := em.readLastEmittedEventID()
   316  	if prevEmitted != nil && prevEmitted.Epoch() >= em.epoch {
   317  		if selfParent == nil || *selfParent != *prevEmitted {
   318  			errlock.Permanent(errors.New("local database is corrupted, which may lead to a double sign"))
   319  		}
   320  	}
   321  
   322  	// Set parent-dependent fields
   323  	parentHeaders := make(native.Events, len(parents))
   324  	for i, p := range parents {
   325  		parent := em.world.GetEvent(p)
   326  		if parent == nil {
   327  			em.Log.Crit("Emitter: head not found", "mutEvent", p.String())
   328  		}
   329  		parentHeaders[i] = parent
   330  		if parentHeaders[i].Creator() == em.config.Validator.ID && i != 0 {
   331  			// there are 2 heads from me, i.e. due to a fork, chooseParents could have found multiple self-parents
   332  			em.Periodic.Error(5*time.Second, "I've created a fork, events emitting isn't allowed", "creator", em.config.Validator.ID)
   333  			return nil, nil
   334  		}
   335  		maxLamport = idx.MaxLamport(maxLamport, parent.Lamport())
   336  	}
   337  
   338  	selfParentSeq = 0
   339  	selfParentTime = 0
   340  	var selfParentHeader *native.Event
   341  	if selfParent != nil {
   342  		selfParentHeader = parentHeaders[0]
   343  		selfParentSeq = selfParentHeader.Seq()
   344  		selfParentTime = selfParentHeader.CreationTime()
   345  	}
   346  
   347  	version := uint8(0)
   348  	if em.world.GetRules().Upgrades.Llr {
   349  		version = 1
   350  	}
   351  
   352  	mutEvent := &native.MutableEventPayload{}
   353  	mutEvent.SetVersion(version)
   354  	mutEvent.SetEpoch(em.epoch)
   355  	mutEvent.SetSeq(selfParentSeq + 1)
   356  	mutEvent.SetCreator(em.config.Validator.ID)
   357  
   358  	mutEvent.SetParents(parents)
   359  	mutEvent.SetLamport(maxLamport + 1)
   360  	mutEvent.SetCreationTime(native.MaxTimestamp(native.Timestamp(time.Now().UnixNano()), selfParentTime+1))
   361  
   362  	// add LLR votes
   363  	em.addLlrEpochVote(mutEvent)
   364  	em.addLlrBlockVotes(mutEvent)
   365  
   366  	// node version
   367  	if mutEvent.Seq() <= 1 && len(em.config.VersionToPublish) > 0 {
   368  		version := []byte("v-" + em.config.VersionToPublish)
   369  		if uint32(len(version)) <= em.world.GetRules().Dag.MaxExtraData {
   370  			mutEvent.SetExtra(version)
   371  		}
   372  	}
   373  
   374  	// set consensus fields
   375  	var metric ancestor.Metric
   376  	err := em.world.Build(mutEvent, func() {
   377  		if em.fcIndexer != nil {
   378  			pastMe := em.fcIndexer.ValidatorsPastMe()
   379  			metric = (ancestor.Metric(pastMe) * piecefunc.DecimalUnit) / ancestor.Metric(em.validators.TotalWeight())
   380  			if pastMe < em.validators.Quorum() {
   381  				metric /= 15
   382  			}
   383  			if metric < 0.03*piecefunc.DecimalUnit {
   384  				metric = 0.03 * piecefunc.DecimalUnit
   385  			}
   386  			metric = overheadAdjustedEventMetricF(em.validators.Len(), uint64(em.busyRate.Rate1()*piecefunc.DecimalUnit), metric)
   387  			metric = kickStartMetric(metric/2, mutEvent.Seq()) // adjust emission interval for FC
   388  		} else if em.quorumIndexer != nil {
   389  			metric = eventMetric(em.quorumIndexer.GetMetricOf(hash.Events{mutEvent.ID()}), mutEvent.Seq())
   390  			metric = overheadAdjustedEventMetricF(em.validators.Len(), uint64(em.busyRate.Rate1()*piecefunc.DecimalUnit), metric)
   391  		}
   392  	})
   393  	if err != nil {
   394  		if err == ErrNotEnoughGasPower {
   395  			em.Periodic.Warn(time.Second, "Not enough gas power to emit event. Too small stake?",
   396  				"stake%", 100*float64(em.validators.Get(em.config.Validator.ID))/float64(em.validators.TotalWeight()))
   397  		} else {
   398  			em.Log.Warn("Dropped event while emitting", "err", err)
   399  		}
   400  		return nil, nil
   401  	}
   402  
   403  	// Pre-check if event should be emitted
   404  	// It is checked in advance to avoid adding transactions just to immediately drop the event later
   405  	if !em.isAllowedToEmit(mutEvent, true, metric, selfParentHeader) {
   406  		return nil, nil
   407  	}
   408  
   409  	// Add txs
   410  	em.addTxs(mutEvent, sortedTxs)
   411  
   412  	// Check if event should be emitted
   413  	// Check only if no txs were added, since check in a case with added txs was performed above
   414  	if mutEvent.Txs().Len() == 0 {
   415  		if !em.isAllowedToEmit(mutEvent, mutEvent.Txs().Len() != 0, metric, selfParentHeader) {
   416  			return nil, nil
   417  		}
   418  	}
   419  
   420  	// calc Payload hash
   421  	mutEvent.SetPayloadHash(native.CalcPayloadHash(mutEvent))
   422  
   423  	// sign
   424  	bSig, err := em.world.Signer.Sign(em.config.Validator.PubKey, mutEvent.HashToSign().Bytes())
   425  	if err != nil {
   426  		em.Periodic.Error(time.Second, "Failed to sign event", "err", err)
   427  		return nil, err
   428  	}
   429  	var sig native.Signature
   430  	copy(sig[:], bSig)
   431  	mutEvent.SetSig(sig)
   432  
   433  	// build clean event
   434  	event := mutEvent.Build()
   435  
   436  	// check
   437  	if err := em.world.Check(event, parentHeaders); err != nil {
   438  		em.Periodic.Error(time.Second, "Emitted incorrect event", "err", err)
   439  		return nil, err
   440  	}
   441  
   442  	// set mutEvent name for debug
   443  	em.nameEventForDebug(event)
   444  
   445  	return event, nil
   446  }
   447  
   448  func (em *Emitter) idle() bool {
   449  	return em.originatedTxs.Empty()
   450  }
   451  
   452  func (em *Emitter) isValidator() bool {
   453  	return em.config.Validator.ID != 0 && em.validators.Exists(em.config.Validator.ID)
   454  }
   455  
   456  func (em *Emitter) nameEventForDebug(e *native.EventPayload) {
   457  	name := []rune(hash.GetNodeName(e.Creator()))
   458  	if len(name) < 1 {
   459  		return
   460  	}
   461  
   462  	name = name[len(name)-1:]
   463  	hash.SetEventName(e.ID(), fmt.Sprintf("%s%03d",
   464  		strings.ToLower(string(name)),
   465  		e.Seq()))
   466  }