github.com/MetalBlockchain/metalgo@v1.11.9/snow/consensus/snowball/nnary_snowflake.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 = (*nnarySnowflake)(nil)
    13  
    14  func newNnarySnowflake(alphaPreference int, terminationConditions []terminationCondition, choice ids.ID) nnarySnowflake {
    15  	return nnarySnowflake{
    16  		nnarySlush:            newNnarySlush(choice),
    17  		alphaPreference:       alphaPreference,
    18  		terminationConditions: terminationConditions,
    19  		confidence:            make([]int, len(terminationConditions)),
    20  	}
    21  }
    22  
    23  // nnarySnowflake is the implementation of a snowflake instance with an
    24  // unbounded number of choices
    25  // Invariant:
    26  // len(terminationConditions) == len(confidence)
    27  // terminationConditions[i].alphaConfidence < terminationConditions[i+1].alphaConfidence
    28  // terminationConditions[i].beta <= terminationConditions[i+1].beta
    29  // confidence[i] >= confidence[i+1] (except after finalizing due to early termination)
    30  type nnarySnowflake struct {
    31  	// wrap the n-nary slush logic
    32  	nnarySlush
    33  
    34  	// alphaPreference is the threshold required to update the preference
    35  	alphaPreference int
    36  
    37  	// terminationConditions gives the ascending ordered list of alphaConfidence values
    38  	// required to increment the corresponding confidence counter.
    39  	// The corresponding beta values give the threshold required to finalize this instance.
    40  	terminationConditions []terminationCondition
    41  
    42  	// confidence is the number of consecutive succcessful polls for a given
    43  	// alphaConfidence threshold.
    44  	// This instance finalizes when confidence[i] >= terminationConditions[i].beta for any i
    45  	confidence []int
    46  
    47  	// finalized prevents the state from changing after the required number of
    48  	// consecutive polls has been reached
    49  	finalized bool
    50  }
    51  
    52  func (*nnarySnowflake) Add(_ ids.ID) {}
    53  
    54  func (sf *nnarySnowflake) RecordPoll(count int, choice ids.ID) {
    55  	if sf.finalized {
    56  		return // This instance is already decided.
    57  	}
    58  
    59  	if count < sf.alphaPreference {
    60  		sf.RecordUnsuccessfulPoll()
    61  		return
    62  	}
    63  
    64  	// If I am changing my preference, reset confidence counters
    65  	// before recording a successful poll on the slush instance.
    66  	if choice != sf.Preference() {
    67  		clear(sf.confidence)
    68  	}
    69  	sf.nnarySlush.RecordSuccessfulPoll(choice)
    70  
    71  	for i, terminationCondition := range sf.terminationConditions {
    72  		// If I did not reach this alpha threshold, I did not
    73  		// reach any more alpha thresholds.
    74  		// Clear the remaining confidence counters.
    75  		if count < terminationCondition.alphaConfidence {
    76  			clear(sf.confidence[i:])
    77  			return
    78  		}
    79  
    80  		// I reached this alpha threshold, increment the confidence counter
    81  		// and check if I can finalize.
    82  		sf.confidence[i]++
    83  		if sf.confidence[i] >= terminationCondition.beta {
    84  			sf.finalized = true
    85  			return
    86  		}
    87  	}
    88  }
    89  
    90  func (sf *nnarySnowflake) RecordUnsuccessfulPoll() {
    91  	clear(sf.confidence)
    92  }
    93  
    94  func (sf *nnarySnowflake) Finalized() bool {
    95  	return sf.finalized
    96  }
    97  
    98  func (sf *nnarySnowflake) String() string {
    99  	return fmt.Sprintf("SF(Confidence = %v, Finalized = %v, %s)",
   100  		sf.confidence,
   101  		sf.finalized,
   102  		&sf.nnarySlush)
   103  }