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  }