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