synapsecns/sanguine

View on GitHub
ethergo/submitter/config/config.go

Summary

Maintainability
A
3 hrs
Test Coverage
// Package config provides a configuration struct and getters for the submitter.
//
// Config contains configuration for the submitter. It can be loaded from a YAML file.
// Chain-specific configuration items can be provided via the `Chains` map, which overrides the global config
// for each chain. If a chain-specific item is not provided, the global config is used.
package config

import (
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum/params"
)

// Config contains configuration for the submitter.
//
//go:generate go run github.com/vburenin/ifacemaker -f config.go -s Config -i IConfig -p config -o iconfig_generated.go -c "autogenerated file"
type Config struct {
    // GlobalConfig stores the default configuration
    ChainConfig `yaml:",inline"`
    // Chains overrides the global config for each chain
    Chains map[int]ChainConfig `yaml:"chains"`
    // ReaperInterval is the interval at which scan for transactions to flush
    ReaperInterval time.Duration `yaml:"reaper_interval"`
    // MaxRecordAge is the maximum age of a record before it is flushed
    MaxRecordAge time.Duration `yaml:"max_record_age"`
}

// ChainConfig contains configuration for a specific chain.
type ChainConfig struct {
    // MaxBatchSize is the maximum number of transactions to send in a batch
    // if this is zero, the default will be used. This field is ignored if batching is disabled.
    MaxBatchSize int `yaml:"max_batch_size"`
    // Batch is whether or not to batch transactions at the rpc level
    DoNotBatch bool `yaml:"skip_batching"`
    // MaxGasPrice is the maximum gas price to use for transactions
    MaxGasPrice *big.Int `yaml:"max_gas_price"`
    // MinGasPrice is the gas price that will be used if 0 is returned from the gas price oracle
    MinGasPrice *big.Int `yaml:"min_gas_price"`
    // BumpIntervalSeconds is the number of seconds to wait before bumping a transaction
    BumpIntervalSeconds int `yaml:"bump_interval_seconds"`
    // GasBumpPercentages is the percentage to bump the gas price by
    // this is applied to the greatrer of the chainprice or the last price
    GasBumpPercentage int `yaml:"gas_bump_percentage"`
    // GasEstimate is the gas estimate to use for transactions
    // if dynamic gas estimation is enabled, this is only used as a default if the estimate fails
    GasEstimate uint64 `yaml:"gas_estimate"`
    // DynamicGasEstimate is whether or not to use dynamic gas estimation
    DynamicGasEstimate bool `yaml:"dynamic_gas_estimate"`
    // SupportsEIP1559 is whether or not this chain supports EIP1559
    SupportsEIP1559 bool `yaml:"supports_eip_1559"`
}

const (
    // DefaultMaxBatchSize is the default maximum number of transactions to send in a batch.
    DefaultMaxBatchSize = 10

    // DefaultBumpIntervalSeconds is the default number of seconds to wait before bumping a transaction.
    DefaultBumpIntervalSeconds = 30

    // DefaultGasBumpPercentage is the default percentage to bump the gas price by.
    // See: https://github.com/ethereum/go-ethereum/blob/8c5576b1ac89473c7ec15c9b03d1ca02e9499dcc/core/txpool/legacypool/legacypool.go#L146
    DefaultGasBumpPercentage = 10

    // DefaultGasEstimate is the default gas estimate to use for transactions.
    DefaultGasEstimate = uint64(1200000)
)

// DefaultMaxPrice is the default max price of a tx.
var DefaultMaxPrice = big.NewInt(500 * params.GWei)

// DefaultMinGasPrice is the default min price of a tx.
var DefaultMinGasPrice = big.NewInt(0.01 * params.GWei)

// DefaultReaperInterval is the default interval at which to scan for transactions to flush.
var DefaultReaperInterval = time.Minute * 5

// DefaultMaxRecordAge is the default maximum age of a record before it is flushed.
var DefaultMaxRecordAge = time.Hour * 24 * 7

// note: there's probably a way to clean these getters up with generics, the real problem comes with the fact that
// that this would require the caller to override the entire struct, which is not ideal..

// GetReaperInterval returns the reaper interval.
func (c *Config) GetReaperInterval() time.Duration {
    if c.ReaperInterval == 0 {
        return DefaultReaperInterval
    }
    return c.ReaperInterval
}

// GetMaxRecordAge returns the maximum record age.
func (c *Config) GetMaxRecordAge() time.Duration {
    if c.MaxRecordAge == 0 {
        return DefaultMaxRecordAge
    }
    return c.MaxRecordAge
}

// GetMaxBatchSize returns the maximum number of transactions to send in a batch.
func (c *Config) GetMaxBatchSize(chainID int) int {
    chainConfig, ok := c.Chains[chainID]
    if ok && chainConfig.MaxBatchSize != 0 {
        return chainConfig.MaxBatchSize
    }
    maxBatch := c.MaxBatchSize
    if maxBatch == 0 {
        return DefaultMaxBatchSize
    }
    return maxBatch
}

