github.com/status-im/status-go@v1.1.0/params/config.go (about)

     1  package params
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"net/url"
    10  	"os"
    11  	"path/filepath"
    12  	"strings"
    13  	"time"
    14  
    15  	validator "gopkg.in/go-playground/validator.v9"
    16  
    17  	"github.com/ethereum/go-ethereum/common"
    18  	"github.com/ethereum/go-ethereum/log"
    19  	"github.com/ethereum/go-ethereum/p2p/discv5"
    20  	"github.com/ethereum/go-ethereum/params"
    21  
    22  	"github.com/status-im/status-go/eth-node/crypto"
    23  	"github.com/status-im/status-go/eth-node/types"
    24  	"github.com/status-im/status-go/static"
    25  	wakucommon "github.com/status-im/status-go/waku/common"
    26  	wakuv2common "github.com/status-im/status-go/wakuv2/common"
    27  )
    28  
    29  // ----------
    30  // LightEthConfig
    31  // ----------
    32  
    33  // LightEthConfig holds LES-related configuration
    34  // Status nodes are always lightweight clients (due to mobile platform constraints)
    35  type LightEthConfig struct {
    36  	// Enabled flag specifies whether protocol is enabled
    37  	Enabled bool
    38  
    39  	// DatabaseCache is memory (in MBs) allocated to internal caching (min 16MB / database forced)
    40  	DatabaseCache int
    41  
    42  	// TrustedNodes is a list of trusted servers
    43  	TrustedNodes []string
    44  
    45  	//MinTrustedFraction is minimum percentage of connected trusted servers to validate header(1-100)
    46  	MinTrustedFraction int
    47  }
    48  
    49  // ----------
    50  // DatabaseConfig
    51  // ----------
    52  
    53  type DatabaseConfig struct {
    54  	PGConfig PGConfig
    55  }
    56  
    57  // ----------
    58  // PGConfig
    59  // ----------
    60  
    61  type PGConfig struct {
    62  	// Enabled whether we should use a Postgres instance
    63  	Enabled bool
    64  	// The URI of the server
    65  	URI string
    66  }
    67  
    68  // ----------
    69  // WakuConfig
    70  // ----------
    71  
    72  // WakuConfig provides a configuration for Waku service.
    73  type WakuConfig struct {
    74  	// Enabled set to true enables Waku subprotocol.
    75  	Enabled bool
    76  
    77  	// LightClient should be true if the node should start with an empty bloom filter and not forward messages from other nodes
    78  	LightClient bool
    79  
    80  	// FullNode should be true if waku should always acta as a full node
    81  	FullNode bool
    82  
    83  	// EnableMailServer is mode when node is capable of delivering expired messages on demand
    84  	EnableMailServer bool
    85  
    86  	// DataDir is the file system folder Waku should use for any data storage needs.
    87  	// For instance, MailServer will use this directory to store its data.
    88  	DataDir string
    89  
    90  	// MinimumPoW minimum PoW for Waku messages
    91  	// We enforce a minimum as a bland spam prevention mechanism.
    92  	MinimumPoW float64
    93  
    94  	// MailServerPassword for symmetric encryption of waku message history requests.
    95  	// (if no account file selected, then this password is used for symmetric encryption).
    96  	MailServerPassword string
    97  
    98  	// MailServerRateLimit minimum time between queries to mail server per peer.
    99  	MailServerRateLimit int
   100  
   101  	// MailServerDataRetention is a number of days data should be stored by MailServer.
   102  	MailServerDataRetention int
   103  
   104  	// TTL time to live for messages, in seconds
   105  	TTL int
   106  
   107  	// MaxMessageSize is a maximum size of a devp2p packet handled by the Waku protocol,
   108  	// not only the size of envelopes sent in that packet.
   109  	MaxMessageSize uint32
   110  
   111  	// DatabaseConfig is configuration for which data store we use.
   112  	DatabaseConfig DatabaseConfig
   113  
   114  	// EnableRateLimiter set to true enables IP and peer ID rate limiting.
   115  	EnableRateLimiter bool
   116  
   117  	// PacketRateLimitIP sets the limit on the number of packets per second
   118  	// from a given IP.
   119  	PacketRateLimitIP int64
   120  
   121  	// PacketRateLimitPeerID sets the limit on the number of packets per second
   122  	// from a given peer ID.
   123  	PacketRateLimitPeerID int64
   124  
   125  	// BytesRateLimitIP sets the limit on the number of bytes per second
   126  	// from a given IP.
   127  	BytesRateLimitIP int64
   128  
   129  	// BytesRateLimitPeerID sets the limit on the number of bytes per second
   130  	// from a given peer ID.
   131  	BytesRateLimitPeerID int64
   132  
   133  	// RateLimitTolerance is a number of how many a limit must be exceeded
   134  	// in order to drop a peer.
   135  	// If equal to 0, the peers are never dropped.
   136  	RateLimitTolerance int64
   137  
   138  	// BloomFilterMode tells us whether we should be sending a bloom
   139  	// filter rather than TopicInterest
   140  	BloomFilterMode bool
   141  
   142  	// SoftBlacklistedPeerIDs is a list of peer ids that should be soft-blacklisted (messages should be dropped but connection kept)
   143  	SoftBlacklistedPeerIDs []string
   144  
   145  	// EnableConfirmations when true, instructs that confirmation should be sent for received messages
   146  	EnableConfirmations bool
   147  }
   148  
   149  // ----------
   150  // WakuV2Config
   151  // ----------
   152  
   153  // WakuConfig provides a configuration for Waku service.
   154  type WakuV2Config struct {
   155  	// Enabled set to true enables Waku subprotocol.
   156  	Enabled bool
   157  
   158  	// Host interface in which to start libp2p protocol
   159  	Host string
   160  
   161  	// Port number in which to start libp2p protocol (0 for random)
   162  	Port int
   163  
   164  	// LightClient should be true if the node will not relay messages and only rely on lightpush/filter nodes
   165  	LightClient bool
   166  
   167  	// FullNode should be true if waku should always acta as a full node
   168  	FullNode bool
   169  
   170  	// DiscoveryLimit indicates the maximum number of peers to discover
   171  	DiscoveryLimit int
   172  
   173  	// DataDir is the file system folder Waku should use for any data storage needs.
   174  	// For instance, MailServer will use this directory to store its data.
   175  	DataDir string
   176  
   177  	// MaxMessageSize is a maximum size of a devp2p packet handled by the Waku protocol,
   178  	// not only the size of envelopes sent in that packet.
   179  	MaxMessageSize uint32
   180  
   181  	// EnableConfirmations when true, instructs that confirmation should be sent for received messages
   182  	EnableConfirmations bool
   183  
   184  	// A name->libp2p_addr map for Wakuv2 custom nodes
   185  	CustomNodes map[string]string
   186  
   187  	// PeerExchange determines whether WakuV2 Peer Exchange is enabled or not
   188  	// Deprecated: will be calculated based on LightClient
   189  	PeerExchange bool
   190  
   191  	// Nameserver determines which nameserver will be used for dns discovery
   192  	Nameserver string
   193  
   194  	// EnableDiscV5 indicates if DiscoveryV5 is enabled or not
   195  	// Deprecated: will be calculated based on LightClient
   196  	EnableDiscV5 bool
   197  
   198  	// UDPPort number to start discovery v5
   199  	UDPPort int
   200  
   201  	// AutoUpdate instructs the node to update their own ip address and port with the values seen by other nodes
   202  	AutoUpdate bool
   203  
   204  	// EnableStore indicates if WakuStore protocol should be enabled or not
   205  	EnableStore bool
   206  
   207  	// StoreCapacity indicates the max number of messages to store
   208  	StoreCapacity int
   209  
   210  	// StoreSeconds indicates the maximum number of seconds before a message is removed from the store
   211  	StoreSeconds int
   212  
   213  	TelemetryServerURL string
   214  
   215  	// EnableMissingMessageVerification indicates whether the storenodes must be queried periodically to retrieve any missing message
   216  	EnableMissingMessageVerification bool
   217  
   218  	// EnableMissingMessageVerification indicates whether storenodes must be queried periodically to confirm if messages sent are actually propagated in the network
   219  	EnableStoreConfirmationForMessagesSent bool
   220  }
   221  
   222  // ----------
   223  // SwarmConfig
   224  // ----------
   225  
   226  // SwarmConfig holds Swarm-related configuration
   227  type SwarmConfig struct {
   228  	// Enabled flag specifies whether protocol is enabled
   229  	Enabled bool
   230  }
   231  
   232  // String dumps config object as nicely indented JSON
   233  func (c *SwarmConfig) String() string {
   234  	data, _ := json.MarshalIndent(c, "", "    ") // nolint: gas
   235  	return string(data)
   236  }
   237  
   238  // ----------
   239  // ClusterConfig
   240  // ----------
   241  
   242  // ClusterConfig holds configuration for supporting cluster peers, which is a temporary
   243  // means for mobile devices to get connected to Ethereum network (UDP-based discovery
   244  // may not be available, so we need means to discover the network manually).
   245  type ClusterConfig struct {
   246  	// Enabled flag specifies that nodes in this configuration are taken into account.
   247  	Enabled bool
   248  
   249  	// Fleet is a name of a selected fleet. If it has a value, nodes are loaded
   250  	// from a file, namely `fleet-*.{{ .Fleet }}.json`. Nodes can be added to any list
   251  	// in `ClusterConfig`.
   252  	Fleet string
   253  
   254  	// StaticNodes is a list of static nodes.
   255  	StaticNodes []string
   256  
   257  	// BootNodes is a list of bootnodes.
   258  	// Deprecated: won't be used at all in wakuv2
   259  	BootNodes []string
   260  
   261  	// TrustedMailServers is a list of verified and trusted Mail Server nodes.
   262  	TrustedMailServers []string
   263  
   264  	// PushNotificationsServers is a list of default push notification servers.
   265  	PushNotificationsServers []string
   266  
   267  	// WakuNodes is a list of waku2 multiaddresses
   268  	WakuNodes []string
   269  
   270  	// DiscV5Nodes is a list of enr to be used for ambient discovery
   271  	DiscV5BootstrapNodes []string
   272  
   273  	//Waku network identifier
   274  	ClusterID uint16
   275  }
   276  
   277  // String dumps config object as nicely indented JSON
   278  func (c *ClusterConfig) String() string {
   279  	data, _ := json.MarshalIndent(c, "", "    ") // nolint: gas
   280  	return string(data)
   281  }
   282  
   283  // Limits represent min and max amount of peers
   284  type Limits struct {
   285  	Min, Max int
   286  }
   287  
   288  // NewLimits creates new Limits config with given min and max values.
   289  func NewLimits(min, max int) Limits {
   290  	return Limits{
   291  		Min: min,
   292  		Max: max,
   293  	}
   294  }
   295  
   296  // ----------
   297  // UpstreamRPCConfig
   298  // ----------
   299  
   300  // UpstreamRPCConfig stores configuration for upstream rpc connection.
   301  type UpstreamRPCConfig struct {
   302  	// Enabled flag specifies whether feature is enabled
   303  	Enabled bool
   304  
   305  	// URL sets the rpc upstream host address for communication with
   306  	// a non-local infura endpoint.
   307  	URL string
   308  }
   309  
   310  type ProviderConfig struct {
   311  	// Enabled flag specifies whether feature is enabled
   312  	Enabled bool `validate:"required"`
   313  
   314  	// To identify provider
   315  	Name string `validate:"required"`
   316  
   317  	// URL sets the rpc upstream host address for communication with
   318  	// a non-local infura endpoint.
   319  	User         string `json:",omitempty"`
   320  	Password     string `json:",omitempty"`
   321  	APIKey       string `json:"APIKey,omitempty"`
   322  	APIKeySecret string `json:"APIKeySecret,omitempty"`
   323  }
   324  
   325  // ----------
   326  // NodeConfig
   327  // ----------
   328  
   329  // NodeConfig stores configuration options for a node
   330  type NodeConfig struct {
   331  	// NetworkID sets network to use for selecting peers to connect to
   332  	NetworkID uint64 `json:"NetworkId" validate:"required"`
   333  
   334  	RootDataDir string `json:",omitempty"`
   335  
   336  	// DataDir is the file system folder the node should use for any data storage needs.
   337  	DataDir string `validate:"required"`
   338  
   339  	// KeyStoreDir is the file system folder that contains private keys.
   340  	KeyStoreDir string `validate:"required"`
   341  
   342  	// KeycardPairingDataFile is the file where we keep keycard pairings data.
   343  	// It's specified by clients (and not in status-go) when creating a new account,
   344  	// because this file is initialized by status-keycard-go and we need to use it before initializing the node.
   345  	// I guess proper way would be to ask status-go for the file path, or just duplicate the file path in both backend and client.
   346  	// note: this field won't be saved into db, it's local to the device.
   347  	KeycardPairingDataFile string
   348  
   349  	// NodeKey is the hex-encoded node ID (private key). Should be a valid secp256k1 private key that will be used for both
   350  	// remote peer identification as well as network traffic encryption.
   351  	NodeKey string
   352  
   353  	// NoDiscovery set to true will disable discovery protocol.
   354  	// Deprecated: won't be used at all in wakuv2
   355  	NoDiscovery bool
   356  
   357  	// ListenAddr is an IP address and port of this node (e.g. 127.0.0.1:30303).
   358  	ListenAddr string
   359  
   360  	// AdvertiseAddr is a public IP address the node wants to be found with.
   361  	// It is especially useful when using floating IPs attached to a server.
   362  	// This configuration value is used by rendezvous protocol, and it's optional
   363  	// If no value is specified, it will attempt to determine the node's external
   364  	// IP address. A value can be specified in case the returned address is incorrect
   365  	AdvertiseAddr string
   366  
   367  	// Name sets the instance name of the node. It must not contain the / character.
   368  	Name string `validate:"excludes=/"`
   369  
   370  	// Version exposes program's version. It is used in the devp2p node identifier.
   371  	Version string
   372  
   373  	// APIModules is a comma-separated list of API modules exposed via *any* (HTTP/WS/IPC) RPC interface.
   374  	APIModules string `validate:"required"`
   375  
   376  	// HTTPEnabled specifies whether the http RPC server is to be enabled by default.
   377  	HTTPEnabled bool
   378  
   379  	// HTTPHost is the host interface on which to start the HTTP RPC server.
   380  	// Pass empty string if no HTTP RPC interface needs to be started.
   381  	HTTPHost string
   382  
   383  	// HTTPPort is the TCP port number on which to start the Geth's HTTP RPC server.
   384  	HTTPPort int
   385  
   386  	// WSEnabled specifies whether the Websocket RPC server is to be enabled by default.
   387  	WSEnabled bool
   388  
   389  	// WSHost is the host interface on which to start Geth's Websocket RPC server.
   390  	WSHost string
   391  
   392  	// WSPort is the TCP port number on which to start the Geth's Websocket RPC server.
   393  	WSPort int
   394  
   395  	// HTTPVirtualHosts is the list of virtual hostnames which are allowed on incoming requests.
   396  	// This is by default {'localhost'}. Using this prevents attacks like
   397  	// DNS rebinding, which bypasses SOP by simply masquerading as being within the same
   398  	// origin. These attacks do not utilize CORS, since they are not cross-domain.
   399  	// By explicitly checking the Host-header, the server will not allow requests
   400  	// made against the server with a malicious host domain.
   401  	// Requests using an IP address directly are not affected.
   402  	HTTPVirtualHosts []string
   403  
   404  	// HTTPCors is the Cross-Origin Resource Sharing header to send to requesting
   405  	// clients. Please be aware that CORS is a browser enforced security, it's fully
   406  	// useless for custom HTTP clients.
   407  	HTTPCors []string
   408  
   409  	// IPCEnabled specifies whether IPC-RPC Server is enabled or not
   410  	IPCEnabled bool
   411  
   412  	// IPCFile is filename of exposed IPC RPC Server
   413  	IPCFile string
   414  
   415  	// TLSEnabled specifies whether TLS support should be enabled on node or not
   416  	// TLS support is only planned in go-ethereum, so we are using our own patch.
   417  	TLSEnabled bool
   418  
   419  	// MaxPeers is the maximum number of (global) peers that can be connected.
   420  	// Set to zero, if only static or trusted peers are allowed to connect.
   421  	MaxPeers int
   422  
   423  	// MaxPendingPeers is the maximum number of peers that can be pending in the
   424  	// handshake phase, counted separately for inbound and outbound connections.
   425  	MaxPendingPeers int
   426  
   427  	log log.Logger
   428  
   429  	// LogEnabled enables the logger
   430  	LogEnabled bool `json:"LogEnabled"`
   431  
   432  	// LogMobileSystem enables log redirection to android/ios system logger.
   433  	LogMobileSystem bool
   434  
   435  	// LogFile is a folder which contains LogFile
   436  	LogDir string
   437  
   438  	// LogFile is filename where exposed logs get written to
   439  	LogFile string
   440  
   441  	// RuntimeLoglevel defines minimum log level for this session only, not affecting the db-stored node configuration
   442  	RuntimeLogLevel string `validate:"omitempty,eq=ERROR|eq=WARN|eq=INFO|eq=DEBUG|eq=TRACE"`
   443  
   444  	// LogLevel defines minimum log level. Valid names are "ERROR", "WARN", "INFO", "DEBUG", and "TRACE".
   445  	LogLevel string `validate:"eq=ERROR|eq=WARN|eq=INFO|eq=DEBUG|eq=TRACE"`
   446  
   447  	// LogMaxBackups defines number of rotated log files that will be stored.
   448  	LogMaxBackups int
   449  
   450  	// LogMaxSize in megabytes after current size is reached log file will be rotated.
   451  	LogMaxSize int
   452  
   453  	// LogCompressRotated if true all rotated files will be gzipped.
   454  	LogCompressRotated bool
   455  
   456  	// LogToStderr defines whether logged info should also be output to os.Stderr
   457  	LogToStderr bool
   458  
   459  	// EnableStatusService should be true to enable methods under status namespace.
   460  	EnableStatusService bool
   461  
   462  	// UpstreamConfig extra config for providing upstream infura server.
   463  	UpstreamConfig UpstreamRPCConfig `json:"UpstreamConfig"`
   464  
   465  	// Initial networks to load
   466  	Networks []Network
   467  
   468  	// ClusterConfig extra configuration for supporting cluster peers.
   469  	ClusterConfig ClusterConfig `json:"ClusterConfig," validate:"structonly"`
   470  
   471  	// LightEthConfig extra configuration for LES
   472  	LightEthConfig LightEthConfig `json:"LightEthConfig," validate:"structonly"`
   473  
   474  	// WakuConfig provides a configuration for Waku subprotocol.
   475  	WakuConfig WakuConfig `json:"WakuConfig" validate:"structonly"`
   476  
   477  	// WakuV2Config provides a configuration for WakuV2 protocol.
   478  	WakuV2Config WakuV2Config `json:"WakuV2Config" validate:"structonly"`
   479  
   480  	// BridgeConfig provides a configuration for Whisper-Waku bridge.
   481  	BridgeConfig BridgeConfig `json:"BridgeConfig" validate:"structonly"`
   482  
   483  	// ShhextConfig extra configuration for service running under shhext namespace.
   484  	ShhextConfig ShhextConfig `json:"ShhextConfig," validate:"structonly"`
   485  
   486  	// WalletConfig extra configuration for wallet.Service.
   487  	WalletConfig WalletConfig
   488  
   489  	// WalleLocalNotificationsConfig extra configuration for localnotifications.Service.
   490  	LocalNotificationsConfig LocalNotificationsConfig
   491  
   492  	// BrowsersConfig extra configuration for browsers.Service.
   493  	BrowsersConfig BrowsersConfig
   494  
   495  	// PermissionsConfig extra configuration for permissions.Service.
   496  	PermissionsConfig PermissionsConfig
   497  
   498  	// MailserversConfig extra configuration for mailservers.Service
   499  	// (persistent storage of user's mailserver records).
   500  	MailserversConfig MailserversConfig
   501  
   502  	// Web3ProviderConfig extra configuration for provider.Service
   503  	// (desktop provider API)
   504  	Web3ProviderConfig Web3ProviderConfig
   505  
   506  	// ConnectorConfig extra configuration for connector.Service
   507  	ConnectorConfig ConnectorConfig
   508  
   509  	// SwarmConfig extra configuration for Swarm and ENS
   510  	SwarmConfig SwarmConfig `json:"SwarmConfig," validate:"structonly"`
   511  
   512  	TorrentConfig TorrentConfig
   513  
   514  	// RegisterTopics a list of specific topics where the peer wants to be
   515  	// discoverable.
   516  	RegisterTopics []discv5.Topic `json:"RegisterTopics"`
   517  
   518  	// RequiredTopics list of topics where a client wants to search for
   519  	// discoverable peers with the discovery limits.
   520  	RequireTopics map[discv5.Topic]Limits `json:"RequireTopics"`
   521  
   522  	// MailServerRegistryAddress is the MailServerRegistry contract address
   523  	MailServerRegistryAddress string
   524  
   525  	// PushNotificationServerConfig is the config for the push notification server
   526  	PushNotificationServerConfig PushNotificationServerConfig `json:"PushNotificationServerConfig"`
   527  
   528  	OutputMessageCSVEnabled bool
   529  
   530  	// ProcessBackedupMessages should be set to true when user follows recovery (using seed phrase or keycard) onboarding flow
   531  	ProcessBackedupMessages bool
   532  }
   533  
   534  type TokenOverride struct {
   535  	Symbol  string         `json:"symbol"`
   536  	Address common.Address `json:"address"`
   537  }
   538  
   539  type Network struct {
   540  	ChainID                uint64          `json:"chainId"`
   541  	ChainName              string          `json:"chainName"`
   542  	DefaultRPCURL          string          `json:"defaultRpcUrl"`      // proxy rpc url
   543  	DefaultFallbackURL     string          `json:"defaultFallbackURL"` // proxy fallback url
   544  	RPCURL                 string          `json:"rpcUrl"`
   545  	OriginalRPCURL         string          `json:"originalRpcUrl"`
   546  	FallbackURL            string          `json:"fallbackURL"`
   547  	OriginalFallbackURL    string          `json:"originalFallbackURL"`
   548  	BlockExplorerURL       string          `json:"blockExplorerUrl,omitempty"`
   549  	IconURL                string          `json:"iconUrl,omitempty"`
   550  	NativeCurrencyName     string          `json:"nativeCurrencyName,omitempty"`
   551  	NativeCurrencySymbol   string          `json:"nativeCurrencySymbol,omitempty"`
   552  	NativeCurrencyDecimals uint64          `json:"nativeCurrencyDecimals"`
   553  	IsTest                 bool            `json:"isTest"`
   554  	Layer                  uint64          `json:"layer"`
   555  	Enabled                bool            `json:"enabled"`
   556  	ChainColor             string          `json:"chainColor"`
   557  	ShortName              string          `json:"shortName"`
   558  	TokenOverrides         []TokenOverride `json:"tokenOverrides"`
   559  	RelatedChainID         uint64          `json:"relatedChainId"`
   560  }
   561  
   562  // WalletConfig extra configuration for wallet.Service.
   563  type WalletConfig struct {
   564  	Enabled                       bool
   565  	OpenseaAPIKey                 string            `json:"OpenseaAPIKey"`
   566  	RaribleMainnetAPIKey          string            `json:"RaribleMainnetAPIKey"`
   567  	RaribleTestnetAPIKey          string            `json:"RaribleTestnetAPIKey"`
   568  	AlchemyAPIKeys                map[uint64]string `json:"AlchemyAPIKeys"`
   569  	InfuraAPIKey                  string            `json:"InfuraAPIKey"`
   570  	InfuraAPIKeySecret            string            `json:"InfuraAPIKeySecret"`
   571  	StatusProxyMarketUser         string            `json:"StatusProxyMarketUser"`
   572  	StatusProxyMarketPassword     string            `json:"StatusProxyMarketPassword"`
   573  	StatusProxyBlockchainUser     string            `json:"StatusProxyBlockchainUser"`
   574  	StatusProxyBlockchainPassword string            `json:"StatusProxyBlockchainPassword"`
   575  	StatusProxyEnabled            bool              `json:"StatusProxyEnabled"`
   576  	StatusProxyStageName          string            `json:"StatusProxyStageName"`
   577  	EnableCelerBridge             bool              `json:"EnableCelerBridge"`
   578  }
   579  
   580  // MarshalJSON custom marshalling to avoid exposing sensitive data in log,
   581  // there's a function called `startNode` will log NodeConfig which include WalletConfig
   582  func (wc WalletConfig) MarshalJSON() ([]byte, error) {
   583  	return json.Marshal(struct {
   584  		Enabled            bool `json:"Enabled"`
   585  		StatusProxyEnabled bool `json:"StatusProxyEnabled"`
   586  		EnableCelerBridge  bool `json:"EnableCelerBridge"`
   587  	}{
   588  		Enabled:            wc.Enabled,
   589  		StatusProxyEnabled: wc.StatusProxyEnabled,
   590  		EnableCelerBridge:  wc.EnableCelerBridge,
   591  	})
   592  }
   593  
   594  // LocalNotificationsConfig extra configuration for localnotifications.Service.
   595  type LocalNotificationsConfig struct {
   596  	Enabled bool
   597  }
   598  
   599  // BrowsersConfig extra configuration for browsers.Service.
   600  type BrowsersConfig struct {
   601  	Enabled bool
   602  }
   603  
   604  // PermissionsConfig extra configuration for permissions.Service.
   605  type PermissionsConfig struct {
   606  	Enabled bool
   607  }
   608  
   609  // MailserversConfig extra configuration for mailservers.Service.
   610  type MailserversConfig struct {
   611  	Enabled bool
   612  }
   613  
   614  // ProviderConfig extra configuration for provider.Service
   615  type Web3ProviderConfig struct {
   616  	Enabled bool
   617  }
   618  
   619  // ConnectorConfig extra configuration for provider.Service
   620  type ConnectorConfig struct {
   621  	Enabled bool
   622  }
   623  
   624  // BridgeConfig provides configuration for Whisper-Waku bridge.
   625  type BridgeConfig struct {
   626  	Enabled bool
   627  }
   628  
   629  type PushNotificationServer struct {
   630  	*ecdsa.PublicKey
   631  }
   632  
   633  func (p *PushNotificationServer) MarshalText() ([]byte, error) {
   634  	return []byte(hex.EncodeToString(crypto.FromECDSAPub(p.PublicKey))), nil
   635  }
   636  
   637  func (p *PushNotificationServer) UnmarshalText(data []byte) error {
   638  	pubKeyBytes, err := hex.DecodeString(string(data))
   639  	if err != nil {
   640  		return err
   641  	}
   642  
   643  	pk, err := crypto.UnmarshalPubkey(pubKeyBytes)
   644  	if err != nil {
   645  		return err
   646  	}
   647  
   648  	p.PublicKey = pk
   649  	return nil
   650  }
   651  
   652  type PushNotificationServerConfig struct {
   653  	Enabled   bool
   654  	Identity  *ecdsa.PrivateKey
   655  	GorushURL string
   656  }
   657  
   658  // ShhextConfig defines options used by shhext service.
   659  type ShhextConfig struct {
   660  	PFSEnabled bool
   661  	// InstallationId id of the current installation
   662  	InstallationID string
   663  	// MailServerConfirmations should be true if client wants to receive confirmatons only from a selected mail servers.
   664  	MailServerConfirmations bool
   665  	// EnableConnectionManager turns on management of the mail server connections if true.
   666  	EnableConnectionManager bool
   667  	// EnableLastUsedMonitor guarantees that last used mail server will be tracked and persisted into the storage.
   668  	EnableLastUsedMonitor bool
   669  	// ConnectionTarget will be used by connection manager. It will ensure that we connected with configured number of servers.
   670  	ConnectionTarget int
   671  	// RequestsDelay used to ensure that no similar requests are sent within short periods of time.
   672  	RequestsDelay time.Duration
   673  	// MaxServerFailures defines maximum allowed expired requests before server will be swapped to another one.
   674  	MaxServerFailures int
   675  
   676  	// MaxMessageDeliveryAttempts defines how many times we will try to deliver not-acknowledged envelopes.
   677  	MaxMessageDeliveryAttempts int
   678  
   679  	// WhisperCacheDir is a folder where whisper filters may persist messages before delivering them
   680  	// to a client.
   681  	WhisperCacheDir string
   682  
   683  	// DisableGenericDiscoveryTopic indicates whether we should be listening on the old discovery
   684  	DisableGenericDiscoveryTopic bool
   685  
   686  	// SendV1Messages indicates whether we should be sending v1-compatible only messages
   687  	SendV1Messages bool
   688  
   689  	// DatasyncEnabled indicates whether we should enable dataasync
   690  	DataSyncEnabled bool
   691  
   692  	// VerifyTransactionURL is the URL for verifying transactions.
   693  	// IMPORTANT: It should always be mainnet unless used for testing
   694  	VerifyTransactionURL string
   695  
   696  	// VerifyENSURL is the URL for verifying ens names.
   697  	// IMPORTANT: It should always be mainnet unless used for testing
   698  	VerifyENSURL string
   699  
   700  	// VerifyENSContractAddress is the address of the contract used to verify ENS
   701  	// No default is provided and if not set ENS resolution is disabled
   702  	VerifyENSContractAddress string
   703  
   704  	VerifyTransactionChainID int64
   705  
   706  	// DefaultPushNotificationsServers is the default-status run push notification servers
   707  	DefaultPushNotificationsServers []*PushNotificationServer
   708  
   709  	// AnonMetricsSendID is the public key used by a metrics node to decrypt metrics protobufs
   710  	AnonMetricsSendID string
   711  
   712  	// AnonMetricsServerEnabled indicates whether or not the
   713  	AnonMetricsServerEnabled bool
   714  
   715  	// AnonMetricsServerPostgresURI is the uri used to connect to a postgres db
   716  	AnonMetricsServerPostgresURI string
   717  
   718  	// BandwidthStatsEnabled indicates if a signal is going to be emitted to indicate the upload and download rate
   719  	BandwidthStatsEnabled bool
   720  }
   721  
   722  // TorrentConfig provides configuration for the BitTorrent client used for message history archives.
   723  type TorrentConfig struct {
   724  	// Enabled set to true enables Community History Archive protocol
   725  	Enabled bool
   726  	// Port number which the BitTorrent client will listen to for conntections
   727  	Port int
   728  	// DataDir is the file system folder Status should use for message archive torrent data.
   729  	DataDir string
   730  	// TorrentDir is the file system folder Status should use for storing torrent metadata files.
   731  	TorrentDir string
   732  }
   733  
   734  // Validate validates the ShhextConfig struct and returns an error if inconsistent values are found
   735  func (c *ShhextConfig) Validate(validate *validator.Validate) error {
   736  	if err := validate.Struct(c); err != nil {
   737  		return err
   738  	}
   739  	return nil
   740  }
   741  
   742  // Option is an additional setting when creating a NodeConfig
   743  // using NewNodeConfigWithDefaults.
   744  type Option func(*NodeConfig) error
   745  
   746  // WithFleet loads one of the preconfigured Status fleets.
   747  func WithFleet(fleet string) Option {
   748  	return func(c *NodeConfig) error {
   749  		if fleet == FleetUndefined {
   750  			return nil
   751  		}
   752  		c.NoDiscovery = false
   753  		c.ClusterConfig.Enabled = true
   754  		return loadConfigFromAsset(fmt.Sprintf("../config/cli/fleet-%s.json", fleet), c)
   755  	}
   756  }
   757  
   758  // WithLES enabled LES protocol.
   759  func WithLES() Option {
   760  	return func(c *NodeConfig) error {
   761  		return loadConfigFromAsset("../config/cli/les-enabled.json", c)
   762  	}
   763  }
   764  
   765  // WithMailserver enables MailServer.
   766  func WithMailserver() Option {
   767  	return func(c *NodeConfig) error {
   768  		return loadConfigFromAsset("../config/cli/mailserver-enabled.json", c)
   769  	}
   770  }
   771  
   772  func WithDiscV5BootstrapNodes(nodes []string) Option {
   773  	return func(c *NodeConfig) error {
   774  		c.ClusterConfig.DiscV5BootstrapNodes = nodes
   775  		return nil
   776  	}
   777  }
   778  
   779  func WithWakuNodes(nodes []string) Option {
   780  	return func(c *NodeConfig) error {
   781  		c.ClusterConfig.WakuNodes = nodes
   782  		return nil
   783  	}
   784  }
   785  
   786  // NewNodeConfigWithDefaults creates new node configuration object
   787  // with some defaults suitable for adhoc use.
   788  func NewNodeConfigWithDefaults(dataDir string, networkID uint64, opts ...Option) (*NodeConfig, error) {
   789  	c, err := NewNodeConfig(dataDir, networkID)
   790  	if err != nil {
   791  		return nil, err
   792  	}
   793  
   794  	c.NoDiscovery = true
   795  	c.HTTPHost = ""
   796  	c.ListenAddr = ":30303"
   797  	c.LogEnabled = true
   798  	c.LogLevel = "INFO"
   799  	c.LogMaxSize = 100
   800  	c.LogCompressRotated = true
   801  	c.LogMaxBackups = 3
   802  	c.LogToStderr = true
   803  	c.WakuConfig.Enabled = true
   804  
   805  	for _, opt := range opts {
   806  		if err := opt(c); err != nil {
   807  			return nil, err
   808  		}
   809  	}
   810  
   811  	c.updatePeerLimits()
   812  
   813  	if err := c.Validate(); err != nil {
   814  		return nil, err
   815  	}
   816  
   817  	return c, nil
   818  }
   819  
   820  func (c *NodeConfig) setDefaultPushNotificationsServers() error {
   821  	if c.ClusterConfig.Fleet == FleetUndefined {
   822  		return nil
   823  	}
   824  
   825  	// If empty load defaults from the fleet
   826  	if len(c.ClusterConfig.PushNotificationsServers) == 0 {
   827  		log.Debug("empty push notification servers, setting", "fleet", c.ClusterConfig.Fleet)
   828  		defaultConfig := &NodeConfig{}
   829  		err := loadConfigFromAsset(fmt.Sprintf("../config/cli/fleet-%s.json", c.ClusterConfig.Fleet), defaultConfig)
   830  		if err != nil {
   831  			return err
   832  		}
   833  		c.ClusterConfig.PushNotificationsServers = defaultConfig.ClusterConfig.PushNotificationsServers
   834  	}
   835  
   836  	// If empty set the default servers
   837  	if len(c.ShhextConfig.DefaultPushNotificationsServers) == 0 {
   838  		log.Debug("setting default push notification servers", "cluster servers", c.ClusterConfig.PushNotificationsServers)
   839  		for _, pk := range c.ClusterConfig.PushNotificationsServers {
   840  			keyBytes, err := hex.DecodeString("04" + pk)
   841  			if err != nil {
   842  				return err
   843  			}
   844  
   845  			key, err := crypto.UnmarshalPubkey(keyBytes)
   846  			if err != nil {
   847  				return err
   848  			}
   849  			c.ShhextConfig.DefaultPushNotificationsServers = append(c.ShhextConfig.DefaultPushNotificationsServers, &PushNotificationServer{PublicKey: key})
   850  		}
   851  	}
   852  	return nil
   853  }
   854  
   855  // UpdateWithDefaults updates config with missing default values, as
   856  // the config is only generated once and is thereafter pulled from the database.
   857  // The way it is stored in the database makes this step necessary as it's stored as a blob and can't be easily migrated.
   858  func (c *NodeConfig) UpdateWithDefaults() error {
   859  	// Empty APIModules will fallback to services' APIs definition.
   860  	// If any API is defined as public, it will be exposed.
   861  	// We disallow empty APIModules to avoid confusion
   862  	// when some APIs suddenly become available for Dapps.
   863  	// More: https://github.com/status-im/status-go/issues/1870.
   864  	if c.APIModules == "" {
   865  		c.APIModules = "net,web3,eth"
   866  	}
   867  
   868  	// Override defaultMinPoW passed by the client
   869  	if c.WakuConfig.Enabled {
   870  		c.WakuConfig.MinimumPoW = WakuMinimumPoW
   871  	}
   872  
   873  	// Ensure TorrentConfig is valid
   874  	if c.TorrentConfig.Enabled {
   875  		if c.TorrentConfig.DataDir == "" {
   876  			c.TorrentConfig.DataDir = filepath.Join(c.RootDataDir, ArchivesRelativePath)
   877  		}
   878  		if c.TorrentConfig.TorrentDir == "" {
   879  			c.TorrentConfig.TorrentDir = filepath.Join(c.RootDataDir, TorrentTorrentsRelativePath)
   880  		}
   881  	}
   882  
   883  	return c.setDefaultPushNotificationsServers()
   884  }
   885  
   886  // NewNodeConfigWithDefaultsAndFiles creates new node configuration object
   887  // with some defaults suitable for adhoc use and applies config files on top.
   888  func NewNodeConfigWithDefaultsAndFiles(
   889  	dataDir string, networkID uint64, opts []Option, files []string,
   890  ) (*NodeConfig, error) {
   891  	c, err := NewNodeConfigWithDefaults(dataDir, networkID, opts...)
   892  	if err != nil {
   893  		return nil, err
   894  	}
   895  
   896  	for _, file := range files {
   897  		if err := loadConfigConfigFromFile(file, c); err != nil {
   898  			return nil, err
   899  		}
   900  	}
   901  
   902  	c.updatePeerLimits()
   903  
   904  	if err := c.Validate(); err != nil {
   905  		return nil, err
   906  	}
   907  
   908  	return c, nil
   909  }
   910  
   911  // updatePeerLimits will set default peer limits expectations based on enabled services.
   912  func (c *NodeConfig) updatePeerLimits() {
   913  	if c.NoDiscovery {
   914  		return
   915  	}
   916  	if c.LightEthConfig.Enabled {
   917  		c.RequireTopics[discv5.Topic(LesTopic(int(c.NetworkID)))] = LesDiscoveryLimits
   918  	}
   919  }
   920  
   921  // NewNodeConfig creates new node configuration object with bare-minimum defaults.
   922  // Important: the returned config is not validated.
   923  func NewNodeConfig(dataDir string, networkID uint64) (*NodeConfig, error) {
   924  	var keyStoreDir, keycardPairingDataFile, wakuDir, wakuV2Dir string
   925  
   926  	if dataDir != "" {
   927  		keyStoreDir = filepath.Join(dataDir, "keystore")
   928  		keycardPairingDataFile = filepath.Join(dataDir, "keycard", "pairings.json")
   929  
   930  		wakuDir = filepath.Join(dataDir, "waku")
   931  		wakuV2Dir = filepath.Join(dataDir, "wakuv2")
   932  	}
   933  
   934  	config := &NodeConfig{
   935  		NetworkID:              networkID,
   936  		RootDataDir:            dataDir,
   937  		DataDir:                dataDir,
   938  		KeyStoreDir:            keyStoreDir,
   939  		KeycardPairingDataFile: keycardPairingDataFile,
   940  		Version:                Version,
   941  		HTTPHost:               "localhost",
   942  		HTTPPort:               8545,
   943  		HTTPVirtualHosts:       []string{"localhost"},
   944  		ListenAddr:             ":0",
   945  		APIModules:             "eth,net,web3,peer,wallet",
   946  		MaxPeers:               25,
   947  		MaxPendingPeers:        0,
   948  		IPCFile:                "geth.ipc",
   949  		log:                    log.New("package", "status-go/params.NodeConfig"),
   950  		LogFile:                "",
   951  		LogLevel:               "ERROR",
   952  		NoDiscovery:            true,
   953  		UpstreamConfig: UpstreamRPCConfig{
   954  			URL: getUpstreamURL(networkID),
   955  		},
   956  		LightEthConfig: LightEthConfig{
   957  			DatabaseCache: 16,
   958  		},
   959  		WakuConfig: WakuConfig{
   960  			DataDir:        wakuDir,
   961  			MinimumPoW:     WakuMinimumPoW,
   962  			TTL:            WakuTTL,
   963  			MaxMessageSize: wakucommon.DefaultMaxMessageSize,
   964  		},
   965  		WakuV2Config: WakuV2Config{
   966  			Host:           "0.0.0.0",
   967  			Port:           0,
   968  			DataDir:        wakuV2Dir,
   969  			MaxMessageSize: wakuv2common.DefaultMaxMessageSize,
   970  		},
   971  		ShhextConfig: ShhextConfig{},
   972  		SwarmConfig:  SwarmConfig{},
   973  		TorrentConfig: TorrentConfig{
   974  			Enabled:    false,
   975  			Port:       9025,
   976  			DataDir:    dataDir + "/archivedata",
   977  			TorrentDir: dataDir + "/torrents",
   978  		},
   979  		RegisterTopics: []discv5.Topic{},
   980  		RequireTopics:  map[discv5.Topic]Limits{},
   981  	}
   982  
   983  	return config, nil
   984  }
   985  
   986  // NewConfigFromJSON parses incoming JSON and returned it as Config
   987  func NewConfigFromJSON(configJSON string) (*NodeConfig, error) {
   988  	config, err := NewNodeConfig("", 0)
   989  	if err != nil {
   990  		return nil, err
   991  	}
   992  
   993  	if err := loadConfigFromJSON(configJSON, config); err != nil {
   994  		return nil, err
   995  	}
   996  
   997  	if err := config.Validate(); err != nil {
   998  		return nil, err
   999  	}
  1000  
  1001  	return config, nil
  1002  }
  1003  
  1004  func LoadClusterConfigFromFleet(fleet string) (*ClusterConfig, error) {
  1005  	nodeConfig := &NodeConfig{}
  1006  	err := loadConfigFromAsset(fmt.Sprintf("../config/cli/fleet-%s.json", fleet), nodeConfig)
  1007  	if err != nil {
  1008  		return nil, err
  1009  	}
  1010  
  1011  	return &nodeConfig.ClusterConfig, nil
  1012  }
  1013  
  1014  func loadConfigFromJSON(configJSON string, nodeConfig *NodeConfig) error {
  1015  	decoder := json.NewDecoder(strings.NewReader(configJSON))
  1016  	// override default configuration with values by JSON input
  1017  	return decoder.Decode(&nodeConfig)
  1018  }
  1019  
  1020  func loadConfigConfigFromFile(path string, config *NodeConfig) error {
  1021  	jsonConfig, err := ioutil.ReadFile(path)
  1022  	if err != nil {
  1023  		return err
  1024  	}
  1025  	return loadConfigFromJSON(string(jsonConfig), config)
  1026  }
  1027  
  1028  func loadConfigFromAsset(name string, config *NodeConfig) error {
  1029  	data, err := static.Asset(name)
  1030  	if err != nil {
  1031  		return err
  1032  	}
  1033  	return loadConfigFromJSON(string(data), config)
  1034  }
  1035  
  1036  // Validate checks if NodeConfig fields have valid values.
  1037  //
  1038  // It returns nil if there are no errors, otherwise one or more errors
  1039  // can be returned. Multiple errors are joined with a new line.
  1040  //
  1041  // A single error for a struct:
  1042  //
  1043  //	type TestStruct struct {
  1044  //	    TestField string `validate:"required"`
  1045  //	}
  1046  //
  1047  // has the following format:
  1048  //
  1049  //	Key: 'TestStruct.TestField' Error:Field validation for 'TestField' failed on the 'required' tag
  1050  func (c *NodeConfig) Validate() error {
  1051  	validate := NewValidator()
  1052  
  1053  	if err := validate.Struct(c); err != nil {
  1054  		return err
  1055  	}
  1056  
  1057  	if c.NodeKey != "" {
  1058  		if _, err := crypto.HexToECDSA(c.NodeKey); err != nil {
  1059  			return fmt.Errorf("NodeKey is invalid (%s): %v", c.NodeKey, err)
  1060  		}
  1061  	}
  1062  
  1063  	if c.UpstreamConfig.Enabled && c.LightEthConfig.Enabled {
  1064  		return fmt.Errorf("both UpstreamConfig and LightEthConfig are enabled, but they are mutually exclusive")
  1065  	}
  1066  
  1067  	if err := c.validateChildStructs(validate); err != nil {
  1068  		return err
  1069  	}
  1070  
  1071  	if c.WakuConfig.Enabled && c.WakuV2Config.Enabled && c.WakuConfig.DataDir == c.WakuV2Config.DataDir {
  1072  		return fmt.Errorf("both Waku and WakuV2 are enabled and use the same data dir")
  1073  	}
  1074  
  1075  	// Waku's data directory must be relative to the main data directory
  1076  	// if EnableMailServer is true.
  1077  	if c.WakuConfig.Enabled && c.WakuConfig.EnableMailServer {
  1078  		if !strings.HasPrefix(c.WakuConfig.DataDir, c.DataDir) {
  1079  			return fmt.Errorf("WakuConfig.DataDir must start with DataDir fragment")
  1080  		}
  1081  	}
  1082  
  1083  	if !c.NoDiscovery && len(c.ClusterConfig.BootNodes) == 0 {
  1084  		// No point in running discovery if we don't have bootnodes.
  1085  		// In case we do have bootnodes, NoDiscovery should be true.
  1086  		return fmt.Errorf("NoDiscovery is false, but ClusterConfig.BootNodes is empty")
  1087  	}
  1088  
  1089  	if c.ShhextConfig.PFSEnabled && len(c.ShhextConfig.InstallationID) == 0 {
  1090  		return fmt.Errorf("PFSEnabled is true, but InstallationID is empty")
  1091  	}
  1092  
  1093  	return nil
  1094  }
  1095  
  1096  func (c *NodeConfig) validateChildStructs(validate *validator.Validate) error {
  1097  	// Validate child structs
  1098  	if err := c.UpstreamConfig.Validate(validate); err != nil {
  1099  		return err
  1100  	}
  1101  	if err := c.ClusterConfig.Validate(validate); err != nil {
  1102  		return err
  1103  	}
  1104  	if err := c.LightEthConfig.Validate(validate); err != nil {
  1105  		return err
  1106  	}
  1107  	if err := c.SwarmConfig.Validate(validate); err != nil {
  1108  		return err
  1109  	}
  1110  	if err := c.ShhextConfig.Validate(validate); err != nil {
  1111  		return err
  1112  	}
  1113  	if err := c.TorrentConfig.Validate(validate); err != nil {
  1114  		return err
  1115  	}
  1116  	return nil
  1117  }
  1118  
  1119  // Validate validates the UpstreamRPCConfig struct and returns an error if inconsistent values are found
  1120  func (c *UpstreamRPCConfig) Validate(validate *validator.Validate) error {
  1121  	if !c.Enabled {
  1122  		return nil
  1123  	}
  1124  
  1125  	if err := validate.Struct(c); err != nil {
  1126  		return err
  1127  	}
  1128  
  1129  	if _, err := url.ParseRequestURI(c.URL); err != nil {
  1130  		return fmt.Errorf("UpstreamRPCConfig.URL '%s' is invalid: %v", c.URL, err.Error())
  1131  	}
  1132  
  1133  	return nil
  1134  }
  1135  
  1136  // Validate validates the ClusterConfig struct and returns an error if inconsistent values are found
  1137  func (c *ClusterConfig) Validate(validate *validator.Validate) error {
  1138  	if !c.Enabled {
  1139  		return nil
  1140  	}
  1141  
  1142  	if err := validate.Struct(c); err != nil {
  1143  		return err
  1144  	}
  1145  
  1146  	return nil
  1147  }
  1148  
  1149  // Validate validates the LightEthConfig struct and returns an error if inconsistent values are found
  1150  func (c *LightEthConfig) Validate(validate *validator.Validate) error {
  1151  	if !c.Enabled {
  1152  		return nil
  1153  	}
  1154  
  1155  	if err := validate.Struct(c); err != nil {
  1156  		return err
  1157  	}
  1158  
  1159  	return nil
  1160  }
  1161  
  1162  // Validate validates the SwarmConfig struct and returns an error if inconsistent values are found
  1163  func (c *SwarmConfig) Validate(validate *validator.Validate) error {
  1164  	if !c.Enabled {
  1165  		return nil
  1166  	}
  1167  
  1168  	if err := validate.Struct(c); err != nil {
  1169  		return err
  1170  	}
  1171  
  1172  	return nil
  1173  }
  1174  
  1175  func (c *TorrentConfig) Validate(validate *validator.Validate) error {
  1176  	if !c.Enabled {
  1177  		return nil
  1178  	}
  1179  
  1180  	if err := validate.Struct(c); err != nil {
  1181  		return err
  1182  	}
  1183  
  1184  	if c.Enabled && (c.DataDir == "" || c.TorrentDir == "") {
  1185  		return fmt.Errorf("TorrentConfig.DataDir and TorrentConfig.TorrentDir cannot be \"\"")
  1186  	}
  1187  	return nil
  1188  }
  1189  
  1190  func getUpstreamURL(networkID uint64) string {
  1191  	switch networkID {
  1192  	case MainNetworkID:
  1193  		return MainnetEthereumNetworkURL
  1194  	case GoerliNetworkID:
  1195  		return GoerliEthereumNetworkURL
  1196  	}
  1197  
  1198  	return ""
  1199  }
  1200  
  1201  // Save dumps configuration to the disk
  1202  func (c *NodeConfig) Save() error {
  1203  	data, err := json.MarshalIndent(c, "", "    ")
  1204  	if err != nil {
  1205  		return err
  1206  	}
  1207  
  1208  	if err := os.MkdirAll(c.DataDir, os.ModePerm); err != nil {
  1209  		return err
  1210  	}
  1211  
  1212  	configFilePath := filepath.Join(c.DataDir, "config.json")
  1213  	if err := ioutil.WriteFile(configFilePath, data, os.ModePerm); err != nil {
  1214  		return err
  1215  	}
  1216  
  1217  	c.log.Info("config file saved", "path", configFilePath)
  1218  	return nil
  1219  }
  1220  
  1221  // String dumps config object as nicely indented JSON
  1222  func (c *NodeConfig) String() string {
  1223  	data, _ := json.MarshalIndent(c, "", "    ")
  1224  	return string(data)
  1225  }
  1226  
  1227  // FormatAPIModules returns a slice of APIModules.
  1228  func (c *NodeConfig) FormatAPIModules() []string {
  1229  	if len(c.APIModules) == 0 {
  1230  		return nil
  1231  	}
  1232  
  1233  	return strings.Split(c.APIModules, ",")
  1234  }
  1235  
  1236  // AddAPIModule adds a mobule to APIModules
  1237  func (c *NodeConfig) AddAPIModule(m string) {
  1238  	c.APIModules = fmt.Sprintf("%s,%s", c.APIModules, m)
  1239  }
  1240  
  1241  // LesTopic returns discovery v5 topic derived from genesis of the provided network.
  1242  // 1 - mainnet, 5 - goerli
  1243  func LesTopic(netid int) string {
  1244  	switch netid {
  1245  	case 1:
  1246  		return LESDiscoveryIdentifier + types.Bytes2Hex(params.MainnetGenesisHash.Bytes()[:8])
  1247  	case 5:
  1248  		return LESDiscoveryIdentifier + types.Bytes2Hex(params.RinkebyGenesisHash.Bytes()[:8])
  1249  	default:
  1250  		return ""
  1251  	}
  1252  }