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