api: make is completely sequential

This commit is contained in:
Victor Farazdagi 2017-05-25 15:34:13 +03:00
parent 3c961473e1
commit 35eb15fed7
4 changed files with 93 additions and 13 deletions

View File

@ -1,6 +1,8 @@
package api package api
import ( import (
"sync"
"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/status-im/status-go/geth/common" "github.com/status-im/status-go/geth/common"
@ -9,6 +11,7 @@ import (
// StatusAPI provides API to access Status related functionality. // StatusAPI provides API to access Status related functionality.
type StatusAPI struct { type StatusAPI struct {
sync.Mutex
b *StatusBackend b *StatusBackend
} }
@ -21,21 +24,33 @@ func NewStatusAPI() *StatusAPI {
// NodeManager returns reference to node manager // NodeManager returns reference to node manager
func (api *StatusAPI) NodeManager() common.NodeManager { func (api *StatusAPI) NodeManager() common.NodeManager {
api.Lock()
defer api.Unlock()
return api.b.NodeManager() return api.b.NodeManager()
} }
// AccountManager returns reference to account manager // AccountManager returns reference to account manager
func (api *StatusAPI) AccountManager() common.AccountManager { func (api *StatusAPI) AccountManager() common.AccountManager {
api.Lock()
defer api.Unlock()
return api.b.AccountManager() return api.b.AccountManager()
} }
// JailManager returns reference to jail // JailManager returns reference to jail
func (api *StatusAPI) JailManager() common.JailManager { func (api *StatusAPI) JailManager() common.JailManager {
api.Lock()
defer api.Unlock()
return api.b.JailManager() return api.b.JailManager()
} }
// StartNode start Status node, fails if node is already started // StartNode start Status node, fails if node is already started
func (api *StatusAPI) StartNode(config *params.NodeConfig) error { func (api *StatusAPI) StartNode(config *params.NodeConfig) error {
api.Lock()
defer api.Unlock()
nodeStarted, err := api.b.StartNode(config) nodeStarted, err := api.b.StartNode(config)
if err != nil { if err != nil {
return err return err
@ -49,6 +64,9 @@ func (api *StatusAPI) StartNode(config *params.NodeConfig) error {
// Returns immediately w/o waiting for node to start (relies on listening // Returns immediately w/o waiting for node to start (relies on listening
// for node.started signal) // for node.started signal)
func (api *StatusAPI) StartNodeNonBlocking(config *params.NodeConfig) error { func (api *StatusAPI) StartNodeNonBlocking(config *params.NodeConfig) error {
api.Lock()
defer api.Unlock()
_, err := api.b.StartNode(config) _, err := api.b.StartNode(config)
if err != nil { if err != nil {
return err return err
@ -59,11 +77,17 @@ func (api *StatusAPI) StartNodeNonBlocking(config *params.NodeConfig) error {
// StopNode stop Status node. Stopped node cannot be resumed. // StopNode stop Status node. Stopped node cannot be resumed.
func (api *StatusAPI) StopNode() error { func (api *StatusAPI) StopNode() error {
api.Lock()
defer api.Unlock()
return api.b.StopNode() return api.b.StopNode()
} }
// RestartNode restart running Status node, fails if node is not running // RestartNode restart running Status node, fails if node is not running
func (api *StatusAPI) RestartNode() error { func (api *StatusAPI) RestartNode() error {
api.Lock()
defer api.Unlock()
nodeStarted, err := api.b.RestartNode() nodeStarted, err := api.b.RestartNode()
if err != nil { if err != nil {
return err return err
@ -75,6 +99,9 @@ func (api *StatusAPI) RestartNode() error {
// ResetChainData remove chain data from data directory. // ResetChainData remove chain data from data directory.
// Node is stopped, and new node is started, with clean data directory. // Node is stopped, and new node is started, with clean data directory.
func (api *StatusAPI) ResetChainData() error { func (api *StatusAPI) ResetChainData() error {
api.Lock()
defer api.Unlock()
nodeStarted, err := api.b.ResetChainData() nodeStarted, err := api.b.ResetChainData()
if err != nil { if err != nil {
return err return err
@ -85,11 +112,17 @@ func (api *StatusAPI) ResetChainData() error {
// 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 (api *StatusAPI) PopulateStaticPeers() error { func (api *StatusAPI) PopulateStaticPeers() error {
api.Lock()
defer api.Unlock()
return api.b.nodeManager.PopulateStaticPeers() return api.b.nodeManager.PopulateStaticPeers()
} }
// AddPeer adds new static peer node // AddPeer adds new static peer node
func (api *StatusAPI) AddPeer(url string) error { func (api *StatusAPI) AddPeer(url string) error {
api.Lock()
defer api.Unlock()
return api.b.nodeManager.AddPeer(url) return api.b.nodeManager.AddPeer(url)
} }
@ -98,6 +131,9 @@ func (api *StatusAPI) AddPeer(url string) error {
// Public key of CKD#1 is returned, with CKD#2 securely encoded into account key file (to be used for // Public key of CKD#1 is returned, with CKD#2 securely encoded into account key file (to be used for
// sub-account derivations) // sub-account derivations)
func (api *StatusAPI) CreateAccount(password string) (address, pubKey, mnemonic string, err error) { func (api *StatusAPI) CreateAccount(password string) (address, pubKey, mnemonic string, err error) {
api.Lock()
defer api.Unlock()
return api.b.CreateAccount(password) return api.b.CreateAccount(password)
} }
@ -105,18 +141,27 @@ func (api *StatusAPI) CreateAccount(password string) (address, pubKey, mnemonic
// CKD#2 is used as root for master accounts (when parentAddress is ""). // CKD#2 is used as root for master accounts (when parentAddress is "").
// Otherwise (when parentAddress != ""), child is derived directly from parent. // Otherwise (when parentAddress != ""), child is derived directly from parent.
func (api *StatusAPI) CreateChildAccount(parentAddress, password string) (address, pubKey string, err error) { func (api *StatusAPI) CreateChildAccount(parentAddress, password string) (address, pubKey string, err error) {
api.Lock()
defer api.Unlock()
return api.b.CreateChildAccount(parentAddress, password) return api.b.CreateChildAccount(parentAddress, password)
} }
// RecoverAccount re-creates master key using given details. // RecoverAccount re-creates master key using given details.
// Once master key is re-generated, it is inserted into keystore (if not already there). // Once master key is re-generated, it is inserted into keystore (if not already there).
func (api *StatusAPI) RecoverAccount(password, mnemonic string) (address, pubKey string, err error) { func (api *StatusAPI) RecoverAccount(password, mnemonic string) (address, pubKey string, err error) {
api.Lock()
defer api.Unlock()
return api.b.RecoverAccount(password, mnemonic) return api.b.RecoverAccount(password, mnemonic)
} }
// VerifyAccountPassword tries to decrypt a given account key file, with a provided password. // VerifyAccountPassword tries to decrypt a given account key file, with a provided password.
// If no error is returned, then account is considered verified. // If no error is returned, then account is considered verified.
func (api *StatusAPI) VerifyAccountPassword(keyStoreDir, address, password string) (*keystore.Key, error) { func (api *StatusAPI) VerifyAccountPassword(keyStoreDir, address, password string) (*keystore.Key, error) {
api.Lock()
defer api.Unlock()
return api.b.VerifyAccountPassword(keyStoreDir, address, password) return api.b.VerifyAccountPassword(keyStoreDir, address, password)
} }
@ -124,48 +169,75 @@ func (api *StatusAPI) VerifyAccountPassword(keyStoreDir, address, password strin
// using provided password. Once verification is done, decrypted key is injected into Whisper (as a single identity, // using provided password. Once verification is done, decrypted key is injected into Whisper (as a single identity,
// all previous identities are removed). // all previous identities are removed).
func (api *StatusAPI) SelectAccount(address, password string) error { func (api *StatusAPI) SelectAccount(address, password string) error {
api.Lock()
defer api.Unlock()
return api.b.SelectAccount(address, password) return api.b.SelectAccount(address, password)
} }
// Logout clears whisper identities // Logout clears whisper identities
func (api *StatusAPI) Logout() error { func (api *StatusAPI) Logout() error {
api.Lock()
defer api.Unlock()
return api.b.Logout() return api.b.Logout()
} }
// CompleteTransaction instructs backend to complete sending of a given transaction // CompleteTransaction instructs backend to complete sending of a given transaction
func (api *StatusAPI) CompleteTransaction(id, password string) (gethcommon.Hash, error) { func (api *StatusAPI) CompleteTransaction(id, password string) (gethcommon.Hash, error) {
api.Lock()
defer api.Unlock()
return api.b.CompleteTransaction(id, password) return api.b.CompleteTransaction(id, password)
} }
// CompleteTransactions instructs backend to complete sending of multiple transactions // CompleteTransactions instructs backend to complete sending of multiple transactions
func (api *StatusAPI) CompleteTransactions(ids, password string) map[string]common.RawCompleteTransactionResult { func (api *StatusAPI) CompleteTransactions(ids, password string) map[string]common.RawCompleteTransactionResult {
api.Lock()
defer api.Unlock()
return api.b.CompleteTransactions(ids, password) return api.b.CompleteTransactions(ids, password)
} }
// DiscardTransaction discards a given transaction from transaction queue // DiscardTransaction discards a given transaction from transaction queue
func (api *StatusAPI) DiscardTransaction(id string) error { func (api *StatusAPI) DiscardTransaction(id string) error {
api.Lock()
defer api.Unlock()
return api.b.DiscardTransaction(id) return api.b.DiscardTransaction(id)
} }
// DiscardTransactions discards given multiple transactions from transaction queue // DiscardTransactions discards given multiple transactions from transaction queue
func (api *StatusAPI) DiscardTransactions(ids string) map[string]common.RawDiscardTransactionResult { func (api *StatusAPI) DiscardTransactions(ids string) map[string]common.RawDiscardTransactionResult {
api.Lock()
defer api.Unlock()
return api.b.DiscardTransactions(ids) return api.b.DiscardTransactions(ids)
} }
// Parse creates a new jail cell context, with the given chatID as identifier. // Parse creates a new jail cell context, with the given chatID as identifier.
// New context executes provided JavaScript code, right after the initialization. // New context executes provided JavaScript code, right after the initialization.
func (api *StatusAPI) JailParse(chatID string, js string) string { func (api *StatusAPI) JailParse(chatID string, js string) string {
api.Lock()
defer api.Unlock()
return api.b.jailManager.Parse(chatID, js) return api.b.jailManager.Parse(chatID, js)
} }
// Call executes given JavaScript function w/i a jail cell context identified by the chatID. // Call executes given JavaScript function w/i a jail cell context identified by the chatID.
// Jail cell is clonned before call is executed i.e. all calls execute w/i their own contexts. // Jail cell is clonned before call is executed i.e. all calls execute w/i their own contexts.
func (api *StatusAPI) JailCall(chatID string, path string, args string) string { func (api *StatusAPI) JailCall(chatID string, path string, args string) string {
api.Lock()
defer api.Unlock()
return api.b.jailManager.Call(chatID, path, args) return api.b.jailManager.Call(chatID, path, args)
} }
// BaseJS allows to setup initial JavaScript to be loaded on each jail.Parse() // BaseJS allows to setup initial JavaScript to be loaded on each jail.Parse()
func (api *StatusAPI) JailBaseJS(js string) { func (api *StatusAPI) JailBaseJS(js string) {
api.Lock()
defer api.Unlock()
api.b.jailManager.BaseJS(js) api.b.jailManager.BaseJS(js)
} }

View File

@ -1,7 +1,9 @@
package api_test package api_test
import ( import (
"fmt"
"testing" "testing"
"time"
"github.com/status-im/status-go/geth/api" "github.com/status-im/status-go/geth/api"
"github.com/status-im/status-go/geth/params" "github.com/status-im/status-go/geth/params"
@ -35,15 +37,21 @@ func (s *APITestSuite) TestStartStopRaces() {
progress := make(chan struct{}, 100) progress := make(chan struct{}, 100)
start := func() { start := func() {
fmt.Println("start node")
s.api.StartNode(nodeConfig) s.api.StartNode(nodeConfig)
progress <- struct{}{} progress <- struct{}{}
} }
stop := func() { stop := func() {
fmt.Println("stop node")
s.api.StopNode() s.api.StopNode()
progress <- struct{}{} progress <- struct{}{}
} }
for i := 0; i < 50; i++ { // start one node and sync it a bit
start()
time.Sleep(5 * time.Second)
for i := 0; i < 20; i++ {
go start() go start()
go stop() go stop()
} }
@ -51,7 +59,7 @@ func (s *APITestSuite) TestStartStopRaces() {
cnt := 0 cnt := 0
for range progress { for range progress {
cnt += 1 cnt += 1
if cnt >= 100 { if cnt >= 40 {
break break
} }
} }

View File

@ -124,7 +124,7 @@ func scriptsWeb3Js() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "scripts/web3.js", size: 496217, mode: os.FileMode(420), modTime: time.Unix(1495573395, 0)} info := bindataFileInfo{name: "scripts/web3.js", size: 496217, mode: os.FileMode(420), modTime: time.Unix(1495715456, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -269,7 +269,7 @@ func configLinter_exclude_listTxt() (*asset, error) {
return a, nil return a, nil
} }
var _configTestDataJson = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x84\x8d\x31\x6b\xc3\x40\x0c\x46\x77\xff\x0a\xa1\xb9\xc3\xc9\xae\xe4\xb3\xb7\x6c\x9d\x8a\xc1\x81\xce\x3a\x9d\x3c\xfa\xc0\x97\xd2\x96\x92\xff\x5e\x8e\x06\x02\x85\x92\x41\x20\x1e\x7c\xef\x7d\x77\x00\xf8\x5a\xb2\xe3\x0c\xed\x07\xc0\xf5\x6b\xb7\xd5\xad\xec\xb9\xe2\x0c\x14\x9e\x7e\xf1\xcb\xf9\xbc\x2c\xe5\xb8\xe0\x0c\x51\x9e\xf9\x46\xdf\xd6\x3b\x93\x0e\xe0\xda\x38\x9e\xcc\xca\xfb\x7e\xa1\xbb\xf4\x94\xf3\xe1\xb5\x09\x31\x7c\x6a\xd6\x8d\x38\xa4\x29\xb0\x6d\xec\xa2\xe3\x18\x9d\x79\x70\x62\xa5\x61\x4a\x22\x14\x53\x4a\x23\xde\x22\x8b\xd6\xfa\x51\x8e\xdc\xd6\x5a\xf3\xd6\x0e\xff\xc6\xfa\x7f\x62\xc2\x16\x88\xa3\xa8\x06\x73\xe2\x3e\x0e\x6c\x63\x8c\x6a\x2e\xc2\x3e\x91\xa6\x81\xfb\x31\xc5\x87\xb1\xee\xfa\x13\x00\x00\xff\xff\x93\xde\xa0\x86\x2d\x01\x00\x00") var _configTestDataJson = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x84\x8d\x31\x6b\xc4\x30\x0c\x46\xf7\xfc\x0a\xa1\xb9\x83\x1d\x57\xb2\x93\xed\xb6\x4e\x25\x90\x83\xce\xb2\xac\x8c\x31\xc4\x57\xda\x52\xee\xbf\x17\xd3\x83\x83\x42\xb9\x41\x20\x1e\x7c\xef\x7d\x0f\x00\xf8\x5a\x8b\xe1\x0c\xfd\x07\xc0\xf5\x6b\xd7\xd5\xb4\xee\xa5\xe1\x0c\xa3\x7b\xfa\xc5\x2f\xe7\xf3\xb2\xd4\xe3\x82\x33\x24\x7e\xa6\x1b\x7d\x5b\xef\x8c\x07\x80\x6b\xe7\x78\x52\xad\xef\xfb\xc5\xdf\xa5\xa7\x52\x0e\x6b\x5d\x88\xee\x53\x8a\x6c\x9e\x5c\x9e\x1c\xe9\x46\xc6\x12\x63\x32\xa2\x60\x9e\xc4\x87\x29\x33\xfb\x94\x73\x8e\x78\x8b\x2c\xd2\xda\x47\x3d\x4a\x5f\x4b\x2b\x5b\x3f\xfc\x1b\x1b\xff\x89\x31\xa9\xf3\x94\x58\xc4\xa9\x79\x1a\x53\x20\x8d\x29\x89\x1a\x33\xd9\xe4\x25\x07\x1a\x63\x4e\x0f\x63\xc3\xf5\x27\x00\x00\xff\xff\x86\xe9\x3c\x6a\x2d\x01\x00\x00")
func configTestDataJsonBytes() ([]byte, error) { func configTestDataJsonBytes() ([]byte, error) {
return bindataRead( return bindataRead(
@ -284,7 +284,7 @@ func configTestDataJson() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "config/test-data.json", size: 301, mode: os.FileMode(420), modTime: time.Unix(1495573389, 0)} info := bindataFileInfo{name: "config/test-data.json", size: 301, mode: os.FileMode(420), modTime: time.Unix(1495715449, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -404,7 +404,7 @@ func testdataJailCommandsJs() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "testdata/jail/commands.js", size: 7677, mode: os.FileMode(420), modTime: time.Unix(1492580435, 0)} info := bindataFileInfo{name: "testdata/jail/commands.js", size: 7677, mode: os.FileMode(420), modTime: time.Unix(1495640010, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -424,7 +424,7 @@ func testdataJailStatusJs() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "testdata/jail/status.js", size: 3402, mode: os.FileMode(420), modTime: time.Unix(1492580435, 0)} info := bindataFileInfo{name: "testdata/jail/status.js", size: 3402, mode: os.FileMode(420), modTime: time.Unix(1495640010, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -444,7 +444,7 @@ func testdataJailTxSendContextNoMessageIdJs() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "testdata/jail/tx-send/context-no-message-id.js", size: 1793, mode: os.FileMode(420), modTime: time.Unix(1492580435, 0)} info := bindataFileInfo{name: "testdata/jail/tx-send/context-no-message-id.js", size: 1793, mode: os.FileMode(420), modTime: time.Unix(1495640010, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -464,7 +464,7 @@ func testdataJailTxSendMessageIdNoContextJs() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "testdata/jail/tx-send/message-id-no-context.js", size: 1875, mode: os.FileMode(420), modTime: time.Unix(1492580435, 0)} info := bindataFileInfo{name: "testdata/jail/tx-send/message-id-no-context.js", size: 1875, mode: os.FileMode(420), modTime: time.Unix(1495640010, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -484,7 +484,7 @@ func testdataJailTxSendNoMessageIdOrContextJs() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "testdata/jail/tx-send/no-message-id-or-context.js", size: 1354, mode: os.FileMode(420), modTime: time.Unix(1492580435, 0)} info := bindataFileInfo{name: "testdata/jail/tx-send/no-message-id-or-context.js", size: 1354, mode: os.FileMode(420), modTime: time.Unix(1495640010, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -504,7 +504,7 @@ func testdataJailTxSendTxSendJs() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "testdata/jail/tx-send/tx-send.js", size: 2987, mode: os.FileMode(420), modTime: time.Unix(1492580435, 0)} info := bindataFileInfo{name: "testdata/jail/tx-send/tx-send.js", size: 2987, mode: os.FileMode(420), modTime: time.Unix(1495640010, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -524,7 +524,7 @@ func testdataNodeTestSol() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "testdata/node/test.sol", size: 119, mode: os.FileMode(420), modTime: time.Unix(1488290438, 0)} info := bindataFileInfo{name: "testdata/node/test.sol", size: 119, mode: os.FileMode(420), modTime: time.Unix(1495640010, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }

View File

@ -1,6 +1,6 @@
{ {
"Node": { "Node": {
"SyncSeconds": 10, "SyncSeconds": 20,
"HTTPPort": 8645, "HTTPPort": 8645,
"WSPort": 8646 "WSPort": 8646
}, },