diff --git a/Makefile b/Makefile index ca759685f..ef04230d1 100644 --- a/Makefile +++ b/Makefile @@ -81,6 +81,11 @@ test-extkeys: @build/env.sh go tool cover -html=coverage.out -o coverage.html @build/env.sh go tool cover -func=coverage.out +test-cmd: + build/env.sh go test -v -coverprofile=coverage.out ./cmd/status + @build/env.sh go tool cover -html=coverage.out -o coverage.html + @build/env.sh go tool cover -func=coverage.out + clean: rm -fr build/bin/* rm coverage.out coverage-all.out coverage.html diff --git a/build/mainnet-flags.sh b/build/mainnet-flags.sh index b078b9fb7..4a0e67539 100755 --- a/build/mainnet-flags.sh +++ b/build/mainnet-flags.sh @@ -9,5 +9,5 @@ fi # set gitCommit when running from a Git checkout. if [ -f ".git/HEAD" ]; then - echo "-ldflags '-X github.com/status-im/status-go/geth.UseTestnet=false -X main.buildStamp=`date -u '+%Y-%m-%d.%H:%M:%S'` -X main.gitCommit=$(git rev-parse HEAD)'"; + echo "-ldflags '-X github.com/status-im/status-go/geth.UseTestnetFlag=false -X main.buildStamp=`date -u '+%Y-%m-%d.%H:%M:%S'` -X main.gitCommit=$(git rev-parse HEAD)'"; fi diff --git a/build/testnet-flags.sh b/build/testnet-flags.sh index 2b04db662..e833f571d 100755 --- a/build/testnet-flags.sh +++ b/build/testnet-flags.sh @@ -9,5 +9,5 @@ fi # set gitCommit when running from a Git checkout. if [ -f ".git/HEAD" ]; then - echo "-ldflags '-X github.com/status-im/status-go/geth.UseTestnet=true -X main.buildStamp=`date -u '+%Y-%m-%d.%H:%M:%S'` -X main.gitCommit=$(git rev-parse HEAD)'"; + echo "-ldflags '-X github.com/status-im/status-go/geth.UseTestnetFlag=true -X main.buildStamp=`date -u '+%Y-%m-%d.%H:%M:%S'` -X main.gitCommit=$(git rev-parse HEAD)'"; fi diff --git a/cmd/status/library.go b/cmd/status/library.go index f14c19e36..c81e2e8b1 100644 --- a/cmd/status/library.go +++ b/cmd/status/library.go @@ -235,7 +235,7 @@ func Call(chatId *C.char, path *C.char, params *C.char) *C.char { //export AddPeer func AddPeer(url *C.char) *C.char { - success, err := geth.GetNodeManager().AddPeer(C.GoString(url)) + success, err := geth.NodeManagerInstance().AddPeer(C.GoString(url)) errString := "" if err != nil { fmt.Fprintln(os.Stderr, err) diff --git a/cmd/status/main.go b/cmd/status/main.go index 096ffac7b..3bdeee006 100644 --- a/cmd/status/main.go +++ b/cmd/status/main.go @@ -8,23 +8,18 @@ import ( var ( gitCommit = "rely on linker: -ldflags -X main.GitCommit" buildStamp = "rely on linker: -ldflags -X main.buildStamp" - - versionMajor = 1 // Major version component of the current release - versionMinor = 1 // Minor version component of the current release - versionPatch = 0 // Patch version component of the current release - versionMeta = "unstable" // Version metadata to append to the version string ) func main() { - verString := fmt.Sprintf("%d.%d.%d", versionMajor, versionMinor, versionPatch) - if versionMeta != "" { - verString += "-" + versionMeta + verString := fmt.Sprintf("%d.%d.%d", geth.VersionMajor, geth.VersionMinor, geth.VersionPatch) + if geth.VersionMeta != "" { + verString += "-" + geth.VersionMeta } if gitCommit != "" { verString += "-" + gitCommit[:8] } netVersion := "mainnet" - if geth.UseTestnet == "true" { + if geth.UseTestnet { netVersion = "testnet" } fmt.Printf("Status\nGit Commit: %s\nBuild Time: %s\nVersion: %s\nNetwork: %s\n", diff --git a/cmd/status/utils.go b/cmd/status/utils.go index 44609cc07..e75679859 100644 --- a/cmd/status/utils.go +++ b/cmd/status/utils.go @@ -11,7 +11,6 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/les/status" @@ -90,7 +89,7 @@ func testExportedAPI(t *testing.T, done chan struct{}) { func testCreateChildAccount(t *testing.T) bool { geth.Logout() // to make sure that we start with empty account (which might get populated during previous tests) - accountManager, err := geth.GetNodeManager().AccountManager() + accountManager, err := geth.NodeManagerInstance().AccountManager() if err != nil { t.Error(err) return false @@ -112,7 +111,7 @@ func testCreateChildAccount(t *testing.T) bool { address, pubKey, mnemonic := createAccountResponse.Address, createAccountResponse.PubKey, createAccountResponse.Mnemonic t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic) - account, err := utils.MakeAddress(accountManager, address) + account, err := geth.ParseAccountString(accountManager, address) if err != nil { t.Errorf("can not get account from address: %v", err) return false @@ -221,7 +220,7 @@ func testCreateChildAccount(t *testing.T) bool { } func testRecoverAccount(t *testing.T) bool { - accountManager, _ := geth.GetNodeManager().AccountManager() + accountManager, _ := geth.NodeManagerInstance().AccountManager() // create an account address, pubKey, mnemonic, err := geth.CreateAccount(newAccountPassword) @@ -250,7 +249,7 @@ func testRecoverAccount(t *testing.T) bool { } // now test recovering, but make sure that account/key file is removed i.e. simulate recovering on a new device - account, err := utils.MakeAddress(accountManager, address) + account, err := geth.ParseAccountString(accountManager, address) if err != nil { t.Errorf("can not get account from address: %v", err) } @@ -312,7 +311,7 @@ func testRecoverAccount(t *testing.T) bool { } // time to login with recovered data - whisperService, err := geth.GetNodeManager().WhisperService() + whisperService, err := geth.NodeManagerInstance().WhisperService() if err != nil { t.Errorf("whisper service not running: %v", err) } @@ -335,7 +334,7 @@ func testRecoverAccount(t *testing.T) bool { func testAccountSelect(t *testing.T) bool { // test to see if the account was injected in whisper - whisperService, err := geth.GetNodeManager().WhisperService() + whisperService, err := geth.NodeManagerInstance().WhisperService() if err != nil { t.Errorf("whisper service not running: %v", err) } @@ -418,7 +417,7 @@ func testAccountSelect(t *testing.T) bool { } func testAccountLogout(t *testing.T) bool { - whisperService, err := geth.GetNodeManager().WhisperService() + whisperService, err := geth.NodeManagerInstance().WhisperService() if err != nil { t.Errorf("whisper service not running: %v", err) return false @@ -472,7 +471,7 @@ func testAccountLogout(t *testing.T) bool { func testCompleteTransaction(t *testing.T) bool { // obtain reference to status backend - lightEthereum, err := geth.GetNodeManager().LightEthereumService() + lightEthereum, err := geth.NodeManagerInstance().LightEthereumService() if err != nil { t.Errorf("Test failed: LES service is not running: %v", err) return false @@ -551,7 +550,7 @@ func testCompleteTransaction(t *testing.T) bool { func testCompleteMultipleQueuedTransactions(t *testing.T) bool { // obtain reference to status backend - lightEthereum, err := geth.GetNodeManager().LightEthereumService() + lightEthereum, err := geth.NodeManagerInstance().LightEthereumService() if err != nil { t.Errorf("Test failed: LES service is not running: %v", err) return false @@ -680,7 +679,7 @@ func testCompleteMultipleQueuedTransactions(t *testing.T) bool { func testDiscardTransaction(t *testing.T) bool { // obtain reference to status backend - lightEthereum, err := geth.GetNodeManager().LightEthereumService() + lightEthereum, err := geth.NodeManagerInstance().LightEthereumService() if err != nil { t.Errorf("Test failed: LES service is not running: %v", err) return false @@ -794,7 +793,7 @@ func testDiscardTransaction(t *testing.T) bool { func testDiscardMultipleQueuedTransactions(t *testing.T) bool { // obtain reference to status backend - lightEthereum, err := geth.GetNodeManager().LightEthereumService() + lightEthereum, err := geth.NodeManagerInstance().LightEthereumService() if err != nil { t.Errorf("Test failed: LES service is not running: %v", err) return false diff --git a/geth/accounts.go b/geth/accounts.go index 4812c7692..3a048d59d 100644 --- a/geth/accounts.go +++ b/geth/accounts.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/status-im/status-go/extkeys" @@ -20,6 +19,7 @@ var ( ErrWhisperNoIdentityFound = errors.New("failed to locate identity previously injected into Whisper") ErrNoAccountSelected = errors.New("no account has been selected, please login") ErrInvalidMasterKeyCreated = errors.New("can not create master extended key") + ErrInvalidAccountAddressOrKey = errors.New("cannot parse address or key to valid account address") ) // CreateAccount creates an internal geth account @@ -53,7 +53,7 @@ func CreateAccount(password string) (address, pubKey, mnemonic string, err error // CKD#2 is used as root for master accounts (when parentAddress is ""). // Otherwise (when parentAddress != ""), child is derived directly from parent. func CreateChildAccount(parentAddress, password string) (address, pubKey string, err error) { - nodeManager := GetNodeManager() + nodeManager := NodeManagerInstance() accountManager, err := nodeManager.AccountManager() if err != nil { return "", "", err @@ -67,7 +67,7 @@ func CreateChildAccount(parentAddress, password string) (address, pubKey string, return "", "", ErrNoAccountSelected } - account, err := utils.MakeAddress(accountManager, parentAddress) + account, err := ParseAccountString(accountManager, parentAddress) if err != nil { return "", "", ErrAddressToAccountMappingFailure } @@ -128,13 +128,13 @@ func RecoverAccount(password, mnemonic string) (address, pubKey string, err erro // using provided password. Once verification is done, decrypted key is injected into Whisper (as a single identity, // all previous identities are removed). func SelectAccount(address, password string) error { - nodeManager := GetNodeManager() + nodeManager := NodeManagerInstance() accountManager, err := nodeManager.AccountManager() if err != nil { return err } - account, err := utils.MakeAddress(accountManager, address) + account, err := ParseAccountString(accountManager, address) if err != nil { return ErrAddressToAccountMappingFailure } @@ -169,7 +169,7 @@ func SelectAccount(address, password string) error { // Logout clears whisper identities func Logout() error { - nodeManager := GetNodeManager() + nodeManager := NodeManagerInstance() whisperService, err := nodeManager.WhisperService() if err != nil { return err @@ -195,7 +195,7 @@ func UnlockAccount(address, password string, seconds int) error { // importExtendedKey processes incoming extended key, extracts required info and creates corresponding account key. // Once account key is formed, that key is put (if not already) into keystore i.e. key is *encoded* into key file. func importExtendedKey(extKey *extkeys.ExtendedKey, password string) (address, pubKey string, err error) { - accountManager, err := GetNodeManager().AccountManager() + accountManager, err := NodeManagerInstance().AccountManager() if err != nil { return "", "", err } @@ -218,7 +218,7 @@ func importExtendedKey(extKey *extkeys.ExtendedKey, password string) (address, p } func onAccountsListRequest(entities []accounts.Account) []accounts.Account { - nodeManager := GetNodeManager() + nodeManager := NodeManagerInstance() if nodeManager.SelectedAccount == nil { return []accounts.Account{} @@ -246,7 +246,7 @@ func onAccountsListRequest(entities []accounts.Account) []accounts.Account { // refreshSelectedAccount re-populates list of sub-accounts of the currently selected account (if any) func refreshSelectedAccount() { - nodeManager := GetNodeManager() + nodeManager := NodeManagerInstance() if nodeManager.SelectedAccount == nil { return @@ -273,7 +273,7 @@ func refreshSelectedAccount() { // that belong to the currently selected account. // The extKey is CKD#2 := root of sub-accounts of the main account func findSubAccounts(extKey *extkeys.ExtendedKey, subAccountIndex uint32) ([]accounts.Account, error) { - nodeManager := GetNodeManager() + nodeManager := NodeManagerInstance() accountManager, err := nodeManager.AccountManager() if err != nil { return []accounts.Account{}, err diff --git a/geth/accounts_test.go b/geth/accounts_test.go index 4f269d60c..8258f43fa 100644 --- a/geth/accounts_test.go +++ b/geth/accounts_test.go @@ -5,7 +5,6 @@ import ( "reflect" "testing" - "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/status-im/status-go/geth" @@ -18,7 +17,7 @@ func TestAccountsList(t *testing.T) { return } - les, err := geth.GetNodeManager().LightEthereumService() + les, err := geth.NodeManagerInstance().LightEthereumService() if err != nil { t.Errorf("expected LES service: %v", err) } @@ -130,7 +129,7 @@ func TestCreateChildAccount(t *testing.T) { geth.Logout() // to make sure that we start with empty account (which might get populated during previous tests) - accountManager, err := geth.GetNodeManager().AccountManager() + accountManager, err := geth.NodeManagerInstance().AccountManager() if err != nil { t.Error(err) return @@ -144,7 +143,7 @@ func TestCreateChildAccount(t *testing.T) { } t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic) - account, err := utils.MakeAddress(accountManager, address) + account, err := geth.ParseAccountString(accountManager, address) if err != nil { t.Errorf("can not get account from address: %v", err) return @@ -217,7 +216,7 @@ func TestRecoverAccount(t *testing.T) { return } - accountManager, _ := geth.GetNodeManager().AccountManager() + accountManager, _ := geth.NodeManagerInstance().AccountManager() // create an account address, pubKey, mnemonic, err := geth.CreateAccount(newAccountPassword) @@ -238,7 +237,7 @@ func TestRecoverAccount(t *testing.T) { } // now test recovering, but make sure that account/key file is removed i.e. simulate recovering on a new device - account, err := utils.MakeAddress(accountManager, address) + account, err := geth.ParseAccountString(accountManager, address) if err != nil { t.Errorf("can not get account from address: %v", err) } @@ -284,7 +283,7 @@ func TestRecoverAccount(t *testing.T) { } // time to login with recovered data - whisperService, err := geth.GetNodeManager().WhisperService() + whisperService, err := geth.NodeManagerInstance().WhisperService() if err != nil { t.Errorf("whisper service not running: %v", err) } @@ -312,7 +311,7 @@ func TestAccountSelect(t *testing.T) { } // test to see if the account was injected in whisper - whisperService, err := geth.GetNodeManager().WhisperService() + whisperService, err := geth.NodeManagerInstance().WhisperService() if err != nil { t.Errorf("whisper service not running: %v", err) } @@ -377,7 +376,7 @@ func TestAccountLogout(t *testing.T) { return } - whisperService, err := geth.GetNodeManager().WhisperService() + whisperService, err := geth.NodeManagerInstance().WhisperService() if err != nil { t.Errorf("whisper service not running: %v", err) } diff --git a/geth/node.go b/geth/node.go index 84cc82d7e..c2a4417b9 100644 --- a/geth/node.go +++ b/geth/node.go @@ -1,304 +1,249 @@ package geth -/* -#include -#include -extern bool StatusServiceSignalEvent( const char *jsonEvent ); -*/ -import "C" import ( - "encoding/json" "errors" - "flag" "fmt" - "io/ioutil" + "io" + "math/big" + "os" "path/filepath" + "reflect" "runtime" - "sync" + "strings" + "syscall" - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/rpc" whisper "github.com/ethereum/go-ethereum/whisper/whisperv2" - "gopkg.in/urfave/cli.v1" ) const ( - clientIdentifier = "Geth" // Client identifier to advertise over the network - versionMajor = 1 // Major version component of the current release - versionMinor = 5 // Minor version component of the current release - versionPatch = 0 // Patch version component of the current release - versionMeta = "unstable" // Version metadata to append to the version string + ClientIdentifier = "StatusIM" // Client identifier to advertise over the network + VersionMajor = 1 // Major version component of the current release + VersionMinor = 1 // Minor version component of the current release + VersionPatch = 0 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string - RPCPort = 8545 // RPC port (replaced in unit tests) - NetworkPort = 30303 + RPCPort = 8545 // RPC port (replaced in unit tests) + NetworkPort = 30303 + MaxPeers = 25 + MaxLightPeers = 20 + MaxPendingPeers = 0 + + ProcessFileDescriptorLimit = uint64(2048) + DatabaseCacheSize = 128 // Megabytes of memory allocated to internal caching (min 16MB / database forced) EventNodeStarted = "node.started" ) +// Gas price settings var ( - ErrDataDirPreprocessingFailed = errors.New("failed to pre-process data directory") - ErrInvalidGethNode = errors.New("no running geth node detected") - ErrInvalidAccountManager = errors.New("could not retrieve account manager") - ErrInvalidWhisperService = errors.New("whisper service is unavailable") - ErrInvalidLightEthereumService = errors.New("can not retrieve LES service") - ErrInvalidClient = errors.New("RPC client is not properly initialized") - ErrInvalidJailedRequestQueue = errors.New("Jailed request queue is not properly initialized") - ErrNodeStartFailure = errors.New("could not create the in-memory node object") + GasPrice = new(big.Int).Mul(big.NewInt(20), common.Shannon) // Minimal gas price to accept for mining a transactions + GpoMinGasPrice = new(big.Int).Mul(big.NewInt(20), common.Shannon) // Minimum suggested gas price + GpoMaxGasPrice = new(big.Int).Mul(big.NewInt(500), common.Shannon) // Maximum suggested gas price + GpoFullBlockRatio = 80 // Full block threshold for gas price calculation (%) + GpobaseStepDown = 10 // Suggested gas price base step down ratio (1/1000) + GpobaseStepUp = 100 // Suggested gas price base step up ratio (1/1000) + GpobaseCorrectionFactor = 110 // Suggested gas price base correction factor (%) ) -type SelectedExtKey struct { - Address common.Address - AccountKey *accounts.Key - SubAccounts []accounts.Account -} - -type NodeManager struct { - currentNode *node.Node // currently running geth node - ctx *cli.Context // the CLI context used to start the geth node - lightEthereum *les.LightEthereum // LES service - accountManager *accounts.Manager // the account manager attached to the currentNode - jailedRequestQueue *JailedRequestQueue // bridge via which jail notifies node of incoming requests - SelectedAccount *SelectedExtKey // account that was processed during the last call to SelectAccount() - whisperService *whisper.Whisper // Whisper service - client *rpc.Client // RPC client - nodeStarted chan struct{} // channel to wait for node to start -} - +// default node configuration options var ( - UseTestnet = "true" // can be overridden via -ldflags '-X geth.UseTestnet' - nodeManagerInstance *NodeManager - createOnce sync.Once + UseTestnetFlag = "true" // to be overridden via -ldflags '-X geth.UseTestnetFlag' + UseTestnet = false ) -func NewNodeManager(datadir string, rpcport int) *NodeManager { - createOnce.Do(func() { - nodeManagerInstance = &NodeManager{ - jailedRequestQueue: NewJailedRequestsQueue(), - } - nodeManagerInstance.MakeNode(datadir, rpcport) - }) - - return nodeManagerInstance -} - -func GetNodeManager() *NodeManager { - return nodeManagerInstance -} - -// createAndStartNode creates a node entity and starts the -// node running locally exposing given RPC port -func CreateAndRunNode(datadir string, rpcport int) error { - nodeManager := NewNodeManager(datadir, rpcport) - - if nodeManager.HasNode() { - nodeManager.RunNode() - - <-nodeManager.nodeStarted // block until node is ready - return nil +func init() { + if UseTestnetFlag == "true" { // set at compile time, here we make sure to set corresponding boolean flag + UseTestnet = true } +} - return ErrNodeStartFailure +// node-related errors +var ( + ErrRLimitRaiseFailure = errors.New("failed to register the whisper service") + ErrDatabaseAccessFailure = errors.New("could not open database") + ErrChainConfigurationFailure = errors.New("could not make chain configuration") + ErrEthServiceRegistrationFailure = errors.New("failed to register the Ethereum service") + ErrSshServiceRegistrationFailure = errors.New("failed to register the Whisper service") + ErrLightEthRegistrationFailure = errors.New("failed to register the LES service") +) + +type Node struct { + geth *node.Node // reference to the running Geth node + started chan struct{} // channel to wait for node to start +} + +// Inited checks whether status node has been properly initialized +func (n *Node) Inited() bool { + return n != nil && n.geth != nil } // MakeNode create a geth node entity -func (m *NodeManager) MakeNode(datadir string, rpcport int) *node.Node { - // TODO remove admin rpcapi flag - set := flag.NewFlagSet("test", 0) - set.Bool("lightkdf", true, "Reduce key-derivation RAM & CPU usage at some expense of KDF strength") - set.Bool("shh", true, "whisper") - set.Bool("light", true, "enable light client mode") - if UseTestnet == "true" { - set.Bool("testnet", true, "test network") - } - set.Bool("rpc", true, "enable rpc") - set.String("rpcaddr", "localhost", "host for RPC") - set.Int("rpcport", rpcport, "rpc port") - set.String("rpccorsdomain", "*", "allow all domains") - set.String("verbosity", "3", "verbosity level") - set.String("rpcapi", "db,eth,net,web3,shh,personal,admin", "rpc api(s)") - set.String("datadir", datadir, "data directory for geth") - set.String("logdir", datadir, "log dir for glog") - set.Int("port", NetworkPort, "network listening port") - m.ctx = cli.NewContext(nil, set, nil) +func MakeNode(dataDir string, rpcPort int) *Node { + glog.CopyStandardLogTo("INFO") + glog.SetToStderr(true) - utils.DebugSetup(m.ctx) - - // create node and start requested protocols - m.currentNode = utils.MakeNode(m.ctx, clientIdentifier, "") - utils.RegisterEthService(m.ctx, m.currentNode, makeDefaultExtra()) - - // Whisper must be explicitly enabled, but is auto-enabled in --dev mode. - shhEnabled := m.ctx.GlobalBool(utils.WhisperEnabledFlag.Name) - shhAutoEnabled := !m.ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && m.ctx.GlobalIsSet(utils.DevModeFlag.Name) - if shhEnabled || shhAutoEnabled { - utils.RegisterShhService(m.currentNode) + bootstrapNodes := params.MainnetBootnodes + if UseTestnet { + dataDir = filepath.Join(dataDir, "testnet") + bootstrapNodes = params.TestnetBootnodes } - m.accountManager = m.currentNode.AccountManager() - m.nodeStarted = make(chan struct{}) - - return m.currentNode -} - -// StartNode starts a geth node entity -func (m *NodeManager) RunNode() { - go func() { - utils.StartNode(m.currentNode) - - if m.currentNode.AccountManager() == nil { - glog.V(logger.Warn).Infoln("cannot get account manager") - } - if err := m.currentNode.Service(&m.whisperService); err != nil { - glog.V(logger.Warn).Infoln("cannot get whisper service:", err) - } - if err := m.currentNode.Service(&m.lightEthereum); err != nil { - glog.V(logger.Warn).Infoln("cannot get light ethereum service:", err) - } - - // setup handlers - m.lightEthereum.StatusBackend.SetTransactionQueueHandler(onSendTransactionRequest) - m.lightEthereum.StatusBackend.SetAccountsFilterHandler(onAccountsListRequest) - m.lightEthereum.StatusBackend.SetTransactionReturnHandler(onSendTransactionReturn) - - var err error - m.client, err = m.currentNode.Attach() - if err != nil { - glog.V(logger.Warn).Infoln("cannot get RPC client service:", ErrInvalidClient) - } - - // @TODO Remove after LES supports discover out of box - m.populateStaticPeers() - - m.onNodeStarted() // node started, notify listeners - m.currentNode.Wait() - }() -} - -func (m *NodeManager) onNodeStarted() { - // notify local listener - m.nodeStarted <- struct{}{} - close(m.nodeStarted) - - // send signal up to native app - event := GethEvent{ - Type: EventNodeStarted, - Event: struct{}{}, + // configure required node (should you need to update node's config, e.g. add bootstrap nodes, see node.Config) + config := &node.Config{ + DataDir: dataDir, + UseLightweightKDF: true, + Name: ClientIdentifier, + Version: fmt.Sprintf("%d.%d.%d-%s", VersionMajor, VersionMinor, VersionPatch, VersionMeta), + NoDiscovery: true, + DiscoveryV5: true, + DiscoveryV5Addr: fmt.Sprintf(":%d", NetworkPort+1), + BootstrapNodes: bootstrapNodes, + BootstrapNodesV5: params.DiscoveryV5Bootnodes, + ListenAddr: fmt.Sprintf(":%d", NetworkPort), + MaxPeers: MaxPeers, + MaxPendingPeers: MaxPendingPeers, + HTTPHost: node.DefaultHTTPHost, + HTTPPort: rpcPort, + HTTPCors: "*", + HTTPModules: strings.Split("db,eth,net,web3,shh,personal,admin", ","), // TODO remove "admin" on main net } - body, _ := json.Marshal(&event) - C.StatusServiceSignalEvent(C.CString(string(body))) -} - -func (m *NodeManager) AddPeer(url string) (bool, error) { - if m == nil || !m.HasNode() { - return false, ErrInvalidGethNode - } - - server := m.currentNode.Server() - if server == nil { - return false, errors.New("node not started") - } - // Try to add the url as a static peer and return - parsedNode, err := discover.ParseNode(url) + stack, err := node.New(config) if err != nil { - return false, fmt.Errorf("invalid enode: %v", err) - } - server.AddPeer(parsedNode) - - return true, nil -} - -func (m *NodeManager) HasNode() bool { - return m != nil && m.currentNode != nil -} - -func (m *NodeManager) HasAccountManager() bool { - return m.accountManager != nil -} - -func (m *NodeManager) AccountManager() (*accounts.Manager, error) { - if m == nil || !m.HasNode() { - return nil, ErrInvalidGethNode + Fatalf(ErrNodeMakeFailure) } - if !m.HasAccountManager() { - return nil, ErrInvalidAccountManager + // start Ethereum service + if err := activateEthService(stack, makeDefaultExtra()); err != nil { + Fatalf(fmt.Errorf("%v: %v", ErrEthServiceRegistrationFailure, err)) } - return m.accountManager, nil + // start Whisper service + if err := activateShhService(stack); err != nil { + Fatalf(fmt.Errorf("%v: %v", ErrSshServiceRegistrationFailure, err)) + } + + return &Node{ + geth: stack, + started: make(chan struct{}), + } } -func (m *NodeManager) HasWhisperService() bool { - return m.whisperService != nil +// activateEthService configures and registers the eth.Ethereum service with a given node. +func activateEthService(stack *node.Node, extra []byte) error { + ethConf := ð.Config{ + Etherbase: common.Address{}, + ChainConfig: makeChainConfig(stack), + FastSync: false, + LightMode: true, + LightServ: 60, + LightPeers: MaxLightPeers, + MaxPeers: MaxPeers, + DatabaseCache: DatabaseCacheSize, + DatabaseHandles: makeDatabaseHandles(), + NetworkId: 1, // Olympic + MinerThreads: runtime.NumCPU(), + GasPrice: GasPrice, + GpoMinGasPrice: GpoMinGasPrice, + GpoMaxGasPrice: GpoMaxGasPrice, + GpoFullBlockRatio: GpoFullBlockRatio, + GpobaseStepDown: GpobaseStepDown, + GpobaseStepUp: GpobaseStepUp, + GpobaseCorrectionFactor: GpobaseCorrectionFactor, + SolcPath: "solc", + AutoDAG: false, + } + + if UseTestnet { + ethConf.NetworkId = 3 + ethConf.Genesis = core.DefaultTestnetGenesisBlock() + } + + if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + return les.New(ctx, ethConf) + }); err != nil { + return fmt.Errorf("%v: %v", ErrLightEthRegistrationFailure, err) + } + + return nil } -func (m *NodeManager) WhisperService() (*whisper.Whisper, error) { - if m == nil || !m.HasNode() { - return nil, ErrInvalidGethNode +// activateShhService configures Whisper and adds it to the given node. +func activateShhService(stack *node.Node) error { + serviceConstructor := func(*node.ServiceContext) (node.Service, error) { + return whisper.New(), nil + } + if err := stack.Register(serviceConstructor); err != nil { + return err } - if !m.HasWhisperService() { - return nil, ErrInvalidWhisperService - } - - return m.whisperService, nil + return nil } -func (m *NodeManager) HasLightEthereumService() bool { - return m.lightEthereum != nil +// makeChainConfig reads the chain configuration from the database in the datadir. +func makeChainConfig(stack *node.Node) *params.ChainConfig { + config := new(params.ChainConfig) + + if UseTestnet { + config = params.TestnetChainConfig + } else { + // Homestead fork + config.HomesteadBlock = params.MainNetHomesteadBlock + // DAO fork + config.DAOForkBlock = params.MainNetDAOForkBlock + config.DAOForkSupport = true + + // DoS reprice fork + config.EIP150Block = params.MainNetHomesteadGasRepriceBlock + config.EIP150Hash = params.MainNetHomesteadGasRepriceHash + + // DoS state cleanup fork + config.EIP155Block = params.MainNetSpuriousDragon + config.EIP158Block = params.MainNetSpuriousDragon + config.ChainId = params.MainNetChainID + } + + return config } -func (m *NodeManager) LightEthereumService() (*les.LightEthereum, error) { - if m == nil || !m.HasNode() { - return nil, ErrInvalidGethNode +// makeDatabaseHandles makes sure that enough file descriptors are available to the process +// (and returns half of them for node's database to use) +func makeDatabaseHandles() int { + // current limit + var limit syscall.Rlimit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + Fatalf(err) } - if !m.HasLightEthereumService() { - return nil, ErrInvalidLightEthereumService + // increase limit + limit.Cur = limit.Max + if limit.Cur > ProcessFileDescriptorLimit { + limit.Cur = ProcessFileDescriptorLimit + } + if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + Fatalf(err) } - return m.lightEthereum, nil -} - -func (m *NodeManager) HasRPCClient() bool { - return m.client != nil -} - -func (m *NodeManager) RPCClient() (*rpc.Client, error) { - if m == nil || !m.HasNode() { - return nil, ErrInvalidGethNode + // re-query limit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + Fatalf(err) } - if !m.HasRPCClient() { - return nil, ErrInvalidClient + // cap limit + if limit.Cur > ProcessFileDescriptorLimit { + limit.Cur = ProcessFileDescriptorLimit } - return m.client, nil -} - -func (m *NodeManager) HasJailedRequestQueue() bool { - return m.jailedRequestQueue != nil -} - -func (m *NodeManager) JailedRequestQueue() (*JailedRequestQueue, error) { - if m == nil || !m.HasNode() { - return nil, ErrInvalidGethNode - } - - if !m.HasJailedRequestQueue() { - return nil, ErrInvalidJailedRequestQueue - } - - return m.jailedRequestQueue, nil + return int(limit.Cur) / 2 } func makeDefaultExtra() []byte { @@ -307,7 +252,7 @@ func makeDefaultExtra() []byte { Name string GoVersion string Os string - }{uint(versionMajor<<16 | versionMinor<<8 | versionPatch), clientIdentifier, runtime.Version(), runtime.GOOS} + }{uint(VersionMajor<<16 | VersionMinor<<8 | VersionPatch), ClientIdentifier, runtime.Version(), runtime.GOOS} extra, err := rlp.EncodeToBytes(clientInfo) if err != nil { glog.V(logger.Warn).Infoln("error setting canonical miner information:", err) @@ -322,18 +267,22 @@ func makeDefaultExtra() []byte { return extra } -func (m *NodeManager) populateStaticPeers() { - // manually add static nodes (LES auto-discovery is not stable yet) - configFile, err := ioutil.ReadFile(filepath.Join("../data", "static-nodes.json")) - if err != nil { - return - } - var enodes []string - if err = json.Unmarshal(configFile, &enodes); err != nil { - return +func Fatalf(reason interface{}, args ...interface{}) { + // decide on output stream + w := io.MultiWriter(os.Stdout, os.Stderr) + outf, _ := os.Stdout.Stat() + errf, _ := os.Stderr.Stat() + if outf != nil && errf != nil && os.SameFile(outf, errf) { + w = os.Stderr } - for _, enode := range enodes { - m.AddPeer(enode) + // find out whether error or string has been passed as a reason + r := reflect.ValueOf(reason) + if r.Kind() == reflect.String { + fmt.Fprintf(w, "Fatal Failure: "+reason.(string)+"\n", args) + } else { + fmt.Fprintf(w, "Fatal Failure: %v\n", reason.(error)) } + + os.Exit(1) } diff --git a/geth/node_manager.go b/geth/node_manager.go new file mode 100644 index 000000000..79c3f80a7 --- /dev/null +++ b/geth/node_manager.go @@ -0,0 +1,289 @@ +package geth + +/* +#include +#include +extern bool StatusServiceSignalEvent( const char *jsonEvent ); +*/ +import "C" +import ( + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "os" + "os/signal" + "path/filepath" + "sync" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/les" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" + "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/rpc" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv2" +) + +// SelectedExtKey is a container for currently selected (logged in) account +type SelectedExtKey struct { + Address common.Address + AccountKey *accounts.Key + SubAccounts []accounts.Account +} + +// NodeManager manages Status node (which abstracts contained geth node) +type NodeManager struct { + node *Node // reference to Status node + services *NodeServiceStack // default stack of services running on geth node + SelectedAccount *SelectedExtKey // account that was processed during the last call to SelectAccount() +} + +// NodeServiceStack contains "standard" node services (which are always available) +type NodeServiceStack struct { + lightEthereum *les.LightEthereum // LES service + whisperService *whisper.Whisper // Whisper service + rpcClient *rpc.Client // RPC client + jailedRequestQueue *JailedRequestQueue // bridge via which jail notifies node of incoming requests +} + +var ( + ErrDataDirPreprocessingFailed = errors.New("failed to pre-process data directory") + ErrInvalidGethNode = errors.New("no running geth node detected") + ErrInvalidAccountManager = errors.New("could not retrieve account manager") + ErrInvalidWhisperService = errors.New("whisper service is unavailable") + ErrInvalidLightEthereumService = errors.New("can not retrieve LES service") + ErrInvalidClient = errors.New("RPC client is not properly initialized") + ErrInvalidJailedRequestQueue = errors.New("jailed request queue is not properly initialized") + ErrNodeMakeFailure = errors.New("error creating p2p node") + ErrNodeStartFailure = errors.New("error starting p2p node") +) + +var ( + nodeManagerInstance *NodeManager + createOnce sync.Once +) + +// CreateAndRunNode creates and starts running Geth node locally (exposing given RPC port along the way) +func CreateAndRunNode(dataDir string, rpcPort int) error { + nodeManager := NewNodeManager(dataDir, rpcPort) + + if nodeManager.NodeInited() { + nodeManager.RunNode() + + <-nodeManager.node.started // block until node is ready + return nil + } + + return ErrNodeStartFailure +} + +// NewNodeManager makes new instance of node manager +func NewNodeManager(dataDir string, rpcPort int) *NodeManager { + createOnce.Do(func() { + nodeManagerInstance = &NodeManager{ + services: &NodeServiceStack{ + jailedRequestQueue: NewJailedRequestsQueue(), + }, + } + nodeManagerInstance.node = MakeNode(dataDir, rpcPort) + }) + + return nodeManagerInstance +} + +// NodeManagerInstance exposes node manager instance +func NodeManagerInstance() *NodeManager { + return nodeManagerInstance +} + +// RunNode starts Geth node +func (m *NodeManager) RunNode() { + go func() { + m.StartNode() + + if _, err := m.AccountManager(); err != nil { + glog.V(logger.Warn).Infoln(ErrInvalidAccountManager) + } + if err := m.node.geth.Service(&m.services.whisperService); err != nil { + glog.V(logger.Warn).Infoln("cannot get whisper service:", err) + } + if err := m.node.geth.Service(&m.services.lightEthereum); err != nil { + glog.V(logger.Warn).Infoln("cannot get light ethereum service:", err) + } + + // setup handlers + lightEthereum, err := m.LightEthereumService() + if err != nil { + panic("service stack misses LES") + } + + lightEthereum.StatusBackend.SetTransactionQueueHandler(onSendTransactionRequest) + lightEthereum.StatusBackend.SetAccountsFilterHandler(onAccountsListRequest) + lightEthereum.StatusBackend.SetTransactionReturnHandler(onSendTransactionReturn) + + m.services.rpcClient, err = m.node.geth.Attach() + if err != nil { + glog.V(logger.Warn).Infoln("cannot get RPC client service:", ErrInvalidClient) + } + + // @TODO Remove after LES supports discover out of box + m.populateStaticPeers() + + m.onNodeStarted() // node started, notify listeners + m.node.geth.Wait() + }() +} + +// StartNode starts running P2P node +func (m *NodeManager) StartNode() { + if m == nil || !m.NodeInited() { + panic(ErrInvalidGethNode) + } + + if err := m.node.geth.Start(); err != nil { + panic(fmt.Sprintf("%v: %v", ErrNodeStartFailure, err)) + } + + // allow interrupting running nodes + go func() { + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, os.Interrupt) + defer signal.Stop(sigc) + <-sigc + glog.V(logger.Info).Infoln("Got interrupt, shutting down...") + go m.node.geth.Stop() + for i := 3; i > 0; i-- { + <-sigc + if i > 1 { + glog.V(logger.Info).Infof("Already shutting down, interrupt %d more times for panic.", i-1) + } + } + panic("interrupted!") + }() +} + +// HasNode checks whether manager has initialized node attached +func (m *NodeManager) NodeInited() bool { + if m == nil || !m.node.Inited() { + return false + } + + return true +} + +// AccountManager exposes reference to accounts manager +func (m *NodeManager) AccountManager() (*accounts.Manager, error) { + if m == nil || !m.NodeInited() { + return nil, ErrInvalidGethNode + } + + return m.node.geth.AccountManager(), nil +} + +// LightEthereumService exposes LES +func (m *NodeManager) LightEthereumService() (*les.LightEthereum, error) { + if m == nil || !m.NodeInited() { + return nil, ErrInvalidGethNode + } + + if m.services.lightEthereum == nil { + return nil, ErrInvalidLightEthereumService + } + + return m.services.lightEthereum, nil +} + +// WhisperService exposes Whisper service +func (m *NodeManager) WhisperService() (*whisper.Whisper, error) { + if m == nil || !m.NodeInited() { + return nil, ErrInvalidGethNode + } + + if m.services.whisperService == nil { + return nil, ErrInvalidWhisperService + } + + return m.services.whisperService, nil +} + +// RPCClient exposes Geth's RPC client +func (m *NodeManager) RPCClient() (*rpc.Client, error) { + if m == nil || !m.NodeInited() { + return nil, ErrInvalidGethNode + } + + if m.services.rpcClient == nil { + return nil, ErrInvalidClient + } + + return m.services.rpcClient, nil +} + +// JailedRequestQueue exposes reference to queue of jailed requests +func (m *NodeManager) JailedRequestQueue() (*JailedRequestQueue, error) { + if m == nil || !m.NodeInited() { + return nil, ErrInvalidGethNode + } + + if m.services.jailedRequestQueue == nil { + return nil, ErrInvalidJailedRequestQueue + } + + return m.services.jailedRequestQueue, nil +} + +// AddPeer adds new peer node +func (m *NodeManager) AddPeer(url string) (bool, error) { + if m == nil || !m.NodeInited() { + return false, ErrInvalidGethNode + } + + server := m.node.geth.Server() + if server == nil { + return false, ErrInvalidGethNode + } + + // Try to add the url as a static peer and return + parsedNode, err := discover.ParseNode(url) + if err != nil { + return false, fmt.Errorf("invalid enode: %v", err) + } + server.AddPeer(parsedNode) + + return true, nil +} + +// onNodeStarted sends upward notification letting the app know that Geth node is ready to be used +func (m *NodeManager) onNodeStarted() { + // notify local listener + m.node.started <- struct{}{} + close(m.node.started) + + // send signal up to native app + event := GethEvent{ + Type: EventNodeStarted, + Event: struct{}{}, + } + + body, _ := json.Marshal(&event) + C.StatusServiceSignalEvent(C.CString(string(body))) +} + +// populateStaticPeers connects current node with our publicly available LES cluster +func (m *NodeManager) populateStaticPeers() { + // manually add static nodes (LES auto-discovery is not stable yet) + configFile, err := ioutil.ReadFile(filepath.Join("../data", "static-nodes.json")) + if err != nil { + return + } + var enodes []string + if err = json.Unmarshal(configFile, &enodes); err != nil { + return + } + + for _, enode := range enodes { + m.AddPeer(enode) + } +} diff --git a/geth/node_test.go b/geth/node_manager_test.go similarity index 100% rename from geth/node_test.go rename to geth/node_manager_test.go diff --git a/geth/txqueue.go b/geth/txqueue.go index 72a93caae..ba2fd5e9c 100644 --- a/geth/txqueue.go +++ b/geth/txqueue.go @@ -92,7 +92,7 @@ func sendTransactionErrorCode(err error) string { } func CompleteTransaction(id, password string) (common.Hash, error) { - lightEthereum, err := GetNodeManager().LightEthereumService() + lightEthereum, err := NodeManagerInstance().LightEthereumService() if err != nil { return common.Hash{}, err } @@ -125,7 +125,7 @@ func CompleteTransactions(ids, password string) map[string]RawCompleteTransactio } func DiscardTransaction(id string) error { - lightEthereum, err := GetNodeManager().LightEthereumService() + lightEthereum, err := NodeManagerInstance().LightEthereumService() if err != nil { return err } @@ -195,7 +195,7 @@ func (q *JailedRequestQueue) PostProcessRequest(vm *otto.Otto, req RPCCall, mess func (q *JailedRequestQueue) ProcessSendTransactionRequest(vm *otto.Otto, req RPCCall) (common.Hash, error) { // obtain status backend from LES service - lightEthereum, err := GetNodeManager().LightEthereumService() + lightEthereum, err := NodeManagerInstance().LightEthereumService() if err != nil { return common.Hash{}, err } diff --git a/geth/txqueue_test.go b/geth/txqueue_test.go index b49c21eab..77bc87c8e 100644 --- a/geth/txqueue_test.go +++ b/geth/txqueue_test.go @@ -21,7 +21,7 @@ func TestQueuedTransactions(t *testing.T) { } // obtain reference to status backend - lightEthereum, err := geth.GetNodeManager().LightEthereumService() + lightEthereum, err := geth.NodeManagerInstance().LightEthereumService() if err != nil { t.Errorf("Test failed: LES service is not running: %v", err) return @@ -91,7 +91,7 @@ func TestDoubleCompleteQueuedTransactions(t *testing.T) { } // obtain reference to status backend - lightEthereum, err := geth.GetNodeManager().LightEthereumService() + lightEthereum, err := geth.NodeManagerInstance().LightEthereumService() if err != nil { t.Errorf("Test failed: LES service is not running: %v", err) return @@ -212,7 +212,7 @@ func TestDiscardQueuedTransactions(t *testing.T) { } // obtain reference to status backend - lightEthereum, err := geth.GetNodeManager().LightEthereumService() + lightEthereum, err := geth.NodeManagerInstance().LightEthereumService() if err != nil { t.Errorf("Test failed: LES service is not running: %v", err) return @@ -327,7 +327,7 @@ func TestCompleteMultipleQueuedTransactions(t *testing.T) { } // obtain reference to status backend - lightEthereum, err := geth.GetNodeManager().LightEthereumService() + lightEthereum, err := geth.NodeManagerInstance().LightEthereumService() if err != nil { t.Errorf("Test failed: LES service is not running: %v", err) return @@ -452,7 +452,7 @@ func TestDiscardMultipleQueuedTransactions(t *testing.T) { } // obtain reference to status backend - lightEthereum, err := geth.GetNodeManager().LightEthereumService() + lightEthereum, err := geth.NodeManagerInstance().LightEthereumService() if err != nil { t.Errorf("Test failed: LES service is not running: %v", err) return @@ -653,7 +653,7 @@ func TestEvictionOfQueuedTransactions(t *testing.T) { } // obtain reference to status backend - lightEthereum, err := geth.GetNodeManager().LightEthereumService() + lightEthereum, err := geth.NodeManagerInstance().LightEthereumService() if err != nil { t.Errorf("Test failed: LES service is not running: %v", err) return diff --git a/geth/utils.go b/geth/utils.go index 6dfe9a4d7..51aeabfdb 100644 --- a/geth/utils.go +++ b/geth/utils.go @@ -12,10 +12,11 @@ import ( "os" "path" "path/filepath" + "strconv" "sync" "time" - "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" @@ -86,8 +87,8 @@ func PrepareTestNode() (err error) { muPrepareTestNode.Lock() defer muPrepareTestNode.Unlock() - manager := GetNodeManager() - if manager.HasNode() { + manager := NodeManagerInstance() + if manager.NodeInited() { return nil } @@ -117,17 +118,17 @@ func PrepareTestNode() (err error) { // internally once.Do() is used, so call below is thread-safe CreateAndRunNode(dataDir, 8546) // to avoid conflicts with running react-native app, run on different port - manager = GetNodeManager() - if !manager.HasNode() { + manager = NodeManagerInstance() + if !manager.NodeInited() { panic(ErrInvalidGethNode) } - if !manager.HasRPCClient() { + if service, err := manager.RPCClient(); err != nil || service == nil { panic(ErrInvalidGethNode) } - if !manager.HasWhisperService() { + if service, err := manager.WhisperService(); err != nil || service == nil { panic(ErrInvalidGethNode) } - if !manager.HasLightEthereumService() { + if service, err := manager.LightEthereumService(); err != nil || service == nil { panic(ErrInvalidGethNode) } @@ -181,12 +182,12 @@ func PanicAfter(waitSeconds time.Duration, abort chan struct{}, desc string) { } func FromAddress(accountAddress string) common.Address { - accountManager, err := GetNodeManager().AccountManager() + accountManager, err := NodeManagerInstance().AccountManager() if err != nil { return common.Address{} } - from, err := utils.MakeAddress(accountManager, accountAddress) + from, err := ParseAccountString(accountManager, accountAddress) if err != nil { return common.Address{} } @@ -195,15 +196,31 @@ func FromAddress(accountAddress string) common.Address { } func ToAddress(accountAddress string) *common.Address { - accountManager, err := GetNodeManager().AccountManager() + accountManager, err := NodeManagerInstance().AccountManager() if err != nil { return nil } - to, err := utils.MakeAddress(accountManager, accountAddress) + to, err := ParseAccountString(accountManager, accountAddress) if err != nil { return nil } return &to.Address } + +// parseAccount parses hex encoded string or key index in the accounts key store +// and converts it to an internal account representation. +func ParseAccountString(accman *accounts.Manager, account string) (accounts.Account, error) { + // valid address, convert to account + if common.IsHexAddress(account) { + return accounts.Account{Address: common.HexToAddress(account)}, nil + } + // valid key index, return account referenced by that key + index, err := strconv.Atoi(account) + if err != nil { + return accounts.Account{}, ErrInvalidAccountAddressOrKey + } + + return accman.AccountByIndex(index) +} diff --git a/geth/whisper.go b/geth/whisper.go index 19125e8da..9fb2e5902 100644 --- a/geth/whisper.go +++ b/geth/whisper.go @@ -36,7 +36,7 @@ func onWhisperMessage(message *whisper.Message) { } func AddWhisperFilter(args whisper.NewFilterArgs) int { - whisperService, err := GetNodeManager().WhisperService() + whisperService, err := NodeManagerInstance().WhisperService() if err != nil { return -1 } @@ -54,7 +54,7 @@ func AddWhisperFilter(args whisper.NewFilterArgs) int { } func RemoveWhisperFilter(idFilter int) { - whisperService, err := GetNodeManager().WhisperService() + whisperService, err := NodeManagerInstance().WhisperService() if err != nil { return } diff --git a/geth/whisper_test.go b/geth/whisper_test.go index 57aff0ad8..003590bb5 100644 --- a/geth/whisper_test.go +++ b/geth/whisper_test.go @@ -18,7 +18,7 @@ func TestWhisperMessaging(t *testing.T) { return } - whisperService, err := geth.GetNodeManager().WhisperService() + whisperService, err := geth.NodeManagerInstance().WhisperService() if err != nil { t.Errorf("whisper service not running: %v", err) } diff --git a/jail/jail.go b/jail/jail.go index dcc02efff..a52e6f78e 100644 --- a/jail/jail.go +++ b/jail/jail.go @@ -260,8 +260,8 @@ func (jail *Jail) RPCClient() (*rpc.Client, error) { return jail.client, nil } - nodeManager := geth.GetNodeManager() - if !nodeManager.HasNode() { + nodeManager := geth.NodeManagerInstance() + if !nodeManager.NodeInited() { return nil, geth.ErrInvalidGethNode } @@ -284,8 +284,8 @@ func (jail *Jail) RequestQueue() (*geth.JailedRequestQueue, error) { return jail.requestQueue, nil } - nodeManager := geth.GetNodeManager() - if !nodeManager.HasNode() { + nodeManager := geth.NodeManagerInstance() + if !nodeManager.NodeInited() { return nil, geth.ErrInvalidGethNode }