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 }