// GetBatch returns whether or not to batch transactions at the rpc level.
func (c *Config) GetBatch(chainID int) bool {
    chainConfig, ok := c.Chains[chainID]
    if ok {
        return !chainConfig.DoNotBatch
    }
    return !c.DoNotBatch
}

// GetMaxGasPrice returns the maximum gas price to use for transactions.
func (c *Config) GetMaxGasPrice(chainID int) (maxPrice *big.Int) {
    maxPrice = c.MaxGasPrice

    chainConfig, ok := c.Chains[chainID]
    if ok && chainConfig.MaxGasPrice != nil {
        maxPrice = chainConfig.MaxGasPrice
    }

    if maxPrice == nil || maxPrice == big.NewInt(0) {
        maxPrice = DefaultMaxPrice
    }
    return
}

// GetMinGasPrice returns the minimum gas price to use for transactions.
func (c *Config) GetMinGasPrice(chainID int) (minPrice *big.Int) {
    minPrice = c.MinGasPrice

    chainConfig, ok := c.Chains[chainID]
    if ok && chainConfig.MinGasPrice != nil {
        minPrice = chainConfig.MinGasPrice
    }

    if minPrice == nil || minPrice == big.NewInt(0) {
        minPrice = DefaultMinGasPrice
    }
    return
}

// GetBumpInterval returns the number of seconds to wait before bumping a transaction
// TODO: test this method.
func (c *Config) GetBumpInterval(chainID int) time.Duration {
    var bumpInterval int
    chainConfig, ok := c.Chains[chainID]
    if ok {
        bumpInterval = chainConfig.BumpIntervalSeconds
    }
    // if bumpInterval is not set for the chain, use the global config
    if bumpInterval == 0 {
        bumpInterval = c.BumpIntervalSeconds
    }

    // if the bump interval isn't set at all, use the default
    if bumpInterval == 0 {
        bumpInterval = DefaultBumpIntervalSeconds
    }
    return time.Duration(bumpInterval) * time.Second
}

// GetGasBumpPercentage returns the percentage to bump the gas price by
// TODO: test this method.
func (c *Config) GetGasBumpPercentage(chainID int) (gasBumpPercentage int) {
    chainConfig, ok := c.Chains[chainID]
    if ok {
        gasBumpPercentage = chainConfig.GasBumpPercentage
    }
    // if gasBumpPercentage is not set for the chain, use the global config
    if gasBumpPercentage == 0 {
        gasBumpPercentage = c.GasBumpPercentage
    }

    // if the gasBumpPercentage isn't set at all, use the default
    if gasBumpPercentage == 0 {
        gasBumpPercentage = DefaultGasBumpPercentage
    }
    return gasBumpPercentage
}

// GetGasEstimate returns the gas estimate to use for transactions
// TODO: test this method.
func (c *Config) GetGasEstimate(chainID int) (gasEstimate uint64) {
    chainConfig, ok := c.Chains[chainID]
    if ok {
        gasEstimate = chainConfig.GasEstimate
    }
    // if gasBumpPercentage is not set for the chain, use the global config
    if gasEstimate == 0 {
        gasEstimate = c.GasEstimate
    }

    // if the gasBumpPercentage isn't set at all, use the default
    if gasEstimate == 0 {
        gasEstimate = DefaultGasEstimate
    }
    return gasEstimate
}

// GetDynamicGasEstimate returns whether or not to use dynamic gas estimation
// TODO: test this method.
func (c *Config) GetDynamicGasEstimate(chainID int) bool {
    chainConfig, ok := c.Chains[chainID]
    if ok {
        return chainConfig.DynamicGasEstimate
    }
    return c.DynamicGasEstimate
}

// SupportsEIP1559 returns whether or not this chain supports EIP1559.
func (c *Config) SupportsEIP1559(chainID int) bool {
    chainConfig, ok := c.Chains[chainID]
    if ok {
        return chainConfig.SupportsEIP1559
    }
    return c.ChainConfig.SupportsEIP1559
}

// SetGlobalMaxGasPrice is a helper function that sets the global gas price.
func (c *Config) SetGlobalMaxGasPrice(maxPrice *big.Int) {
    c.MaxGasPrice = maxPrice
}

// SetMinGasPrice is a helper function that sets the base gas price.
func (c *Config) SetMinGasPrice(basePrice *big.Int) {
    c.MinGasPrice = basePrice
}

// SetGlobalEIP1559Support is a helper function that sets the global EIP1559 support.
func (c *Config) SetGlobalEIP1559Support(supportsEIP1559 bool) {
    c.ChainConfig.SupportsEIP1559 = supportsEIP1559
}

var _ IConfig = &Config{}