github.com/MetalBlockchain/metalgo@v1.11.9/snow/consensus/snowball/parameters.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 "errors" 8 "fmt" 9 "time" 10 ) 11 12 const ( 13 // MinPercentConnectedBuffer is the safety buffer for calculation of 14 // MinPercentConnected. This increases the required percentage above 15 // alpha/k. This value must be [0-1]. 16 // 0 means MinPercentConnected = alpha/k. 17 // 1 means MinPercentConnected = 1 (fully connected). 18 MinPercentConnectedBuffer = .2 19 20 errMsg = `__________ .___ 21 \______ \____________ __| _/__.__. 22 | | _/\_ __ \__ \ / __ < | | 23 | | \ | | \// __ \_/ /_/ |\___ | 24 |______ / |__| (____ /\____ |/ ____| 25 \/ \/ \/\/ 26 27 🏆 🏆 🏆 🏆 🏆 🏆 🏆 28 ________ ________ ________________ 29 / _____/ \_____ \ / _ \__ ___/ 30 / \ ___ / | \ / /_\ \| | 31 \ \_\ \/ | \/ | \ | 32 \______ /\_______ /\____|__ /____| 33 \/ \/ \/ 34 ` 35 ) 36 37 var ( 38 DefaultParameters = Parameters{ 39 K: 20, 40 AlphaPreference: 15, 41 AlphaConfidence: 15, 42 Beta: 20, 43 ConcurrentRepolls: 4, 44 OptimalProcessing: 10, 45 MaxOutstandingItems: 256, 46 MaxItemProcessingTime: 30 * time.Second, 47 } 48 49 ErrParametersInvalid = errors.New("parameters invalid") 50 ) 51 52 // Parameters required for snowball consensus 53 type Parameters struct { 54 // K is the number of nodes to query and sample in a round. 55 K int `json:"k" yaml:"k"` 56 // Alpha is used for backwards compatibility purposes and is only referenced 57 // during json parsing. 58 Alpha *int `json:"alpha,omitempty" yaml:"alpha,omitempty"` 59 // AlphaPreference is the vote threshold to change your preference. 60 AlphaPreference int `json:"alphaPreference" yaml:"alphaPreference"` 61 // AlphaConfidence is the vote threshold to increase your confidence. 62 AlphaConfidence int `json:"alphaConfidence" yaml:"alphaConfidence"` 63 // Beta is the number of consecutive successful queries required for 64 // finalization. 65 Beta int `json:"beta" yaml:"beta"` 66 // ConcurrentRepolls is the number of outstanding polls the engine will 67 // target to have while there is something processing. 68 ConcurrentRepolls int `json:"concurrentRepolls" yaml:"concurrentRepolls"` 69 // OptimalProcessing is used to limit block creation when a large number of 70 // blocks are processing. 71 OptimalProcessing int `json:"optimalProcessing" yaml:"optimalProcessing"` 72 73 // Reports unhealthy if more than this number of items are outstanding. 74 MaxOutstandingItems int `json:"maxOutstandingItems" yaml:"maxOutstandingItems"` 75 76 // Reports unhealthy if there is an item processing for longer than this 77 // duration. 78 MaxItemProcessingTime time.Duration `json:"maxItemProcessingTime" yaml:"maxItemProcessingTime"` 79 } 80 81 // Verify returns nil if the parameters describe a valid initialization. 82 // 83 // An initialization is valid if the following conditions are met: 84 // 85 // - K/2 < AlphaPreference <= AlphaConfidence <= K 86 // - 0 < ConcurrentRepolls <= Beta 87 // - 0 < OptimalProcessing 88 // - 0 < MaxOutstandingItems 89 // - 0 < MaxItemProcessingTime 90 // 91 // Note: K/2 < K implies that 0 <= K/2, so we don't need an explicit check that 92 // AlphaPreference is positive. 93 func (p Parameters) Verify() error { 94 switch { 95 case p.AlphaPreference <= p.K/2: 96 return fmt.Errorf("%w: k = %d, alphaPreference = %d: fails the condition that: k/2 < alphaPreference", ErrParametersInvalid, p.K, p.AlphaPreference) 97 case p.AlphaConfidence < p.AlphaPreference: 98 return fmt.Errorf("%w: alphaPreference = %d, alphaConfidence = %d: fails the condition that: alphaPreference <= alphaConfidence", ErrParametersInvalid, p.AlphaPreference, p.AlphaConfidence) 99 case p.K < p.AlphaConfidence: 100 return fmt.Errorf("%w: k = %d, alphaConfidence = %d: fails the condition that: alphaConfidence <= k", ErrParametersInvalid, p.K, p.AlphaConfidence) 101 case p.AlphaConfidence == 3 && p.AlphaPreference == 28: 102 return fmt.Errorf("%w: alphaConfidence = %d, alphaPreference = %d: fails the condition that: alphaPreference <= alphaConfidence\n%s", ErrParametersInvalid, p.AlphaConfidence, p.AlphaPreference, errMsg) 103 case p.ConcurrentRepolls <= 0: 104 return fmt.Errorf("%w: concurrentRepolls = %d: fails the condition that: 0 < concurrentRepolls", ErrParametersInvalid, p.ConcurrentRepolls) 105 case p.ConcurrentRepolls > p.Beta: 106 return fmt.Errorf("%w: concurrentRepolls = %d, beta = %d: fails the condition that: concurrentRepolls <= beta", ErrParametersInvalid, p.ConcurrentRepolls, p.Beta) 107 case p.OptimalProcessing <= 0: 108 return fmt.Errorf("%w: optimalProcessing = %d: fails the condition that: 0 < optimalProcessing", ErrParametersInvalid, p.OptimalProcessing) 109 case p.MaxOutstandingItems <= 0: 110 return fmt.Errorf("%w: maxOutstandingItems = %d: fails the condition that: 0 < maxOutstandingItems", ErrParametersInvalid, p.MaxOutstandingItems) 111 case p.MaxItemProcessingTime <= 0: 112 return fmt.Errorf("%w: maxItemProcessingTime = %d: fails the condition that: 0 < maxItemProcessingTime", ErrParametersInvalid, p.MaxItemProcessingTime) 113 default: 114 return nil 115 } 116 } 117 118 func (p Parameters) MinPercentConnectedHealthy() float64 { 119 // AlphaConfidence is used here to ensure that the node can still feasibly 120 // accept operations. If AlphaPreference were used, committing could be 121 // extremely unlikely to happen, even while healthy. 122 alphaRatio := float64(p.AlphaConfidence) / float64(p.K) 123 return alphaRatio*(1-MinPercentConnectedBuffer) + MinPercentConnectedBuffer 124 } 125 126 type terminationCondition struct { 127 alphaConfidence int 128 beta int 129 } 130 131 func newSingleTerminationCondition(alphaConfidence int, beta int) []terminationCondition { 132 return []terminationCondition{ 133 { 134 alphaConfidence: alphaConfidence, 135 beta: beta, 136 }, 137 } 138 }