fixes race condition in node stop method
This commit is contained in:
parent
78865c674b
commit
b61f0d0000
12
Makefile
12
Makefile
|
@ -47,12 +47,12 @@ statusgo-ios-simulator-mainnet: xgo
|
|||
@echo "iOS framework cross compilation done (mainnet)."
|
||||
|
||||
ci:
|
||||
build/env.sh go test -v -cover ./geth/api
|
||||
build/env.sh go test -v -cover ./geth/common
|
||||
build/env.sh go test -v -cover ./geth/jail
|
||||
build/env.sh go test -v -cover ./geth/node
|
||||
build/env.sh go test -v -cover ./geth/params
|
||||
build/env.sh go test -v -cover ./extkeys
|
||||
build/env.sh go test -v ./geth/api
|
||||
build/env.sh go test -v ./geth/common
|
||||
build/env.sh go test -v ./geth/jail
|
||||
build/env.sh go test -v ./geth/node
|
||||
build/env.sh go test -v ./geth/params
|
||||
build/env.sh go test -v ./extkeys
|
||||
|
||||
generate:
|
||||
cp ./node_modules/web3/dist/web3.js ./static/scripts/web3.js
|
||||
|
|
|
@ -72,8 +72,6 @@ func (m *StatusBackend) onNodeStart(backendReady chan struct{}, nodeStarted <-ch
|
|||
if err := m.registerHandlers(); err != nil {
|
||||
log.Error("Handler registration failed", "err", err)
|
||||
}
|
||||
|
||||
m.accountManager.ReSelectAccount()
|
||||
}
|
||||
|
||||
// RestartNode restart running Status node, fails if node is not running
|
||||
|
|
|
@ -83,13 +83,14 @@ func (s *BackendTestSuite) LightEthereumService() *les.LightEthereum {
|
|||
func (s *BackendTestSuite) RestartTestNode() {
|
||||
require := s.Require()
|
||||
require.NotNil(s.backend)
|
||||
require.True(s.backend.IsNodeRunning())
|
||||
|
||||
require.True(s.backend.IsNodeRunning())
|
||||
nodeRestarted, err := s.backend.RestartNode()
|
||||
require.NoError(err)
|
||||
require.NotNil(nodeRestarted)
|
||||
require.True(s.backend.IsNodeRunning())
|
||||
<-nodeRestarted
|
||||
require.True(s.backend.IsNodeRunning())
|
||||
}
|
||||
|
||||
func (s *BackendTestSuite) TestNewBackend() {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
|
@ -96,6 +97,17 @@ func PanicAfter(waitSeconds time.Duration, abort chan struct{}, desc string) {
|
|||
}()
|
||||
}
|
||||
|
||||
// NameOf returns name of caller, at runtime
|
||||
func NameOf(f interface{}) string {
|
||||
v := reflect.ValueOf(f)
|
||||
if v.Kind() == reflect.Func {
|
||||
if rf := runtime.FuncForPC(v.Pointer()); rf != nil {
|
||||
return rf.Name()
|
||||
}
|
||||
}
|
||||
return v.String()
|
||||
}
|
||||
|
||||
// MessageIDFromContext returns message id from context (if exists)
|
||||
func MessageIDFromContext(ctx context.Context) string {
|
||||
if ctx == nil {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"os/signal"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
|
@ -17,6 +18,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
|
||||
"github.com/status-im/status-go/geth/common"
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
)
|
||||
|
||||
|
@ -24,6 +26,8 @@ import (
|
|||
var (
|
||||
ErrNodeAlreadyExists = errors.New("there is a running node already, stop it before starting another one")
|
||||
ErrNoRunningNode = errors.New("there is no running node")
|
||||
ErrNodeOpTimedOut = errors.New("operation takes too long, timed out")
|
||||
ErrInvalidRunningNode = errors.New("running node is not correctly initialized")
|
||||
ErrInvalidNodeManager = errors.New("node manager is not properly initialized")
|
||||
ErrInvalidWhisperService = errors.New("whisper service is unavailable")
|
||||
ErrInvalidLightEthereumService = errors.New("LES service is unavailable")
|
||||
|
@ -37,6 +41,7 @@ type NodeManager struct {
|
|||
sync.RWMutex
|
||||
config *params.NodeConfig // Status node configuration
|
||||
node *node.Node // reference to Geth P2P stack/node
|
||||
nodeStopped chan struct{} // channel to wait for termination notifications
|
||||
whisperService *whisper.Whisper // reference to Whisper service
|
||||
lesService *les.LightEthereum // reference to LES service
|
||||
rpcClient *rpc.Client // reference to RPC client
|
||||
|
@ -78,16 +83,12 @@ func (m *NodeManager) StartNode(config *params.NodeConfig) (<-chan struct{}, err
|
|||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if m.node != nil {
|
||||
return nil, ErrNodeAlreadyExists
|
||||
}
|
||||
|
||||
return m.startNode(config)
|
||||
}
|
||||
|
||||
// startNode start Status node, fails if node is already started
|
||||
func (m *NodeManager) startNode(config *params.NodeConfig) (<-chan struct{}, error) {
|
||||
if m.node != nil {
|
||||
if m.node != nil || m.nodeStopped != nil {
|
||||
return nil, ErrNodeAlreadyExists
|
||||
}
|
||||
|
||||
|
@ -99,6 +100,7 @@ func (m *NodeManager) startNode(config *params.NodeConfig) (<-chan struct{}, err
|
|||
m.config = config // preserve config of successfully created node
|
||||
|
||||
nodeStarted := make(chan struct{})
|
||||
m.nodeStopped = make(chan struct{})
|
||||
go func() {
|
||||
defer HaltOnPanic()
|
||||
|
||||
|
@ -108,6 +110,7 @@ func (m *NodeManager) startNode(config *params.NodeConfig) (<-chan struct{}, err
|
|||
m.lesService = nil
|
||||
m.whisperService = nil
|
||||
m.rpcClient = nil
|
||||
m.nodeStopped = nil
|
||||
m.node = nil
|
||||
m.Unlock()
|
||||
SendSignal(SignalEnvelope{
|
||||
|
@ -155,6 +158,7 @@ func (m *NodeManager) onNodeStarted(nodeStarted chan struct{}) {
|
|||
Type: EventNodeStopped,
|
||||
Event: struct{}{},
|
||||
})
|
||||
close(m.nodeStopped)
|
||||
log.Info("Node is stopped", "enode", nodeInfo.Enode)
|
||||
}
|
||||
|
||||
|
@ -167,7 +171,7 @@ func (m *NodeManager) IsNodeRunning() bool {
|
|||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
return m.node != nil
|
||||
return m.node != nil && m.nodeStopped != nil
|
||||
}
|
||||
|
||||
// StopNode stop Status node. Stopped node cannot be resumed.
|
||||
|
@ -188,16 +192,28 @@ func (m *NodeManager) stopNode() error {
|
|||
return ErrNoRunningNode
|
||||
}
|
||||
|
||||
if m.nodeStopped == nil { // node may be running, but required channel not set
|
||||
return ErrInvalidRunningNode
|
||||
}
|
||||
|
||||
if err := m.node.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// wait till the previous node is fully stopped
|
||||
select {
|
||||
case <-m.nodeStopped:
|
||||
// pass
|
||||
case <-time.After(30 * time.Second):
|
||||
return fmt.Errorf("%v: %s", ErrNodeOpTimedOut, common.NameOf(m.StopNode))
|
||||
}
|
||||
|
||||
m.config = nil
|
||||
m.lesService = nil
|
||||
m.whisperService = nil
|
||||
m.rpcClient = nil
|
||||
m.nodeStopped = nil
|
||||
m.node = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -304,7 +304,9 @@ func (s *ManagerTestSuite) TestResetChainData() {
|
|||
time.Sleep(2 * time.Second) // allow to sync for some time
|
||||
|
||||
s.True(s.NodeManager.IsNodeRunning())
|
||||
require.NoError(s.NodeManager.ResetChainData())
|
||||
nodeReady, err := s.NodeManager.ResetChainData()
|
||||
require.NoError(err)
|
||||
<-nodeReady
|
||||
s.True(s.NodeManager.IsNodeRunning()) // new node, with previous config should be running
|
||||
|
||||
// make sure we can read the first byte, and it is valid (for Rinkeby)
|
||||
|
|
Loading…
Reference in New Issue