github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/config/config.go (about)

     1  package config
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"net/http"
     7  	"os"
     8  	"path/filepath"
     9  	"time"
    10  
    11  	"github.com/nspcc-dev/neo-go/pkg/config/netmode"
    12  	"gopkg.in/yaml.v3"
    13  )
    14  
    15  const (
    16  	// UserAgentWrapper is a string that user agent string should be wrapped into.
    17  	UserAgentWrapper = "/"
    18  	// UserAgentPrefix is a prefix used to generate user agent string.
    19  	UserAgentPrefix = "NEO-GO:"
    20  	// UserAgentFormat is a formatted string used to generate user agent string.
    21  	UserAgentFormat = UserAgentWrapper + UserAgentPrefix + "%s" + UserAgentWrapper
    22  	// DefaultMaxIteratorResultItems is the default upper bound of traversed
    23  	// iterator items per JSON-RPC response. It covers both session-based and
    24  	// naive iterators.
    25  	DefaultMaxIteratorResultItems = 100
    26  	// DefaultMaxFindResultItems is the default maximum number of resulting
    27  	// contract states items that can be retrieved by `findstates` JSON-RPC handler.
    28  	DefaultMaxFindResultItems = 100
    29  	// DefaultMaxFindStorageResultItems is the default maximum number of resulting
    30  	// contract storage items that can be retrieved by `findstorge` JSON-RPC handler.
    31  	DefaultMaxFindStorageResultItems = 50
    32  	// DefaultMaxNEP11Tokens is the default maximum number of resulting NEP11 tokens
    33  	// that can be traversed by `getnep11balances` JSON-RPC handler.
    34  	DefaultMaxNEP11Tokens = 100
    35  	// DefaultMaxRequestBodyBytes is the default maximum allowed size of HTTP
    36  	// request body in bytes.
    37  	DefaultMaxRequestBodyBytes = 5 * 1024 * 1024
    38  	// DefaultMaxRequestHeaderBytes is the maximum permitted size of the headers
    39  	// in an HTTP request.
    40  	DefaultMaxRequestHeaderBytes = http.DefaultMaxHeaderBytes
    41  )
    42  
    43  // Version is the version of the node, set at the build time.
    44  var Version string
    45  
    46  // Config top level struct representing the config
    47  // for the node.
    48  type Config struct {
    49  	ProtocolConfiguration    ProtocolConfiguration    `yaml:"ProtocolConfiguration"`
    50  	ApplicationConfiguration ApplicationConfiguration `yaml:"ApplicationConfiguration"`
    51  }
    52  
    53  // GenerateUserAgent creates a user agent string based on the build time environment.
    54  func (c Config) GenerateUserAgent() string {
    55  	return fmt.Sprintf(UserAgentFormat, Version)
    56  }
    57  
    58  // Blockchain generates a Blockchain configuration based on Protocol and
    59  // Application settings.
    60  func (c Config) Blockchain() Blockchain {
    61  	return Blockchain{
    62  		ProtocolConfiguration: c.ProtocolConfiguration,
    63  		Ledger:                c.ApplicationConfiguration.Ledger,
    64  	}
    65  }
    66  
    67  // Load attempts to load the config from the given
    68  // path for the given netMode. If relativePath is not empty, relative paths in the
    69  // config will be updated based on the provided relative path.
    70  func Load(path string, netMode netmode.Magic, relativePath ...string) (Config, error) {
    71  	configPath := fmt.Sprintf("%s/protocol.%s.yml", path, netMode)
    72  	return LoadFile(configPath, relativePath...)
    73  }
    74  
    75  // LoadFile loads config from the provided path. It also applies backwards compatibility
    76  // fixups if necessary. If relativePath is not empty, relative paths in the config will
    77  // be updated based on the provided relative path.
    78  func LoadFile(configPath string, relativePath ...string) (Config, error) {
    79  	if _, err := os.Stat(configPath); os.IsNotExist(err) {
    80  		return Config{}, fmt.Errorf("config '%s' doesn't exist", configPath)
    81  	}
    82  
    83  	configData, err := os.ReadFile(configPath)
    84  	if err != nil {
    85  		return Config{}, fmt.Errorf("unable to read config: %w", err)
    86  	}
    87  
    88  	config := Config{
    89  		ApplicationConfiguration: ApplicationConfiguration{
    90  			P2P: P2P{
    91  				PingInterval: 30 * time.Second,
    92  				PingTimeout:  90 * time.Second,
    93  			},
    94  		},
    95  	}
    96  	decoder := yaml.NewDecoder(bytes.NewReader(configData))
    97  	decoder.KnownFields(true)
    98  	err = decoder.Decode(&config)
    99  	if err != nil {
   100  		return Config{}, fmt.Errorf("failed to unmarshal config YAML: %w", err)
   101  	}
   102  	if len(relativePath) == 1 && relativePath[0] != "" {
   103  		updateRelativePaths(relativePath[0], &config)
   104  	}
   105  
   106  	err = config.ProtocolConfiguration.Validate()
   107  	if err != nil {
   108  		return Config{}, err
   109  	}
   110  
   111  	return config, nil
   112  }
   113  
   114  // updateRelativePaths updates relative paths in the config structure based on the provided relative path.
   115  func updateRelativePaths(relativePath string, config *Config) {
   116  	updatePath := func(path *string) {
   117  		if *path != "" && !filepath.IsAbs(*path) {
   118  			*path = filepath.Join(relativePath, *path)
   119  		}
   120  	}
   121  
   122  	updatePath(&config.ApplicationConfiguration.LogPath)
   123  	updatePath(&config.ApplicationConfiguration.DBConfiguration.BoltDBOptions.FilePath)
   124  	updatePath(&config.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath)
   125  	updatePath(&config.ApplicationConfiguration.Consensus.UnlockWallet.Path)
   126  	updatePath(&config.ApplicationConfiguration.P2PNotary.UnlockWallet.Path)
   127  	updatePath(&config.ApplicationConfiguration.Oracle.UnlockWallet.Path)
   128  	updatePath(&config.ApplicationConfiguration.StateRoot.UnlockWallet.Path)
   129  }