code.vegaprotocol.io/vega@v0.79.0/core/netparams/checks/checks.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package checks
    17  
    18  import (
    19  	"errors"
    20  	"fmt"
    21  	"time"
    22  
    23  	"code.vegaprotocol.io/vega/libs/num"
    24  	"code.vegaprotocol.io/vega/logging"
    25  	types "code.vegaprotocol.io/vega/protos/vega"
    26  )
    27  
    28  type Collateral interface {
    29  	AssetExists(asset string) bool
    30  }
    31  
    32  type Assets interface {
    33  	IsEnabled(asset string) bool
    34  }
    35  
    36  func SpamPoWHashFunction(supportedFunctions []string) func(string) error {
    37  	return func(name string) error {
    38  		for _, v := range supportedFunctions {
    39  			if v == name {
    40  				return nil
    41  			}
    42  		}
    43  		return errors.New("Spam Proof of Work hash function must be SHA3")
    44  	}
    45  }
    46  
    47  func LongBlockAuctionDurationTable() func(interface{}, interface{}) error {
    48  	return func(v interface{}, _ interface{}) error {
    49  		lbadTable, ok := v.(*types.LongBlockAuctionDurationTable)
    50  		if !ok {
    51  			return fmt.Errorf("invalid long block auction duration table")
    52  		}
    53  		seenThresholds := map[string]struct{}{}
    54  		for i, tad := range lbadTable.ThresholdAndDuration {
    55  			thr, err := time.ParseDuration(tad.Threshold)
    56  			if err != nil {
    57  				return fmt.Errorf("invalid long block auction duration table - threshold at index %d is not a valid duration", i)
    58  			}
    59  			if thr.Nanoseconds() <= 0 {
    60  				return fmt.Errorf("invalid long block auction duration table - threshold at index %d is not a positive duration", i)
    61  			}
    62  			dur, err := time.ParseDuration(tad.Duration)
    63  			if err != nil {
    64  				return fmt.Errorf("invalid long block auction duration table - duration at index %d is not a valid duration", i)
    65  			}
    66  			if dur.Nanoseconds() <= 0 {
    67  				return fmt.Errorf("invalid long block auction duration table - duration at index %d is not a positive duration", i)
    68  			}
    69  			if dur.Seconds() < 1 {
    70  				return fmt.Errorf("invalid long block auction duration table - duration at index %d is less than one second", i)
    71  			}
    72  			if _, ok := seenThresholds[tad.Threshold]; ok {
    73  				return fmt.Errorf("invalid long block auction duration table - duplicate threshold")
    74  			}
    75  			seenThresholds[tad.Threshold] = struct{}{}
    76  		}
    77  		return nil
    78  	}
    79  }
    80  
    81  func MarginScalingFactor() func(interface{}, interface{}) error {
    82  	return func(v interface{}, _ interface{}) error {
    83  		sf := v.(*types.ScalingFactors)
    84  		if sf.SearchLevel >= sf.InitialMargin || sf.InitialMargin >= sf.CollateralRelease {
    85  			return errors.New("invalid scaling factors (searchLevel < initialMargin < collateralRelease)")
    86  		}
    87  		return nil
    88  	}
    89  }
    90  
    91  func MarginScalingFactorRange(min, max num.Decimal) func(interface{}, interface{}) error {
    92  	return func(v interface{}, _ interface{}) error {
    93  		sf := v.(*types.ScalingFactors)
    94  		if sf.SearchLevel < min.InexactFloat64() || sf.CollateralRelease > max.InexactFloat64() {
    95  			return errors.New("invalid scaling factors (" + min.String() + "< searchLevel < initialMargin < collateralRelease <=" + max.String() + ")")
    96  		}
    97  		return nil
    98  	}
    99  }
   100  
   101  func PriceMonitoringParametersAuctionExtension(min, max time.Duration) func(interface{}, interface{}) error {
   102  	return func(v interface{}, _ interface{}) error {
   103  		pmp := v.(*types.PriceMonitoringParameters)
   104  		for _, pmt := range pmp.Triggers {
   105  			if time.Duration(pmt.AuctionExtension*int64(time.Second)) < min || time.Duration(pmt.AuctionExtension*int64(time.Second)) > max {
   106  				return errors.New("invalid AuctionExtension: must be between " + min.String() + " and " + max.String())
   107  			}
   108  		}
   109  		return nil
   110  	}
   111  }
   112  
   113  func PriceMonitoringParametersHorizon(min, max time.Duration) func(interface{}, interface{}) error {
   114  	return func(v interface{}, _ interface{}) error {
   115  		pmp := v.(*types.PriceMonitoringParameters)
   116  		for _, pmt := range pmp.Triggers {
   117  			if time.Duration(pmt.Horizon*int64(time.Second)) < min || time.Duration(pmt.Horizon*int64(time.Second)) > max {
   118  				return errors.New("invalid Horizon: must be between " + min.String() + " and " + max.String())
   119  			}
   120  		}
   121  		return nil
   122  	}
   123  }
   124  
   125  func PriceMonitoringParametersProbability(min, max num.Decimal) func(interface{}, interface{}) error {
   126  	return func(v interface{}, _ interface{}) error {
   127  		pmp := v.(*types.PriceMonitoringParameters)
   128  		for _, pmt := range pmp.Triggers {
   129  			p, e := num.DecimalFromString(pmt.Probability)
   130  			if e != nil {
   131  				return e
   132  			}
   133  			if p.LessThan(min) || p.GreaterThanOrEqual(max) {
   134  				return errors.New("invalid Probability: must be " + min.String() + " <= x < " + max.String())
   135  			}
   136  		}
   137  		return nil
   138  	}
   139  }
   140  
   141  func RewardAssetUpdate(
   142  	log *logging.Logger,
   143  	assets Assets,
   144  	collateral Collateral,
   145  ) func(value string) error {
   146  	return func(value string) error {
   147  		if !assets.IsEnabled(value) {
   148  			log.Debug("tried to push a reward update with an non-enabled asset",
   149  				logging.String("asset-id", value))
   150  			return fmt.Errorf("invalid asset %v", value)
   151  		}
   152  
   153  		if !collateral.AssetExists(value) {
   154  			log.Debug("unable to update reward asset in collateral",
   155  				logging.String("asset-id", value))
   156  			return fmt.Errorf("asset does not exists in collateral %v", value)
   157  		}
   158  		return nil
   159  	}
   160  }