geth,cmd/status: pause/resume node fixes #96
This commit is contained in:
parent
a77c2362d5
commit
fd36dcfdb4
|
@ -205,6 +205,18 @@ func StartNode(datadir *C.char) *C.char {
|
|||
return makeJSONErrorResponse(err)
|
||||
}
|
||||
|
||||
//export StopNode
|
||||
func StopNode() *C.char {
|
||||
err := geth.NodeManagerInstance().StopNode()
|
||||
return makeJSONErrorResponse(err)
|
||||
}
|
||||
|
||||
//export ResumeNode
|
||||
func ResumeNode() *C.char {
|
||||
err := geth.NodeManagerInstance().ResumeNode()
|
||||
return makeJSONErrorResponse(err)
|
||||
}
|
||||
|
||||
//export ResetChainData
|
||||
func ResetChainData() *C.char {
|
||||
err := geth.NodeManagerInstance().ResetChainData()
|
||||
|
|
|
@ -79,6 +79,14 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
|
|||
"test jailed calls",
|
||||
testJailFunctionCall,
|
||||
},
|
||||
{
|
||||
"reset blockchain data",
|
||||
testResetChainData,
|
||||
},
|
||||
{
|
||||
"pause node",
|
||||
testStopResumeNode,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
@ -90,6 +98,119 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
|
|||
done <- struct{}{}
|
||||
}
|
||||
|
||||
func testResetChainData(t *testing.T) bool {
|
||||
resetChainDataResponse := geth.JSONError{}
|
||||
rawResponse := ResetChainData()
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &resetChainDataResponse); err != nil {
|
||||
t.Errorf("cannot decode ResetChainData reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
if resetChainDataResponse.Error != "" {
|
||||
t.Errorf("unexpected error: %s", resetChainDataResponse.Error)
|
||||
return false
|
||||
}
|
||||
|
||||
time.Sleep(15 * time.Second) // allow to re-sync blockchain
|
||||
|
||||
testCompleteTransaction(t)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func testStopResumeNode(t *testing.T) bool {
|
||||
geth.Logout() // to make sure that we start with empty account (which might get populated during previous tests)
|
||||
|
||||
whisperService, err := geth.NodeManagerInstance().WhisperService()
|
||||
if err != nil {
|
||||
t.Errorf("whisper service not running: %v", err)
|
||||
}
|
||||
|
||||
// create an account
|
||||
address1, pubKey1, _, err := geth.CreateAccount(newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("could not create account: %v", err)
|
||||
return false
|
||||
}
|
||||
t.Logf("account created: {address: %s, key: %s}", address1, pubKey1)
|
||||
|
||||
// make sure that identity is not (yet injected)
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
t.Error("identity already present in whisper")
|
||||
}
|
||||
|
||||
// select account
|
||||
loginResponse := geth.JSONError{}
|
||||
rawResponse := Login(C.CString(address1), C.CString(newAccountPassword))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if loginResponse.Error != "" {
|
||||
t.Errorf("could not select account: %v", err)
|
||||
return false
|
||||
}
|
||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
t.Errorf("identity not injected into whisper: %v", err)
|
||||
}
|
||||
|
||||
// stop and resume node, then make sure that selected account is still selected
|
||||
stopNodeFn := func() bool {
|
||||
response := geth.JSONError{}
|
||||
rawResponse = StopNode()
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &response); err != nil {
|
||||
t.Errorf("cannot decode StopNode reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
if response.Error != "" {
|
||||
t.Errorf("unexpected error: %s", response.Error)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
resumeNodeFn := func() bool {
|
||||
response := geth.JSONError{}
|
||||
rawResponse = ResumeNode()
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &response); err != nil {
|
||||
t.Errorf("cannot decode ResumeNode reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
if response.Error != "" {
|
||||
t.Errorf("unexpected error: %s", response.Error)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if !stopNodeFn() {
|
||||
return false
|
||||
}
|
||||
if !resumeNodeFn() {
|
||||
return false
|
||||
}
|
||||
|
||||
// now, verify that we still have account logged in
|
||||
whisperService, err = geth.NodeManagerInstance().WhisperService()
|
||||
if err != nil {
|
||||
t.Errorf("whisper service not running: %v", err)
|
||||
}
|
||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
t.Errorf("identity evicted from whisper on node restart: %v", err)
|
||||
}
|
||||
|
||||
// additionally, let's complete transaction (just to make sure that node lives through pause/resume w/o issues)
|
||||
testCompleteTransaction(t)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func testRestartNodeRPC(t *testing.T) bool {
|
||||
// stop RPC
|
||||
stopNodeRPCServerResponse := geth.JSONError{}
|
||||
|
|
|
@ -167,6 +167,27 @@ func SelectAccount(address, password string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ReSelectAccount selects previously selected account, often, after node restart.
|
||||
func ReSelectAccount() error {
|
||||
nodeManager := NodeManagerInstance()
|
||||
|
||||
selectedAccount := nodeManager.SelectedAccount
|
||||
if selectedAccount == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
whisperService, err := nodeManager.WhisperService()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := whisperService.InjectIdentity(selectedAccount.AccountKey.PrivateKey); err != nil {
|
||||
return ErrWhisperIdentityInjectionFailure
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Logout clears whisper identities
|
||||
func Logout() error {
|
||||
nodeManager := NodeManagerInstance()
|
||||
|
|
|
@ -413,3 +413,185 @@ func TestAccountLogout(t *testing.T) {
|
|||
t.Error("identity not cleared from whisper")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectedAccountOnNodeRestart(t *testing.T) {
|
||||
err := geth.PrepareTestNode()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// we need to make sure that selected account is injected as identity into Whisper
|
||||
whisperService, err := geth.NodeManagerInstance().WhisperService()
|
||||
if err != nil {
|
||||
t.Errorf("whisper service not running: %v", err)
|
||||
}
|
||||
|
||||
// create test accounts
|
||||
address1, pubKey1, _, err := geth.CreateAccount(newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("could not create account: %v", err)
|
||||
return
|
||||
}
|
||||
t.Logf("account1 created: {address: %s, key: %s}", address1, pubKey1)
|
||||
address2, pubKey2, _, err := geth.CreateAccount(newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("could not create account: %v", err)
|
||||
return
|
||||
}
|
||||
t.Logf("account2 created: {address: %s, key: %s}", address2, pubKey2)
|
||||
|
||||
// make sure that identity is not (yet injected)
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
t.Error("identity already present in whisper")
|
||||
}
|
||||
|
||||
// make sure that no account is selected by default
|
||||
if geth.NodeManagerInstance().SelectedAccount != nil {
|
||||
t.Error("account selected, but should not be")
|
||||
return
|
||||
}
|
||||
|
||||
// select account
|
||||
err = geth.SelectAccount(address1, "wrongPassword")
|
||||
if err == nil {
|
||||
t.Error("select account is expected to throw error: wrong password used")
|
||||
return
|
||||
}
|
||||
err = geth.SelectAccount(address1, newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("could not select account: %v", err)
|
||||
return
|
||||
}
|
||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
t.Errorf("identity not injected into whisper: %v", err)
|
||||
}
|
||||
|
||||
// select another account, make sure that previous account is wiped out from Whisper cache
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) {
|
||||
t.Error("identity already present in whisper")
|
||||
}
|
||||
err = geth.SelectAccount(address2, newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed: could not select account: %v", err)
|
||||
return
|
||||
}
|
||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) {
|
||||
t.Errorf("identity not injected into whisper: %v", err)
|
||||
}
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
t.Error("identity should be removed, but it is still present in whisper")
|
||||
}
|
||||
|
||||
// stop node (and all of its sub-protocols)
|
||||
if err := geth.NodeManagerInstance().StopNode(); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// make sure that account is still selected
|
||||
if geth.NodeManagerInstance().SelectedAccount == nil {
|
||||
t.Error("no selected account")
|
||||
return
|
||||
}
|
||||
if geth.NodeManagerInstance().SelectedAccount.Address.Hex() != "0x"+address2 {
|
||||
t.Error("incorrect address selected")
|
||||
return
|
||||
}
|
||||
|
||||
// resume node
|
||||
if err := geth.NodeManagerInstance().ResumeNode(); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// re-check selected account (account2 MUST be selected)
|
||||
if geth.NodeManagerInstance().SelectedAccount == nil {
|
||||
t.Error("no selected account")
|
||||
return
|
||||
}
|
||||
if geth.NodeManagerInstance().SelectedAccount.Address.Hex() != "0x"+address2 {
|
||||
t.Error("incorrect address selected")
|
||||
return
|
||||
}
|
||||
|
||||
// make sure that Whisper gets identity re-injected
|
||||
whisperService, err = geth.NodeManagerInstance().WhisperService()
|
||||
if err != nil {
|
||||
t.Errorf("whisper service not running: %v", err)
|
||||
}
|
||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) {
|
||||
t.Errorf("identity not injected into whisper: %v", err)
|
||||
}
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
t.Error("identity should not be present, but it is still present in whisper")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeRestartWithNoSelectedAccount(t *testing.T) {
|
||||
err := geth.PrepareTestNode()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
geth.Logout()
|
||||
|
||||
// we need to make sure that selected account is injected as identity into Whisper
|
||||
whisperService, err := geth.NodeManagerInstance().WhisperService()
|
||||
if err != nil {
|
||||
t.Errorf("whisper service not running: %v", err)
|
||||
}
|
||||
|
||||
// create test accounts
|
||||
address1, pubKey1, _, err := geth.CreateAccount(newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("could not create account: %v", err)
|
||||
return
|
||||
}
|
||||
t.Logf("account1 created: {address: %s, key: %s}", address1, pubKey1)
|
||||
|
||||
// make sure that identity is not present
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
t.Error("identity already present in whisper")
|
||||
}
|
||||
|
||||
// make sure that no account is selected
|
||||
if geth.NodeManagerInstance().SelectedAccount != nil {
|
||||
t.Error("account selected, but should not be")
|
||||
return
|
||||
}
|
||||
|
||||
// stop node (and all of its sub-protocols)
|
||||
if err := geth.NodeManagerInstance().StopNode(); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// make sure that no account is selected
|
||||
if geth.NodeManagerInstance().SelectedAccount != nil {
|
||||
t.Error("account selected, but should not be")
|
||||
return
|
||||
}
|
||||
|
||||
// resume node
|
||||
if err := geth.NodeManagerInstance().ResumeNode(); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// make sure that no account is selected
|
||||
if geth.NodeManagerInstance().SelectedAccount != nil {
|
||||
t.Error("account selected, but should not be")
|
||||
return
|
||||
}
|
||||
|
||||
// make sure that Whisper gets identity re-injected
|
||||
whisperService, err = geth.NodeManagerInstance().WhisperService()
|
||||
if err != nil {
|
||||
t.Errorf("whisper service not running: %v", err)
|
||||
}
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
t.Error("identity should not be present, but it is present in whisper")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,6 +208,23 @@ func (m *NodeManager) RestartNode() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ResumeNode resumes previously stopped P2P node
|
||||
func (m *NodeManager) ResumeNode() error {
|
||||
if m == nil || !m.NodeInited() {
|
||||
return ErrInvalidGethNode
|
||||
}
|
||||
|
||||
m.RunNode()
|
||||
m.WaitNodeStarted()
|
||||
|
||||
// re-select the previously selected account
|
||||
if err := ReSelectAccount(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetChainData purges chain data (by removing data directory). Safe to apply on running P2P node.
|
||||
func (m *NodeManager) ResetChainData() error {
|
||||
if m == nil || !m.NodeInited() {
|
||||
|
@ -227,8 +244,9 @@ func (m *NodeManager) ResetChainData() error {
|
|||
return err
|
||||
}
|
||||
|
||||
m.RunNode()
|
||||
m.WaitNodeStarted()
|
||||
if err := m.ResumeNode(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue