github.com/MetalBlockchain/metalgo@v1.11.9/snow/consensus/snowball/nnary_snowball.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 = (*nnarySnowball)(nil) 13 14 func newNnarySnowball(alphaPreference int, terminationConditions []terminationCondition, choice ids.ID) nnarySnowball { 15 return nnarySnowball{ 16 nnarySnowflake: newNnarySnowflake(alphaPreference, terminationConditions, choice), 17 preference: choice, 18 preferenceStrength: make(map[ids.ID]int), 19 } 20 } 21 22 // nnarySnowball is a naive implementation of a multi-color snowball instance 23 type nnarySnowball struct { 24 // wrap the n-nary snowflake logic 25 nnarySnowflake 26 27 // preference is the choice with the largest number of polls which preferred 28 // it. Ties are broken by switching choice lazily 29 preference ids.ID 30 31 // maxPreferenceStrength is the maximum value stored in [preferenceStrength] 32 maxPreferenceStrength int 33 34 // preferenceStrength tracks the total number of network polls which 35 // preferred that choice 36 preferenceStrength map[ids.ID]int 37 } 38 39 func (sb *nnarySnowball) Preference() ids.ID { 40 // It is possible, with low probability, that the snowflake preference is 41 // not equal to the snowball preference when snowflake finalizes. However, 42 // this case is handled for completion. Therefore, if snowflake is 43 // finalized, then our finalized snowflake choice should be preferred. 44 if sb.Finalized() { 45 return sb.nnarySnowflake.Preference() 46 } 47 return sb.preference 48 } 49 50 func (sb *nnarySnowball) RecordPoll(count int, choice ids.ID) { 51 if count >= sb.alphaPreference { 52 preferenceStrength := sb.preferenceStrength[choice] + 1 53 sb.preferenceStrength[choice] = preferenceStrength 54 55 if preferenceStrength > sb.maxPreferenceStrength { 56 sb.preference = choice 57 sb.maxPreferenceStrength = preferenceStrength 58 } 59 } 60 sb.nnarySnowflake.RecordPoll(count, choice) 61 } 62 63 func (sb *nnarySnowball) String() string { 64 return fmt.Sprintf("SB(Preference = %s, PreferenceStrength = %d, %s)", 65 sb.preference, sb.maxPreferenceStrength, &sb.nnarySnowflake) 66 }