github.com/MetalBlockchain/metalgo@v1.11.9/snow/consensus/snowball/nnary_snowball.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package snowball
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/MetalBlockchain/metalgo/ids"
    10  )
    11  
    12  var _ Nnary = (*nnarySnowball)(nil)
    13  
    14  func newNnarySnowball(alphaPreference int, terminationConditions []terminationCondition, choice ids.ID) nnarySnowball {
    15  	return nnarySnowball{
    16  		nnarySnowflake:     newNnarySnowflake(alphaPreference, terminationConditions, choice),
    17  		preference:         choice,
    18  		preferenceStrength: make(map[ids.ID]int),
    19  	}
    20  }
    21  
    22  // nnarySnowball is a naive implementation of a multi-color snowball instance
    23  type nnarySnowball struct {
    24  	// wrap the n-nary snowflake logic
    25  	nnarySnowflake
    26  
    27  	// preference is the choice with the largest number of polls which preferred
    28  	// it. Ties are broken by switching choice lazily
    29  	preference ids.ID
    30  
    31  	// maxPreferenceStrength is the maximum value stored in [preferenceStrength]
    32  	maxPreferenceStrength int
    33  
    34  	// preferenceStrength tracks the total number of network polls which
    35  	// preferred that choice
    36  	preferenceStrength map[ids.ID]int
    37  }
    38  
    39  func (sb *nnarySnowball) Preference() ids.ID {
    40  	// It is possible, with low probability, that the snowflake preference is
    41  	// not equal to the snowball preference when snowflake finalizes. However,
    42  	// this case is handled for completion. Therefore, if snowflake is
    43  	// finalized, then our finalized snowflake choice should be preferred.
    44  	if sb.Finalized() {
    45  		return sb.nnarySnowflake.Preference()
    46  	}
    47  	return sb.preference
    48  }
    49  
    50  func (sb *nnarySnowball) RecordPoll(count int, choice ids.ID) {
    51  	if count >= sb.alphaPreference {
    52  		preferenceStrength := sb.preferenceStrength[choice] + 1
    53  		sb.preferenceStrength[choice] = preferenceStrength
    54  
    55  		if preferenceStrength > sb.maxPreferenceStrength {
    56  			sb.preference = choice
    57  			sb.maxPreferenceStrength = preferenceStrength
    58  		}
    59  	}
    60  	sb.nnarySnowflake.RecordPoll(count, choice)
    61  }
    62  
    63  func (sb *nnarySnowball) String() string {
    64  	return fmt.Sprintf("SB(Preference = %s, PreferenceStrength = %d, %s)",
    65  		sb.preference, sb.maxPreferenceStrength, &sb.nnarySnowflake)
    66  }