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 }