github.com/MetalBlockchain/metalgo@v1.11.9/snow/engine/snowman/voter.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package snowman
     5  
     6  import (
     7  	"context"
     8  
     9  	"go.uber.org/zap"
    10  
    11  	"github.com/MetalBlockchain/metalgo/ids"
    12  	"github.com/MetalBlockchain/metalgo/snow/engine/snowman/job"
    13  	"github.com/MetalBlockchain/metalgo/utils/bag"
    14  )
    15  
    16  var _ job.Job[ids.ID] = (*voter)(nil)
    17  
    18  // Voter records chits received from [nodeID] once its dependencies are met.
    19  type voter struct {
    20  	t               *Transitive
    21  	nodeID          ids.NodeID
    22  	requestID       uint32
    23  	responseOptions []ids.ID
    24  }
    25  
    26  // The resolution results from the dependencies of the voter aren't explicitly
    27  // used. The responseOptions are used to determine which block to apply the vote
    28  // to. The dependencies are only used to optimistically delay the application of
    29  // the vote until the blocks have been issued.
    30  func (v *voter) Execute(ctx context.Context, _ []ids.ID, _ []ids.ID) error {
    31  	var (
    32  		vote       ids.ID
    33  		shouldVote bool
    34  		voteIndex  int
    35  	)
    36  	for i, voteOption := range v.responseOptions {
    37  		// To prevent any potential deadlocks with undisclosed dependencies,
    38  		// votes must be bubbled to the nearest valid block
    39  		vote, shouldVote = v.t.getProcessingAncestor(ctx, voteOption)
    40  		if shouldVote {
    41  			voteIndex = i
    42  			break
    43  		}
    44  	}
    45  
    46  	var results []bag.Bag[ids.ID]
    47  	if shouldVote {
    48  		v.t.selectedVoteIndex.Observe(float64(voteIndex))
    49  		results = v.t.polls.Vote(v.requestID, v.nodeID, vote)
    50  	} else {
    51  		results = v.t.polls.Drop(v.requestID, v.nodeID)
    52  	}
    53  
    54  	if len(results) == 0 {
    55  		return nil
    56  	}
    57  
    58  	for _, result := range results {
    59  		result := result
    60  		v.t.Ctx.Log.Debug("finishing poll",
    61  			zap.Stringer("result", &result),
    62  		)
    63  		if err := v.t.Consensus.RecordPoll(ctx, result); err != nil {
    64  			return err
    65  		}
    66  	}
    67  
    68  	if err := v.t.VM.SetPreference(ctx, v.t.Consensus.Preference()); err != nil {
    69  		return err
    70  	}
    71  
    72  	if v.t.Consensus.NumProcessing() == 0 {
    73  		v.t.Ctx.Log.Debug("Snowman engine can quiesce")
    74  		return nil
    75  	}
    76  
    77  	v.t.Ctx.Log.Debug("Snowman engine can't quiesce")
    78  	v.t.repoll(ctx)
    79  	return nil
    80  }