Allow to start ephemeral StatusNode (#829)
This change will greatly simplify writing unit tests when a node is required but data persistence is irrelevant. I also Introduced some refactoring and unit tests for `StatusNode`.
This commit is contained in:
parent
ef160e8720
commit
364f88efd9
|
@ -164,7 +164,7 @@ func main() {
|
|||
exitCode := syncAndStopNode(interruptCh, backend.StatusNode(), *syncAndExit)
|
||||
// Call was interrupted. Wait for graceful shutdown.
|
||||
if exitCode == -1 {
|
||||
if node, err := backend.StatusNode().GethNode(); err == nil && node != nil {
|
||||
if node := backend.StatusNode().GethNode(); node != nil {
|
||||
node.Wait()
|
||||
}
|
||||
return
|
||||
|
@ -173,15 +173,12 @@ func main() {
|
|||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
node, err := backend.StatusNode().GethNode()
|
||||
if err != nil {
|
||||
logger.Error("Getting node failed", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
node := backend.StatusNode().GethNode()
|
||||
if node != nil {
|
||||
// wait till node has been stopped
|
||||
node.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// startDebug starts the debugging API server.
|
||||
func startDebug(backend *api.StatusBackend) error {
|
||||
|
@ -195,9 +192,9 @@ func startCollectingStats(interruptCh <-chan struct{}, statusNode *node.StatusNo
|
|||
|
||||
logger.Info("Starting stats", "stats", *statsAddr)
|
||||
|
||||
node, err := statusNode.GethNode()
|
||||
if err != nil {
|
||||
logger.Error("Failed to run metrics because could not get node", "error", err)
|
||||
node := statusNode.GethNode()
|
||||
if node == nil {
|
||||
logger.Error("Failed to run metrics because it could not get the node")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -112,12 +112,6 @@ func (b *StatusBackend) startNode(config *params.NodeConfig) (err error) {
|
|||
|
||||
err = b.statusNode.Start(config)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case node.RPCClientError:
|
||||
err = fmt.Errorf("%v: %v", node.ErrRPCClient, err)
|
||||
case node.EthNodeError:
|
||||
err = fmt.Errorf("%v: %v", node.ErrNodeStartFailure, err)
|
||||
}
|
||||
signal.Send(signal.Envelope{
|
||||
Type: signal.EventNodeCrashed,
|
||||
Event: signal.NodeCrashEvent{
|
||||
|
@ -162,11 +156,7 @@ func (b *StatusBackend) RestartNode() error {
|
|||
if !b.IsNodeRunning() {
|
||||
return node.ErrNoRunningNode
|
||||
}
|
||||
config, err := b.statusNode.Config()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newcfg := *config
|
||||
newcfg := *(b.statusNode.Config())
|
||||
if err := b.stopNode(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -178,11 +168,7 @@ func (b *StatusBackend) RestartNode() error {
|
|||
func (b *StatusBackend) ResetChainData() error {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
config, err := b.statusNode.Config()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newcfg := *config
|
||||
newcfg := *(b.statusNode.Config())
|
||||
if err := b.stopNode(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -217,10 +203,7 @@ func (b *StatusBackend) getVerifiedAccount(password string) (*account.SelectedEx
|
|||
b.log.Error("failed to get a selected account", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
config, err := b.StatusNode().Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config := b.StatusNode().Config()
|
||||
_, err = b.accountManager.VerifyAccountPassword(config.KeyStoreDir, selectedAccount.Address.String(), password)
|
||||
if err != nil {
|
||||
b.log.Error("failed to verify account", "account", selectedAccount.Address.String(), "error", err)
|
||||
|
@ -269,7 +252,7 @@ func (b *StatusBackend) DiscardTransactions(ids []string) map[string]error {
|
|||
func (b *StatusBackend) registerHandlers() error {
|
||||
rpcClient := b.StatusNode().RPCClient()
|
||||
if rpcClient == nil {
|
||||
return node.ErrRPCClient
|
||||
return errors.New("RPC client unavailable")
|
||||
}
|
||||
|
||||
rpcClient.RegisterHandler(params.AccountsMethodName, func(context.Context, ...interface{}) (interface{}, error) {
|
||||
|
|
|
@ -27,14 +27,11 @@ import (
|
|||
"github.com/status-im/status-go/shhext"
|
||||
)
|
||||
|
||||
// node-related errors
|
||||
// Errors related to node and services creation.
|
||||
var (
|
||||
ErrEthServiceRegistrationFailure = errors.New("failed to register the Ethereum service")
|
||||
ErrNodeMakeFailure = errors.New("error creating p2p node")
|
||||
ErrWhisperServiceRegistrationFailure = errors.New("failed to register the Whisper service")
|
||||
ErrLightEthRegistrationFailure = errors.New("failed to register the LES service")
|
||||
ErrNodeMakeFailure = errors.New("error creating p2p node")
|
||||
ErrNodeRunFailure = errors.New("error running p2p node")
|
||||
ErrNodeStartFailure = errors.New("error starting p2p node")
|
||||
)
|
||||
|
||||
// All general log messages in this package should be routed through this logger.
|
||||
|
@ -42,17 +39,20 @@ var logger = log.New("package", "status-go/geth/node")
|
|||
|
||||
// MakeNode create a geth node entity
|
||||
func MakeNode(config *params.NodeConfig) (*node.Node, error) {
|
||||
// If DataDir is empty, it means we want to create an ephemeral node
|
||||
// keeping data only in memory.
|
||||
if config.DataDir != "" {
|
||||
// make sure data directory exists
|
||||
if err := os.MkdirAll(filepath.Join(config.DataDir), os.ModePerm); err != nil {
|
||||
return nil, err
|
||||
if err := os.MkdirAll(filepath.Clean(config.DataDir), os.ModePerm); err != nil {
|
||||
return nil, fmt.Errorf("make node: make data directory: %v", err)
|
||||
}
|
||||
|
||||
// make sure keys directory exists
|
||||
if err := os.MkdirAll(filepath.Join(config.KeyStoreDir), os.ModePerm); err != nil {
|
||||
return nil, err
|
||||
if err := os.MkdirAll(filepath.Clean(config.KeyStoreDir), os.ModePerm); err != nil {
|
||||
return nil, fmt.Errorf("make node: make keys directory: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// configure required node (should you need to update node's config, e.g. add bootstrap nodes, see node.Config)
|
||||
stackConfig := defaultEmbeddedNodeConfig(config)
|
||||
|
||||
if len(config.NodeKeyFile) > 0 {
|
||||
|
@ -71,14 +71,14 @@ func MakeNode(config *params.NodeConfig) (*node.Node, error) {
|
|||
return nil, ErrNodeMakeFailure
|
||||
}
|
||||
|
||||
// Start Ethereum service if we are not expected to use an upstream server.
|
||||
// start Ethereum service if we are not expected to use an upstream server
|
||||
if !config.UpstreamConfig.Enabled {
|
||||
if err := activateEthService(stack, config); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", ErrEthServiceRegistrationFailure, err)
|
||||
if err := activateLightEthService(stack, config); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", ErrLightEthRegistrationFailure, err)
|
||||
}
|
||||
}
|
||||
|
||||
// start Whisper service
|
||||
// start Whisper service.
|
||||
if err := activateShhService(stack, config); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", ErrWhisperServiceRegistrationFailure, err)
|
||||
}
|
||||
|
@ -104,13 +104,9 @@ func defaultEmbeddedNodeConfig(config *params.NodeConfig) *node.Config {
|
|||
MaxPendingPeers: config.MaxPendingPeers,
|
||||
},
|
||||
IPCPath: makeIPCPath(config),
|
||||
HTTPCors: []string{"*"},
|
||||
HTTPCors: nil,
|
||||
HTTPModules: config.FormatAPIModules(),
|
||||
HTTPVirtualHosts: []string{"localhost"},
|
||||
WSHost: makeWSHost(config),
|
||||
WSPort: config.WSPort,
|
||||
WSOrigins: []string{"*"},
|
||||
WSModules: config.FormatAPIModules(),
|
||||
}
|
||||
|
||||
if config.RPCEnabled {
|
||||
|
@ -118,7 +114,7 @@ func defaultEmbeddedNodeConfig(config *params.NodeConfig) *node.Config {
|
|||
nc.HTTPPort = config.HTTPPort
|
||||
}
|
||||
|
||||
if config.ClusterConfig.Enabled {
|
||||
if config.ClusterConfig != nil && config.ClusterConfig.Enabled {
|
||||
nc.P2P.StaticNodes = parseNodes(config.ClusterConfig.StaticNodes)
|
||||
nc.P2P.BootstrapNodesV5 = parseNodesV5(config.ClusterConfig.BootNodes)
|
||||
}
|
||||
|
@ -126,9 +122,9 @@ func defaultEmbeddedNodeConfig(config *params.NodeConfig) *node.Config {
|
|||
return nc
|
||||
}
|
||||
|
||||
// activateEthService configures and registers the eth.Ethereum service with a given node.
|
||||
func activateEthService(stack *node.Node, config *params.NodeConfig) error {
|
||||
if !config.LightEthConfig.Enabled {
|
||||
// activateLightEthService configures and registers the eth.Ethereum service with a given node.
|
||||
func activateLightEthService(stack *node.Node, config *params.NodeConfig) error {
|
||||
if config.LightEthConfig == nil || !config.LightEthConfig.Enabled {
|
||||
logger.Info("LES protocol is disabled")
|
||||
return nil
|
||||
}
|
||||
|
@ -147,18 +143,14 @@ func activateEthService(stack *node.Node, config *params.NodeConfig) error {
|
|||
ethConf.NetworkId = config.NetworkID
|
||||
ethConf.DatabaseCache = config.LightEthConfig.DatabaseCache
|
||||
|
||||
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
||||
return stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
||||
return les.New(ctx, ðConf)
|
||||
}); err != nil {
|
||||
return fmt.Errorf("%v: %v", ErrLightEthRegistrationFailure, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// activateShhService configures Whisper and adds it to the given node.
|
||||
func activateShhService(stack *node.Node, config *params.NodeConfig) (err error) {
|
||||
if !config.WhisperConfig.Enabled {
|
||||
if config.WhisperConfig == nil || !config.WhisperConfig.Enabled {
|
||||
logger.Info("SHH protocol is disabled")
|
||||
return nil
|
||||
}
|
||||
|
@ -239,15 +231,6 @@ func makeIPCPath(config *params.NodeConfig) string {
|
|||
return path.Join(config.DataDir, config.IPCFile)
|
||||
}
|
||||
|
||||
// makeWSHost returns WS-RPC Server host, given enabled/disabled flag
|
||||
func makeWSHost(config *params.NodeConfig) string {
|
||||
if !config.WSEnabled {
|
||||
return ""
|
||||
}
|
||||
|
||||
return config.WSHost
|
||||
}
|
||||
|
||||
// parseNodes creates list of discover.Node out of enode strings.
|
||||
func parseNodes(enodes []string) []*discover.Node {
|
||||
nodes := make([]*discover.Node, len(enodes))
|
||||
|
|
|
@ -5,26 +5,25 @@ import (
|
|||
|
||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
||||
|
||||
. "github.com/status-im/status-go/t/utils"
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWhisperLightModeEnabledSetsEmptyBloomFilter(t *testing.T) {
|
||||
config, err := MakeTestNodeConfig(GetNetworkID())
|
||||
require.NoError(t, err)
|
||||
config.WhisperConfig.LightClient = true
|
||||
|
||||
node, nodeErr := MakeNode(config)
|
||||
require.NoError(t, nodeErr)
|
||||
require.NoError(t, node.Start())
|
||||
config := params.NodeConfig{
|
||||
WhisperConfig: ¶ms.WhisperConfig{
|
||||
Enabled: true,
|
||||
LightClient: true,
|
||||
},
|
||||
}
|
||||
node := New()
|
||||
require.NoError(t, node.Start(&config))
|
||||
defer func() {
|
||||
err := node.Stop()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, node.Stop())
|
||||
}()
|
||||
|
||||
var whisper *whisper.Whisper
|
||||
err = node.Service(&whisper)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, node.gethService(&whisper))
|
||||
|
||||
bloomFilter := whisper.BloomFilter()
|
||||
expectedEmptyBloomFilter := make([]byte, 64)
|
||||
|
@ -33,20 +32,19 @@ func TestWhisperLightModeEnabledSetsEmptyBloomFilter(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWhisperLightModeEnabledSetsNilBloomFilter(t *testing.T) {
|
||||
config, err := MakeTestNodeConfig(GetNetworkID())
|
||||
require.NoError(t, err)
|
||||
config.WhisperConfig.LightClient = false
|
||||
|
||||
node, nodeErr := MakeNode(config)
|
||||
require.NoError(t, nodeErr)
|
||||
require.NoError(t, node.Start())
|
||||
config := params.NodeConfig{
|
||||
WhisperConfig: ¶ms.WhisperConfig{
|
||||
Enabled: true,
|
||||
LightClient: false,
|
||||
},
|
||||
}
|
||||
node := New()
|
||||
require.NoError(t, node.Start(&config))
|
||||
defer func() {
|
||||
err := node.Stop()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, node.Stop())
|
||||
}()
|
||||
|
||||
var whisper *whisper.Whisper
|
||||
err = node.Service(&whisper)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, node.gethService(&whisper))
|
||||
require.Nil(t, whisper.BloomFilter())
|
||||
}
|
||||
|
|
|
@ -24,23 +24,17 @@ import (
|
|||
"github.com/status-im/status-go/geth/rpc"
|
||||
)
|
||||
|
||||
// tickerResolution is the delta to check blockchain sync progress.
|
||||
const tickerResolution = time.Second
|
||||
|
||||
// errors
|
||||
var (
|
||||
ErrNodeExists = errors.New("node is already running")
|
||||
ErrNodeRunning = errors.New("node is already running")
|
||||
ErrNoGethNode = errors.New("geth node is not available")
|
||||
ErrNoRunningNode = errors.New("there is no running node")
|
||||
ErrInvalidStatusNode = errors.New("status node is not properly initialized")
|
||||
ErrInvalidService = errors.New("service is unavailable")
|
||||
ErrInvalidAccountManager = errors.New("could not retrieve account manager")
|
||||
ErrAccountKeyStoreMissing = errors.New("account key store is not set")
|
||||
ErrRPCClient = errors.New("failed to init RPC client")
|
||||
)
|
||||
|
||||
// RPCClientError reported when rpc client is initialized.
|
||||
type RPCClientError error
|
||||
|
||||
// EthNodeError is reported when node crashed on start up.
|
||||
type EthNodeError error
|
||||
|
||||
// StatusNode abstracts contained geth node and provides helper methods to
|
||||
// interact with it.
|
||||
type StatusNode struct {
|
||||
|
@ -65,52 +59,67 @@ func New() *StatusNode {
|
|||
}
|
||||
}
|
||||
|
||||
// Config exposes reference to running node's configuration
|
||||
func (n *StatusNode) Config() *params.NodeConfig {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
return n.config
|
||||
}
|
||||
|
||||
// GethNode returns underlying geth node.
|
||||
func (n *StatusNode) GethNode() *node.Node {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
return n.gethNode
|
||||
}
|
||||
|
||||
// Start starts current StatusNode, will fail if it's already started.
|
||||
func (n *StatusNode) Start(config *params.NodeConfig, services ...node.ServiceConstructor) error {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
if err := n.isAvailable(); err == nil {
|
||||
return ErrNodeExists
|
||||
if n.isRunning() {
|
||||
return ErrNodeRunning
|
||||
}
|
||||
|
||||
return n.start(config, services)
|
||||
}
|
||||
|
||||
// start starts current StatusNode, will fail if it's already started.
|
||||
func (n *StatusNode) start(config *params.NodeConfig, services []node.ServiceConstructor) error {
|
||||
ethNode, err := MakeNode(config)
|
||||
if err != nil {
|
||||
if err := n.createNode(config); err != nil {
|
||||
return err
|
||||
}
|
||||
n.gethNode = ethNode
|
||||
n.config = config
|
||||
|
||||
for _, service := range services {
|
||||
if err := ethNode.Register(service); err != nil {
|
||||
if err := n.start(services); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// start underlying node
|
||||
if err := ethNode.Start(); err != nil {
|
||||
return EthNodeError(err)
|
||||
}
|
||||
|
||||
// init RPC client for this node
|
||||
if err := n.setupRPCClient(); err != nil {
|
||||
n.log.Error("Failed to create an RPC client", "error", err)
|
||||
return RPCClientError(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// start peer pool only if Discovery V5 is enabled
|
||||
if ethNode.Server().DiscV5 != nil {
|
||||
if n.gethNode.Server().DiscV5 != nil {
|
||||
return n.startPeerPool()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *StatusNode) createNode(config *params.NodeConfig) (err error) {
|
||||
n.gethNode, err = MakeNode(config)
|
||||
return
|
||||
}
|
||||
|
||||
// start starts current StatusNode, will fail if it's already started.
|
||||
func (n *StatusNode) start(services []node.ServiceConstructor) error {
|
||||
for _, service := range services {
|
||||
if err := n.gethNode.Register(service); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return n.gethNode.Start()
|
||||
}
|
||||
|
||||
func (n *StatusNode) setupRPCClient() (err error) {
|
||||
// setup public RPC client
|
||||
gethNodeClient, err := n.gethNode.AttachPublic()
|
||||
|
@ -157,45 +166,58 @@ func (n *StatusNode) startPeerPool() error {
|
|||
func (n *StatusNode) Stop() error {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
if !n.isRunning() {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
|
||||
return n.stop()
|
||||
}
|
||||
|
||||
// stop will stop current StatusNode. A stopped node cannot be resumed.
|
||||
func (n *StatusNode) stop() error {
|
||||
if err := n.isAvailable(); err != nil {
|
||||
return err
|
||||
}
|
||||
if n.gethNode.Server().DiscV5 != nil {
|
||||
n.stopPeerPool()
|
||||
if err := n.stopPeerPool(); err != nil {
|
||||
n.log.Error("Error stopping the PeerPool", "error", err)
|
||||
}
|
||||
n.register = nil
|
||||
n.peerPool = nil
|
||||
n.db = nil
|
||||
|
||||
if err := n.gethNode.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
n.gethNode = nil
|
||||
n.config = nil
|
||||
|
||||
n.rpcClient = nil
|
||||
n.rpcPrivateClient = nil
|
||||
// We need to clear `gethNode` because config is passed to `Start()`
|
||||
// and may be completely different. Similarly with `config`.
|
||||
n.gethNode = nil
|
||||
n.config = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *StatusNode) stopPeerPool() error {
|
||||
if n.gethNode.Server().DiscV5 == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *StatusNode) stopPeerPool() {
|
||||
n.register.Stop()
|
||||
n.peerPool.Stop()
|
||||
if err := n.db.Close(); err != nil {
|
||||
n.log.Error("error closing status db", "error", err)
|
||||
}
|
||||
return n.db.Close()
|
||||
}
|
||||
|
||||
// ResetChainData removes chain data if node is not running.
|
||||
func (n *StatusNode) ResetChainData(config *params.NodeConfig) error {
|
||||
if n.IsRunning() {
|
||||
return ErrNodeExists
|
||||
}
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
if n.isRunning() {
|
||||
return ErrNodeRunning
|
||||
}
|
||||
|
||||
chainDataDir := filepath.Join(config.DataDir, config.Name, "lightchaindata")
|
||||
if _, err := os.Stat(chainDataDir); os.IsNotExist(err) {
|
||||
// is it really an error, if we want to remove it as next step?
|
||||
return err
|
||||
}
|
||||
err := os.RemoveAll(chainDataDir)
|
||||
|
@ -210,38 +232,24 @@ func (n *StatusNode) IsRunning() bool {
|
|||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
if err := n.isAvailable(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return n.isRunning()
|
||||
}
|
||||
|
||||
// GethNode returns underlying geth node.
|
||||
func (n *StatusNode) GethNode() (*node.Node, error) {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
if err := n.isAvailable(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return n.gethNode, nil
|
||||
func (n *StatusNode) isRunning() bool {
|
||||
return n.gethNode != nil && n.gethNode.Server() != nil
|
||||
}
|
||||
|
||||
// populateStaticPeers connects current node with our publicly available LES/SHH/Swarm cluster
|
||||
func (n *StatusNode) populateStaticPeers() error {
|
||||
if err := n.isAvailable(); err != nil {
|
||||
return err
|
||||
}
|
||||
if !n.config.ClusterConfig.Enabled {
|
||||
if n.config.ClusterConfig == nil || !n.config.ClusterConfig.Enabled {
|
||||
n.log.Info("Static peers are disabled")
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, enode := range n.config.ClusterConfig.StaticNodes {
|
||||
err := n.addPeer(enode)
|
||||
if err != nil {
|
||||
n.log.Warn("Static peer addition failed", "error", err)
|
||||
continue
|
||||
if err := n.addPeer(enode); err != nil {
|
||||
n.log.Error("Static peer addition failed", "error", err)
|
||||
return err
|
||||
}
|
||||
n.log.Info("Static peer added", "enode", enode)
|
||||
}
|
||||
|
@ -250,18 +258,14 @@ func (n *StatusNode) populateStaticPeers() error {
|
|||
}
|
||||
|
||||
func (n *StatusNode) removeStaticPeers() error {
|
||||
if !n.config.ClusterConfig.Enabled {
|
||||
if n.config.ClusterConfig == nil || !n.config.ClusterConfig.Enabled {
|
||||
n.log.Info("Static peers are disabled")
|
||||
return nil
|
||||
}
|
||||
server := n.gethNode.Server()
|
||||
if server == nil {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
|
||||
for _, enode := range n.config.ClusterConfig.StaticNodes {
|
||||
err := n.removePeer(enode)
|
||||
if err != nil {
|
||||
n.log.Warn("Static peer deletion failed", "error", err)
|
||||
if err := n.removePeer(enode); err != nil {
|
||||
n.log.Error("Static peer deletion failed", "error", err)
|
||||
return err
|
||||
}
|
||||
n.log.Info("Static peer deleted", "enode", enode)
|
||||
|
@ -273,9 +277,15 @@ func (n *StatusNode) removeStaticPeers() error {
|
|||
func (n *StatusNode) ReconnectStaticPeers() error {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
if !n.isRunning() {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
|
||||
if err := n.removeStaticPeers(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return n.populateStaticPeers()
|
||||
}
|
||||
|
||||
|
@ -283,20 +293,23 @@ func (n *StatusNode) ReconnectStaticPeers() error {
|
|||
func (n *StatusNode) AddPeer(url string) error {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
if err := n.isAvailable(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return n.addPeer(url)
|
||||
}
|
||||
|
||||
// addPeer adds new static peer node
|
||||
func (n *StatusNode) addPeer(url string) error {
|
||||
// Try to add the url as a static peer and return
|
||||
parsedNode, err := discover.ParseNode(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !n.isRunning() {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
|
||||
n.gethNode.Server().AddPeer(parsedNode)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -305,38 +318,37 @@ func (n *StatusNode) removePeer(url string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !n.isRunning() {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
|
||||
n.gethNode.Server().RemovePeer(parsedNode)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PeerCount returns the number of connected peers.
|
||||
func (n *StatusNode) PeerCount() int {
|
||||
if !n.IsRunning() {
|
||||
return 0
|
||||
}
|
||||
return n.gethNode.Server().PeerCount()
|
||||
}
|
||||
|
||||
// Config exposes reference to running node's configuration
|
||||
func (n *StatusNode) Config() (*params.NodeConfig, error) {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
if err := n.isAvailable(); err != nil {
|
||||
return nil, err
|
||||
if !n.isRunning() {
|
||||
return 0
|
||||
}
|
||||
return n.config, nil
|
||||
|
||||
return n.gethNode.Server().PeerCount()
|
||||
}
|
||||
|
||||
// gethService is a wrapper for gethNode.Service which retrieves a currently
|
||||
// running service registered of a specific type.
|
||||
func (n *StatusNode) gethService(serviceInstance interface{}, serviceName string) error {
|
||||
if err := n.isAvailable(); err != nil {
|
||||
return err
|
||||
func (n *StatusNode) gethService(serviceInstance interface{}) error {
|
||||
if !n.isRunning() {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
if err := n.gethNode.Service(serviceInstance); err != nil || serviceInstance == nil {
|
||||
n.log.Warn("Cannot obtain ", serviceName, " service", "error", err)
|
||||
return ErrInvalidService
|
||||
|
||||
if err := n.gethNode.Service(serviceInstance); err != nil {
|
||||
return fmt.Errorf("service unavailable: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -344,12 +356,12 @@ func (n *StatusNode) gethService(serviceInstance interface{}, serviceName string
|
|||
|
||||
// LightEthereumService exposes reference to LES service running on top of the node
|
||||
func (n *StatusNode) LightEthereumService() (l *les.LightEthereum, err error) {
|
||||
return l, n.gethService(&l, "LES")
|
||||
return l, n.gethService(&l)
|
||||
}
|
||||
|
||||
// WhisperService exposes reference to Whisper service running on top of the node
|
||||
func (n *StatusNode) WhisperService() (w *whisper.Whisper, err error) {
|
||||
return w, n.gethService(&w, "whisper")
|
||||
return w, n.gethService(&w)
|
||||
}
|
||||
|
||||
// AccountManager exposes reference to node's accounts manager
|
||||
|
@ -357,14 +369,11 @@ func (n *StatusNode) AccountManager() (*accounts.Manager, error) {
|
|||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
if err := n.isAvailable(); err != nil {
|
||||
return nil, err
|
||||
if n.gethNode == nil {
|
||||
return nil, ErrNoGethNode
|
||||
}
|
||||
accountManager := n.gethNode.AccountManager()
|
||||
if accountManager == nil {
|
||||
return nil, ErrInvalidAccountManager
|
||||
}
|
||||
return accountManager, nil
|
||||
|
||||
return n.gethNode.AccountManager(), nil
|
||||
}
|
||||
|
||||
// AccountKeyStore exposes reference to accounts key store
|
||||
|
@ -372,14 +381,11 @@ func (n *StatusNode) AccountKeyStore() (*keystore.KeyStore, error) {
|
|||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
if err := n.isAvailable(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accountManager := n.gethNode.AccountManager()
|
||||
if accountManager == nil {
|
||||
return nil, ErrInvalidAccountManager
|
||||
if n.gethNode == nil {
|
||||
return nil, ErrNoGethNode
|
||||
}
|
||||
|
||||
accountManager := n.gethNode.AccountManager()
|
||||
backends := accountManager.Backends(keystore.KeyStoreType)
|
||||
if len(backends) == 0 {
|
||||
return nil, ErrAccountKeyStoreMissing
|
||||
|
@ -408,23 +414,12 @@ func (n *StatusNode) RPCPrivateClient() *rpc.Client {
|
|||
return n.rpcPrivateClient
|
||||
}
|
||||
|
||||
// isAvailable check if we have a node running and make sure is fully started
|
||||
func (n *StatusNode) isAvailable() error {
|
||||
if n.gethNode == nil || n.gethNode.Server() == nil {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// tickerResolution is the delta to check blockchain sync progress.
|
||||
const tickerResolution = time.Second
|
||||
|
||||
// EnsureSync waits until blockchain synchronization
|
||||
// is complete and returns.
|
||||
func (n *StatusNode) EnsureSync(ctx context.Context) error {
|
||||
// Don't wait for any blockchain sync for the
|
||||
// local private chain as blocks are never mined.
|
||||
if n.config.NetworkID == params.StatusChainNetworkID {
|
||||
if n.config.NetworkID == 0 || n.config.NetworkID == params.StatusChainNetworkID {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
"github.com/status-im/status-go/geth/node"
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
. "github.com/status-im/status-go/t/utils"
|
||||
)
|
||||
|
||||
type TestServiceAPI struct{}
|
||||
|
@ -52,7 +51,7 @@ func (s *testService) Stop() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func createStatusNode(config *params.NodeConfig) (*node.StatusNode, error) {
|
||||
func createAndStartStatusNode(config *params.NodeConfig) (*node.StatusNode, error) {
|
||||
services := []gethnode.ServiceConstructor{
|
||||
func(_ *gethnode.ServiceContext) (gethnode.Service, error) {
|
||||
return &testService{}, nil
|
||||
|
@ -65,11 +64,9 @@ func createStatusNode(config *params.NodeConfig) (*node.StatusNode, error) {
|
|||
func TestNodeRPCClientCallOnlyPublicAPIs(t *testing.T) {
|
||||
var err error
|
||||
|
||||
config, err := MakeTestNodeConfig(GetNetworkID())
|
||||
require.NoError(t, err)
|
||||
config.APIModules = "" // no whitelisted API modules; use only public APIs
|
||||
|
||||
statusNode, err := createStatusNode(config)
|
||||
statusNode, err := createAndStartStatusNode(¶ms.NodeConfig{
|
||||
APIModules: "", // no whitelisted API modules; use only public APIs
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
err := statusNode.Stop()
|
||||
|
@ -94,11 +91,9 @@ func TestNodeRPCClientCallOnlyPublicAPIs(t *testing.T) {
|
|||
func TestNodeRPCClientCallWhitelistedPrivateService(t *testing.T) {
|
||||
var err error
|
||||
|
||||
config, err := MakeTestNodeConfig(GetNetworkID())
|
||||
require.NoError(t, err)
|
||||
config.APIModules = "pri"
|
||||
|
||||
statusNode, err := createStatusNode(config)
|
||||
statusNode, err := createAndStartStatusNode(¶ms.NodeConfig{
|
||||
APIModules: "pri",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
err := statusNode.Stop()
|
||||
|
@ -118,10 +113,7 @@ func TestNodeRPCClientCallWhitelistedPrivateService(t *testing.T) {
|
|||
func TestNodeRPCPrivateClientCallPrivateService(t *testing.T) {
|
||||
var err error
|
||||
|
||||
config, err := MakeTestNodeConfig(GetNetworkID())
|
||||
require.NoError(t, err)
|
||||
|
||||
statusNode, err := createStatusNode(config)
|
||||
statusNode, err := createAndStartStatusNode(¶ms.NodeConfig{})
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
err := statusNode.Stop()
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
package node
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/les"
|
||||
gethnode "github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
||||
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestStatusNodeStart(t *testing.T) {
|
||||
var err error
|
||||
|
||||
config := params.NodeConfig{}
|
||||
n := New()
|
||||
|
||||
// checks before node is started
|
||||
require.Nil(t, n.GethNode())
|
||||
require.Nil(t, n.Config())
|
||||
require.Nil(t, n.RPCClient())
|
||||
require.Equal(t, 0, n.PeerCount())
|
||||
_, err = n.AccountManager()
|
||||
require.EqualError(t, err, ErrNoGethNode.Error())
|
||||
_, err = n.AccountKeyStore()
|
||||
require.EqualError(t, err, ErrNoGethNode.Error())
|
||||
|
||||
// start node
|
||||
require.NoError(t, n.Start(&config))
|
||||
|
||||
// checks after node is started
|
||||
require.True(t, n.IsRunning())
|
||||
require.NotNil(t, n.GethNode())
|
||||
require.NotNil(t, n.Config())
|
||||
require.NotNil(t, n.RPCClient())
|
||||
require.Equal(t, 0, n.PeerCount())
|
||||
accountManager, err := n.AccountManager()
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, accountManager)
|
||||
keyStore, err := n.AccountKeyStore()
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, keyStore)
|
||||
// try to start already started node
|
||||
require.EqualError(t, n.Start(&config), ErrNodeRunning.Error())
|
||||
|
||||
// stop node
|
||||
require.NoError(t, n.Stop())
|
||||
// try to stop already stopped node
|
||||
require.EqualError(t, n.Stop(), ErrNoRunningNode.Error())
|
||||
|
||||
// checks after node is stopped
|
||||
require.Nil(t, n.GethNode())
|
||||
require.Nil(t, n.RPCClient())
|
||||
require.Equal(t, 0, n.PeerCount())
|
||||
_, err = n.AccountManager()
|
||||
require.EqualError(t, err, ErrNoGethNode.Error())
|
||||
_, err = n.AccountKeyStore()
|
||||
require.EqualError(t, err, ErrNoGethNode.Error())
|
||||
}
|
||||
|
||||
func TestStatusNodeWithDataDir(t *testing.T) {
|
||||
var err error
|
||||
|
||||
dir, err := ioutil.TempDir("", "status-node-test")
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
require.NoError(t, os.RemoveAll(dir))
|
||||
}()
|
||||
|
||||
// keystore directory
|
||||
keyStoreDir := path.Join(dir, "keystore")
|
||||
err = os.MkdirAll(keyStoreDir, os.ModePerm)
|
||||
require.NoError(t, err)
|
||||
|
||||
config := params.NodeConfig{
|
||||
DataDir: dir,
|
||||
KeyStoreDir: keyStoreDir,
|
||||
}
|
||||
n := New()
|
||||
|
||||
require.NoError(t, n.Start(&config))
|
||||
require.NoError(t, n.Stop())
|
||||
}
|
||||
|
||||
func TestStatusNodeServiceGetters(t *testing.T) {
|
||||
config := params.NodeConfig{
|
||||
WhisperConfig: ¶ms.WhisperConfig{
|
||||
Enabled: true,
|
||||
},
|
||||
LightEthConfig: ¶ms.LightEthConfig{
|
||||
Enabled: true,
|
||||
},
|
||||
}
|
||||
n := New()
|
||||
|
||||
var (
|
||||
instance interface{}
|
||||
err error
|
||||
)
|
||||
|
||||
services := []struct {
|
||||
getter func() (interface{}, error)
|
||||
typ reflect.Type
|
||||
}{
|
||||
{
|
||||
getter: func() (interface{}, error) {
|
||||
return n.WhisperService()
|
||||
},
|
||||
typ: reflect.TypeOf(&whisper.Whisper{}),
|
||||
},
|
||||
{
|
||||
getter: func() (interface{}, error) {
|
||||
return n.LightEthereumService()
|
||||
},
|
||||
typ: reflect.TypeOf(&les.LightEthereum{}),
|
||||
},
|
||||
}
|
||||
|
||||
for _, service := range services {
|
||||
t.Run(service.typ.String(), func(t *testing.T) {
|
||||
// checks before node is started
|
||||
instance, err = service.getter()
|
||||
require.EqualError(t, err, ErrNoRunningNode.Error())
|
||||
require.Nil(t, instance)
|
||||
|
||||
// start node
|
||||
require.NoError(t, n.Start(&config))
|
||||
|
||||
// checks after node is started
|
||||
instance, err = service.getter()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, instance)
|
||||
require.Equal(t, service.typ, reflect.TypeOf(instance))
|
||||
|
||||
// stop node
|
||||
require.NoError(t, n.Stop())
|
||||
|
||||
// checks after node is stopped
|
||||
instance, err = service.getter()
|
||||
require.EqualError(t, err, ErrNoRunningNode.Error())
|
||||
require.Nil(t, instance)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusNodeAddPeer(t *testing.T) {
|
||||
var err error
|
||||
|
||||
peer, err := gethnode.New(&gethnode.Config{
|
||||
P2P: p2p.Config{
|
||||
MaxPeers: math.MaxInt32,
|
||||
NoDiscovery: true,
|
||||
ListenAddr: ":0",
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, peer.Start())
|
||||
defer func() {
|
||||
require.NoError(t, peer.Stop())
|
||||
}()
|
||||
peerURL := peer.Server().Self().String()
|
||||
|
||||
n := New()
|
||||
|
||||
// checks before node is started
|
||||
require.EqualError(t, n.AddPeer(peerURL), ErrNoRunningNode.Error())
|
||||
|
||||
// start status node
|
||||
config := params.NodeConfig{
|
||||
MaxPeers: math.MaxInt32,
|
||||
}
|
||||
require.NoError(t, n.Start(&config))
|
||||
defer func() {
|
||||
require.NoError(t, n.Stop())
|
||||
}()
|
||||
|
||||
errCh := waitForPeerAsync(n, peerURL, time.Second*5)
|
||||
|
||||
// checks after node is started
|
||||
require.NoError(t, n.AddPeer(peerURL))
|
||||
require.NoError(t, <-errCh)
|
||||
require.Equal(t, 1, n.PeerCount())
|
||||
}
|
||||
|
||||
func TestStatusNodeReconnectStaticPeers(t *testing.T) {
|
||||
var err error
|
||||
|
||||
peer, err := gethnode.New(&gethnode.Config{
|
||||
P2P: p2p.Config{
|
||||
MaxPeers: math.MaxInt32,
|
||||
NoDiscovery: true,
|
||||
ListenAddr: ":0",
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, peer.Start())
|
||||
defer func() {
|
||||
require.NoError(t, peer.Stop())
|
||||
}()
|
||||
peerURL := peer.Server().Self().String()
|
||||
|
||||
n := New()
|
||||
|
||||
var errCh <-chan error
|
||||
|
||||
// checks before node is started
|
||||
require.EqualError(t, n.ReconnectStaticPeers(), ErrNoRunningNode.Error())
|
||||
|
||||
// start status node
|
||||
config := params.NodeConfig{
|
||||
MaxPeers: math.MaxInt32,
|
||||
ClusterConfig: ¶ms.ClusterConfig{
|
||||
Enabled: true,
|
||||
StaticNodes: []string{peerURL},
|
||||
},
|
||||
}
|
||||
errCh = waitForPeerAsync(n, peerURL, time.Second*30)
|
||||
require.NoError(t, n.Start(&config))
|
||||
defer func() {
|
||||
require.NoError(t, n.Stop())
|
||||
}()
|
||||
|
||||
// checks after node is started
|
||||
require.NoError(t, <-errCh)
|
||||
require.Equal(t, 1, n.PeerCount())
|
||||
|
||||
// reconnect static peers
|
||||
// it takes at least 30 seconds to bring back previously connected peer
|
||||
errCh = waitForPeerAsync(n, peerURL, time.Second*60)
|
||||
require.NoError(t, n.ReconnectStaticPeers(), ErrNoRunningNode.Error())
|
||||
require.NoError(t, <-errCh)
|
||||
require.Equal(t, 1, n.PeerCount())
|
||||
}
|
||||
|
||||
func waitForPeer(node *StatusNode, peerURL string, timeout time.Duration) error {
|
||||
if !node.IsRunning() {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
|
||||
parsedPeer, err := discover.ParseNode(peerURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
server := node.GethNode().Server()
|
||||
ch := make(chan *p2p.PeerEvent)
|
||||
subscription := server.SubscribeEvents(ch)
|
||||
defer subscription.Unsubscribe()
|
||||
|
||||
for {
|
||||
select {
|
||||
case ev := <-ch:
|
||||
if ev.Type == p2p.PeerEventTypeAdd && ev.Peer == parsedPeer.ID {
|
||||
return nil
|
||||
}
|
||||
case err := <-subscription.Err():
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case <-time.After(timeout):
|
||||
// it may happen that the peer is already connected
|
||||
// but even was not received
|
||||
for _, p := range node.GethNode().Server().Peers() {
|
||||
if p.ID() == parsedPeer.ID {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return errors.New("wait for peer: timeout")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func waitForPeerAsync(node *StatusNode, peerURL string, timeout time.Duration) <-chan error {
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
errCh <- waitForPeer(node, peerURL, timeout)
|
||||
}()
|
||||
|
||||
return errCh
|
||||
}
|
|
@ -248,15 +248,6 @@ type NodeConfig struct {
|
|||
// HTTPPort is the TCP port number on which to start the Geth's HTTP RPC server.
|
||||
HTTPPort int
|
||||
|
||||
// WSHost is a host interface for the WebSocket RPC server
|
||||
WSHost string
|
||||
|
||||
// WSPort is the TCP port number on which to start the Geth's WebSocket RPC server.
|
||||
WSPort int
|
||||
|
||||
// WSEnabled specifies whether WS-RPC Server is enabled or not
|
||||
WSEnabled bool
|
||||
|
||||
// IPCFile is filename of exposed IPC RPC Server
|
||||
IPCFile string
|
||||
|
||||
|
@ -322,8 +313,6 @@ func NewNodeConfig(dataDir string, clstrCfgFile string, networkID uint64, devMod
|
|||
HTTPPort: HTTPPort,
|
||||
ListenAddr: ListenAddr,
|
||||
APIModules: APIModules,
|
||||
WSHost: WSHost,
|
||||
WSPort: WSPort,
|
||||
MaxPeers: MaxPeers,
|
||||
MaxPendingPeers: MaxPendingPeers,
|
||||
IPCFile: IPCFile,
|
||||
|
|
|
@ -144,8 +144,6 @@ var loadConfigTestCases = []struct {
|
|||
require.Equal(t, params.HTTPPort, nodeConfig.HTTPPort)
|
||||
require.Equal(t, params.HTTPHost, nodeConfig.HTTPHost)
|
||||
require.True(t, nodeConfig.RPCEnabled)
|
||||
require.False(t, nodeConfig.WSEnabled)
|
||||
require.Equal(t, 4242, nodeConfig.WSPort)
|
||||
require.True(t, nodeConfig.IPCEnabled)
|
||||
require.Equal(t, 64, nodeConfig.LightEthConfig.DatabaseCache)
|
||||
},
|
||||
|
|
|
@ -32,9 +32,6 @@ const (
|
|||
// APIModules is a list of modules to expose via any type of RPC (HTTP, IPC, in-proc)
|
||||
APIModules = "eth,net,web3,shh,shhext"
|
||||
|
||||
// WSHost is a host interface for the websocket RPC server
|
||||
WSHost = "localhost"
|
||||
|
||||
// SendTransactionMethodName defines the name for a giving transaction.
|
||||
SendTransactionMethodName = "eth_sendTransaction"
|
||||
|
||||
|
@ -44,9 +41,6 @@ const (
|
|||
// PersonalSignMethodName defines the name for `personal.sign` API.
|
||||
PersonalSignMethodName = "personal_sign"
|
||||
|
||||
// WSPort is a WS-RPC port (replaced in unit tests)
|
||||
WSPort = 8546
|
||||
|
||||
// MaxPeers is the maximum number of global peers
|
||||
MaxPeers = 25
|
||||
|
||||
|
|
|
@ -65,8 +65,8 @@ func (s *PeersTestSuite) TestStaticPeersReconnect() {
|
|||
// both on rinkeby and ropsten we can expect atleast 2 peers connected
|
||||
expectedPeersCount := 2
|
||||
events := make(chan *p2p.PeerEvent, 10)
|
||||
node, err := s.backend.StatusNode().GethNode()
|
||||
s.Require().NoError(err)
|
||||
node := s.backend.StatusNode().GethNode()
|
||||
s.Require().NotNil(node)
|
||||
|
||||
subscription := node.Server().SubscribeEvents(events)
|
||||
defer subscription.Unsubscribe()
|
||||
|
|
|
@ -219,8 +219,8 @@ func (s *AccountsTestSuite) TestSelectedAccountOnRestart() {
|
|||
s.NoError(s.Backend.SelectAccount(address2, TestConfig.Account1.Password))
|
||||
|
||||
// stop node (and all of its sub-protocols)
|
||||
nodeConfig, err := s.Backend.StatusNode().Config()
|
||||
s.NoError(err)
|
||||
nodeConfig := s.Backend.StatusNode().Config()
|
||||
s.NotNil(nodeConfig)
|
||||
preservedNodeConfig := *nodeConfig
|
||||
s.NoError(s.Backend.StopNode())
|
||||
|
||||
|
|
|
@ -46,16 +46,16 @@ func (s *ManagerTestSuite) TestReferencesWithoutStartedNode() {
|
|||
{
|
||||
"non-null manager, no running node, get NodeConfig",
|
||||
func() (interface{}, error) {
|
||||
return s.StatusNode.Config()
|
||||
return s.StatusNode.Config(), nil
|
||||
},
|
||||
node.ErrNoRunningNode,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"non-null manager, no running node, get Node",
|
||||
func() (interface{}, error) {
|
||||
return s.StatusNode.GethNode()
|
||||
return s.StatusNode.GethNode(), nil
|
||||
},
|
||||
node.ErrNoRunningNode,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"non-null manager, no running node, get LES",
|
||||
|
@ -76,14 +76,14 @@ func (s *ManagerTestSuite) TestReferencesWithoutStartedNode() {
|
|||
func() (interface{}, error) {
|
||||
return s.StatusNode.AccountManager()
|
||||
},
|
||||
node.ErrNoRunningNode,
|
||||
node.ErrNoGethNode,
|
||||
},
|
||||
{
|
||||
"non-null manager, no running node, get AccountKeyStore",
|
||||
func() (interface{}, error) {
|
||||
return s.StatusNode.AccountKeyStore()
|
||||
},
|
||||
node.ErrNoRunningNode,
|
||||
node.ErrNoGethNode,
|
||||
},
|
||||
{
|
||||
"non-null manager, no running node, get RPC Client",
|
||||
|
@ -116,14 +116,14 @@ func (s *ManagerTestSuite) TestReferencesWithStartedNode() {
|
|||
{
|
||||
"node is running, get NodeConfig",
|
||||
func() (interface{}, error) {
|
||||
return s.StatusNode.Config()
|
||||
return s.StatusNode.Config(), nil
|
||||
},
|
||||
¶ms.NodeConfig{},
|
||||
},
|
||||
{
|
||||
"node is running, get Node",
|
||||
func() (interface{}, error) {
|
||||
return s.StatusNode.GethNode()
|
||||
return s.StatusNode.GethNode(), nil
|
||||
},
|
||||
&gethnode.Node{},
|
||||
},
|
||||
|
@ -188,7 +188,7 @@ func (s *ManagerTestSuite) TestNodeStartStop() {
|
|||
s.True(s.StatusNode.IsRunning())
|
||||
|
||||
// try starting another node (w/o stopping the previously started node)
|
||||
s.Equal(node.ErrNodeExists, s.StatusNode.Start(nodeConfig))
|
||||
s.Equal(node.ErrNodeRunning, s.StatusNode.Start(nodeConfig))
|
||||
|
||||
// now stop node
|
||||
time.Sleep(100 * time.Millisecond) //https://github.com/status-im/status-go/issues/429#issuecomment-339663163
|
||||
|
|
|
@ -40,7 +40,6 @@ func (s *RPCTestSuite) TestCallRPC() {
|
|||
s.NoError(err)
|
||||
|
||||
nodeConfig.IPCEnabled = false
|
||||
nodeConfig.WSEnabled = false
|
||||
nodeConfig.HTTPHost = "" // to make sure that no HTTP interface is started
|
||||
|
||||
if upstreamEnabled {
|
||||
|
|
|
@ -29,9 +29,9 @@ func WithDataDir(path string) TestNodeOption {
|
|||
// FirstBlockHash validates Attach operation for the StatusNode.
|
||||
func FirstBlockHash(statusNode *node.StatusNode) (string, error) {
|
||||
// obtain RPC client for running node
|
||||
runningNode, err := statusNode.GethNode()
|
||||
if err != nil {
|
||||
return "", err
|
||||
runningNode := statusNode.GethNode()
|
||||
if runningNode == nil {
|
||||
return "", node.ErrNoGethNode
|
||||
}
|
||||
|
||||
rpcClient, err := runningNode.Attach()
|
||||
|
|
|
@ -43,10 +43,10 @@ func (s *WhisperExtensionSuite) SetupTest() {
|
|||
}
|
||||
|
||||
func (s *WhisperExtensionSuite) TestSentSignal() {
|
||||
node1, err := s.nodes[0].GethNode()
|
||||
s.NoError(err)
|
||||
node2, err := s.nodes[1].GethNode()
|
||||
s.NoError(err)
|
||||
node1 := s.nodes[0].GethNode()
|
||||
s.NotNil(node1)
|
||||
node2 := s.nodes[1].GethNode()
|
||||
s.NotNil(node2)
|
||||
node1.Server().AddPeer(node2.Server().Self())
|
||||
confirmed := make(chan common.Hash, 1)
|
||||
signal.SetDefaultNodeNotificationHandler(func(rawSignal string) {
|
||||
|
@ -125,8 +125,8 @@ func (s *WhisperExtensionSuite) TestExpiredSignal() {
|
|||
|
||||
func (s *WhisperExtensionSuite) TearDown() {
|
||||
for _, n := range s.nodes {
|
||||
cfg, err := n.Config()
|
||||
s.NoError(err)
|
||||
cfg := n.Config()
|
||||
s.NotNil(cfg)
|
||||
s.NoError(n.Stop())
|
||||
s.NoError(os.Remove(cfg.DataDir))
|
||||
}
|
||||
|
|
|
@ -28,17 +28,18 @@ func TestWhisperMailboxTestSuite(t *testing.T) {
|
|||
}
|
||||
|
||||
func (s *WhisperMailboxSuite) TestRequestMessageFromMailboxAsync() {
|
||||
var err error
|
||||
// Start mailbox and status node.
|
||||
mailboxBackend, stop := s.startMailboxBackend()
|
||||
defer stop()
|
||||
mailboxNode, err := mailboxBackend.StatusNode().GethNode()
|
||||
s.Require().NoError(err)
|
||||
s.Require().True(mailboxBackend.IsNodeRunning())
|
||||
mailboxNode := mailboxBackend.StatusNode().GethNode()
|
||||
mailboxEnode := mailboxNode.Server().NodeInfo().Enode
|
||||
|
||||
sender, stop := s.startBackend("sender")
|
||||
defer stop()
|
||||
node, err := sender.StatusNode().GethNode()
|
||||
s.Require().NoError(err)
|
||||
s.Require().True(sender.IsNodeRunning())
|
||||
node := sender.StatusNode().GethNode()
|
||||
|
||||
s.Require().NotEqual(mailboxEnode, node.Server().NodeInfo().Enode)
|
||||
|
||||
|
@ -124,6 +125,8 @@ func (s *WhisperMailboxSuite) TestRequestMessageFromMailboxAsync() {
|
|||
}
|
||||
|
||||
func (s *WhisperMailboxSuite) TestRequestMessagesInGroupChat() {
|
||||
var err error
|
||||
|
||||
// Start mailbox, alice, bob, charlie node.
|
||||
mailboxBackend, stop := s.startMailboxBackend()
|
||||
defer stop()
|
||||
|
@ -138,8 +141,8 @@ func (s *WhisperMailboxSuite) TestRequestMessagesInGroupChat() {
|
|||
defer stop()
|
||||
|
||||
// Add mailbox to static peers.
|
||||
mailboxNode, err := mailboxBackend.StatusNode().GethNode()
|
||||
s.Require().NoError(err)
|
||||
s.Require().True(mailboxBackend.IsNodeRunning())
|
||||
mailboxNode := mailboxBackend.StatusNode().GethNode()
|
||||
mailboxEnode := mailboxNode.Server().NodeInfo().Enode
|
||||
|
||||
err = aliceBackend.StatusNode().AddPeer(mailboxEnode)
|
||||
|
|
|
@ -167,8 +167,8 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() {
|
|||
s.False(whisperService.HasKeyPair(pubKey1), "identity should be removed, but it is still present in whisper")
|
||||
|
||||
// stop node (and all of its sub-protocols)
|
||||
nodeConfig, err := s.Backend.StatusNode().Config()
|
||||
s.NoError(err)
|
||||
nodeConfig := s.Backend.StatusNode().Config()
|
||||
s.NotNil(nodeConfig)
|
||||
preservedNodeConfig := *nodeConfig
|
||||
s.NoError(s.Backend.StopNode())
|
||||
|
||||
|
|
Loading…
Reference in New Issue