- Replace command line flags with `-c` config flag. Part of #1180 - Convert node config private keys to hex-encoded string versions. - Remove `GenerateConfig` from library. - Remove unused `FirebaseConfig` from library. - Fix loading of `config/status-chain-genesis.json` in non-dev machines.
This commit is contained in:
parent
0480d1a376
commit
3d00af7fa3
|
@ -14,7 +14,7 @@
|
||||||
"host": "127.0.0.1",
|
"host": "127.0.0.1",
|
||||||
"program": "${workspaceRoot}/cmd/statusd",
|
"program": "${workspaceRoot}/cmd/statusd",
|
||||||
"env": {},
|
"env": {},
|
||||||
"args": ["-shh", "-les", "-discovery=true"],
|
"args": ["-c", "${workspaceRoot}/config/cli/fleet-eth.test.json"],
|
||||||
"showLog": true,
|
"showLog": true,
|
||||||
"output": "${workspaceRoot}/build/bin/statusd.debug"
|
"output": "${workspaceRoot}/build/bin/statusd.debug"
|
||||||
}
|
}
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -198,6 +198,10 @@ xgo:
|
||||||
go get github.com/karalabe/xgo
|
go get github.com/karalabe/xgo
|
||||||
|
|
||||||
setup: dep-install lint-install mock-install ##@other Prepare project for first build
|
setup: dep-install lint-install mock-install ##@other Prepare project for first build
|
||||||
|
go get -u github.com/kevinburke/go-bindata/go-bindata
|
||||||
|
|
||||||
|
generate: ##@other Regenerate assets and other auto-generated stuff
|
||||||
|
go generate ./static
|
||||||
|
|
||||||
mock-install: ##@other Install mocking tools
|
mock-install: ##@other Install mocking tools
|
||||||
go get -u github.com/golang/mock/mockgen
|
go get -u github.com/golang/mock/mockgen
|
||||||
|
|
|
@ -13,24 +13,19 @@ services:
|
||||||
ipv4_address: 172.16.238.10
|
ipv4_address: 172.16.238.10
|
||||||
|
|
||||||
wnode:
|
wnode:
|
||||||
image: status-go:latest
|
image: statusteam/status-go:latest
|
||||||
command:
|
command:
|
||||||
- statusd
|
- "-c"
|
||||||
- "-les=false"
|
- "/config/wnode-config.json"
|
||||||
- "-shh"
|
|
||||||
- "-listenaddr=:30303"
|
|
||||||
- "-discovery=true"
|
|
||||||
- "-standalone=false"
|
|
||||||
- "-bootnodes=enode://3f04db09bedc8d85a198de94c84da73aa7782fafc61b28c525ec5cca5a6cc16be7ebbb5cd001780f71d8408d35a2f6326faa1e524d9d8875294172ebec988743@172.16.238.10:30303"
|
|
||||||
- "-http"
|
|
||||||
- "-httphost=0.0.0.0"
|
|
||||||
- "-log=DEBUG"
|
|
||||||
ports:
|
ports:
|
||||||
- 8080
|
- 8080
|
||||||
- 8545
|
- 8545
|
||||||
- 30303
|
- 30303
|
||||||
networks:
|
networks:
|
||||||
cluster:
|
cluster:
|
||||||
|
volumes:
|
||||||
|
- ./wnode-config.json:/config/wnode-config.json:ro
|
||||||
|
- ./.ethereumtest:/data/ethereumtest/:rw
|
||||||
depends_on:
|
depends_on:
|
||||||
- bootnode
|
- bootnode
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"NetworkId": 777,
|
||||||
|
"DataDir": "/data/ethereumtest/status",
|
||||||
|
"KeyStoreDir": "/data/ethereumtest/keystore",
|
||||||
|
"NoDiscovery": false,
|
||||||
|
"Rendezvous": false,
|
||||||
|
"ListenAddr": ":30303",
|
||||||
|
"RPCEnabled": true,
|
||||||
|
"HTTPHost": "0.0.0.0",
|
||||||
|
"LogEnabled": true,
|
||||||
|
"LogLevel": "DEBUG",
|
||||||
|
"LogToStderr": true,
|
||||||
|
"ClusterConfig": {
|
||||||
|
"Enabled": false,
|
||||||
|
"BootNodes": [
|
||||||
|
"enode://3f04db09bedc8d85a198de94c84da73aa7782fafc61b28c525ec5cca5a6cc16be7ebbb5cd001780f71d8408d35a2f6326faa1e524d9d8875294172ebec988743@172.16.238.10:30303"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -121,6 +121,11 @@ func (b *StatusBackend) startNode(config *params.NodeConfig) (err error) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Start by validating configuration
|
||||||
|
if err := config.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
services := []gethnode.ServiceConstructor{}
|
services := []gethnode.ServiceConstructor{}
|
||||||
services = appendIf(config.UpstreamConfig.Enabled, services, b.rpcFiltersService())
|
services = appendIf(config.UpstreamConfig.Enabled, services, b.rpcFiltersService())
|
||||||
|
|
||||||
|
|
|
@ -9,13 +9,15 @@ import (
|
||||||
"github.com/status-im/status-go/node"
|
"github.com/status-im/status-go/node"
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/rpc"
|
"github.com/status-im/status-go/rpc"
|
||||||
|
"github.com/status-im/status-go/t/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBackendStartNodeConcurrently(t *testing.T) {
|
func TestBackendStartNodeConcurrently(t *testing.T) {
|
||||||
backend := NewStatusBackend()
|
backend := NewStatusBackend()
|
||||||
config := params.NodeConfig{}
|
config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
|
||||||
|
require.NoError(t, err)
|
||||||
count := 2
|
count := 2
|
||||||
resultCh := make(chan error)
|
resultCh := make(chan error)
|
||||||
|
|
||||||
|
@ -24,7 +26,7 @@ func TestBackendStartNodeConcurrently(t *testing.T) {
|
||||||
|
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
go func() {
|
go func() {
|
||||||
resultCh <- backend.StartNode(&config)
|
resultCh <- backend.StartNode(config)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -40,16 +42,17 @@ func TestBackendStartNodeConcurrently(t *testing.T) {
|
||||||
require.Contains(t, results, nil)
|
require.Contains(t, results, nil)
|
||||||
require.Contains(t, results, node.ErrNodeRunning)
|
require.Contains(t, results, node.ErrNodeRunning)
|
||||||
|
|
||||||
err := backend.StopNode()
|
err = backend.StopNode()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBackendRestartNodeConcurrently(t *testing.T) {
|
func TestBackendRestartNodeConcurrently(t *testing.T) {
|
||||||
backend := NewStatusBackend()
|
backend := NewStatusBackend()
|
||||||
config := params.NodeConfig{}
|
config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
|
||||||
|
require.NoError(t, err)
|
||||||
count := 3
|
count := 3
|
||||||
|
|
||||||
err := backend.StartNode(&config)
|
err = backend.StartNode(config)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer func() {
|
defer func() {
|
||||||
require.NoError(t, backend.StopNode())
|
require.NoError(t, backend.StopNode())
|
||||||
|
@ -72,9 +75,10 @@ func TestBackendRestartNodeConcurrently(t *testing.T) {
|
||||||
|
|
||||||
func TestBackendGettersConcurrently(t *testing.T) {
|
func TestBackendGettersConcurrently(t *testing.T) {
|
||||||
backend := NewStatusBackend()
|
backend := NewStatusBackend()
|
||||||
config := params.NodeConfig{}
|
config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
err := backend.StartNode(&config)
|
err = backend.StartNode(config)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer func() {
|
defer func() {
|
||||||
require.NoError(t, backend.StopNode())
|
require.NoError(t, backend.StopNode())
|
||||||
|
@ -123,9 +127,10 @@ func TestBackendGettersConcurrently(t *testing.T) {
|
||||||
|
|
||||||
func TestBackendAccountsConcurrently(t *testing.T) {
|
func TestBackendAccountsConcurrently(t *testing.T) {
|
||||||
backend := NewStatusBackend()
|
backend := NewStatusBackend()
|
||||||
config := params.NodeConfig{}
|
config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
err := backend.StartNode(&config)
|
err = backend.StartNode(config)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer func() {
|
defer func() {
|
||||||
require.NoError(t, backend.StopNode())
|
require.NoError(t, backend.StopNode())
|
||||||
|
@ -208,10 +213,11 @@ func TestBackendConnectionChangesToOffline(t *testing.T) {
|
||||||
|
|
||||||
func TestBackendCallRPCConcurrently(t *testing.T) {
|
func TestBackendCallRPCConcurrently(t *testing.T) {
|
||||||
backend := NewStatusBackend()
|
backend := NewStatusBackend()
|
||||||
config := params.NodeConfig{}
|
config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
|
||||||
|
require.NoError(t, err)
|
||||||
count := 3
|
count := 3
|
||||||
|
|
||||||
err := backend.StartNode(&config)
|
err = backend.StartNode(config)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer func() {
|
defer func() {
|
||||||
require.NoError(t, backend.StopNode())
|
require.NoError(t, backend.StopNode())
|
||||||
|
@ -278,7 +284,9 @@ func TestAppStateChange(t *testing.T) {
|
||||||
|
|
||||||
func TestBlockedRPCMethods(t *testing.T) {
|
func TestBlockedRPCMethods(t *testing.T) {
|
||||||
backend := NewStatusBackend()
|
backend := NewStatusBackend()
|
||||||
err := backend.StartNode(¶ms.NodeConfig{})
|
config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = backend.StartNode(config)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer func() { require.NoError(t, backend.StopNode()) }()
|
defer func() { require.NoError(t, backend.StopNode()) }()
|
||||||
|
|
||||||
|
|
|
@ -192,7 +192,7 @@ func makeNodeConfig() (*params.NodeConfig, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeConfig, err := params.NewNodeConfig(path.Join(workDir, ".ethereum"), "", params.FleetUndefined, uint64(params.RopstenNetworkID))
|
nodeConfig, err := params.NewNodeConfigWithDefaults(path.Join(workDir, ".ethereum"), params.FleetUndefined, uint64(params.RopstenNetworkID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ func newCommandSet(statusBackend *api.StatusBackend) *commandSet {
|
||||||
// StartNode loads the configuration out of the passed string and
|
// StartNode loads the configuration out of the passed string and
|
||||||
// starts a node with it.
|
// starts a node with it.
|
||||||
func (cs *commandSet) StartNode(config string) error {
|
func (cs *commandSet) StartNode(config string) error {
|
||||||
nodeConfig, err := params.LoadNodeConfig(config)
|
nodeConfig, err := params.NewConfigFromJSON(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,7 +180,9 @@ func mkConfigJSON(name string) (string, func(), error) {
|
||||||
configJSON := `{
|
configJSON := `{
|
||||||
"NetworkId": ` + strconv.Itoa(params.RopstenNetworkID) + `,
|
"NetworkId": ` + strconv.Itoa(params.RopstenNetworkID) + `,
|
||||||
"DataDir": "` + tmpDir + `",
|
"DataDir": "` + tmpDir + `",
|
||||||
|
"KeyStoreDir": "` + tmpDir + `/keystore",
|
||||||
"LogLevel": "INFO",
|
"LogLevel": "INFO",
|
||||||
|
"NoDiscovery": true,
|
||||||
"RPCEnabled": true
|
"RPCEnabled": true
|
||||||
}`
|
}`
|
||||||
return configJSON, cleanup, nil
|
return configJSON, cleanup, nil
|
||||||
|
|
|
@ -1,26 +1,37 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrorEmpty returned when value is empty.
|
// configFlags represents an array of JSON configuration files passed to a command line utility
|
||||||
var ErrorEmpty = errors.New("empty value not allowed")
|
type configFlags []string
|
||||||
|
|
||||||
// StringSlice is a type of flag that allows setting multiple string values.
|
func (f *configFlags) String() string {
|
||||||
type StringSlice []string
|
return strings.Join(*f, ", ")
|
||||||
|
|
||||||
func (s *StringSlice) String() string {
|
|
||||||
return "string slice"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set trims space from string and stores it.
|
func (f *configFlags) Set(value string) error {
|
||||||
func (s *StringSlice) Set(value string) error {
|
if !path.IsAbs(value) {
|
||||||
trimmed := strings.TrimSpace(value)
|
// Convert to absolute path
|
||||||
if len(trimmed) == 0 {
|
cwd, err := os.Getwd()
|
||||||
return ErrorEmpty
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value = path.Join(cwd, value)
|
||||||
}
|
}
|
||||||
*s = append(*s, trimmed)
|
|
||||||
|
// Check that the file exists
|
||||||
|
stat, err := os.Stat(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if stat.IsDir() {
|
||||||
|
return fmt.Errorf("path does not represent a file: %s", value)
|
||||||
|
}
|
||||||
|
*f = append(*f, value)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ func TestStatusFlag(t *testing.T) {
|
||||||
for i, s := range scenarios {
|
for i, s := range scenarios {
|
||||||
msg := fmt.Sprintf("scenario %d", i)
|
msg := fmt.Sprintf("scenario %d", i)
|
||||||
|
|
||||||
c, err := params.NewNodeConfig("", "", params.FleetBeta, 0)
|
c, err := params.NewNodeConfig("", params.FleetBeta, 0)
|
||||||
require.Nil(t, err, msg)
|
require.Nil(t, err, msg)
|
||||||
|
|
||||||
c.IPCEnabled = s.ipcEnabled
|
c.IPCEnabled = s.ipcEnabled
|
||||||
|
|
|
@ -12,14 +12,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/status-im/status-go/logutils"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
gethmetrics "github.com/ethereum/go-ethereum/metrics"
|
gethmetrics "github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
|
||||||
"github.com/status-im/status-go/api"
|
"github.com/status-im/status-go/api"
|
||||||
"github.com/status-im/status-go/cmd/statusd/debug"
|
"github.com/status-im/status-go/cmd/statusd/debug"
|
||||||
"github.com/status-im/status-go/cmd/statusd/topics"
|
"github.com/status-im/status-go/logutils"
|
||||||
nodemetrics "github.com/status-im/status-go/metrics/node"
|
nodemetrics "github.com/status-im/status-go/metrics/node"
|
||||||
"github.com/status-im/status-go/node"
|
"github.com/status-im/status-go/node"
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
|
@ -36,90 +33,59 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
clusterConfigFile = flag.String("clusterconfig", "", "Cluster configuration file")
|
configFiles configFlags
|
||||||
nodeKeyFile = flag.String("nodekey", "", "P2P node key file (private key)")
|
logLevel = flag.String("log", "", `Log level, one of: "ERROR", "WARN", "INFO", "DEBUG", and "TRACE"`)
|
||||||
dataDir = flag.String("datadir", params.DataDir, "Data directory for the databases and keystore")
|
cliEnabled = flag.Bool("cli", false, "Enable debugging CLI server")
|
||||||
networkID = flag.Int("networkid", params.RopstenNetworkID, "Network identifier (integer, 1=Homestead, 3=Ropsten, 4=Rinkeby, 777=StatusChain)")
|
cliPort = flag.String("cli-port", debug.CLIPort, "CLI server's listening port")
|
||||||
lesEnabled = flag.Bool("les", false, "Enable LES protocol")
|
pprofEnabled = flag.Bool("pprof", false, "Enable runtime profiling via pprof")
|
||||||
whisperEnabled = flag.Bool("shh", false, "Enable Whisper protocol")
|
pprofPort = flag.Int("pprof-port", 52525, "Port for runtime profiling via pprof")
|
||||||
statusService = flag.String("status", "", `Enable StatusService, possible values: "ipc", "http"`)
|
logWithoutColors = flag.Bool("log-without-color", false, "Disables log colors")
|
||||||
debugAPI = flag.Bool("debug", false, `Enable debug API endpoints under "debug_" namespace`)
|
version = flag.Bool("version", false, "Print version and dump configuration")
|
||||||
swarmEnabled = flag.Bool("swarm", false, "Enable Swarm protocol")
|
|
||||||
maxPeers = flag.Int("maxpeers", 25, "maximum number of p2p peers (including all protocols)")
|
|
||||||
httpEnabled = flag.Bool("http", false, "Enable HTTP RPC endpoint")
|
|
||||||
httpHost = flag.String("httphost", "127.0.0.1", "HTTP RPC host of the listening socket")
|
|
||||||
httpPort = flag.Int("httpport", params.HTTPPort, "HTTP RPC server's listening port")
|
|
||||||
httpModules = flag.String("httpmodules", params.APIModules, "Comma separated list of HTTP RPC APIs")
|
|
||||||
ipcEnabled = flag.Bool("ipc", false, "Enable IPC RPC endpoint")
|
|
||||||
ipcFile = flag.String("ipcfile", "", "Set IPC file path")
|
|
||||||
cliEnabled = flag.Bool("cli", false, "Enable debugging CLI server")
|
|
||||||
cliPort = flag.String("cliport", debug.CLIPort, "CLI server's listening port")
|
|
||||||
pprofEnabled = flag.Bool("pprof", false, "Enable runtime profiling via pprof")
|
|
||||||
pprofPort = flag.Int("pprofport", 52525, "Port for runtime profiling via pprof")
|
|
||||||
logLevel = flag.String("log", "INFO", `Log level, one of: "ERROR", "WARN", "INFO", "DEBUG", and "TRACE"`)
|
|
||||||
logFile = flag.String("logfile", "", "Path to the log file")
|
|
||||||
logWithoutColors = flag.Bool("log-without-color", false, "Disables log colors")
|
|
||||||
version = flag.Bool("version", false, "Print version")
|
|
||||||
|
|
||||||
listenAddr = flag.String("listenaddr", ":30303", "IP address and port of this node (e.g. 127.0.0.1:30303)")
|
|
||||||
advertiseAddr = flag.String("advertiseaddr", "", "IP address the node wants to reached with (useful if floating IP is used)")
|
|
||||||
fleet = flag.String("fleet", params.FleetBeta, "Name of the fleet like 'eth.staging' (default to 'eth.beta')")
|
|
||||||
standalone = flag.Bool("standalone", false, "Don't actively connect to peers, wait for incoming connections")
|
|
||||||
bootnodes = flag.String("bootnodes", "", "A list of bootnodes separated by comma")
|
|
||||||
discoveryFlag = flag.Bool("discovery", false, "Enable discovery protocol")
|
|
||||||
rendezvous = flag.Bool("rendezvous", false, "Enable rendezvous protocol")
|
|
||||||
rendezvousNodes = StringSlice{}
|
|
||||||
|
|
||||||
// don't change the name of this flag, https://github.com/ethereum/go-ethereum/blob/master/metrics/metrics.go#L41
|
// don't change the name of this flag, https://github.com/ethereum/go-ethereum/blob/master/metrics/metrics.go#L41
|
||||||
metrics = flag.Bool("metrics", false, "Expose ethereum metrics with debug_metrics jsonrpc call.")
|
metrics = flag.Bool("metrics", false, "Expose ethereum metrics with debug_metrics jsonrpc call")
|
||||||
// shh stuff
|
|
||||||
passwordFile = flag.String("shh.passwordfile", "", "Password file (password is used for symmetric encryption)")
|
|
||||||
minPow = flag.Float64("shh.pow", params.WhisperMinimumPoW, "PoW for messages to be added to queue, in float format")
|
|
||||||
ttl = flag.Int("shh.ttl", params.WhisperTTL, "Time to live for messages, in seconds")
|
|
||||||
lightClient = flag.Bool("shh.lightclient", false, "Start with empty bloom filter, and don't forward messages")
|
|
||||||
|
|
||||||
// MailServer
|
|
||||||
enableMailServer = flag.Bool("shh.mailserver", false, "Delivers expired messages on demand")
|
|
||||||
|
|
||||||
// Push Notification
|
|
||||||
firebaseAuth = flag.String("shh.firebaseauth", "", "FCM Authorization Key used for sending Push Notifications")
|
|
||||||
|
|
||||||
syncAndExit = flag.Int("sync-and-exit", -1, "Timeout in minutes for blockchain sync and exit, zero means no timeout unless sync is finished")
|
syncAndExit = flag.Int("sync-and-exit", -1, "Timeout in minutes for blockchain sync and exit, zero means no timeout unless sync is finished")
|
||||||
|
|
||||||
ntpSyncEnabled = flag.Bool("ntp", true, "Enable/disable whisper NTP synchronization")
|
|
||||||
|
|
||||||
// Topics that will be search and registered by discovery v5.
|
|
||||||
searchTopics = topics.TopicLimitsFlag{}
|
|
||||||
registerTopics = topics.TopicFlag{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// All general log messages in this package should be routed through this logger.
|
// All general log messages in this package should be routed through this logger.
|
||||||
var logger = log.New("package", "status-go/cmd/statusd")
|
var logger = log.New("package", "status-go/cmd/statusd")
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.Var(&searchTopics, "topic.search", "Topic that will be searched in discovery v5, e.g (mailserver=1,1)")
|
flag.Var(&configFiles, "c", "JSON configuration file(s). Multiple configuration files can be specified, and will be merged in occurrence order")
|
||||||
flag.Var(®isterTopics, "topic.register", "Topic that will be registered using discovery v5.")
|
|
||||||
flag.Var(&rendezvousNodes, "rendezvous-node", "Rendezvous server.")
|
colors := terminal.IsTerminal(int(os.Stdin.Fd()))
|
||||||
|
if err := logutils.OverrideRootLog(true, "ERROR", "", colors); err != nil {
|
||||||
|
stdlog.Fatalf("Error initializing logger: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
flag.Usage = printUsage
|
flag.Usage = printUsage
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if flag.NArg() > 0 {
|
if flag.NArg() > 0 {
|
||||||
stdlog.Printf("Extra args in command line: %v", flag.Args())
|
|
||||||
printUsage()
|
printUsage()
|
||||||
|
logger.Error("Extra args in command line: %v", flag.Args())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
colors := !(*logWithoutColors) && terminal.IsTerminal(int(os.Stdin.Fd()))
|
config, err := params.NewNodeConfigWithDefaults("statusd-data", params.FleetBeta, params.RopstenNetworkID)
|
||||||
if err := logutils.OverrideRootLog(logEnabled(), *logLevel, *logFile, colors); err != nil {
|
if err == nil {
|
||||||
stdlog.Fatalf("Error initializing logger: %s", err)
|
err = parseConfig(configFiles, config)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
printUsage()
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err.Error())
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
config, err := makeNodeConfig()
|
colors := !(*logWithoutColors) && terminal.IsTerminal(int(os.Stdin.Fd()))
|
||||||
if err != nil {
|
if err = logutils.OverrideRootLog(logEnabled(config), config.LogLevel, config.LogFile, colors); err != nil {
|
||||||
stdlog.Fatalf("Making config failed, %s", err)
|
stdlog.Fatalf("Error initializing logger: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We want statusd to be distinct from StatusIM client.
|
// We want statusd to be distinct from StatusIM client.
|
||||||
config.Name = serverClientName
|
config.Name = serverClientName
|
||||||
|
|
||||||
|
@ -206,95 +172,15 @@ func startCollectingNodeMetrics(interruptCh <-chan struct{}, statusNode *node.St
|
||||||
<-interruptCh
|
<-interruptCh
|
||||||
}
|
}
|
||||||
|
|
||||||
func logEnabled() bool {
|
func logEnabled(config *params.NodeConfig) bool {
|
||||||
return *logLevel != "" || *logFile != ""
|
return config.LogLevel != "" || config.LogFile != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeNodeConfig parses incoming CLI options and returns node configuration object
|
var (
|
||||||
func makeNodeConfig() (*params.NodeConfig, error) {
|
errStatusServiceRequiresIPC = errors.New("to enable the StatusService on IPC, -ipc flag must be set")
|
||||||
nodeConfig, err := params.NewNodeConfig(*dataDir, *clusterConfigFile, *fleet, uint64(*networkID))
|
errStatusServiceRequiresHTTP = errors.New("to enable the StatusService on HTTP, -http flag must be set")
|
||||||
if err != nil {
|
errStatusServiceInvalidFlag = errors.New("-status flag valid values are: ipc, http")
|
||||||
return nil, err
|
)
|
||||||
}
|
|
||||||
|
|
||||||
nodeConfig.ListenAddr = *listenAddr
|
|
||||||
nodeConfig.AdvertiseAddr = *advertiseAddr
|
|
||||||
|
|
||||||
// TODO(divan): move this logic into params package
|
|
||||||
if *nodeKeyFile != "" {
|
|
||||||
nodeConfig.NodeKeyFile = *nodeKeyFile
|
|
||||||
}
|
|
||||||
|
|
||||||
if *logLevel != "" {
|
|
||||||
nodeConfig.LogLevel = *logLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
if *logFile != "" {
|
|
||||||
nodeConfig.LogFile = *logFile
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeConfig.LogEnabled = logEnabled()
|
|
||||||
|
|
||||||
nodeConfig.RPCEnabled = *httpEnabled
|
|
||||||
nodeConfig.WhisperConfig.Enabled = *whisperEnabled
|
|
||||||
nodeConfig.MaxPeers = *maxPeers
|
|
||||||
|
|
||||||
nodeConfig.HTTPHost = *httpHost
|
|
||||||
nodeConfig.HTTPPort = *httpPort
|
|
||||||
nodeConfig.APIModules = *httpModules
|
|
||||||
nodeConfig.IPCEnabled = *ipcEnabled
|
|
||||||
|
|
||||||
if *ipcFile != "" {
|
|
||||||
nodeConfig.IPCEnabled = true
|
|
||||||
nodeConfig.IPCFile = *ipcFile
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeConfig.LightEthConfig.Enabled = *lesEnabled
|
|
||||||
nodeConfig.SwarmConfig.Enabled = *swarmEnabled
|
|
||||||
|
|
||||||
if *standalone {
|
|
||||||
nodeConfig.ClusterConfig.Enabled = false
|
|
||||||
nodeConfig.ClusterConfig.BootNodes = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rendezvousNodes) > 0 {
|
|
||||||
nodeConfig.ClusterConfig.RendezvousNodes = []string(rendezvousNodes)
|
|
||||||
}
|
|
||||||
nodeConfig.NoDiscovery = !(*discoveryFlag)
|
|
||||||
nodeConfig.Rendezvous = *rendezvous
|
|
||||||
nodeConfig.RequireTopics = map[discv5.Topic]params.Limits(searchTopics)
|
|
||||||
nodeConfig.RegisterTopics = []discv5.Topic(registerTopics)
|
|
||||||
|
|
||||||
// Even if standalone is true and discovery is disabled,
|
|
||||||
// it's possible to use bootnodes.
|
|
||||||
if *bootnodes != "" {
|
|
||||||
nodeConfig.ClusterConfig.BootNodes = strings.Split(*bootnodes, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
if nodeConfig, err = configureStatusService(*statusService, nodeConfig); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeConfig.DebugAPIEnabled = *debugAPI
|
|
||||||
if nodeConfig.DebugAPIEnabled {
|
|
||||||
nodeConfig.AddAPIModule("debug")
|
|
||||||
}
|
|
||||||
|
|
||||||
if *whisperEnabled {
|
|
||||||
return whisperConfig(nodeConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RPC configuration
|
|
||||||
if !*httpEnabled {
|
|
||||||
nodeConfig.HTTPHost = "" // HTTP RPC is disabled
|
|
||||||
}
|
|
||||||
|
|
||||||
return nodeConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var errStatusServiceRequiresIPC = errors.New("to enable the StatusService on IPC, -ipc flag must be set")
|
|
||||||
var errStatusServiceRequiresHTTP = errors.New("to enable the StatusService on HTTP, -http flag must be set")
|
|
||||||
var errStatusServiceInvalidFlag = errors.New("-status flag valid values are: ipc, http")
|
|
||||||
|
|
||||||
func configureStatusService(flagValue string, nodeConfig *params.NodeConfig) (*params.NodeConfig, error) {
|
func configureStatusService(flagValue string, nodeConfig *params.NodeConfig) (*params.NodeConfig, error) {
|
||||||
switch flagValue {
|
switch flagValue {
|
||||||
|
@ -318,6 +204,19 @@ func configureStatusService(flagValue string, nodeConfig *params.NodeConfig) (*p
|
||||||
return nodeConfig, nil
|
return nodeConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseConfig(configFiles configFlags, config *params.NodeConfig) error {
|
||||||
|
// Merge specified configuration files, in order
|
||||||
|
if err := params.LoadConfigFromFiles(configFiles, config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if *logLevel != "" {
|
||||||
|
config.LogLevel = *logLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// printVersion prints verbose output about version and config.
|
// printVersion prints verbose output about version and config.
|
||||||
func printVersion(config *params.NodeConfig, buildStamp string) {
|
func printVersion(config *params.NodeConfig, buildStamp string) {
|
||||||
fmt.Println(strings.Title(config.Name))
|
fmt.Println(strings.Title(config.Name))
|
||||||
|
@ -333,7 +232,6 @@ func printVersion(config *params.NodeConfig, buildStamp string) {
|
||||||
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
|
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
|
||||||
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
|
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
|
||||||
|
|
||||||
config.LightEthConfig.Genesis = "SKIP"
|
|
||||||
fmt.Println("Loaded Config: ", config)
|
fmt.Println("Loaded Config: ", config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,11 +239,10 @@ func printUsage() {
|
||||||
usage := `
|
usage := `
|
||||||
Usage: statusd [options]
|
Usage: statusd [options]
|
||||||
Examples:
|
Examples:
|
||||||
statusd # run status node with defaults
|
statusd -c ./default.json # run node with configuration specified in ./default.json file
|
||||||
statusd -networkid 4 # run node on Rinkeby network
|
statusd -c ./default.json -c ./standalone.json # run node with configuration specified in ./default.json file, after merging ./standalone.json file
|
||||||
statusd -datadir /dir # specify different dir for data
|
statusd -c ./default.json -metrics # run node with configuration specified in ./default.json file, and expose ethereum metrics with debug_metrics jsonrpc call
|
||||||
statusd -ipc # enable IPC for usage with "geth attach"
|
statusd -c ./default.json -cli # run node with configuration specified in ./default.json file, and enable connection by statusd-cli on default port
|
||||||
statusd -cli # enable connection by statusd-cli on default port
|
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
`
|
`
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"github.com/status-im/status-go/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// whisperConfig creates node configuration object from flags
|
|
||||||
func whisperConfig(nodeConfig *params.NodeConfig) (*params.NodeConfig, error) {
|
|
||||||
whisperConfig := nodeConfig.WhisperConfig
|
|
||||||
|
|
||||||
whisperConfig.Enabled = true
|
|
||||||
whisperConfig.EnableMailServer = *enableMailServer
|
|
||||||
whisperConfig.LightClient = *lightClient
|
|
||||||
whisperConfig.MinimumPoW = *minPow
|
|
||||||
whisperConfig.TTL = *ttl
|
|
||||||
whisperConfig.EnableNTPSync = *ntpSyncEnabled
|
|
||||||
|
|
||||||
if whisperConfig.EnableMailServer {
|
|
||||||
if *passwordFile == "" {
|
|
||||||
return nil, errors.New("passwordfile should be specified if MailServer is enabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
password, err := readFile(*passwordFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("password file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
whisperConfig.MailServerPassword = string(password)
|
|
||||||
}
|
|
||||||
|
|
||||||
// firebase configuration
|
|
||||||
firebaseConfig := whisperConfig.FirebaseConfig
|
|
||||||
firebaseConfig.AuthorizationKeyFile = *firebaseAuth
|
|
||||||
if firebaseConfig.AuthorizationKeyFile != "" {
|
|
||||||
if _, err := firebaseConfig.ReadAuthorizationKeyFile(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nodeConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readFile(path string) ([]byte, error) {
|
|
||||||
data, err := ioutil.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
data = bytes.TrimRight(data, "\n")
|
|
||||||
|
|
||||||
if len(data) == 0 {
|
|
||||||
return nil, errors.New("file is empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
return data, nil
|
|
||||||
}
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"Rendezvous": true,
|
||||||
|
"ClusterConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"Fleet": "eth.beta",
|
||||||
|
"BootNodes": [
|
||||||
|
"enode://436cc6f674928fdc9a9f7990f2944002b685d1c37f025c1be425185b5b1f0900feaf1ccc2a6130268f9901be4a7d252f37302c8335a2c1a62736e9232691cc3a@174.138.105.243:30404",
|
||||||
|
"enode://5395aab7833f1ecb671b59bf0521cf20224fe8162fc3d2675de4ee4d5636a75ec32d13268fc184df8d1ddfa803943906882da62a4df42d4fccf6d17808156a87@206.189.243.57:30404",
|
||||||
|
"enode://7427dfe38bd4cf7c58bb96417806fab25782ec3e6046a8053370022cbaa281536e8d64ecd1b02e1f8f72768e295d06258ba43d88304db068e6f2417ae8bcb9a6@104.154.88.123:30404",
|
||||||
|
"enode://ebefab39b69bbbe64d8cd86be765b3be356d8c4b24660f65d493143a0c44f38c85a257300178f7845592a1b0332811542e9a58281c835babdd7535babb64efc1@35.202.99.224:30404"
|
||||||
|
],
|
||||||
|
"TrustedMailServers": [
|
||||||
|
"enode://c42f368a23fa98ee546fd247220759062323249ef657d26d357a777443aec04db1b29a3a22ef3e7c548e18493ddaf51a31b0aed6079bd6ebe5ae838fcfaf3a49@206.189.243.162:30504",
|
||||||
|
"enode://7aa648d6e855950b2e3d3bf220c496e0cae4adfddef3e1e6062e6b177aec93bc6cdcf1282cb40d1656932ebfdd565729da440368d7c4da7dbd4d004b1ac02bf8@206.189.243.169:30504",
|
||||||
|
"enode://8a64b3c349a2e0ef4a32ea49609ed6eb3364be1110253c20adc17a3cebbc39a219e5d3e13b151c0eee5d8e0f9a8ba2cd026014e67b41a4ab7d1d5dd67ca27427@206.189.243.168:30504",
|
||||||
|
"enode://7de99e4cb1b3523bd26ca212369540646607c721ad4f3e5c821ed9148150ce6ce2e72631723002210fac1fd52dfa8bbdf3555e05379af79515e1179da37cc3db@35.188.19.210:30504",
|
||||||
|
"enode://015e22f6cd2b44c8a51bd7a23555e271e0759c7d7f52432719665a74966f2da456d28e154e836bee6092b4d686fe67e331655586c57b718be3997c1629d24167@35.226.21.19:30504",
|
||||||
|
"enode://531e252ec966b7e83f5538c19bf1cde7381cc7949026a6e499b6e998e695751aadf26d4c98d5a4eabfb7cefd31c3c88d600a775f14ed5781520a88ecd25da3c6@35.225.227.79:30504"
|
||||||
|
],
|
||||||
|
"StaticNodes": [
|
||||||
|
"enode://a6a2a9b3a7cbb0a15da74301537ebba549c990e3325ae78e1272a19a3ace150d03c184b8ac86cc33f1f2f63691e467d49308f02d613277754c4dccd6773b95e8@206.189.243.176:30304",
|
||||||
|
"enode://207e53d9bf66be7441e3daba36f53bfbda0b6099dba9a865afc6260a2d253fb8a56a72a48598a4f7ba271792c2e4a8e1a43aaef7f34857f520c8c820f63b44c8@35.224.15.65:30304"
|
||||||
|
],
|
||||||
|
"RendezvousNodes": [
|
||||||
|
"/ip4/174.138.105.243/tcp/30703/ethv4/16Uiu2HAmRHPzF3rQg55PgYPcQkyvPVH9n2hWsYPhUJBZ6kVjJgdV",
|
||||||
|
"/ip4/206.189.243.57/tcp/30703/ethv4/16Uiu2HAmLqTXuY4Sb6G28HNooaFUXUKzpzKXCcgyJxgaEE2i5vnf"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"Rendezvous": true,
|
||||||
|
"ClusterConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"Fleet": "eth.staging",
|
||||||
|
"BootNodes": [
|
||||||
|
"enode://10a78c17929a7019ef4aa2249d7302f76ae8a06f40b2dc88b7b31ebff4a623fbb44b4a627acba296c1ced3775d91fbe18463c15097a6a36fdb2c804ff3fc5b35@35.238.97.234:30404",
|
||||||
|
"enode://f79fb3919f72ca560ad0434dcc387abfe41e0666201ebdada8ede0462454a13deb05cda15f287d2c4bd85da81f0eb25d0a486bbbc8df427b971ac51533bd00fe@174.138.107.239:30404"
|
||||||
|
],
|
||||||
|
"TrustedMailServers": [
|
||||||
|
"enode://69f72baa7f1722d111a8c9c68c39a31430e9d567695f6108f31ccb6cd8f0adff4991e7fdca8fa770e75bc8a511a87d24690cbc80e008175f40c157d6f6788d48@206.189.240.16:30504",
|
||||||
|
"enode://e4fc10c1f65c8aed83ac26bc1bfb21a45cc1a8550a58077c8d2de2a0e0cd18e40fd40f7e6f7d02dc6cd06982b014ce88d6e468725ffe2c138e958788d0002a7f@35.239.193.41:30504"
|
||||||
|
],
|
||||||
|
"StaticNodes": [
|
||||||
|
"enode://914c0b30f27bab30c1dfd31dad7652a46fda9370542aee1b062498b1345ee0913614b8b9e3e84622e84a7203c5858ae1d9819f63aece13ee668e4f6668063989@167.99.19.148:30305",
|
||||||
|
"enode://2d897c6e846949f9dcf10279f00e9b8325c18fe7fa52d658520ad7be9607c83008b42b06aefd97cfe1fdab571f33a2a9383ff97c5909ed51f63300834913237e@35.192.0.86:30305"
|
||||||
|
],
|
||||||
|
"RendezvousNodes": [
|
||||||
|
"/ip4/174.138.107.239/tcp/30703/ethv4/16Uiu2HAkyJHeetQ4DNpd4NZ2ntzxMo25zcdpvGQRqkD5pB9BE6RU",
|
||||||
|
"/ip4/35.238.97.234/tcp/30703/ethv4/16Uiu2HAm1sVyXmkMNjdeDWqK2urbyC3oBHi8MDpCdYkns1nYafqz"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"Rendezvous": false,
|
||||||
|
"LogLevel": "DEBUG",
|
||||||
|
"ClusterConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"Fleet": "eth.test",
|
||||||
|
"BootNodes": [
|
||||||
|
"enode://daae2e72820e86e942fa2a8aa7d6e9954d4043a753483d8bd338e16be82cf962392d5c0e1ae57c3d793c3d3dddd8fd58339262e4234dc966f953cd73b535f5fa@47.52.188.149:30404",
|
||||||
|
"enode://9e0988575eb7717c25dea72fd11c7b37767dc09c1a7686f7c2ec577d308d24b377ceb675de4317474a1a870e47882732967f4fa785b02ba95d669b31d464dec0@206.189.243.164:30404",
|
||||||
|
"enode://c1e5018887c863d64e431b69bf617561087825430e4401733f5ba77c70db14236df381fefb0ebe1ac42294b9e261bbe233dbdb83e32c586c66ae26c8de70cb4c@35.188.168.137:30404"
|
||||||
|
],
|
||||||
|
"TrustedMailServers": [
|
||||||
|
"enode://954c06603a6e755bffe9992615f4755848bda9aadda74d920aa31d1d8e4f6022dc556dca6768f8a0f9459f57b729509db3c8b3bb80acfbd8a2123087f6cbd7bd@47.52.188.196:30504",
|
||||||
|
"enode://e4865fe6c2a9c1a563a6447990d8e9ce672644ae3e08277ce38ec1f1b690eef6320c07a5d60c3b629f5d4494f93d6b86a745a0bf64ab295bbf6579017adc6ed8@206.189.243.161:30504",
|
||||||
|
"enode://707e57453acd3e488c44b9d0e17975371e2f8fb67525eae5baca9b9c8e06c86cde7c794a6c2e36203bf9f56cae8b0e50f3b33c4c2b694a7baeea1754464ce4e3@35.192.229.172:30504"
|
||||||
|
],
|
||||||
|
"StaticNodes": [
|
||||||
|
"enode://ad38f94030a846cc7005b7a1f3b6b01bf4ef59d34e8d3d6f4d12df23d14ba8656702a435d34cf4df3b412c0c1923df5adcce8461321a0d8ffb9435b26e572c2a@47.52.255.194:30305",
|
||||||
|
"enode://1d193635e015918fb85bbaf774863d12f65d70c6977506187ef04420d74ec06c9e8f0dcb57ea042f85df87433dab17a1260ed8dde1bdf9d6d5d2de4b7bf8e993@206.189.243.163:30305",
|
||||||
|
"enode://f593a27731bc0f8eb088e2d39222c2d59dfb9bf0b3950d7a828d51e8ab9e08fffbd9916a82fd993c1a080c57c2bd70ed6c36f489a969de697aff93088dbee1a9@35.194.31.108:30305"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"LightEthConfig": {
|
||||||
|
"Enabled": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,26 +22,10 @@ import (
|
||||||
// All general log messages in this package should be routed through this logger.
|
// All general log messages in this package should be routed through this logger.
|
||||||
var logger = log.New("package", "status-go/lib")
|
var logger = log.New("package", "status-go/lib")
|
||||||
|
|
||||||
//GenerateConfig for status node
|
|
||||||
//export GenerateConfig
|
|
||||||
func GenerateConfig(datadir *C.char, fleet *C.char, networkID C.int) *C.char {
|
|
||||||
config, err := params.NewNodeConfig(C.GoString(datadir), "", C.GoString(fleet), uint64(networkID))
|
|
||||||
if err != nil {
|
|
||||||
return makeJSONResponse(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
outBytes, err := json.Marshal(config)
|
|
||||||
if err != nil {
|
|
||||||
return makeJSONResponse(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return C.CString(string(outBytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
//StartNode - start Status node
|
//StartNode - start Status node
|
||||||
//export StartNode
|
//export StartNode
|
||||||
func StartNode(configJSON *C.char) *C.char {
|
func StartNode(configJSON *C.char) *C.char {
|
||||||
config, err := params.LoadNodeConfig(C.GoString(configJSON))
|
config, err := params.NewConfigFromJSON(C.GoString(configJSON))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return makeJSONResponse(err)
|
return makeJSONResponse(err)
|
||||||
}
|
}
|
||||||
|
@ -67,7 +51,7 @@ func StopNode() *C.char {
|
||||||
func ValidateNodeConfig(configJSON *C.char) *C.char {
|
func ValidateNodeConfig(configJSON *C.char) *C.char {
|
||||||
var resp APIDetailedResponse
|
var resp APIDetailedResponse
|
||||||
|
|
||||||
_, err := params.LoadNodeConfig(C.GoString(configJSON))
|
_, err := params.NewConfigFromJSON(C.GoString(configJSON))
|
||||||
|
|
||||||
// Convert errors to APIDetailedResponse
|
// Convert errors to APIDetailedResponse
|
||||||
switch err := err.(type) {
|
switch err := err.(type) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,9 +24,9 @@ func TestExportedAPI(t *testing.T) {
|
||||||
|
|
||||||
func TestValidateNodeConfig(t *testing.T) {
|
func TestValidateNodeConfig(t *testing.T) {
|
||||||
noErrorsCallback := func(resp APIDetailedResponse) {
|
noErrorsCallback := func(resp APIDetailedResponse) {
|
||||||
|
assert.Empty(t, resp.FieldErrors)
|
||||||
|
assert.Empty(t, resp.Message)
|
||||||
require.True(t, resp.Status, "expected status equal true")
|
require.True(t, resp.Status, "expected status equal true")
|
||||||
require.Empty(t, resp.FieldErrors)
|
|
||||||
require.Empty(t, resp.Message)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
|
@ -37,7 +38,15 @@ func TestValidateNodeConfig(t *testing.T) {
|
||||||
Name: "response for valid config",
|
Name: "response for valid config",
|
||||||
Config: `{
|
Config: `{
|
||||||
"NetworkId": 1,
|
"NetworkId": 1,
|
||||||
"DataDir": "/tmp"
|
"DataDir": "/tmp",
|
||||||
|
"KeyStoreDir": "/tmp",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"EnableMailServer": true,
|
||||||
|
"DataDir": "/tmp",
|
||||||
|
"MailServerPassword": "status-offline-inbox"
|
||||||
|
}
|
||||||
}`,
|
}`,
|
||||||
Callback: noErrorsCallback,
|
Callback: noErrorsCallback,
|
||||||
},
|
},
|
||||||
|
@ -49,18 +58,85 @@ func TestValidateNodeConfig(t *testing.T) {
|
||||||
require.Contains(t, resp.Message, "validation: invalid character '}'")
|
require.Contains(t, resp.Message, "validation: invalid character '}'")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "response for config missing DataDir",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 3,
|
||||||
|
"KeyStoreDir": "/tmp",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": false
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
Callback: func(resp APIDetailedResponse) {
|
||||||
|
require.False(t, resp.Status)
|
||||||
|
require.Equal(t, 1, len(resp.FieldErrors))
|
||||||
|
require.Equal(t, resp.FieldErrors[0].Parameter, "NodeConfig.DataDir")
|
||||||
|
require.Contains(t, resp.Message, "validation: validation failed")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "response for config missing KeyStoreDir",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 3,
|
||||||
|
"DataDir": "/tmp",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": false
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
Callback: func(resp APIDetailedResponse) {
|
||||||
|
require.False(t, resp.Status)
|
||||||
|
require.Equal(t, 1, len(resp.FieldErrors))
|
||||||
|
require.Equal(t, resp.FieldErrors[0].Parameter, "NodeConfig.KeyStoreDir")
|
||||||
|
require.Contains(t, resp.Message, "validation: validation failed")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "response for config missing WhisperConfig.DataDir",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 3,
|
||||||
|
"DataDir": "/tmp",
|
||||||
|
"KeyStoreDir": "/tmp",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"EnableMailServer": true
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
Callback: func(resp APIDetailedResponse) {
|
||||||
|
require.False(t, resp.Status)
|
||||||
|
require.Empty(t, resp.FieldErrors)
|
||||||
|
require.Contains(t, resp.Message, "WhisperConfig.DataDir must be specified when WhisperConfig.EnableMailServer is true")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "response for config missing WhisperConfig.DataDir with WhisperConfig.EnableMailServer set to false",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 3,
|
||||||
|
"DataDir": "/tmp",
|
||||||
|
"KeyStoreDir": "/tmp",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"EnableMailServer": false
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
Callback: noErrorsCallback,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "response for config with multiple errors",
|
Name: "response for config with multiple errors",
|
||||||
Config: `{}`,
|
Config: `{}`,
|
||||||
Callback: func(resp APIDetailedResponse) {
|
Callback: func(resp APIDetailedResponse) {
|
||||||
required := map[string]string{
|
required := map[string]string{
|
||||||
"NodeConfig.NetworkID": "required",
|
"NodeConfig.NetworkID": "required",
|
||||||
"NodeConfig.DataDir": "required",
|
"NodeConfig.DataDir": "required",
|
||||||
|
"NodeConfig.KeyStoreDir": "required",
|
||||||
}
|
}
|
||||||
|
|
||||||
require.False(t, resp.Status)
|
require.False(t, resp.Status)
|
||||||
require.Contains(t, resp.Message, "validation: validation failed")
|
require.Contains(t, resp.Message, "validation: validation failed")
|
||||||
require.Equal(t, 2, len(resp.FieldErrors))
|
require.Equal(t, 3, len(resp.FieldErrors), resp.FieldErrors)
|
||||||
|
|
||||||
for _, err := range resp.FieldErrors {
|
for _, err := range resp.FieldErrors {
|
||||||
require.Contains(t, required, err.Parameter)
|
require.Contains(t, required, err.Parameter)
|
||||||
|
|
|
@ -12,10 +12,10 @@ package main
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -26,13 +26,10 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
gethparams "github.com/ethereum/go-ethereum/params"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/status-im/status-go/account"
|
"github.com/status-im/status-go/account"
|
||||||
"github.com/status-im/status-go/params"
|
|
||||||
"github.com/status-im/status-go/signal"
|
"github.com/status-im/status-go/signal"
|
||||||
. "github.com/status-im/status-go/t/utils" //nolint: golint
|
. "github.com/status-im/status-go/t/utils" //nolint: golint
|
||||||
"github.com/status-im/status-go/transactions"
|
"github.com/status-im/status-go/transactions"
|
||||||
|
@ -55,9 +52,18 @@ func init() {
|
||||||
nodeConfigJSON = `{
|
nodeConfigJSON = `{
|
||||||
"NetworkId": ` + strconv.Itoa(GetNetworkID()) + `,
|
"NetworkId": ` + strconv.Itoa(GetNetworkID()) + `,
|
||||||
"DataDir": "` + testChainDir + `",
|
"DataDir": "` + testChainDir + `",
|
||||||
|
"KeyStoreDir": "` + filepath.Join(testChainDir, "keystore") + `",
|
||||||
"HTTPPort": ` + strconv.Itoa(TestConfig.Node.HTTPPort) + `,
|
"HTTPPort": ` + strconv.Itoa(TestConfig.Node.HTTPPort) + `,
|
||||||
"WSPort": ` + strconv.Itoa(TestConfig.Node.WSPort) + `,
|
"LogLevel": "INFO",
|
||||||
"LogLevel": "INFO"
|
"NoDiscovery": true,
|
||||||
|
"LightEthConfig": {
|
||||||
|
"Enabled": true
|
||||||
|
},
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"DataDir": "` + path.Join(testChainDir, "wnode") + `",
|
||||||
|
"EnableNTPSync": false
|
||||||
|
}
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,10 +91,6 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
|
||||||
name string
|
name string
|
||||||
fn func(t *testing.T) bool
|
fn func(t *testing.T) bool
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
"check default configuration",
|
|
||||||
testGetDefaultConfig,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"stop/resume node",
|
"stop/resume node",
|
||||||
testStopResumeNode,
|
testStopResumeNode,
|
||||||
|
@ -187,39 +189,6 @@ func testVerifyAccountPassword(t *testing.T) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetDefaultConfig(t *testing.T) bool {
|
|
||||||
networks := []struct {
|
|
||||||
chainID int
|
|
||||||
refChainConfig *gethparams.ChainConfig
|
|
||||||
}{
|
|
||||||
{params.MainNetworkID, gethparams.MainnetChainConfig},
|
|
||||||
{params.RopstenNetworkID, gethparams.TestnetChainConfig},
|
|
||||||
{params.RinkebyNetworkID, gethparams.RinkebyChainConfig},
|
|
||||||
// TODO(tiabc): The same for params.StatusChainNetworkID
|
|
||||||
}
|
|
||||||
for i := range networks {
|
|
||||||
network := networks[i]
|
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("networkID=%d", network.chainID), func(t *testing.T) {
|
|
||||||
var (
|
|
||||||
nodeConfig = params.NodeConfig{}
|
|
||||||
rawResponse = GenerateConfig(C.CString("/tmp/data-folder"), C.CString("eth.staging"), C.int(network.chainID))
|
|
||||||
)
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &nodeConfig); err != nil {
|
|
||||||
t.Errorf("cannot decode response (%s): %v", C.GoString(rawResponse), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
genesis := new(core.Genesis)
|
|
||||||
if err := json.Unmarshal([]byte(nodeConfig.LightEthConfig.Genesis), genesis); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
require.Equal(t, network.refChainConfig, genesis.Config)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
//@TODO(adam): quarantined this test until it uses a different directory.
|
//@TODO(adam): quarantined this test until it uses a different directory.
|
||||||
//nolint: deadcode
|
//nolint: deadcode
|
||||||
func testResetChainData(t *testing.T) bool {
|
func testResetChainData(t *testing.T) bool {
|
||||||
|
|
|
@ -120,7 +120,7 @@ func (s *WMailServer) Init(shh *whisper.Whisper, config *params.WhisperConfig) e
|
||||||
return errDirectoryNotProvided
|
return errDirectoryNotProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(config.MailServerPassword) == 0 && config.MailServerAsymKey == nil {
|
if len(config.MailServerPassword) == 0 && len(config.MailServerAsymKey) == 0 {
|
||||||
return errDecryptionMethodNotProvided
|
return errDecryptionMethodNotProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,8 +172,12 @@ func (s *WMailServer) setupRequestMessageDecryptor(config *params.WhisperConfig)
|
||||||
s.symFilter = &whisper.Filter{KeySym: symKey}
|
s.symFilter = &whisper.Filter{KeySym: symKey}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.MailServerAsymKey != nil {
|
if config.MailServerAsymKey != "" {
|
||||||
s.asymFilter = &whisper.Filter{KeyAsym: config.MailServerAsymKey}
|
keyAsym, err := crypto.HexToECDSA(config.MailServerAsymKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.asymFilter = &whisper.Filter{KeyAsym: keyAsym}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -19,11 +19,11 @@ package mailserver
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -72,19 +72,13 @@ func (s *MailserverSuite) SetupTest() {
|
||||||
s.dataDir = tmpDir
|
s.dataDir = tmpDir
|
||||||
|
|
||||||
// required files to validate mail server decryption method
|
// required files to validate mail server decryption method
|
||||||
asymKeyFile := filepath.Join(tmpDir, "asymkey")
|
|
||||||
passwordFile := filepath.Join(tmpDir, "password")
|
|
||||||
privateKey, err := crypto.GenerateKey()
|
privateKey, err := crypto.GenerateKey()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
err = crypto.SaveECDSA(asymKeyFile, privateKey)
|
|
||||||
s.Require().NoError(err)
|
|
||||||
err = ioutil.WriteFile(passwordFile, []byte("testpassword"), os.ModePerm)
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
s.config = ¶ms.WhisperConfig{
|
s.config = ¶ms.WhisperConfig{
|
||||||
DataDir: tmpDir,
|
DataDir: tmpDir,
|
||||||
MailServerAsymKeyFile: asymKeyFile,
|
MailServerAsymKey: hex.EncodeToString(crypto.FromECDSA(privateKey)),
|
||||||
MailServerPasswordFile: passwordFile,
|
MailServerPassword: "testpassword",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +112,7 @@ func (s *MailserverSuite) TestInit() {
|
||||||
config: params.WhisperConfig{
|
config: params.WhisperConfig{
|
||||||
DataDir: s.config.DataDir,
|
DataDir: s.config.DataDir,
|
||||||
MailServerPassword: "",
|
MailServerPassword: "",
|
||||||
MailServerAsymKey: nil,
|
MailServerAsymKey: "",
|
||||||
},
|
},
|
||||||
expectedError: errDecryptionMethodNotProvided,
|
expectedError: errDecryptionMethodNotProvided,
|
||||||
info: "config with an empty password and empty asym key",
|
info: "config with an empty password and empty asym key",
|
||||||
|
@ -134,7 +128,7 @@ func (s *MailserverSuite) TestInit() {
|
||||||
{
|
{
|
||||||
config: params.WhisperConfig{
|
config: params.WhisperConfig{
|
||||||
DataDir: s.config.DataDir,
|
DataDir: s.config.DataDir,
|
||||||
MailServerAsymKey: asymKey,
|
MailServerAsymKey: hex.EncodeToString(crypto.FromECDSA(asymKey)),
|
||||||
},
|
},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
info: "config with correct DataDir and AsymKey",
|
info: "config with correct DataDir and AsymKey",
|
||||||
|
@ -142,7 +136,7 @@ func (s *MailserverSuite) TestInit() {
|
||||||
{
|
{
|
||||||
config: params.WhisperConfig{
|
config: params.WhisperConfig{
|
||||||
DataDir: s.config.DataDir,
|
DataDir: s.config.DataDir,
|
||||||
MailServerAsymKey: asymKey,
|
MailServerAsymKey: hex.EncodeToString(crypto.FromECDSA(asymKey)),
|
||||||
MailServerPassword: "pwd",
|
MailServerPassword: "pwd",
|
||||||
},
|
},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
|
@ -186,11 +180,13 @@ func (s *MailserverSuite) TestInit() {
|
||||||
func (s *MailserverSuite) TestSetupRequestMessageDecryptor() {
|
func (s *MailserverSuite) TestSetupRequestMessageDecryptor() {
|
||||||
// without configured Password and AsymKey
|
// without configured Password and AsymKey
|
||||||
config := *s.config
|
config := *s.config
|
||||||
|
config.MailServerAsymKey = ""
|
||||||
|
config.MailServerPassword = ""
|
||||||
s.Error(errDecryptionMethodNotProvided, s.server.Init(s.shh, &config))
|
s.Error(errDecryptionMethodNotProvided, s.server.Init(s.shh, &config))
|
||||||
|
|
||||||
// Password should work ok
|
// Password should work ok
|
||||||
config = *s.config
|
config = *s.config
|
||||||
s.NoError(config.ReadMailServerPasswordFile())
|
config.MailServerAsymKey = "" // clear asym key field
|
||||||
s.NoError(s.server.Init(s.shh, &config))
|
s.NoError(s.server.Init(s.shh, &config))
|
||||||
s.Require().NotNil(s.server.symFilter)
|
s.Require().NotNil(s.server.symFilter)
|
||||||
s.NotNil(s.server.symFilter.KeySym)
|
s.NotNil(s.server.symFilter.KeySym)
|
||||||
|
@ -199,17 +195,15 @@ func (s *MailserverSuite) TestSetupRequestMessageDecryptor() {
|
||||||
|
|
||||||
// AsymKey can also be used
|
// AsymKey can also be used
|
||||||
config = *s.config
|
config = *s.config
|
||||||
s.NoError(config.ReadMailServerAsymKeyFile())
|
config.MailServerPassword = "" // clear password field
|
||||||
s.NoError(s.server.Init(s.shh, &config))
|
s.NoError(s.server.Init(s.shh, &config))
|
||||||
s.Nil(s.server.symFilter) // important: symmetric filter should be nil
|
s.Nil(s.server.symFilter) // important: symmetric filter should be nil
|
||||||
s.Require().NotNil(s.server.asymFilter)
|
s.Require().NotNil(s.server.asymFilter)
|
||||||
s.Equal(config.MailServerAsymKey, s.server.asymFilter.KeyAsym)
|
s.Equal(config.MailServerAsymKey, hex.EncodeToString(crypto.FromECDSA(s.server.asymFilter.KeyAsym)))
|
||||||
s.server.Close()
|
s.server.Close()
|
||||||
|
|
||||||
// when Password and AsymKey are set, both are supported
|
// when Password and AsymKey are set, both are supported
|
||||||
config = *s.config
|
config = *s.config
|
||||||
s.NoError(config.ReadMailServerPasswordFile())
|
|
||||||
s.NoError(config.ReadMailServerAsymKeyFile())
|
|
||||||
s.NoError(s.server.Init(s.shh, &config))
|
s.NoError(s.server.Init(s.shh, &config))
|
||||||
s.Require().NotNil(s.server.symFilter)
|
s.Require().NotNil(s.server.symFilter)
|
||||||
s.NotNil(s.server.symFilter.KeySym)
|
s.NotNil(s.server.symFilter.KeySym)
|
||||||
|
@ -220,7 +214,7 @@ func (s *MailserverSuite) TestSetupRequestMessageDecryptor() {
|
||||||
func (s *MailserverSuite) TestOpenEnvelopeWithSymKey() {
|
func (s *MailserverSuite) TestOpenEnvelopeWithSymKey() {
|
||||||
// Setup the server with a sym key
|
// Setup the server with a sym key
|
||||||
config := *s.config
|
config := *s.config
|
||||||
s.NoError(config.ReadMailServerPasswordFile())
|
config.MailServerAsymKey = "" // clear asym key
|
||||||
s.NoError(s.server.Init(s.shh, &config))
|
s.NoError(s.server.Init(s.shh, &config))
|
||||||
|
|
||||||
// Prepare a valid envelope
|
// Prepare a valid envelope
|
||||||
|
@ -239,7 +233,7 @@ func (s *MailserverSuite) TestOpenEnvelopeWithSymKey() {
|
||||||
func (s *MailserverSuite) TestOpenEnvelopeWithAsymKey() {
|
func (s *MailserverSuite) TestOpenEnvelopeWithAsymKey() {
|
||||||
// Setup the server with an asymetric key
|
// Setup the server with an asymetric key
|
||||||
config := *s.config
|
config := *s.config
|
||||||
s.NoError(config.ReadMailServerAsymKeyFile())
|
config.MailServerPassword = "" // clear password field
|
||||||
s.NoError(s.server.Init(s.shh, &config))
|
s.NoError(s.server.Init(s.shh, &config))
|
||||||
|
|
||||||
// Prepare a valid envelope
|
// Prepare a valid envelope
|
||||||
|
@ -256,10 +250,10 @@ func (s *MailserverSuite) TestOpenEnvelopeWithAsymKey() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MailserverSuite) TestArchive() {
|
func (s *MailserverSuite) TestArchive() {
|
||||||
err := s.config.ReadMailServerPasswordFile()
|
config := *s.config
|
||||||
s.Require().NoError(err)
|
config.MailServerAsymKey = "" // clear asym key
|
||||||
|
|
||||||
err = s.server.Init(s.shh, s.config)
|
err := s.server.Init(s.shh, &config)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
defer s.server.Close()
|
defer s.server.Close()
|
||||||
|
|
||||||
|
|
120
node/node.go
120
node/node.go
|
@ -27,24 +27,26 @@ import (
|
||||||
"github.com/status-im/status-go/services/personal"
|
"github.com/status-im/status-go/services/personal"
|
||||||
"github.com/status-im/status-go/services/shhext"
|
"github.com/status-im/status-go/services/shhext"
|
||||||
"github.com/status-im/status-go/services/status"
|
"github.com/status-im/status-go/services/status"
|
||||||
|
"github.com/status-im/status-go/static"
|
||||||
"github.com/status-im/status-go/timesource"
|
"github.com/status-im/status-go/timesource"
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Errors related to node and services creation.
|
// Errors related to node and services creation.
|
||||||
var (
|
var (
|
||||||
ErrNodeMakeFailureFormat = "error creating p2p node: %s"
|
ErrNodeMakeFailureFormat = "error creating p2p node: %s"
|
||||||
ErrWhisperServiceRegistrationFailure = errors.New("failed to register the Whisper service")
|
ErrWhisperServiceRegistrationFailure = errors.New("failed to register the Whisper service")
|
||||||
ErrLightEthRegistrationFailure = errors.New("failed to register the LES service")
|
ErrLightEthRegistrationFailure = errors.New("failed to register the LES service")
|
||||||
ErrPersonalServiceRegistrationFailure = errors.New("failed to register the personal api service")
|
ErrLightEthRegistrationFailureUpstreamEnabled = errors.New("failed to register the LES service, upstream is also configured")
|
||||||
ErrStatusServiceRegistrationFailure = errors.New("failed to register the Status service")
|
ErrPersonalServiceRegistrationFailure = errors.New("failed to register the personal api service")
|
||||||
ErrPeerServiceRegistrationFailure = errors.New("failed to register the Peer service")
|
ErrStatusServiceRegistrationFailure = errors.New("failed to register the Status service")
|
||||||
|
ErrPeerServiceRegistrationFailure = errors.New("failed to register the Peer service")
|
||||||
)
|
)
|
||||||
|
|
||||||
// All general log messages in this package should be routed through this logger.
|
// All general log messages in this package should be routed through this logger.
|
||||||
var logger = log.New("package", "status-go/node")
|
var logger = log.New("package", "status-go/node")
|
||||||
|
|
||||||
// MakeNode create a geth node entity
|
// MakeNode creates a geth node entity
|
||||||
func MakeNode(config *params.NodeConfig, db *leveldb.DB) (*node.Node, error) {
|
func MakeNode(config *params.NodeConfig, db *leveldb.DB) (*node.Node, error) {
|
||||||
// If DataDir is empty, it means we want to create an ephemeral node
|
// If DataDir is empty, it means we want to create an ephemeral node
|
||||||
// keeping data only in memory.
|
// keeping data only in memory.
|
||||||
|
@ -60,17 +62,9 @@ func MakeNode(config *params.NodeConfig, db *leveldb.DB) (*node.Node, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stackConfig := defaultEmbeddedNodeConfig(config)
|
stackConfig, err := newGethNodeConfig(config)
|
||||||
|
if err != nil {
|
||||||
if len(config.NodeKeyFile) > 0 {
|
return nil, err
|
||||||
logger.Info("Loading private key file", "file", config.NodeKeyFile)
|
|
||||||
pk, err := crypto.LoadECDSA(config.NodeKeyFile)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Failed loading private key file", "file", config.NodeKeyFile, "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// override node's private key
|
|
||||||
stackConfig.P2P.PrivateKey = pk
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stack, err := node.New(stackConfig)
|
stack, err := node.New(stackConfig)
|
||||||
|
@ -84,6 +78,10 @@ func MakeNode(config *params.NodeConfig, db *leveldb.DB) (*node.Node, error) {
|
||||||
return nil, fmt.Errorf("%v: %v", ErrLightEthRegistrationFailure, err)
|
return nil, fmt.Errorf("%v: %v", ErrLightEthRegistrationFailure, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if config.LightEthConfig.Enabled {
|
||||||
|
return nil, fmt.Errorf("%v: %v", ErrLightEthRegistrationFailureUpstreamEnabled, err)
|
||||||
|
}
|
||||||
|
|
||||||
// `personal_sign` and `personal_ecRecover` methods are important to
|
// `personal_sign` and `personal_ecRecover` methods are important to
|
||||||
// keep DApps working.
|
// keep DApps working.
|
||||||
// Usually, they are provided by an ETH or a LES service, but when using
|
// Usually, they are provided by an ETH or a LES service, but when using
|
||||||
|
@ -112,8 +110,8 @@ func MakeNode(config *params.NodeConfig, db *leveldb.DB) (*node.Node, error) {
|
||||||
return stack, nil
|
return stack, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultEmbeddedNodeConfig returns default stack configuration for mobile client node
|
// newGethNodeConfig returns default stack configuration for mobile client node
|
||||||
func defaultEmbeddedNodeConfig(config *params.NodeConfig) *node.Config {
|
func newGethNodeConfig(config *params.NodeConfig) (*node.Config, error) {
|
||||||
nc := &node.Config{
|
nc := &node.Config{
|
||||||
DataDir: config.DataDir,
|
DataDir: config.DataDir,
|
||||||
KeyStoreDir: config.KeyStoreDir,
|
KeyStoreDir: config.KeyStoreDir,
|
||||||
|
@ -139,26 +137,71 @@ func defaultEmbeddedNodeConfig(config *params.NodeConfig) *node.Config {
|
||||||
nc.HTTPPort = config.HTTPPort
|
nc.HTTPPort = config.HTTPPort
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.ClusterConfig != nil && config.ClusterConfig.Enabled {
|
if config.ClusterConfig.Enabled {
|
||||||
nc.P2P.BootstrapNodesV5 = parseNodesV5(config.ClusterConfig.BootNodes)
|
nc.P2P.BootstrapNodesV5 = parseNodesV5(config.ClusterConfig.BootNodes)
|
||||||
nc.P2P.StaticNodes = parseNodes(config.ClusterConfig.StaticNodes)
|
nc.P2P.StaticNodes = parseNodes(config.ClusterConfig.StaticNodes)
|
||||||
}
|
}
|
||||||
return nc
|
|
||||||
|
if config.NodeKey != "" {
|
||||||
|
sk, err := crypto.HexToECDSA(config.NodeKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// override node's private key
|
||||||
|
nc.P2P.PrivateKey = sk
|
||||||
|
}
|
||||||
|
|
||||||
|
return nc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculateGenesis retrieves genesis value for given network
|
||||||
|
func calculateGenesis(networkID uint64) (*core.Genesis, error) {
|
||||||
|
var genesis *core.Genesis
|
||||||
|
|
||||||
|
switch networkID {
|
||||||
|
case params.MainNetworkID:
|
||||||
|
genesis = core.DefaultGenesisBlock()
|
||||||
|
case params.RopstenNetworkID:
|
||||||
|
genesis = core.DefaultTestnetGenesisBlock()
|
||||||
|
case params.RinkebyNetworkID:
|
||||||
|
genesis = core.DefaultRinkebyGenesisBlock()
|
||||||
|
case params.StatusChainNetworkID:
|
||||||
|
var err error
|
||||||
|
if genesis, err = defaultStatusChainGenesisBlock(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return genesis, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultStatusChainGenesisBlock returns the StatusChain network genesis block.
|
||||||
|
func defaultStatusChainGenesisBlock() (*core.Genesis, error) {
|
||||||
|
genesisJSON, err := static.ConfigStatusChainGenesisJsonBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("status-chain-genesis.json could not be loaded: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var genesis *core.Genesis
|
||||||
|
err = json.Unmarshal(genesisJSON, &genesis)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot unmarshal status-chain-genesis.json: %s", err)
|
||||||
|
}
|
||||||
|
return genesis, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// activateLightEthService configures and registers the eth.Ethereum service with a given node.
|
// activateLightEthService configures and registers the eth.Ethereum service with a given node.
|
||||||
func activateLightEthService(stack *node.Node, config *params.NodeConfig) error {
|
func activateLightEthService(stack *node.Node, config *params.NodeConfig) error {
|
||||||
if config.LightEthConfig == nil || !config.LightEthConfig.Enabled {
|
if !config.LightEthConfig.Enabled {
|
||||||
logger.Info("LES protocol is disabled")
|
logger.Info("LES protocol is disabled")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var genesis *core.Genesis
|
genesis, err := calculateGenesis(config.NetworkID)
|
||||||
if config.LightEthConfig.Genesis != "" {
|
if err != nil {
|
||||||
genesis = new(core.Genesis)
|
return err
|
||||||
if err := json.Unmarshal([]byte(config.LightEthConfig.Genesis), genesis); err != nil {
|
|
||||||
return fmt.Errorf("invalid genesis spec: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ethConf := eth.DefaultConfig
|
ethConf := eth.DefaultConfig
|
||||||
|
@ -202,21 +245,6 @@ func activatePeerService(stack *node.Node) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerMailServer(whisperService *whisper.Whisper, config *params.WhisperConfig) (err error) {
|
func registerMailServer(whisperService *whisper.Whisper, config *params.WhisperConfig) (err error) {
|
||||||
// if the Password is already set, do not override it
|
|
||||||
if config.MailServerPassword == "" && config.MailServerPasswordFile != "" {
|
|
||||||
err = config.ReadMailServerPasswordFile()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// similarly, do not override already configured AsymKey
|
|
||||||
if config.MailServerAsymKey == nil && config.MailServerAsymKeyFile != "" {
|
|
||||||
err = config.ReadMailServerAsymKeyFile()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var mailServer mailserver.WMailServer
|
var mailServer mailserver.WMailServer
|
||||||
whisperService.RegisterServer(&mailServer)
|
whisperService.RegisterServer(&mailServer)
|
||||||
|
|
||||||
|
@ -225,7 +253,7 @@ func registerMailServer(whisperService *whisper.Whisper, config *params.WhisperC
|
||||||
|
|
||||||
// activateShhService configures Whisper and adds it to the given node.
|
// activateShhService configures Whisper and adds it to the given node.
|
||||||
func activateShhService(stack *node.Node, config *params.NodeConfig, db *leveldb.DB) (err error) {
|
func activateShhService(stack *node.Node, config *params.NodeConfig, db *leveldb.DB) (err error) {
|
||||||
if config.WhisperConfig == nil || !config.WhisperConfig.Enabled {
|
if !config.WhisperConfig.Enabled {
|
||||||
logger.Info("SHH protocol is disabled")
|
logger.Info("SHH protocol is disabled")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -254,7 +282,7 @@ func activateShhService(stack *node.Node, config *params.NodeConfig, db *leveldb
|
||||||
|
|
||||||
// enable mail service
|
// enable mail service
|
||||||
if config.WhisperConfig.EnableMailServer {
|
if config.WhisperConfig.EnableMailServer {
|
||||||
if err := registerMailServer(whisperService, config.WhisperConfig); err != nil {
|
if err := registerMailServer(whisperService, &config.WhisperConfig); err != nil {
|
||||||
return nil, fmt.Errorf("failed to register MailServer: %v", err)
|
return nil, fmt.Errorf("failed to register MailServer: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
func TestWhisperLightModeEnabledSetsEmptyBloomFilter(t *testing.T) {
|
func TestWhisperLightModeEnabledSetsEmptyBloomFilter(t *testing.T) {
|
||||||
config := params.NodeConfig{
|
config := params.NodeConfig{
|
||||||
WhisperConfig: ¶ms.WhisperConfig{
|
WhisperConfig: params.WhisperConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
LightClient: true,
|
LightClient: true,
|
||||||
},
|
},
|
||||||
|
@ -33,7 +33,7 @@ func TestWhisperLightModeEnabledSetsEmptyBloomFilter(t *testing.T) {
|
||||||
|
|
||||||
func TestWhisperLightModeEnabledSetsNilBloomFilter(t *testing.T) {
|
func TestWhisperLightModeEnabledSetsNilBloomFilter(t *testing.T) {
|
||||||
config := params.NodeConfig{
|
config := params.NodeConfig{
|
||||||
WhisperConfig: ¶ms.WhisperConfig{
|
WhisperConfig: params.WhisperConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
LightClient: false,
|
LightClient: false,
|
||||||
},
|
},
|
||||||
|
|
|
@ -117,17 +117,18 @@ func (n *StatusNode) startWithDB(config *params.NodeConfig, db *leveldb.DB, serv
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start starts current StatusNode, will fail if it's already started.
|
// Start starts current StatusNode, failing if it's already started.
|
||||||
func (n *StatusNode) Start(config *params.NodeConfig, services ...node.ServiceConstructor) error {
|
func (n *StatusNode) Start(config *params.NodeConfig, services ...node.ServiceConstructor) error {
|
||||||
n.mu.Lock()
|
n.mu.Lock()
|
||||||
defer n.mu.Unlock()
|
defer n.mu.Unlock()
|
||||||
|
|
||||||
n.log.Debug("starting with NodeConfig", "ClusterConfig", config.ClusterConfig)
|
|
||||||
|
|
||||||
if n.isRunning() {
|
if n.isRunning() {
|
||||||
|
n.log.Debug("cannot start, node already running")
|
||||||
return ErrNodeRunning
|
return ErrNodeRunning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n.log.Debug("starting with NodeConfig", "ClusterConfig", config.ClusterConfig)
|
||||||
|
|
||||||
db, err := db.Create(config.DataDir, params.StatusDatabase)
|
db, err := db.Create(config.DataDir, params.StatusDatabase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -186,7 +187,7 @@ func (n *StatusNode) setupRPCClient() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *StatusNode) discoveryEnabled() bool {
|
func (n *StatusNode) discoveryEnabled() bool {
|
||||||
return n.config != nil && (!n.config.NoDiscovery || n.config.Rendezvous) && n.config.ClusterConfig != nil
|
return n.config != nil && (!n.config.NoDiscovery || n.config.Rendezvous) && n.config.ClusterConfig.Enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *StatusNode) discoverNode() *discover.Node {
|
func (n *StatusNode) discoverNode() *discover.Node {
|
||||||
|
@ -355,7 +356,7 @@ func (n *StatusNode) isRunning() bool {
|
||||||
|
|
||||||
// populateStaticPeers connects current node with our publicly available LES/SHH/Swarm cluster
|
// populateStaticPeers connects current node with our publicly available LES/SHH/Swarm cluster
|
||||||
func (n *StatusNode) populateStaticPeers() error {
|
func (n *StatusNode) populateStaticPeers() error {
|
||||||
if n.config.ClusterConfig == nil || !n.config.ClusterConfig.Enabled {
|
if !n.config.ClusterConfig.Enabled {
|
||||||
n.log.Info("Static peers are disabled")
|
n.log.Info("Static peers are disabled")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -372,7 +373,7 @@ func (n *StatusNode) populateStaticPeers() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *StatusNode) removeStaticPeers() error {
|
func (n *StatusNode) removeStaticPeers() error {
|
||||||
if n.config.ClusterConfig == nil || !n.config.ClusterConfig.Enabled {
|
if !n.config.ClusterConfig.Enabled {
|
||||||
n.log.Info("Static peers are disabled")
|
n.log.Info("Static peers are disabled")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,13 @@ import (
|
||||||
"github.com/status-im/status-go/discovery"
|
"github.com/status-im/status-go/discovery"
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/t/helpers"
|
"github.com/status-im/status-go/t/helpers"
|
||||||
|
"github.com/status-im/status-go/t/utils"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStatusNodeStart(t *testing.T) {
|
func TestStatusNodeStart(t *testing.T) {
|
||||||
var err error
|
config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
|
||||||
|
require.NoError(t, err)
|
||||||
config := params.NodeConfig{}
|
|
||||||
n := New()
|
n := New()
|
||||||
|
|
||||||
// checks before node is started
|
// checks before node is started
|
||||||
|
@ -39,7 +39,7 @@ func TestStatusNodeStart(t *testing.T) {
|
||||||
require.EqualError(t, err, ErrNoGethNode.Error())
|
require.EqualError(t, err, ErrNoGethNode.Error())
|
||||||
|
|
||||||
// start node
|
// start node
|
||||||
require.NoError(t, n.Start(&config))
|
require.NoError(t, n.Start(config))
|
||||||
|
|
||||||
// checks after node is started
|
// checks after node is started
|
||||||
require.True(t, n.IsRunning())
|
require.True(t, n.IsRunning())
|
||||||
|
@ -54,7 +54,7 @@ func TestStatusNodeStart(t *testing.T) {
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.NotNil(t, keyStore)
|
require.NotNil(t, keyStore)
|
||||||
// try to start already started node
|
// try to start already started node
|
||||||
require.EqualError(t, n.Start(&config), ErrNodeRunning.Error())
|
require.EqualError(t, n.Start(config), ErrNodeRunning.Error())
|
||||||
|
|
||||||
// stop node
|
// stop node
|
||||||
require.NoError(t, n.Stop())
|
require.NoError(t, n.Stop())
|
||||||
|
@ -97,10 +97,10 @@ func TestStatusNodeWithDataDir(t *testing.T) {
|
||||||
|
|
||||||
func TestStatusNodeServiceGetters(t *testing.T) {
|
func TestStatusNodeServiceGetters(t *testing.T) {
|
||||||
config := params.NodeConfig{
|
config := params.NodeConfig{
|
||||||
WhisperConfig: ¶ms.WhisperConfig{
|
WhisperConfig: params.WhisperConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
},
|
},
|
||||||
LightEthConfig: ¶ms.LightEthConfig{
|
LightEthConfig: params.LightEthConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ func TestStatusNodeReconnectStaticPeers(t *testing.T) {
|
||||||
// start status node
|
// start status node
|
||||||
config := params.NodeConfig{
|
config := params.NodeConfig{
|
||||||
MaxPeers: math.MaxInt32,
|
MaxPeers: math.MaxInt32,
|
||||||
ClusterConfig: ¶ms.ClusterConfig{
|
ClusterConfig: params.ClusterConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
StaticNodes: []string{peerURL},
|
StaticNodes: []string{peerURL},
|
||||||
},
|
},
|
||||||
|
@ -272,7 +272,7 @@ func TestStatusNodeRendezvousDiscovery(t *testing.T) {
|
||||||
config := params.NodeConfig{
|
config := params.NodeConfig{
|
||||||
Rendezvous: true,
|
Rendezvous: true,
|
||||||
NoDiscovery: true,
|
NoDiscovery: true,
|
||||||
ClusterConfig: ¶ms.ClusterConfig{
|
ClusterConfig: params.ClusterConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
// not necessarily with id, just valid multiaddr
|
// not necessarily with id, just valid multiaddr
|
||||||
RendezvousNodes: []string{"/ip4/127.0.0.1/tcp/34012", "/ip4/127.0.0.1/tcp/34011"},
|
RendezvousNodes: []string{"/ip4/127.0.0.1/tcp/34012", "/ip4/127.0.0.1/tcp/34011"},
|
||||||
|
|
|
@ -14,62 +14,3 @@ type Cluster struct {
|
||||||
MailServers []string `json:"mailservers"` // list of trusted mail servers
|
MailServers []string `json:"mailservers"` // list of trusted mail servers
|
||||||
RendezvousNodes []string `json:"rendezvousnodes"`
|
RendezvousNodes []string `json:"rendezvousnodes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consult this list with http://fleets.status.im/.
|
|
||||||
var clusters = map[string]func() Cluster{
|
|
||||||
FleetStaging: func() Cluster {
|
|
||||||
return Cluster{
|
|
||||||
BootNodes: []string{
|
|
||||||
"enode://10a78c17929a7019ef4aa2249d7302f76ae8a06f40b2dc88b7b31ebff4a623fbb44b4a627acba296c1ced3775d91fbe18463c15097a6a36fdb2c804ff3fc5b35@35.238.97.234:30404", // boot-01.gc-us-central1-a.eth.staging
|
|
||||||
"enode://f79fb3919f72ca560ad0434dcc387abfe41e0666201ebdada8ede0462454a13deb05cda15f287d2c4bd85da81f0eb25d0a486bbbc8df427b971ac51533bd00fe@174.138.107.239:30404", // boot-01.do-ams3.eth.staging
|
|
||||||
},
|
|
||||||
StaticNodes: []string{
|
|
||||||
"enode://914c0b30f27bab30c1dfd31dad7652a46fda9370542aee1b062498b1345ee0913614b8b9e3e84622e84a7203c5858ae1d9819f63aece13ee668e4f6668063989@167.99.19.148:30305", // node-01.do-ams3.eth.staging
|
|
||||||
"enode://2d897c6e846949f9dcf10279f00e9b8325c18fe7fa52d658520ad7be9607c83008b42b06aefd97cfe1fdab571f33a2a9383ff97c5909ed51f63300834913237e@35.192.0.86:30305", // "node-01.gc-us-central1-a.eth.staging"
|
|
||||||
},
|
|
||||||
MailServers: []string{
|
|
||||||
"enode://69f72baa7f1722d111a8c9c68c39a31430e9d567695f6108f31ccb6cd8f0adff4991e7fdca8fa770e75bc8a511a87d24690cbc80e008175f40c157d6f6788d48@206.189.240.16:30504", // mail-01.do-ams3.eth.staging
|
|
||||||
"enode://e4fc10c1f65c8aed83ac26bc1bfb21a45cc1a8550a58077c8d2de2a0e0cd18e40fd40f7e6f7d02dc6cd06982b014ce88d6e468725ffe2c138e958788d0002a7f@35.239.193.41:30504", // mail-01.gc-us-central1-a.eth.staging
|
|
||||||
},
|
|
||||||
RendezvousNodes: []string{
|
|
||||||
"/ip4/174.138.107.239/tcp/30703/ethv4/16Uiu2HAkyJHeetQ4DNpd4NZ2ntzxMo25zcdpvGQRqkD5pB9BE6RU",
|
|
||||||
"/ip4/35.238.97.234/tcp/30703/ethv4/16Uiu2HAm1sVyXmkMNjdeDWqK2urbyC3oBHi8MDpCdYkns1nYafqz",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
FleetBeta: func() Cluster {
|
|
||||||
return Cluster{
|
|
||||||
BootNodes: []string{
|
|
||||||
"enode://436cc6f674928fdc9a9f7990f2944002b685d1c37f025c1be425185b5b1f0900feaf1ccc2a6130268f9901be4a7d252f37302c8335a2c1a62736e9232691cc3a@174.138.105.243:30404", // boot-01.do-ams3.eth.beta
|
|
||||||
"enode://5395aab7833f1ecb671b59bf0521cf20224fe8162fc3d2675de4ee4d5636a75ec32d13268fc184df8d1ddfa803943906882da62a4df42d4fccf6d17808156a87@206.189.243.57:30404", // boot-02.do-ams3.eth.beta
|
|
||||||
"enode://7427dfe38bd4cf7c58bb96417806fab25782ec3e6046a8053370022cbaa281536e8d64ecd1b02e1f8f72768e295d06258ba43d88304db068e6f2417ae8bcb9a6@104.154.88.123:30404", // boot-01.gc-us-central1-a.eth.beta
|
|
||||||
"enode://ebefab39b69bbbe64d8cd86be765b3be356d8c4b24660f65d493143a0c44f38c85a257300178f7845592a1b0332811542e9a58281c835babdd7535babb64efc1@35.202.99.224:30404", // boot-02.gc-us-central1-a.eth.beta
|
|
||||||
},
|
|
||||||
StaticNodes: []string{
|
|
||||||
"enode://a6a2a9b3a7cbb0a15da74301537ebba549c990e3325ae78e1272a19a3ace150d03c184b8ac86cc33f1f2f63691e467d49308f02d613277754c4dccd6773b95e8@206.189.243.176:30304", // node-01.do-ams3.eth.beta
|
|
||||||
"enode://207e53d9bf66be7441e3daba36f53bfbda0b6099dba9a865afc6260a2d253fb8a56a72a48598a4f7ba271792c2e4a8e1a43aaef7f34857f520c8c820f63b44c8@35.224.15.65:30304", // node-01.gc-us-central1-a.eth.beta
|
|
||||||
},
|
|
||||||
MailServers: []string{
|
|
||||||
"enode://c42f368a23fa98ee546fd247220759062323249ef657d26d357a777443aec04db1b29a3a22ef3e7c548e18493ddaf51a31b0aed6079bd6ebe5ae838fcfaf3a49@206.189.243.162:30504", // mail-01.do-ams3.eth.beta
|
|
||||||
"enode://7aa648d6e855950b2e3d3bf220c496e0cae4adfddef3e1e6062e6b177aec93bc6cdcf1282cb40d1656932ebfdd565729da440368d7c4da7dbd4d004b1ac02bf8@206.189.243.169:30504", // mail-02.do-ams3.eth.beta
|
|
||||||
"enode://8a64b3c349a2e0ef4a32ea49609ed6eb3364be1110253c20adc17a3cebbc39a219e5d3e13b151c0eee5d8e0f9a8ba2cd026014e67b41a4ab7d1d5dd67ca27427@206.189.243.168:30504", // mail-03.do-ams3.eth.beta
|
|
||||||
"enode://7de99e4cb1b3523bd26ca212369540646607c721ad4f3e5c821ed9148150ce6ce2e72631723002210fac1fd52dfa8bbdf3555e05379af79515e1179da37cc3db@35.188.19.210:30504", // mail-01.gc-us-central1-a.eth.beta
|
|
||||||
"enode://015e22f6cd2b44c8a51bd7a23555e271e0759c7d7f52432719665a74966f2da456d28e154e836bee6092b4d686fe67e331655586c57b718be3997c1629d24167@35.226.21.19:30504", // mail-02.gc-us-central1-a.eth.beta
|
|
||||||
"enode://531e252ec966b7e83f5538c19bf1cde7381cc7949026a6e499b6e998e695751aadf26d4c98d5a4eabfb7cefd31c3c88d600a775f14ed5781520a88ecd25da3c6@35.225.227.79:30504", // mail-03.gc-us-central1-a.eth.beta
|
|
||||||
},
|
|
||||||
RendezvousNodes: []string{
|
|
||||||
"/ip4/174.138.105.243/tcp/30703/ethv4/16Uiu2HAmRHPzF3rQg55PgYPcQkyvPVH9n2hWsYPhUJBZ6kVjJgdV", // boot-01.do-ams3.eth.beta
|
|
||||||
"/ip4/206.189.243.57/tcp/30703/ethv4/16Uiu2HAmLqTXuY4Sb6G28HNooaFUXUKzpzKXCcgyJxgaEE2i5vnf", // boot-02.do-ams3.eth.beta
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClusterForFleet returns a cluster for a given fleet.
|
|
||||||
func ClusterForFleet(fleet string) (Cluster, bool) {
|
|
||||||
cluster, ok := clusters[fleet]
|
|
||||||
if ok {
|
|
||||||
return cluster(), true
|
|
||||||
}
|
|
||||||
return Cluster{}, false
|
|
||||||
}
|
|
||||||
|
|
605
params/config.go
605
params/config.go
|
@ -1,34 +1,23 @@
|
||||||
package params
|
package params
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
"github.com/status-im/status-go/static"
|
||||||
|
validator "gopkg.in/go-playground/validator.v9"
|
||||||
// errors
|
|
||||||
var (
|
|
||||||
ErrMissingDataDir = errors.New("missing required 'DataDir' parameter")
|
|
||||||
ErrMissingNetworkID = errors.New("missing required 'NetworkID' parameter")
|
|
||||||
ErrEmptyPasswordFile = errors.New("password file cannot be empty")
|
|
||||||
ErrNoPasswordFileValueSet = errors.New("password file path not set")
|
|
||||||
ErrEmptyAuthorizationKeyFile = errors.New("authorization key file cannot be empty")
|
|
||||||
ErrAuthorizationKeyFileNotSet = errors.New("authorization key file is not set")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
|
@ -41,46 +30,10 @@ type LightEthConfig struct {
|
||||||
// Enabled flag specifies whether protocol is enabled
|
// Enabled flag specifies whether protocol is enabled
|
||||||
Enabled bool
|
Enabled bool
|
||||||
|
|
||||||
// Genesis is JSON to seed the chain database with
|
|
||||||
Genesis string
|
|
||||||
|
|
||||||
// DatabaseCache is memory (in MBs) allocated to internal caching (min 16MB / database forced)
|
// DatabaseCache is memory (in MBs) allocated to internal caching (min 16MB / database forced)
|
||||||
DatabaseCache int
|
DatabaseCache int
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------
|
|
||||||
// FirebaseConfig
|
|
||||||
// ----------
|
|
||||||
|
|
||||||
// FirebaseConfig holds FCM-related configuration
|
|
||||||
type FirebaseConfig struct {
|
|
||||||
// AuthorizationKeyFile file path that contains FCM authorization key
|
|
||||||
AuthorizationKeyFile string
|
|
||||||
|
|
||||||
// NotificationTriggerURL URL used to send push notification requests to
|
|
||||||
NotificationTriggerURL string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadAuthorizationKeyFile reads and loads FCM authorization key
|
|
||||||
func (c *FirebaseConfig) ReadAuthorizationKeyFile() ([]byte, error) {
|
|
||||||
if len(c.AuthorizationKeyFile) == 0 {
|
|
||||||
return nil, ErrAuthorizationKeyFileNotSet
|
|
||||||
}
|
|
||||||
|
|
||||||
key, err := ioutil.ReadFile(c.AuthorizationKeyFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
key = bytes.TrimRight(key, "\n")
|
|
||||||
|
|
||||||
if len(key) == 0 {
|
|
||||||
return nil, ErrEmptyAuthorizationKeyFile
|
|
||||||
}
|
|
||||||
|
|
||||||
return key, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// WhisperConfig
|
// WhisperConfig
|
||||||
// ----------
|
// ----------
|
||||||
|
@ -103,18 +56,12 @@ type WhisperConfig struct {
|
||||||
// MinimumPoW minimum PoW for Whisper messages
|
// MinimumPoW minimum PoW for Whisper messages
|
||||||
MinimumPoW float64
|
MinimumPoW float64
|
||||||
|
|
||||||
// MailServerPasswordFile contains a password for symmetric encryption with MailServer.
|
|
||||||
MailServerPasswordFile string
|
|
||||||
|
|
||||||
// MailServerPassword for symmetric encryption with MailServer.
|
// MailServerPassword for symmetric encryption with MailServer.
|
||||||
// (if no account file selected, then this password is used for symmetric encryption).
|
// (if no account file selected, then this password is used for symmetric encryption).
|
||||||
MailServerPassword string
|
MailServerPassword string
|
||||||
|
|
||||||
// MailServerAsymKeyFile is a file with an asymmetric key to decrypt messages sent to MailServer.
|
// MailServerAsymKey is an hex-encoded asymmetric key to decrypt messages sent to MailServer.
|
||||||
MailServerAsymKeyFile string
|
MailServerAsymKey string
|
||||||
|
|
||||||
// MailServerAsymKey is an asymmetric key to decrypt messages sent to MailServer.
|
|
||||||
MailServerAsymKey *ecdsa.PrivateKey
|
|
||||||
|
|
||||||
// RateLimit minimum time between queries to mail server per peer
|
// RateLimit minimum time between queries to mail server per peer
|
||||||
MailServerRateLimit int
|
MailServerRateLimit int
|
||||||
|
@ -125,40 +72,10 @@ type WhisperConfig struct {
|
||||||
// TTL time to live for messages, in seconds
|
// TTL time to live for messages, in seconds
|
||||||
TTL int
|
TTL int
|
||||||
|
|
||||||
// FirebaseConfig extra configuration for Firebase Cloud Messaging
|
|
||||||
FirebaseConfig *FirebaseConfig `json:"FirebaseConfig,"`
|
|
||||||
|
|
||||||
// EnableNTPSync enables NTP synchronizations
|
// EnableNTPSync enables NTP synchronizations
|
||||||
EnableNTPSync bool
|
EnableNTPSync bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadMailServerPasswordFile reads and returns content of the password file
|
|
||||||
func (c *WhisperConfig) ReadMailServerPasswordFile() error {
|
|
||||||
if len(c.MailServerPasswordFile) == 0 {
|
|
||||||
return ErrNoPasswordFileValueSet
|
|
||||||
}
|
|
||||||
|
|
||||||
password, err := ioutil.ReadFile(c.MailServerPasswordFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
password = bytes.TrimRight(password, "\n")
|
|
||||||
|
|
||||||
if len(password) == 0 {
|
|
||||||
return ErrEmptyPasswordFile
|
|
||||||
}
|
|
||||||
|
|
||||||
c.MailServerPassword = string(password)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadMailServerAsymKeyFile reads and returns a private key from a given file.
|
|
||||||
func (c *WhisperConfig) ReadMailServerAsymKeyFile() (err error) {
|
|
||||||
c.MailServerAsymKey, err = crypto.LoadECDSA(c.MailServerAsymKeyFile)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// String dumps config object as nicely indented JSON
|
// String dumps config object as nicely indented JSON
|
||||||
func (c *WhisperConfig) String() string {
|
func (c *WhisperConfig) String() string {
|
||||||
data, _ := json.MarshalIndent(c, "", " ") // nolint: gas
|
data, _ := json.MarshalIndent(c, "", " ") // nolint: gas
|
||||||
|
@ -195,17 +112,16 @@ type ClusterConfig struct {
|
||||||
// Fleet is a type of selected fleet.
|
// Fleet is a type of selected fleet.
|
||||||
Fleet string
|
Fleet string
|
||||||
|
|
||||||
// StaticNodes lists the static nodes taken from compiled or passed cluster.json
|
// StaticNodes is a list of static nodes for this fleet.
|
||||||
StaticNodes []string
|
StaticNodes []string
|
||||||
|
|
||||||
// BootNodes list of cluster peer nodes for a given network (Mainnet, Ropsten, Rinkeby, Homestead),
|
// BootNodes is a list of cluster peer nodes for this fleet.
|
||||||
// for a given mode (production vs development)
|
|
||||||
BootNodes []string
|
BootNodes []string
|
||||||
|
|
||||||
// TrustedMailServers is a list of verified Mail Servers.
|
// TrustedMailServers is a list of verified Mail Servers for this fleet.
|
||||||
TrustedMailServers []string
|
TrustedMailServers []string
|
||||||
|
|
||||||
// RendezvousNodes is a rendezvous discovery server.
|
// RendezvousNodes is a list rendezvous discovery nodes.
|
||||||
RendezvousNodes []string
|
RendezvousNodes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,13 +171,11 @@ type NodeConfig struct {
|
||||||
DataDir string `validate:"required"`
|
DataDir string `validate:"required"`
|
||||||
|
|
||||||
// KeyStoreDir is the file system folder that contains private keys.
|
// KeyStoreDir is the file system folder that contains private keys.
|
||||||
// If KeyStoreDir is empty, the default location is the "keystore" subdirectory of DataDir.
|
KeyStoreDir string `validate:"required"`
|
||||||
KeyStoreDir string
|
|
||||||
|
|
||||||
// NodeKeyFile is a filename with node ID (private key)
|
// NodeKey is the hex-encoded node ID (private key). Should be a valid secp256k1 private key that will be used for both
|
||||||
// This file should contain a valid secp256k1 private key that will be used for both
|
|
||||||
// remote peer identification as well as network traffic encryption.
|
// remote peer identification as well as network traffic encryption.
|
||||||
NodeKeyFile string
|
NodeKey string
|
||||||
|
|
||||||
// NoDiscovery set to true will disable discovery protocol.
|
// NoDiscovery set to true will disable discovery protocol.
|
||||||
NoDiscovery bool
|
NoDiscovery bool
|
||||||
|
@ -330,21 +244,17 @@ type NodeConfig struct {
|
||||||
// UpstreamConfig extra config for providing upstream infura server.
|
// UpstreamConfig extra config for providing upstream infura server.
|
||||||
UpstreamConfig UpstreamRPCConfig `json:"UpstreamConfig"`
|
UpstreamConfig UpstreamRPCConfig `json:"UpstreamConfig"`
|
||||||
|
|
||||||
// ClusterConfigFile contains the file name of the cluster configuration. If
|
|
||||||
// empty the statical configuration data will be taken.
|
|
||||||
ClusterConfigFile string `json:"ClusterConfigFile"`
|
|
||||||
|
|
||||||
// ClusterConfig extra configuration for supporting cluster peers.
|
// ClusterConfig extra configuration for supporting cluster peers.
|
||||||
ClusterConfig *ClusterConfig `json:"ClusterConfig," validate:"structonly"`
|
ClusterConfig ClusterConfig `json:"ClusterConfig," validate:"structonly"`
|
||||||
|
|
||||||
// LightEthConfig extra configuration for LES
|
// LightEthConfig extra configuration for LES
|
||||||
LightEthConfig *LightEthConfig `json:"LightEthConfig," validate:"structonly"`
|
LightEthConfig LightEthConfig `json:"LightEthConfig," validate:"structonly"`
|
||||||
|
|
||||||
// WhisperConfig extra configuration for SHH
|
// WhisperConfig extra configuration for SHH
|
||||||
WhisperConfig *WhisperConfig `json:"WhisperConfig," validate:"structonly"`
|
WhisperConfig WhisperConfig `json:"WhisperConfig," validate:"structonly"`
|
||||||
|
|
||||||
// SwarmConfig extra configuration for Swarm and ENS
|
// SwarmConfig extra configuration for Swarm and ENS
|
||||||
SwarmConfig *SwarmConfig `json:"SwarmConfig," validate:"structonly"`
|
SwarmConfig SwarmConfig `json:"SwarmConfig," validate:"structonly"`
|
||||||
|
|
||||||
// RegisterTopics a list of specific topics where the peer wants to be
|
// RegisterTopics a list of specific topics where the peer wants to be
|
||||||
// discoverable.
|
// discoverable.
|
||||||
|
@ -364,91 +274,144 @@ type NodeConfig struct {
|
||||||
MailServerRegistryAddress string
|
MailServerRegistryAddress string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNodeConfig creates new node configuration object
|
// NewNodeConfigWithDefaults creates new node configuration object with some defaults suitable for adhoc use
|
||||||
func NewNodeConfig(dataDir, clstrCfgFile, fleet string, networkID uint64) (*NodeConfig, error) {
|
func NewNodeConfigWithDefaults(dataDir, fleet string, networkID uint64) (*NodeConfig, error) {
|
||||||
|
nodeConfig, err := NewNodeConfig(dataDir, fleet, networkID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if dataDir != "" {
|
||||||
|
nodeConfig.KeyStoreDir = path.Join(dataDir, "keystore")
|
||||||
|
nodeConfig.WhisperConfig.DataDir = path.Join(dataDir, "wnode")
|
||||||
|
}
|
||||||
|
|
||||||
|
if fleet != FleetUndefined {
|
||||||
|
statusConfigJSON, err := static.Asset(fmt.Sprintf("../config/cli/fleet-%s.json", fleet))
|
||||||
|
if err == nil {
|
||||||
|
err = LoadConfigFromJSON(string(statusConfigJSON), nodeConfig)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("default config could not be loaded: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeConfig.HTTPHost = ""
|
||||||
|
nodeConfig.ListenAddr = ":30303"
|
||||||
|
nodeConfig.LogEnabled = true
|
||||||
|
nodeConfig.LogLevel = "INFO"
|
||||||
|
nodeConfig.LogToStderr = true
|
||||||
|
nodeConfig.WhisperConfig.Enabled = true
|
||||||
|
nodeConfig.WhisperConfig.EnableNTPSync = true
|
||||||
|
|
||||||
|
return nodeConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNodeConfig creates new node configuration object with bare-minimum defaults
|
||||||
|
func NewNodeConfig(dataDir, fleet string, networkID uint64) (*NodeConfig, error) {
|
||||||
nodeConfig := &NodeConfig{
|
nodeConfig := &NodeConfig{
|
||||||
NetworkID: networkID,
|
NetworkID: networkID,
|
||||||
DataDir: dataDir,
|
DataDir: dataDir,
|
||||||
Name: ClientIdentifier,
|
Version: Version,
|
||||||
Version: Version,
|
RPCEnabled: false,
|
||||||
RPCEnabled: RPCEnabledDefault,
|
HTTPHost: "localhost",
|
||||||
HTTPHost: HTTPHost,
|
HTTPPort: 8545,
|
||||||
HTTPPort: HTTPPort,
|
ListenAddr: ":0",
|
||||||
ListenAddr: ListenAddr,
|
APIModules: "eth,net,web3,peer",
|
||||||
APIModules: APIModules,
|
MaxPeers: 25,
|
||||||
MaxPeers: MaxPeers,
|
MaxPendingPeers: 0,
|
||||||
MaxPendingPeers: MaxPendingPeers,
|
IPCFile: "geth.ipc",
|
||||||
IPCFile: IPCFile,
|
log: log.New("package", "status-go/params.NodeConfig"),
|
||||||
log: log.New("package", "status-go/params.NodeConfig"),
|
LogFile: "",
|
||||||
LogFile: LogFile,
|
LogLevel: "ERROR",
|
||||||
LogLevel: LogLevel,
|
UpstreamConfig: UpstreamRPCConfig{
|
||||||
LogToStderr: LogToStderr,
|
URL: getUpstreamURL(networkID),
|
||||||
ClusterConfigFile: clstrCfgFile,
|
},
|
||||||
ClusterConfig: &ClusterConfig{
|
ClusterConfig: ClusterConfig{
|
||||||
Enabled: true, // cluster must be enabled by default
|
Enabled: fleet != FleetUndefined,
|
||||||
Fleet: fleet,
|
Fleet: fleet,
|
||||||
StaticNodes: []string{},
|
StaticNodes: []string{},
|
||||||
BootNodes: []string{},
|
BootNodes: []string{},
|
||||||
},
|
},
|
||||||
LightEthConfig: &LightEthConfig{
|
LightEthConfig: LightEthConfig{
|
||||||
Enabled: true,
|
Enabled: false,
|
||||||
DatabaseCache: DatabaseCache,
|
DatabaseCache: 16,
|
||||||
},
|
},
|
||||||
WhisperConfig: &WhisperConfig{
|
WhisperConfig: WhisperConfig{
|
||||||
Enabled: true,
|
Enabled: false,
|
||||||
MinimumPoW: WhisperMinimumPoW,
|
MinimumPoW: WhisperMinimumPoW,
|
||||||
TTL: WhisperTTL,
|
TTL: WhisperTTL,
|
||||||
FirebaseConfig: &FirebaseConfig{
|
EnableNTPSync: false,
|
||||||
NotificationTriggerURL: FirebaseNotificationTriggerURL,
|
|
||||||
},
|
|
||||||
EnableNTPSync: true,
|
|
||||||
},
|
},
|
||||||
SwarmConfig: &SwarmConfig{},
|
SwarmConfig: SwarmConfig{},
|
||||||
RegisterTopics: []discv5.Topic{},
|
RegisterTopics: []discv5.Topic{},
|
||||||
RequireTopics: map[discv5.Topic]Limits{},
|
RequireTopics: map[discv5.Topic]Limits{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust dependent values
|
return nodeConfig, nil
|
||||||
if err := nodeConfig.updateConfig(); err != nil {
|
}
|
||||||
|
|
||||||
|
// NewConfigFromJSON parses incoming JSON and returned it as Config
|
||||||
|
func NewConfigFromJSON(configJSON string) (*NodeConfig, error) {
|
||||||
|
nodeConfig, err := NewNodeConfig("", FleetUndefined, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := LoadConfigFromJSON(configJSON, nodeConfig); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nodeConfig, nil
|
return nodeConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadNodeConfig parses incoming JSON and returned it as Config
|
// LoadConfigFromJSON parses incoming JSON and returned it as Config
|
||||||
func LoadNodeConfig(configJSON string) (*NodeConfig, error) {
|
func LoadConfigFromJSON(configJSON string, nodeConfig *NodeConfig) error {
|
||||||
nodeConfig, err := loadNodeConfig(configJSON)
|
if err := loadNodeConfig(configJSON, nodeConfig); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := nodeConfig.Validate(); err != nil {
|
if err := nodeConfig.Validate(); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nodeConfig, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadNodeConfig(configJSON string) (*NodeConfig, error) {
|
func loadNodeConfig(configJSON string, nodeConfig *NodeConfig) error {
|
||||||
nodeConfig, err := NewNodeConfig("", "", FleetUndefined, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder := json.NewDecoder(strings.NewReader(configJSON))
|
decoder := json.NewDecoder(strings.NewReader(configJSON))
|
||||||
|
|
||||||
// override default configuration with values by JSON input
|
// override default configuration with values by JSON input
|
||||||
if err := decoder.Decode(&nodeConfig); err != nil {
|
if err := decoder.Decode(&nodeConfig); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// repopulate
|
return nil
|
||||||
if err := nodeConfig.updateConfig(); err != nil {
|
}
|
||||||
return nil, err
|
|
||||||
|
func loadConfigConfigFromFile(path string, config *NodeConfig) error {
|
||||||
|
jsonConfig, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nodeConfig, nil
|
if err = loadNodeConfig(string(jsonConfig), config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadConfigFromFiles reads the configuration files specified in configFilePaths,
|
||||||
|
// merging the values in order in the config argument
|
||||||
|
func LoadConfigFromFiles(configFilePaths []string, config *NodeConfig) error {
|
||||||
|
for _, path := range configFilePaths {
|
||||||
|
if err := loadConfigConfigFromFile(path, config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate checks if NodeConfig fields have valid values.
|
// Validate checks if NodeConfig fields have valid values.
|
||||||
|
@ -473,33 +436,159 @@ func (c *NodeConfig) Validate() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ClusterConfig.Enabled {
|
if c.NodeKey != "" {
|
||||||
if err := validate.Struct(c.ClusterConfig); err != nil {
|
if _, err := crypto.HexToECDSA(c.NodeKey); err != nil {
|
||||||
return err
|
return fmt.Errorf("NodeKey is invalid (%s): %v", c.NodeKey, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.LightEthConfig.Enabled {
|
if c.UpstreamConfig.Enabled && c.LightEthConfig.Enabled {
|
||||||
if err := validate.Struct(c.LightEthConfig); err != nil {
|
return fmt.Errorf("both UpstreamConfig and LightEthConfig are enabled, but they are mutually exclusive")
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.WhisperConfig.Enabled {
|
if err := c.validateChildStructs(validate); err != nil {
|
||||||
if err := validate.Struct(c.WhisperConfig); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.SwarmConfig.Enabled {
|
if !c.NoDiscovery && len(c.ClusterConfig.BootNodes) == 0 {
|
||||||
if err := validate.Struct(c.SwarmConfig); err != nil {
|
// No point in running discovery if we don't have bootnodes.
|
||||||
return err
|
// In case we do have bootnodes, NoDiscovery should be true.
|
||||||
|
return fmt.Errorf("NoDiscovery is false, but ClusterConfig.BootNodes is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.ClusterConfig.RendezvousNodes) == 0 {
|
||||||
|
if c.Rendezvous {
|
||||||
|
return fmt.Errorf("Rendezvous is enabled, but ClusterConfig.RendezvousNodes is empty")
|
||||||
|
}
|
||||||
|
} else if !c.Rendezvous {
|
||||||
|
return fmt.Errorf("Rendezvous is disabled, but ClusterConfig.RendezvousNodes is not empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *NodeConfig) validateChildStructs(validate *validator.Validate) error {
|
||||||
|
// Validate child structs
|
||||||
|
if err := c.UpstreamConfig.Validate(validate); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.ClusterConfig.Validate(validate); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.LightEthConfig.Validate(validate); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.WhisperConfig.Validate(validate); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.SwarmConfig.Validate(validate); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates the UpstreamRPCConfig struct and returns an error if inconsistent values are found
|
||||||
|
func (c *UpstreamRPCConfig) Validate(validate *validator.Validate) error {
|
||||||
|
if !c.Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validate.Struct(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := url.ParseRequestURI(c.URL); err != nil {
|
||||||
|
return fmt.Errorf("UpstreamRPCConfig.URL '%s' is invalid: %v", c.URL, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates the ClusterConfig struct and returns an error if inconsistent values are found
|
||||||
|
func (c *ClusterConfig) Validate(validate *validator.Validate) error {
|
||||||
|
if !c.Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validate.Struct(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Fleet == "" {
|
||||||
|
return fmt.Errorf("ClusterConfig.Fleet is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates the LightEthConfig struct and returns an error if inconsistent values are found
|
||||||
|
func (c *LightEthConfig) Validate(validate *validator.Validate) error {
|
||||||
|
if !c.Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validate.Struct(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates the WhisperConfig struct and returns an error if inconsistent values are found
|
||||||
|
func (c *WhisperConfig) Validate(validate *validator.Validate) error {
|
||||||
|
if !c.Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validate.Struct(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.EnableMailServer {
|
||||||
|
if c.DataDir == "" {
|
||||||
|
return fmt.Errorf("WhisperConfig.DataDir must be specified when WhisperConfig.EnableMailServer is true")
|
||||||
|
}
|
||||||
|
if c.MailServerPassword == "" && c.MailServerAsymKey == "" {
|
||||||
|
return fmt.Errorf("WhisperConfig.MailServerPassword or WhisperConfig.MailServerAsymKey must be specified when WhisperConfig.EnableMailServer is true")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.MailServerAsymKey != "" {
|
||||||
|
if _, err := crypto.HexToECDSA(c.MailServerAsymKey); err != nil {
|
||||||
|
return fmt.Errorf("WhisperConfig.MailServerAsymKey is invalid: %s", c.MailServerAsymKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate validates the SwarmConfig struct and returns an error if inconsistent values are found
|
||||||
|
func (c *SwarmConfig) Validate(validate *validator.Validate) error {
|
||||||
|
if !c.Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validate.Struct(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUpstreamURL(networkID uint64) string {
|
||||||
|
switch networkID {
|
||||||
|
case MainNetworkID:
|
||||||
|
return MainnetEthereumNetworkURL
|
||||||
|
case RopstenNetworkID:
|
||||||
|
return RopstenEthereumNetworkURL
|
||||||
|
case RinkebyNetworkID:
|
||||||
|
return RinkebyEthereumNetworkURL
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// Save dumps configuration to the disk
|
// Save dumps configuration to the disk
|
||||||
func (c *NodeConfig) Save() error {
|
func (c *NodeConfig) Save() error {
|
||||||
data, err := json.MarshalIndent(c, "", " ")
|
data, err := json.MarshalIndent(c, "", " ")
|
||||||
|
@ -520,176 +609,6 @@ func (c *NodeConfig) Save() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateConfig traverses configuration and adjusts dependent fields
|
|
||||||
// (we have a development/production and mobile/full node dependent configurations)
|
|
||||||
func (c *NodeConfig) updateConfig() error {
|
|
||||||
// Update separate configurations.
|
|
||||||
if err := c.updateGenesisConfig(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.updateUpstreamConfig(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.updateClusterConfig(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.updatePeerLimits()
|
|
||||||
return c.updateRelativeDirsConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateGenesisConfig does necessary adjustments to config object (depending on network node will be running on)
|
|
||||||
func (c *NodeConfig) updateGenesisConfig() error {
|
|
||||||
var genesis *core.Genesis
|
|
||||||
|
|
||||||
switch c.NetworkID {
|
|
||||||
case MainNetworkID:
|
|
||||||
genesis = core.DefaultGenesisBlock()
|
|
||||||
case RopstenNetworkID:
|
|
||||||
genesis = core.DefaultTestnetGenesisBlock()
|
|
||||||
case RinkebyNetworkID:
|
|
||||||
genesis = core.DefaultRinkebyGenesisBlock()
|
|
||||||
case StatusChainNetworkID:
|
|
||||||
var err error
|
|
||||||
genesis, err = c.DefaultStatusChainGenesisBlock()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode the genesis into JSON
|
|
||||||
enc, err := json.Marshal(genesis)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.LightEthConfig.Genesis = string(enc)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultStatusChainGenesisBlock returns the StatusChain network genesis block.
|
|
||||||
func (c *NodeConfig) DefaultStatusChainGenesisBlock() (*core.Genesis, error) {
|
|
||||||
genesisJSON, err := ioutil.ReadFile(path.Join(GetStatusHome(), "static/config/status-chain-genesis.json"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("status-chain-genesis.json could not be loaded: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var genesis *core.Genesis
|
|
||||||
err = json.Unmarshal(genesisJSON, &genesis)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("cannot unmarshal status-chain-genesis.json: %s", err)
|
|
||||||
}
|
|
||||||
return genesis, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateUpstreamConfig sets the proper UpstreamConfig.URL for the network id being used.
|
|
||||||
func (c *NodeConfig) updateUpstreamConfig() error {
|
|
||||||
|
|
||||||
// If we have a URL already set then keep URL incase
|
|
||||||
// of custom server.
|
|
||||||
if c.UpstreamConfig.URL != "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch c.NetworkID {
|
|
||||||
case MainNetworkID:
|
|
||||||
c.UpstreamConfig.URL = MainnetEthereumNetworkURL
|
|
||||||
case RopstenNetworkID:
|
|
||||||
c.UpstreamConfig.URL = RopstenEthereumNetworkURL
|
|
||||||
case RinkebyNetworkID:
|
|
||||||
c.UpstreamConfig.URL = RinkebyEthereumNetworkURL
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateClusterConfig loads static peer nodes and CHT for a given network and mode.
|
|
||||||
// This is necessary until we have LES protocol support CHT sync, and better node
|
|
||||||
// discovery on mobile devices)
|
|
||||||
func (c *NodeConfig) updateClusterConfig() error {
|
|
||||||
if !c.ClusterConfig.Enabled {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
c.log.Info("update cluster config", "configFile", c.ClusterConfigFile, "fleet", c.ClusterConfig.Fleet)
|
|
||||||
|
|
||||||
var cluster Cluster
|
|
||||||
|
|
||||||
if c.ClusterConfigFile != "" {
|
|
||||||
// Load cluster configuration from external file.
|
|
||||||
configFile, err := ioutil.ReadFile(c.ClusterConfigFile)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cluster configuration file '%s' could not be loaded: %s", c.ClusterConfigFile, err)
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(configFile, &cluster)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to unmarshal cluster configuration file: %s", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cluster, _ = ClusterForFleet(c.ClusterConfig.Fleet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// allow to override bootnodes only if they were not defined earlier
|
|
||||||
if len(c.ClusterConfig.BootNodes) == 0 {
|
|
||||||
c.ClusterConfig.BootNodes = cluster.BootNodes
|
|
||||||
}
|
|
||||||
// allow to override static nodes only if they were not defined earlier
|
|
||||||
if len(c.ClusterConfig.StaticNodes) == 0 {
|
|
||||||
c.ClusterConfig.StaticNodes = cluster.StaticNodes
|
|
||||||
}
|
|
||||||
// No point in running discovery if we don't have bootnodes.
|
|
||||||
// In a case when we do have bootnodes, NoDiscovery=true is preserved.
|
|
||||||
if len(cluster.BootNodes) == 0 {
|
|
||||||
c.NoDiscovery = true
|
|
||||||
}
|
|
||||||
if len(c.ClusterConfig.RendezvousNodes) == 0 {
|
|
||||||
c.ClusterConfig.RendezvousNodes = cluster.RendezvousNodes
|
|
||||||
}
|
|
||||||
if len(c.ClusterConfig.RendezvousNodes) != 0 {
|
|
||||||
c.Rendezvous = true
|
|
||||||
}
|
|
||||||
c.ClusterConfig.TrustedMailServers = cluster.MailServers
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateRelativeDirsConfig updates directories that should be wrt to DataDir
|
|
||||||
func (c *NodeConfig) updateRelativeDirsConfig() error {
|
|
||||||
makeSubDirPath := func(baseDir, subDir string) string {
|
|
||||||
if len(baseDir) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return filepath.Join(baseDir, subDir)
|
|
||||||
}
|
|
||||||
if len(c.KeyStoreDir) == 0 {
|
|
||||||
c.KeyStoreDir = makeSubDirPath(c.DataDir, KeyStoreDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.WhisperConfig.DataDir) == 0 {
|
|
||||||
c.WhisperConfig.DataDir = makeSubDirPath(c.DataDir, WhisperDataDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// updatePeerLimits will set default peer limits expectations based on enabled services.
|
|
||||||
func (c *NodeConfig) updatePeerLimits() {
|
|
||||||
if c.NoDiscovery && !c.Rendezvous {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.WhisperConfig.Enabled {
|
|
||||||
c.RequireTopics[WhisperDiscv5Topic] = WhisperDiscv5Limits
|
|
||||||
// TODO(dshulyak) register mailserver limits when we will change how they are handled.
|
|
||||||
}
|
|
||||||
if c.LightEthConfig.Enabled {
|
|
||||||
c.RequireTopics[discv5.Topic(LesTopic(int(c.NetworkID)))] = LesDiscoveryLimits
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String dumps config object as nicely indented JSON
|
// String dumps config object as nicely indented JSON
|
||||||
func (c *NodeConfig) String() string {
|
func (c *NodeConfig) String() string {
|
||||||
data, _ := json.MarshalIndent(c, "", " ")
|
data, _ := json.MarshalIndent(c, "", " ")
|
||||||
|
|
|
@ -5,32 +5,82 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gopkg.in/go-playground/validator.v9"
|
"gopkg.in/go-playground/validator.v9"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
gethparams "github.com/ethereum/go-ethereum/params"
|
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
|
"github.com/status-im/status-go/t/utils"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
var clusterConfigData = []byte(`{
|
var clusterConfigData = []byte(`{
|
||||||
"staticnodes": [
|
"ClusterConfig": {
|
||||||
"enode://7ab298cedc4185a894d21d8a4615262ec6bdce66c9b6783878258e0d5b31013d30c9038932432f70e5b2b6a5cd323bf820554fcb22fbc7b45367889522e9c449@10.1.1.1:30303",
|
"staticnodes": [
|
||||||
"enode://f59e8701f18c79c5cbc7618dc7bb928d44dc2f5405c7d693dad97da2d8585975942ec6fd36d3fe608bfdc7270a34a4dd00f38cfe96b2baa24f7cd0ac28d382a1@10.1.1.2:30303"
|
"enode://7ab298cedc4185a894d21d8a4615262ec6bdce66c9b6783878258e0d5b31013d30c9038932432f70e5b2b6a5cd323bf820554fcb22fbc7b45367889522e9c449@10.1.1.1:30303",
|
||||||
]
|
"enode://f59e8701f18c79c5cbc7618dc7bb928d44dc2f5405c7d693dad97da2d8585975942ec6fd36d3fe608bfdc7270a34a4dd00f38cfe96b2baa24f7cd0ac28d382a1@10.1.1.2:30303"
|
||||||
|
]
|
||||||
|
}
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
func TestLoadNodeConfigFromNonExistingFile(t *testing.T) {
|
var clusters = map[string]func() params.Cluster{
|
||||||
_, err := params.LoadNodeConfig(`{
|
params.FleetStaging: func() params.Cluster {
|
||||||
"NetworkId": 3,
|
return params.Cluster{
|
||||||
"DataDir": "/tmp/statusgo",
|
BootNodes: []string{
|
||||||
"ClusterConfigFile": "/file/does/not.exist"
|
"enode://10a78c17929a7019ef4aa2249d7302f76ae8a06f40b2dc88b7b31ebff4a623fbb44b4a627acba296c1ced3775d91fbe18463c15097a6a36fdb2c804ff3fc5b35@35.238.97.234:30404", // boot-01.gc-us-central1-a.eth.staging
|
||||||
}`)
|
"enode://f79fb3919f72ca560ad0434dcc387abfe41e0666201ebdada8ede0462454a13deb05cda15f287d2c4bd85da81f0eb25d0a486bbbc8df427b971ac51533bd00fe@174.138.107.239:30404", // boot-01.do-ams3.eth.staging
|
||||||
require.Error(t, err)
|
},
|
||||||
require.Contains(t, err.Error(), "no such file or directory")
|
StaticNodes: []string{
|
||||||
|
"enode://914c0b30f27bab30c1dfd31dad7652a46fda9370542aee1b062498b1345ee0913614b8b9e3e84622e84a7203c5858ae1d9819f63aece13ee668e4f6668063989@167.99.19.148:30305", // node-01.do-ams3.eth.staging
|
||||||
|
"enode://2d897c6e846949f9dcf10279f00e9b8325c18fe7fa52d658520ad7be9607c83008b42b06aefd97cfe1fdab571f33a2a9383ff97c5909ed51f63300834913237e@35.192.0.86:30305", // "node-01.gc-us-central1-a.eth.staging"
|
||||||
|
},
|
||||||
|
MailServers: []string{
|
||||||
|
"enode://69f72baa7f1722d111a8c9c68c39a31430e9d567695f6108f31ccb6cd8f0adff4991e7fdca8fa770e75bc8a511a87d24690cbc80e008175f40c157d6f6788d48@206.189.240.16:30504", // mail-01.do-ams3.eth.staging
|
||||||
|
"enode://e4fc10c1f65c8aed83ac26bc1bfb21a45cc1a8550a58077c8d2de2a0e0cd18e40fd40f7e6f7d02dc6cd06982b014ce88d6e468725ffe2c138e958788d0002a7f@35.239.193.41:30504", // mail-01.gc-us-central1-a.eth.staging
|
||||||
|
},
|
||||||
|
RendezvousNodes: []string{
|
||||||
|
"/ip4/174.138.107.239/tcp/30703/ethv4/16Uiu2HAkyJHeetQ4DNpd4NZ2ntzxMo25zcdpvGQRqkD5pB9BE6RU",
|
||||||
|
"/ip4/35.238.97.234/tcp/30703/ethv4/16Uiu2HAm1sVyXmkMNjdeDWqK2urbyC3oBHi8MDpCdYkns1nYafqz",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
params.FleetBeta: func() params.Cluster {
|
||||||
|
return params.Cluster{
|
||||||
|
BootNodes: []string{
|
||||||
|
"enode://436cc6f674928fdc9a9f7990f2944002b685d1c37f025c1be425185b5b1f0900feaf1ccc2a6130268f9901be4a7d252f37302c8335a2c1a62736e9232691cc3a@174.138.105.243:30404", // boot-01.do-ams3.eth.beta
|
||||||
|
"enode://5395aab7833f1ecb671b59bf0521cf20224fe8162fc3d2675de4ee4d5636a75ec32d13268fc184df8d1ddfa803943906882da62a4df42d4fccf6d17808156a87@206.189.243.57:30404", // boot-02.do-ams3.eth.beta
|
||||||
|
"enode://7427dfe38bd4cf7c58bb96417806fab25782ec3e6046a8053370022cbaa281536e8d64ecd1b02e1f8f72768e295d06258ba43d88304db068e6f2417ae8bcb9a6@104.154.88.123:30404", // boot-01.gc-us-central1-a.eth.beta
|
||||||
|
"enode://ebefab39b69bbbe64d8cd86be765b3be356d8c4b24660f65d493143a0c44f38c85a257300178f7845592a1b0332811542e9a58281c835babdd7535babb64efc1@35.202.99.224:30404", // boot-02.gc-us-central1-a.eth.beta
|
||||||
|
},
|
||||||
|
StaticNodes: []string{
|
||||||
|
"enode://a6a2a9b3a7cbb0a15da74301537ebba549c990e3325ae78e1272a19a3ace150d03c184b8ac86cc33f1f2f63691e467d49308f02d613277754c4dccd6773b95e8@206.189.243.176:30304", // node-01.do-ams3.eth.beta
|
||||||
|
"enode://207e53d9bf66be7441e3daba36f53bfbda0b6099dba9a865afc6260a2d253fb8a56a72a48598a4f7ba271792c2e4a8e1a43aaef7f34857f520c8c820f63b44c8@35.224.15.65:30304", // node-01.gc-us-central1-a.eth.beta
|
||||||
|
},
|
||||||
|
MailServers: []string{
|
||||||
|
"enode://c42f368a23fa98ee546fd247220759062323249ef657d26d357a777443aec04db1b29a3a22ef3e7c548e18493ddaf51a31b0aed6079bd6ebe5ae838fcfaf3a49@206.189.243.162:30504", // mail-01.do-ams3.eth.beta
|
||||||
|
"enode://7aa648d6e855950b2e3d3bf220c496e0cae4adfddef3e1e6062e6b177aec93bc6cdcf1282cb40d1656932ebfdd565729da440368d7c4da7dbd4d004b1ac02bf8@206.189.243.169:30504", // mail-02.do-ams3.eth.beta
|
||||||
|
"enode://8a64b3c349a2e0ef4a32ea49609ed6eb3364be1110253c20adc17a3cebbc39a219e5d3e13b151c0eee5d8e0f9a8ba2cd026014e67b41a4ab7d1d5dd67ca27427@206.189.243.168:30504", // mail-03.do-ams3.eth.beta
|
||||||
|
"enode://7de99e4cb1b3523bd26ca212369540646607c721ad4f3e5c821ed9148150ce6ce2e72631723002210fac1fd52dfa8bbdf3555e05379af79515e1179da37cc3db@35.188.19.210:30504", // mail-01.gc-us-central1-a.eth.beta
|
||||||
|
"enode://015e22f6cd2b44c8a51bd7a23555e271e0759c7d7f52432719665a74966f2da456d28e154e836bee6092b4d686fe67e331655586c57b718be3997c1629d24167@35.226.21.19:30504", // mail-02.gc-us-central1-a.eth.beta
|
||||||
|
"enode://531e252ec966b7e83f5538c19bf1cde7381cc7949026a6e499b6e998e695751aadf26d4c98d5a4eabfb7cefd31c3c88d600a775f14ed5781520a88ecd25da3c6@35.225.227.79:30504", // mail-03.gc-us-central1-a.eth.beta
|
||||||
|
},
|
||||||
|
RendezvousNodes: []string{
|
||||||
|
"/ip4/174.138.105.243/tcp/30703/ethv4/16Uiu2HAmRHPzF3rQg55PgYPcQkyvPVH9n2hWsYPhUJBZ6kVjJgdV", // boot-01.do-ams3.eth.beta
|
||||||
|
"/ip4/206.189.243.57/tcp/30703/ethv4/16Uiu2HAmLqTXuY4Sb6G28HNooaFUXUKzpzKXCcgyJxgaEE2i5vnf", // boot-02.do-ams3.eth.beta
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClusterForFleet returns a cluster for a given fleet.
|
||||||
|
func ClusterForFleet(fleet string) (params.Cluster, bool) {
|
||||||
|
cluster, ok := clusters[fleet]
|
||||||
|
if ok {
|
||||||
|
return cluster(), true
|
||||||
|
}
|
||||||
|
return params.Cluster{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadNodeConfigFromFile(t *testing.T) {
|
func TestLoadNodeConfigFromFile(t *testing.T) {
|
||||||
|
@ -44,14 +94,21 @@ func TestLoadNodeConfigFromFile(t *testing.T) {
|
||||||
clusterFile := filepath.Join(tmpDir, "cluster.json")
|
clusterFile := filepath.Join(tmpDir, "cluster.json")
|
||||||
err = ioutil.WriteFile(clusterFile, clusterConfigData, os.ModePerm)
|
err = ioutil.WriteFile(clusterFile, clusterConfigData, os.ModePerm)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
defer os.Remove(clusterFile)
|
||||||
|
|
||||||
c, err := params.LoadNodeConfig(`{
|
c, err := params.NewConfigFromJSON(`{
|
||||||
"NetworkId": 3,
|
"NetworkId": 3,
|
||||||
"DataDir": "` + tmpDir + `",
|
"DataDir": "` + tmpDir + `",
|
||||||
"ClusterConfigFile": "` + clusterFile + `"
|
"KeyStoreDir": "` + tmpDir + `",
|
||||||
|
"NoDiscovery": true
|
||||||
}`)
|
}`)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, c.ClusterConfig.Enabled)
|
err = params.LoadConfigFromFiles([]string{clusterFile}, c)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, uint64(3), c.NetworkID)
|
||||||
|
require.Equal(t, tmpDir, c.DataDir)
|
||||||
|
require.Equal(t, tmpDir, c.KeyStoreDir)
|
||||||
|
require.False(t, c.ClusterConfig.Enabled)
|
||||||
require.Len(t, c.ClusterConfig.StaticNodes, 2)
|
require.Len(t, c.ClusterConfig.StaticNodes, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,21 +129,16 @@ func TestGenerateAndLoadNodeConfig(t *testing.T) {
|
||||||
Validate func(t *testing.T, dataDir string, c *params.NodeConfig)
|
Validate func(t *testing.T, dataDir string, c *params.NodeConfig)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Name: "default KeyStoreDir",
|
Name: "DataDir and KeyStoreDir specified",
|
||||||
Update: func(config *params.NodeConfig) {},
|
Update: func(c *params.NodeConfig) {},
|
||||||
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
||||||
require.Equal(t, dataDir, c.DataDir)
|
require.Equal(t, tmpDir, c.DataDir)
|
||||||
keyStoreDir := filepath.Join(dataDir, params.KeyStoreDir)
|
require.Equal(t, tmpDir, c.KeyStoreDir)
|
||||||
require.Equal(t, keyStoreDir, c.KeyStoreDir)
|
require.False(t, c.UpstreamConfig.Enabled)
|
||||||
},
|
require.Equal(t, c.ClusterConfig.Fleet != params.FleetUndefined, c.ClusterConfig.Enabled)
|
||||||
},
|
require.True(t, c.WhisperConfig.Enabled)
|
||||||
{
|
require.False(t, c.LightEthConfig.Enabled)
|
||||||
Name: "non-default KeyStoreDir",
|
require.False(t, c.SwarmConfig.Enabled)
|
||||||
Update: func(c *params.NodeConfig) {
|
|
||||||
c.KeyStoreDir = "/foo/bar"
|
|
||||||
},
|
|
||||||
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
|
||||||
require.Equal(t, "/foo/bar", c.KeyStoreDir)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -117,32 +169,38 @@ func TestGenerateAndLoadNodeConfig(t *testing.T) {
|
||||||
{
|
{
|
||||||
Name: "loading LES config",
|
Name: "loading LES config",
|
||||||
NetworkID: params.MainNetworkID,
|
NetworkID: params.MainNetworkID,
|
||||||
Update: func(c *params.NodeConfig) {},
|
Update: func(c *params.NodeConfig) {
|
||||||
|
c.LightEthConfig.Enabled = true
|
||||||
|
},
|
||||||
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
||||||
var genesis core.Genesis
|
require.True(t, c.LightEthConfig.Enabled)
|
||||||
err := json.Unmarshal([]byte(c.LightEthConfig.Genesis), &genesis)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.Zero(t, genesis.Config.ChainID.Cmp(gethparams.MainnetChainConfig.ChainID))
|
|
||||||
require.Zero(t, genesis.Config.HomesteadBlock.Cmp(gethparams.MainnetChainConfig.HomesteadBlock))
|
|
||||||
require.Zero(t, genesis.Config.EIP150Block.Cmp(gethparams.MainnetChainConfig.EIP150Block))
|
|
||||||
require.Zero(t, genesis.Config.EIP155Block.Cmp(gethparams.MainnetChainConfig.EIP155Block))
|
|
||||||
require.Zero(t, genesis.Config.EIP158Block.Cmp(gethparams.MainnetChainConfig.EIP158Block))
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "cluster nodes setup",
|
Name: "cluster nodes setup",
|
||||||
Update: func(c *params.NodeConfig) {},
|
Update: func(c *params.NodeConfig) {
|
||||||
|
cc, _ := ClusterForFleet(c.ClusterConfig.Fleet)
|
||||||
|
c.Rendezvous = true
|
||||||
|
c.ClusterConfig.BootNodes = cc.BootNodes
|
||||||
|
c.ClusterConfig.StaticNodes = cc.StaticNodes
|
||||||
|
c.ClusterConfig.RendezvousNodes = cc.RendezvousNodes
|
||||||
|
c.ClusterConfig.TrustedMailServers = cc.MailServers
|
||||||
|
c.ClusterConfig.Enabled = true
|
||||||
|
c.RequireTopics[params.WhisperDiscv5Topic] = params.WhisperDiscv5Limits
|
||||||
|
},
|
||||||
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
||||||
|
require.True(t, c.Rendezvous)
|
||||||
require.True(t, c.ClusterConfig.Enabled)
|
require.True(t, c.ClusterConfig.Enabled)
|
||||||
require.NotEmpty(t, c.ClusterConfig.BootNodes)
|
require.NotEmpty(t, c.ClusterConfig.BootNodes)
|
||||||
require.NotEmpty(t, c.ClusterConfig.StaticNodes)
|
require.NotEmpty(t, c.ClusterConfig.StaticNodes)
|
||||||
require.NotEmpty(t, c.ClusterConfig.TrustedMailServers)
|
require.NotEmpty(t, c.ClusterConfig.TrustedMailServers)
|
||||||
|
require.Equal(t, params.WhisperDiscv5Limits, c.RequireTopics[params.WhisperDiscv5Topic])
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "custom bootnodes",
|
Name: "custom bootnodes",
|
||||||
Update: func(c *params.NodeConfig) {
|
Update: func(c *params.NodeConfig) {
|
||||||
|
c.ClusterConfig.Enabled = true
|
||||||
c.ClusterConfig.BootNodes = []string{"a", "b", "c"}
|
c.ClusterConfig.BootNodes = []string{"a", "b", "c"}
|
||||||
},
|
},
|
||||||
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
||||||
|
@ -151,17 +209,22 @@ func TestGenerateAndLoadNodeConfig(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "disabled ClusterConfiguration",
|
Name: "disabled Cluster configuration",
|
||||||
Update: func(c *params.NodeConfig) {
|
Update: func(c *params.NodeConfig) {
|
||||||
c.ClusterConfig.Enabled = false
|
c.ClusterConfig.Enabled = false
|
||||||
|
c.ClusterConfig.BootNodes = []string{"a", "b", "c"}
|
||||||
},
|
},
|
||||||
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
||||||
require.False(t, c.ClusterConfig.Enabled)
|
require.False(t, c.ClusterConfig.Enabled)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "peers discovery and topics",
|
Name: "peers discovery and topics",
|
||||||
Update: func(c *params.NodeConfig) {},
|
Update: func(c *params.NodeConfig) {
|
||||||
|
c.NoDiscovery = false
|
||||||
|
c.ClusterConfig.BootNodes = []string{"a", "b", "c"}
|
||||||
|
c.RequireTopics[params.WhisperDiscv5Topic] = params.Limits{2, 2}
|
||||||
|
},
|
||||||
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
||||||
require.NotNil(t, c.RequireTopics)
|
require.NotNil(t, c.RequireTopics)
|
||||||
require.False(t, c.NoDiscovery)
|
require.False(t, c.NoDiscovery)
|
||||||
|
@ -179,13 +242,18 @@ func TestGenerateAndLoadNodeConfig(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "staging fleet",
|
Name: "staging fleet",
|
||||||
Fleet: params.FleetStaging,
|
Fleet: params.FleetStaging,
|
||||||
Update: func(c *params.NodeConfig) {},
|
Update: func(c *params.NodeConfig) {
|
||||||
|
c.ClusterConfig.Enabled = true
|
||||||
|
c.ClusterConfig.Fleet = "eth.staging"
|
||||||
|
cc, _ := ClusterForFleet(c.ClusterConfig.Fleet)
|
||||||
|
c.ClusterConfig.BootNodes = cc.BootNodes
|
||||||
|
},
|
||||||
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
||||||
staging, ok := params.ClusterForFleet("eth.staging")
|
staging, ok := ClusterForFleet("eth.staging")
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
beta, ok := params.ClusterForFleet("eth.beta")
|
beta, ok := ClusterForFleet("eth.beta")
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
require.NotEqual(t, staging, beta)
|
require.NotEqual(t, staging, beta)
|
||||||
|
@ -198,9 +266,13 @@ func TestGenerateAndLoadNodeConfig(t *testing.T) {
|
||||||
{
|
{
|
||||||
Name: "Whisper light client",
|
Name: "Whisper light client",
|
||||||
Update: func(c *params.NodeConfig) {
|
Update: func(c *params.NodeConfig) {
|
||||||
|
c.WhisperConfig.Enabled = true
|
||||||
|
c.WhisperConfig.DataDir = path.Join(tmpDir, "wnode")
|
||||||
c.WhisperConfig.LightClient = true
|
c.WhisperConfig.LightClient = true
|
||||||
},
|
},
|
||||||
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
Validate: func(t *testing.T, dataDir string, c *params.NodeConfig) {
|
||||||
|
require.Equal(t, path.Join(tmpDir, "wnode"), c.WhisperConfig.DataDir)
|
||||||
|
require.True(t, c.WhisperConfig.Enabled)
|
||||||
require.True(t, c.WhisperConfig.LightClient)
|
require.True(t, c.WhisperConfig.LightClient)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -221,9 +293,9 @@ func TestGenerateAndLoadNodeConfig(t *testing.T) {
|
||||||
for _, networkID := range networks {
|
for _, networkID := range networks {
|
||||||
name := fmt.Sprintf("%s_%s_%d", tc.Name, fleet, networkID)
|
name := fmt.Sprintf("%s_%s_%d", tc.Name, fleet, networkID)
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
// Corresponds to GenerateConfig() binding.
|
config, err := utils.MakeTestNodeConfigWithDataDir("", tmpDir, fleet, uint64(networkID))
|
||||||
config, err := params.NewNodeConfig(tmpDir, "", fleet, uint64(networkID))
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
config.KeyStoreDir = tmpDir
|
||||||
|
|
||||||
// Corresponds to config update in status-react.
|
// Corresponds to config update in status-react.
|
||||||
tc.Update(config)
|
tc.Update(config)
|
||||||
|
@ -231,7 +303,7 @@ func TestGenerateAndLoadNodeConfig(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Corresponds to starting node and loading config from JSON blob.
|
// Corresponds to starting node and loading config from JSON blob.
|
||||||
loadedConfig, err := params.LoadNodeConfig(string(configBytes))
|
loadedConfig, err := params.NewConfigFromJSON(string(configBytes))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
tc.Validate(t, tmpDir, loadedConfig)
|
tc.Validate(t, tmpDir, loadedConfig)
|
||||||
})
|
})
|
||||||
|
@ -245,7 +317,7 @@ func TestConfigWriteRead(t *testing.T) {
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
defer os.RemoveAll(tmpDir) // nolint: errcheck
|
defer os.RemoveAll(tmpDir) // nolint: errcheck
|
||||||
|
|
||||||
nodeConfig, err := params.NewNodeConfig(tmpDir, "", params.FleetBeta, params.RopstenNetworkID)
|
nodeConfig, err := utils.MakeTestNodeConfigWithDataDir("", tmpDir, params.FleetBeta, params.RopstenNetworkID)
|
||||||
require.Nil(t, err, "cannot create new config object")
|
require.Nil(t, err, "cannot create new config object")
|
||||||
|
|
||||||
err = nodeConfig.Save()
|
err = nodeConfig.Save()
|
||||||
|
@ -253,8 +325,10 @@ func TestConfigWriteRead(t *testing.T) {
|
||||||
|
|
||||||
loadedConfigData, err := ioutil.ReadFile(filepath.Join(nodeConfig.DataDir, "config.json"))
|
loadedConfigData, err := ioutil.ReadFile(filepath.Join(nodeConfig.DataDir, "config.json"))
|
||||||
require.Nil(t, err, "cannot read configuration from disk")
|
require.Nil(t, err, "cannot read configuration from disk")
|
||||||
require.Contains(t, string(loadedConfigData), fmt.Sprintf(`"NetworkId": %d`, params.RopstenNetworkID))
|
loadedConfig := string(loadedConfigData)
|
||||||
require.Contains(t, string(loadedConfigData), fmt.Sprintf(`"DataDir": "%s"`, tmpDir))
|
require.Contains(t, loadedConfig, fmt.Sprintf(`"NetworkId": %d`, params.RopstenNetworkID))
|
||||||
|
require.Contains(t, loadedConfig, fmt.Sprintf(`"DataDir": "%s"`, tmpDir))
|
||||||
|
require.Contains(t, loadedConfig, fmt.Sprintf(`"Fleet": "%s"`, params.FleetBeta))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestNodeConfigValidate checks validation of individual fields.
|
// TestNodeConfigValidate checks validation of individual fields.
|
||||||
|
@ -264,55 +338,250 @@ func TestNodeConfigValidate(t *testing.T) {
|
||||||
Config string
|
Config string
|
||||||
Error string
|
Error string
|
||||||
FieldErrors map[string]string // map[Field]Tag
|
FieldErrors map[string]string // map[Field]Tag
|
||||||
|
CheckFunc func(*testing.T, *params.NodeConfig)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Name: "Valid JSON config",
|
Name: "Valid JSON config",
|
||||||
Config: `{
|
Config: `{
|
||||||
"NetworkId": 1,
|
"NetworkId": 1,
|
||||||
"DataDir": "/tmp/data"
|
"DataDir": "/tmp/data",
|
||||||
|
"KeyStoreDir": "/tmp/data",
|
||||||
|
"NoDiscovery": true
|
||||||
}`,
|
}`,
|
||||||
Error: "",
|
|
||||||
FieldErrors: nil,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Invalid JSON config",
|
Name: "Invalid JSON config",
|
||||||
Config: `{"NetworkId": }`,
|
Config: `{"NetworkId": }`,
|
||||||
Error: "invalid character '}'",
|
Error: "invalid character '}'",
|
||||||
FieldErrors: nil,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Invalid field type",
|
Name: "Invalid field type",
|
||||||
Config: `{"NetworkId": "abc"}`,
|
Config: `{"NetworkId": "abc"}`,
|
||||||
Error: "json: cannot unmarshal string into Go struct field",
|
Error: "json: cannot unmarshal string into Go struct field",
|
||||||
FieldErrors: nil,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Validate all required fields",
|
Name: "Validate all required fields",
|
||||||
Config: `{}`,
|
Config: `{}`,
|
||||||
Error: "",
|
|
||||||
FieldErrors: map[string]string{
|
FieldErrors: map[string]string{
|
||||||
"NetworkID": "required",
|
"NetworkID": "required",
|
||||||
"DataDir": "required",
|
"DataDir": "required",
|
||||||
|
"KeyStoreDir": "required",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Validate Name does not contain slash",
|
Name: "Validate that Name does not contain slash",
|
||||||
Config: `{
|
Config: `{
|
||||||
"NetworkId": 1,
|
"NetworkId": 1,
|
||||||
"DataDir": "/some/dir",
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
"Name": "invalid/name"
|
"Name": "invalid/name"
|
||||||
}`,
|
}`,
|
||||||
Error: "",
|
|
||||||
FieldErrors: map[string]string{
|
FieldErrors: map[string]string{
|
||||||
"Name": "excludes",
|
"Name": "excludes",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that NodeKey is checked for validity",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"NodeKey": "foo"
|
||||||
|
}`,
|
||||||
|
Error: "NodeKey is invalid",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that UpstreamConfig.URL is validated if UpstreamConfig is enabled",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"UpstreamConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"URL": "[bad.url]"
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
Error: "'[bad.url]' is invalid",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that UpstreamConfig.URL is not validated if UpstreamConfig is disabled",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"UpstreamConfig": {
|
||||||
|
"Enabled": false,
|
||||||
|
"URL": "[bad.url]"
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that UpstreamConfig.URL validation passes if UpstreamConfig.URL is valid",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"UpstreamConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"URL": "` + params.MainnetEthereumNetworkURL + `"
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that ClusterConfig.Fleet is verified to not be empty if ClusterConfig is enabled",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"ClusterConfig": {
|
||||||
|
"Enabled": true
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
Error: "ClusterConfig.Fleet is empty",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that ClusterConfig.BootNodes is verified to not be empty if discovery is disabled",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": false
|
||||||
|
}`,
|
||||||
|
Error: "NoDiscovery is false, but ClusterConfig.BootNodes is empty",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that ClusterConfig.RendezvousNodes is verified to be empty if Rendezvous is disabled",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"Rendezvous": true
|
||||||
|
}`,
|
||||||
|
Error: "Rendezvous is enabled, but ClusterConfig.RendezvousNodes is empty",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that ClusterConfig.RendezvousNodes is verified to contain nodes if Rendezvous is enabled",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"Rendezvous": false,
|
||||||
|
"ClusterConfig": {
|
||||||
|
"RendezvousNodes": ["a"]
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
Error: "Rendezvous is disabled, but ClusterConfig.RendezvousNodes is not empty",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that WhisperConfig.DataDir is checked to not be empty if mailserver is enabled",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"EnableMailServer": true,
|
||||||
|
"MailserverPassword": "foo"
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
Error: "WhisperConfig.DataDir must be specified when WhisperConfig.EnableMailServer is true",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that check for WhisperConfig.DataDir passes if it is not empty and mailserver is enabled",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"EnableMailServer": true,
|
||||||
|
"DataDir": "/foo",
|
||||||
|
"MailserverPassword": "foo"
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
CheckFunc: func(t *testing.T, config *params.NodeConfig) {
|
||||||
|
require.Equal(t, "foo", config.WhisperConfig.MailServerPassword)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that WhisperConfig.DataDir is checked to not be empty if mailserver is enabled",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"EnableMailServer": true,
|
||||||
|
"MailserverPassword": "foo"
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
Error: "WhisperConfig.DataDir must be specified when WhisperConfig.EnableMailServer is true",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that WhisperConfig.MailserverPassword and WhisperConfig.MailServerAsymKey are checked to not be empty if mailserver is enabled",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"EnableMailServer": true,
|
||||||
|
"DataDir": "/foo"
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
Error: "WhisperConfig.MailServerPassword or WhisperConfig.MailServerAsymKey must be specified when WhisperConfig.EnableMailServer is true",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that WhisperConfig.MailServerAsymKey is checked to not be empty if mailserver is enabled",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"EnableMailServer": true,
|
||||||
|
"DataDir": "/foo",
|
||||||
|
"MailServerAsymKey": "06c365919f1fc8e13ff79a84f1dd14b7e45b869aa5fc0e34940481ee20d32f90"
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
CheckFunc: func(t *testing.T, config *params.NodeConfig) {
|
||||||
|
require.Equal(t, "06c365919f1fc8e13ff79a84f1dd14b7e45b869aa5fc0e34940481ee20d32f90", config.WhisperConfig.MailServerAsymKey)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Validate that WhisperConfig.MailServerAsymKey is checked for validity",
|
||||||
|
Config: `{
|
||||||
|
"NetworkId": 1,
|
||||||
|
"DataDir": "/some/dir",
|
||||||
|
"KeyStoreDir": "/some/dir",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"EnableMailServer": true,
|
||||||
|
"DataDir": "/foo",
|
||||||
|
"MailServerAsymKey": "bar"
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
Error: "WhisperConfig.MailServerAsymKey is invalid",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Logf("Test Case %s", tc.Name)
|
t.Logf("Test Case %s", tc.Name)
|
||||||
|
|
||||||
_, err := params.LoadNodeConfig(tc.Config)
|
config, err := params.NewConfigFromJSON(tc.Config)
|
||||||
|
|
||||||
switch err := err.(type) {
|
switch err := err.(type) {
|
||||||
case validator.ValidationErrors:
|
case validator.ValidationErrors:
|
||||||
|
@ -321,10 +590,19 @@ func TestNodeConfigValidate(t *testing.T) {
|
||||||
require.Equal(t, tc.FieldErrors[ve.Field()], ve.Tag())
|
require.Equal(t, tc.FieldErrors[ve.Field()], ve.Tag())
|
||||||
}
|
}
|
||||||
case error:
|
case error:
|
||||||
require.Contains(t, err.Error(), tc.Error)
|
if tc.Error == "" {
|
||||||
|
require.NoError(t, err)
|
||||||
|
} else {
|
||||||
|
require.Contains(t, err.Error(), tc.Error)
|
||||||
|
}
|
||||||
case nil:
|
case nil:
|
||||||
require.Empty(t, tc.Error)
|
if tc.Error != "" {
|
||||||
|
require.Error(t, err, "Error should be '%v'", tc.Error)
|
||||||
|
}
|
||||||
require.Nil(t, tc.FieldErrors)
|
require.Nil(t, tc.FieldErrors)
|
||||||
|
if tc.CheckFunc != nil {
|
||||||
|
tc.CheckFunc(t, config)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,38 +3,9 @@ package params
|
||||||
import "github.com/ethereum/go-ethereum/p2p/discv5"
|
import "github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ClientIdentifier is client identifier to advertise over the network
|
|
||||||
ClientIdentifier = "StatusIM"
|
|
||||||
|
|
||||||
// DataDir is default data directory used by statusd executable
|
|
||||||
DataDir = "statusd-data"
|
|
||||||
|
|
||||||
// StatusDatabase path relative to DataDir.
|
// StatusDatabase path relative to DataDir.
|
||||||
StatusDatabase = "status-db"
|
StatusDatabase = "status-db"
|
||||||
|
|
||||||
// KeyStoreDir is default directory where private keys are stored, relative to DataDir
|
|
||||||
KeyStoreDir = "keystore"
|
|
||||||
|
|
||||||
// IPCFile is filename of exposed IPC RPC Server
|
|
||||||
IPCFile = "geth.ipc"
|
|
||||||
|
|
||||||
// RPCEnabledDefault is the default state of whether the http rpc server is supposed
|
|
||||||
// to be started along with a node.
|
|
||||||
RPCEnabledDefault = false
|
|
||||||
|
|
||||||
// HTTPHost is host interface for the HTTP RPC server
|
|
||||||
HTTPHost = "localhost"
|
|
||||||
|
|
||||||
// HTTPPort is HTTP RPC port (replaced in unit tests)
|
|
||||||
HTTPPort = 8545
|
|
||||||
|
|
||||||
// ListenAddr is an IP address and port of this node (e.g. 127.0.0.1:30303).
|
|
||||||
ListenAddr = ":0"
|
|
||||||
|
|
||||||
// APIModules is a list of modules to expose via HTTP and `CallRPC()` binding.
|
|
||||||
// We also expose all handlers registered with `rpc.Client.RegisterHandler` to `CallRPC()` binding.
|
|
||||||
APIModules = "eth,net,web3,peer"
|
|
||||||
|
|
||||||
// SendTransactionMethodName defines the name for a giving transaction.
|
// SendTransactionMethodName defines the name for a giving transaction.
|
||||||
SendTransactionMethodName = "eth_sendTransaction"
|
SendTransactionMethodName = "eth_sendTransaction"
|
||||||
|
|
||||||
|
@ -47,47 +18,15 @@ const (
|
||||||
// PersonalRecoverMethodName defines the name for `personal.recover` API.
|
// PersonalRecoverMethodName defines the name for `personal.recover` API.
|
||||||
PersonalRecoverMethodName = "personal_ecRecover"
|
PersonalRecoverMethodName = "personal_ecRecover"
|
||||||
|
|
||||||
// MaxPeers is the maximum number of global peers
|
|
||||||
MaxPeers = 25
|
|
||||||
|
|
||||||
// MaxPendingPeers is the maximum number of peers that can be pending in the
|
|
||||||
// handshake phase, counted separately for inbound and outbound connections.
|
|
||||||
MaxPendingPeers = 0
|
|
||||||
|
|
||||||
// DefaultGas default amount of gas used for transactions
|
// DefaultGas default amount of gas used for transactions
|
||||||
DefaultGas = 180000
|
DefaultGas = 180000
|
||||||
|
|
||||||
// DefaultFileDescriptorLimit is fd limit that database can use
|
|
||||||
DefaultFileDescriptorLimit = uint64(2048)
|
|
||||||
|
|
||||||
// DatabaseCache is memory (in MBs) allocated to internal caching (min 16MB / database forced)
|
|
||||||
DatabaseCache = 16
|
|
||||||
|
|
||||||
// LogFile defines where to write logs to
|
|
||||||
LogFile = ""
|
|
||||||
|
|
||||||
// LogLevel defines the minimum log level to report
|
|
||||||
LogLevel = "ERROR"
|
|
||||||
|
|
||||||
// LogLevelSuccinct defines the log level when only errors are reported.
|
|
||||||
// Useful when the default INFO level becomes too verbose.
|
|
||||||
LogLevelSuccinct = "ERROR"
|
|
||||||
|
|
||||||
// LogToStderr defines whether logged info should also be output to os.Stderr
|
|
||||||
LogToStderr = true
|
|
||||||
|
|
||||||
// WhisperDataDir is directory where Whisper data is stored, relative to DataDir
|
|
||||||
WhisperDataDir = "wnode"
|
|
||||||
|
|
||||||
// WhisperMinimumPoW amount of work for Whisper message to be added to sending queue
|
// WhisperMinimumPoW amount of work for Whisper message to be added to sending queue
|
||||||
WhisperMinimumPoW = 0.001
|
WhisperMinimumPoW = 0.001
|
||||||
|
|
||||||
// WhisperTTL is time to live for messages, in seconds
|
// WhisperTTL is time to live for messages, in seconds
|
||||||
WhisperTTL = 120
|
WhisperTTL = 120
|
||||||
|
|
||||||
// FirebaseNotificationTriggerURL is URL where FCM notification requests are sent to
|
|
||||||
FirebaseNotificationTriggerURL = "https://fcm.googleapis.com/fcm/send"
|
|
||||||
|
|
||||||
// MainnetEthereumNetworkURL is URL where the upstream ethereum network is loaded to
|
// MainnetEthereumNetworkURL is URL where the upstream ethereum network is loaded to
|
||||||
// allow us avoid syncing node.
|
// allow us avoid syncing node.
|
||||||
MainnetEthereumNetworkURL = "https://mainnet.infura.io/nKmXgiFgc2KqtoQ8BCGJ"
|
MainnetEthereumNetworkURL = "https://mainnet.infura.io/nKmXgiFgc2KqtoQ8BCGJ"
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
||||||
status-offline-inbox
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
// Package static embeds static (JS, HTML) resources right into the binaries
|
||||||
|
package static
|
||||||
|
|
||||||
|
//go:generate go-bindata -pkg static -o bindata.go ../config/...
|
|
@ -6,14 +6,26 @@
|
||||||
Example usage:
|
Example usage:
|
||||||
|
|
||||||
1. Start a Whisper node with mail server capability:
|
1. Start a Whisper node with mail server capability:
|
||||||
./build/bin/statusd \
|
./build/bin/statusd -c mailserver-config.json
|
||||||
-networkid=4 \
|
|
||||||
-maxpeers=100 \
|
where mailserver-config.json contains:
|
||||||
-shh \
|
``` json
|
||||||
-shh.pow=0.002 \
|
{
|
||||||
-shh.mailserver \
|
"NetworkId": 4,
|
||||||
-shh.passwordfile=./static/keys/wnodepassword \
|
"DataDir": "./ethereumtest/rinkeby_rpc",
|
||||||
-log DEBUG
|
"KeyStoreDir": "./ethereumtest/keystore",
|
||||||
|
"MaxPeers": 100,
|
||||||
|
"LogLevel": "DEBUG",
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"EnableMailServer": true,
|
||||||
|
"DataDir": "./ethereumtest/wnode",
|
||||||
|
"MinimumPoW": 0.002,
|
||||||
|
"MailServerPassword": "status-offline-inbox"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
2. Generate some messages:
|
2. Generate some messages:
|
||||||
go test -v -timeout=30s -run TestSendMessages ./t/benchmarks \
|
go test -v -timeout=30s -run TestSendMessages ./t/benchmarks \
|
||||||
-peerurl=$ENODE_ADDR \
|
-peerurl=$ENODE_ADDR \
|
||||||
|
|
|
@ -54,7 +54,7 @@ mv UTC--2018-01-26T13-47-49.289567120Z--9f04dc05c4c3ec3b8b1f36f7d7d153f3934b1f07
|
||||||
popd
|
popd
|
||||||
```
|
```
|
||||||
|
|
||||||
Update config for tests with new accounts `static/config/public-chain-accounts.json`:
|
Update config for tests with new accounts `t/config/public-chain-accounts.json`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
|
@ -231,7 +231,7 @@ func (s *AccountsTestSuite) TestSelectedAccountOnRestart() {
|
||||||
s.Equal(selectedAccount.Address.Hex(), address2, "incorrect address selected")
|
s.Equal(selectedAccount.Address.Hex(), address2, "incorrect address selected")
|
||||||
|
|
||||||
// resume node
|
// resume node
|
||||||
s.NoError(s.Backend.StartNode(&preservedNodeConfig))
|
s.Require().NoError(s.Backend.StartNode(&preservedNodeConfig))
|
||||||
|
|
||||||
// re-check selected account (account2 MUST be selected)
|
// re-check selected account (account2 MUST be selected)
|
||||||
selectedAccount, err = s.Backend.AccountManager().SelectedAccount()
|
selectedAccount, err = s.Backend.AccountManager().SelectedAccount()
|
||||||
|
|
|
@ -2,10 +2,7 @@ package api_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -40,19 +37,6 @@ func (s *APITestSuite) SetupTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *APITestSuite) TestCHTUpdate() {
|
func (s *APITestSuite) TestCHTUpdate() {
|
||||||
tmpDir, err := ioutil.TempDir(os.TempDir(), "cht-updates")
|
|
||||||
s.NoError(err)
|
|
||||||
defer os.RemoveAll(tmpDir) //nolint: errcheck
|
|
||||||
|
|
||||||
configJSON := `{
|
|
||||||
"NetworkId": ` + strconv.Itoa(params.RopstenNetworkID) + `,
|
|
||||||
"DataDir": "` + tmpDir + `",
|
|
||||||
"LogLevel": "INFO",
|
|
||||||
"RPCEnabled": true
|
|
||||||
}`
|
|
||||||
|
|
||||||
_, err = params.LoadNodeConfig(configJSON)
|
|
||||||
s.NoError(err)
|
|
||||||
// TODO(tiabc): Test that CHT is really updated.
|
// TODO(tiabc): Test that CHT is really updated.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,12 +124,12 @@ func (s *APITestSuite) TestEventsNodeStartStop() {
|
||||||
|
|
||||||
nodeConfig, err := MakeTestNodeConfig(GetNetworkID())
|
nodeConfig, err := MakeTestNodeConfig(GetNetworkID())
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.NoError(s.backend.StartNode(nodeConfig))
|
s.Require().NoError(s.backend.StartNode(nodeConfig))
|
||||||
s.NoError(s.backend.StopNode())
|
s.NoError(s.backend.StopNode())
|
||||||
s.verifyEnvelopes(envelopes, signal.EventNodeStarted, signal.EventNodeReady, signal.EventNodeStopped)
|
s.verifyEnvelopes(envelopes, signal.EventNodeStarted, signal.EventNodeReady, signal.EventNodeStopped)
|
||||||
s.NoError(s.backend.StartNode(nodeConfig))
|
s.Require().NoError(s.backend.StartNode(nodeConfig))
|
||||||
s.verifyEnvelopes(envelopes, signal.EventNodeStarted, signal.EventNodeReady)
|
s.verifyEnvelopes(envelopes, signal.EventNodeStarted, signal.EventNodeReady)
|
||||||
s.NoError(s.backend.RestartNode())
|
s.Require().NoError(s.backend.RestartNode())
|
||||||
s.verifyEnvelopes(envelopes, signal.EventNodeStopped, signal.EventNodeStarted, signal.EventNodeReady)
|
s.verifyEnvelopes(envelopes, signal.EventNodeStopped, signal.EventNodeStarted, signal.EventNodeReady)
|
||||||
s.NoError(s.backend.StopNode())
|
s.NoError(s.backend.StopNode())
|
||||||
s.verifyEnvelopes(envelopes, signal.EventNodeStopped)
|
s.verifyEnvelopes(envelopes, signal.EventNodeStopped)
|
||||||
|
|
|
@ -27,7 +27,7 @@ func (s *APIBackendTestSuite) TestNetworkSwitching() {
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
s.False(s.Backend.IsNodeRunning())
|
s.False(s.Backend.IsNodeRunning())
|
||||||
s.NoError(s.Backend.StartNode(nodeConfig))
|
s.Require().NoError(s.Backend.StartNode(nodeConfig))
|
||||||
s.True(s.Backend.IsNodeRunning())
|
s.True(s.Backend.IsNodeRunning())
|
||||||
|
|
||||||
firstHash, err := e2e.FirstBlockHash(s.Backend.StatusNode())
|
firstHash, err := e2e.FirstBlockHash(s.Backend.StatusNode())
|
||||||
|
@ -42,7 +42,7 @@ func (s *APIBackendTestSuite) TestNetworkSwitching() {
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
s.False(s.Backend.IsNodeRunning())
|
s.False(s.Backend.IsNodeRunning())
|
||||||
s.NoError(s.Backend.StartNode(nodeConfig))
|
s.Require().NoError(s.Backend.StartNode(nodeConfig))
|
||||||
s.True(s.Backend.IsNodeRunning())
|
s.True(s.Backend.IsNodeRunning())
|
||||||
|
|
||||||
// make sure we are on another network indeed
|
// make sure we are on another network indeed
|
||||||
|
@ -89,7 +89,7 @@ func (s *APIBackendTestSuite) TestRestartNode() {
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
s.False(s.Backend.IsNodeRunning())
|
s.False(s.Backend.IsNodeRunning())
|
||||||
s.NoError(s.Backend.StartNode(nodeConfig))
|
require.NoError(s.Backend.StartNode(nodeConfig))
|
||||||
s.True(s.Backend.IsNodeRunning())
|
s.True(s.Backend.IsNodeRunning())
|
||||||
|
|
||||||
firstHash, err := e2e.FirstBlockHash(s.Backend.StatusNode())
|
firstHash, err := e2e.FirstBlockHash(s.Backend.StatusNode())
|
||||||
|
|
|
@ -84,7 +84,7 @@ func (s *BackendTestSuite) TearDownTest() {
|
||||||
// StartTestBackend imports some keys and starts a node.
|
// StartTestBackend imports some keys and starts a node.
|
||||||
func (s *BackendTestSuite) StartTestBackend(opts ...TestNodeOption) {
|
func (s *BackendTestSuite) StartTestBackend(opts ...TestNodeOption) {
|
||||||
nodeConfig, err := MakeTestNodeConfig(GetNetworkID())
|
nodeConfig, err := MakeTestNodeConfig(GetNetworkID())
|
||||||
s.NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
// Apply any options altering node config.
|
// Apply any options altering node config.
|
||||||
for i := range opts {
|
for i := range opts {
|
||||||
|
@ -96,7 +96,7 @@ func (s *BackendTestSuite) StartTestBackend(opts ...TestNodeOption) {
|
||||||
|
|
||||||
// start node
|
// start node
|
||||||
s.False(s.Backend.IsNodeRunning())
|
s.False(s.Backend.IsNodeRunning())
|
||||||
s.NoError(s.Backend.StartNode(nodeConfig))
|
s.Require().NoError(s.Backend.StartNode(nodeConfig))
|
||||||
s.True(s.Backend.IsNodeRunning())
|
s.True(s.Backend.IsNodeRunning())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ func (s *BackendTestSuite) StopTestBackend() {
|
||||||
// RestartTestNode restarts a currently running node.
|
// RestartTestNode restarts a currently running node.
|
||||||
func (s *BackendTestSuite) RestartTestNode() {
|
func (s *BackendTestSuite) RestartTestNode() {
|
||||||
s.True(s.Backend.IsNodeRunning())
|
s.True(s.Backend.IsNodeRunning())
|
||||||
s.NoError(s.Backend.RestartNode())
|
s.Require().NoError(s.Backend.RestartNode())
|
||||||
s.True(s.Backend.IsNodeRunning())
|
s.True(s.Backend.IsNodeRunning())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package e2e
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"path"
|
||||||
|
|
||||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/status-im/status-go/node"
|
"github.com/status-im/status-go/node"
|
||||||
|
@ -20,9 +21,11 @@ func WithUpstream(url string) TestNodeOption {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithDataDir returns TestNodeOption that allows to set another data dir.
|
// WithDataDir returns TestNodeOption that allows to set another data dir.
|
||||||
func WithDataDir(path string) TestNodeOption {
|
func WithDataDir(dataDir string) TestNodeOption {
|
||||||
return func(config *params.NodeConfig) {
|
return func(config *params.NodeConfig) {
|
||||||
config.DataDir = path
|
config.DataDir = dataDir
|
||||||
|
config.KeyStoreDir = path.Join(dataDir, "keystore")
|
||||||
|
config.WhisperConfig.DataDir = path.Join(dataDir, "wnode")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -568,7 +568,7 @@ func (s *WhisperMailboxSuite) startMailboxBackend() (*api.StatusBackend, func())
|
||||||
mailboxConfig.WhisperConfig.Enabled = true
|
mailboxConfig.WhisperConfig.Enabled = true
|
||||||
mailboxConfig.KeyStoreDir = datadir
|
mailboxConfig.KeyStoreDir = datadir
|
||||||
mailboxConfig.WhisperConfig.EnableMailServer = true
|
mailboxConfig.WhisperConfig.EnableMailServer = true
|
||||||
mailboxConfig.WhisperConfig.MailServerPasswordFile = filepath.Join(RootDir, "/static/keys/wnodepassword")
|
mailboxConfig.WhisperConfig.MailServerPassword = "status-offline-inbox"
|
||||||
mailboxConfig.WhisperConfig.DataDir = filepath.Join(datadir, "data")
|
mailboxConfig.WhisperConfig.DataDir = filepath.Join(datadir, "data")
|
||||||
mailboxConfig.DataDir = datadir
|
mailboxConfig.DataDir = datadir
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() {
|
||||||
s.NoError(s.Backend.StopNode())
|
s.NoError(s.Backend.StopNode())
|
||||||
|
|
||||||
// resume node
|
// resume node
|
||||||
s.NoError(s.Backend.StartNode(&preservedNodeConfig))
|
s.Require().NoError(s.Backend.StartNode(&preservedNodeConfig))
|
||||||
|
|
||||||
// re-check selected account (account2 MUST be selected)
|
// re-check selected account (account2 MUST be selected)
|
||||||
selectedAccount, err = s.Backend.AccountManager().SelectedAccount()
|
selectedAccount, err = s.Backend.AccountManager().SelectedAccount()
|
||||||
|
|
|
@ -244,18 +244,28 @@ func MakeTestNodeConfig(networkID int) (*params.NodeConfig, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
configJSON := `{
|
configJSON := `{
|
||||||
|
"Name": "test",
|
||||||
"NetworkId": ` + strconv.Itoa(networkID) + `,
|
"NetworkId": ` + strconv.Itoa(networkID) + `,
|
||||||
"DataDir": "` + testDir + `",
|
"DataDir": "` + testDir + `",
|
||||||
|
"KeyStoreDir": "` + path.Join(testDir, "keystore") + `",
|
||||||
"HTTPPort": ` + strconv.Itoa(TestConfig.Node.HTTPPort) + `,
|
"HTTPPort": ` + strconv.Itoa(TestConfig.Node.HTTPPort) + `,
|
||||||
"WSPort": ` + strconv.Itoa(TestConfig.Node.WSPort) + `,
|
"WSPort": ` + strconv.Itoa(TestConfig.Node.WSPort) + `,
|
||||||
"LogLevel": "` + errorLevel + `"
|
"LogLevel": "` + errorLevel + `",
|
||||||
|
"NoDiscovery": true,
|
||||||
|
"LightEthConfig": {
|
||||||
|
"Enabled": true
|
||||||
|
},
|
||||||
|
"WhisperConfig": {
|
||||||
|
"Enabled": true,
|
||||||
|
"DataDir": "` + path.Join(testDir, "wnode") + `",
|
||||||
|
"EnableNTPSync": false
|
||||||
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
nodeConfig, err := params.LoadNodeConfig(configJSON)
|
nodeConfig, err := params.NewConfigFromJSON(configJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
nodeConfig.WhisperConfig.EnableNTPSync = false
|
|
||||||
|
|
||||||
return nodeConfig, nil
|
return nodeConfig, nil
|
||||||
}
|
}
|
||||||
|
@ -264,14 +274,30 @@ func MakeTestNodeConfig(networkID int) (*params.NodeConfig, error) {
|
||||||
// where specific network addresses are assigned based on provided network id, and assigns
|
// where specific network addresses are assigned based on provided network id, and assigns
|
||||||
// a given name and data dir.
|
// a given name and data dir.
|
||||||
func MakeTestNodeConfigWithDataDir(name, dataDir, fleet string, networkID uint64) (*params.NodeConfig, error) {
|
func MakeTestNodeConfigWithDataDir(name, dataDir, fleet string, networkID uint64) (*params.NodeConfig, error) {
|
||||||
cfg, err := params.NewNodeConfig(dataDir, "", fleet, networkID)
|
cfg, err := params.NewNodeConfig(dataDir, fleet, networkID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cfg.Name = name
|
if name == "" {
|
||||||
cfg.NetworkID = uint64(GetNetworkID())
|
cfg.Name = "test"
|
||||||
|
} else {
|
||||||
|
cfg.Name = name
|
||||||
|
}
|
||||||
|
cfg.NoDiscovery = true
|
||||||
cfg.LightEthConfig.Enabled = false
|
cfg.LightEthConfig.Enabled = false
|
||||||
|
cfg.WhisperConfig.Enabled = true
|
||||||
cfg.WhisperConfig.EnableNTPSync = false
|
cfg.WhisperConfig.EnableNTPSync = false
|
||||||
|
if dataDir != "" {
|
||||||
|
cfg.KeyStoreDir = path.Join(dataDir, "keystore")
|
||||||
|
cfg.WhisperConfig.DataDir = path.Join(dataDir, "wnode")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only attempt to validate if a dataDir is specified, we only support in-memory DB for tests
|
||||||
|
if dataDir != "" {
|
||||||
|
if err := cfg.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
@ -299,19 +325,19 @@ const passphraseEnvName = "ACCOUNT_PASSWORD"
|
||||||
func loadTestConfig() (*testConfig, error) {
|
func loadTestConfig() (*testConfig, error) {
|
||||||
var config testConfig
|
var config testConfig
|
||||||
|
|
||||||
pathOfStatic := path.Join(params.GetStatusHome(), "/static")
|
pathOfConfig := path.Join(params.GetStatusHome(), "/t/config")
|
||||||
err := getTestConfigFromFile(path.Join(pathOfStatic, "config/test-data.json"), &config)
|
err := getTestConfigFromFile(path.Join(pathOfConfig, "test-data.json"), &config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if GetNetworkID() == params.StatusChainNetworkID {
|
if GetNetworkID() == params.StatusChainNetworkID {
|
||||||
err := getTestConfigFromFile(path.Join(pathOfStatic, "config/status-chain-accounts.json"), &config)
|
err := getTestConfigFromFile(path.Join(pathOfConfig, "status-chain-accounts.json"), &config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err := getTestConfigFromFile(path.Join(pathOfStatic, "config/public-chain-accounts.json"), &config)
|
err := getTestConfigFromFile(path.Join(pathOfConfig, "public-chain-accounts.json"), &config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ func (s *TransactorSuite) SetupTest() {
|
||||||
rpcClient, _ := rpc.NewClient(s.client, params.UpstreamRPCConfig{})
|
rpcClient, _ := rpc.NewClient(s.client, params.UpstreamRPCConfig{})
|
||||||
// expected by simulated backend
|
// expected by simulated backend
|
||||||
chainID := gethparams.AllEthashProtocolChanges.ChainID.Uint64()
|
chainID := gethparams.AllEthashProtocolChanges.ChainID.Uint64()
|
||||||
nodeConfig, err := params.NewNodeConfig("/tmp", "", params.FleetBeta, chainID)
|
nodeConfig, err := MakeTestNodeConfigWithDataDir("", "/tmp", params.FleetBeta, chainID)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.nodeConfig = nodeConfig
|
s.nodeConfig = nodeConfig
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue