replaces dependency on go-ethereum "cmd/*" packages. Fixes #72

This commit is contained in:
Victor Farazdagi 2016-12-08 00:07:08 +03:00
parent 09d021e598
commit e5bb6a24f7
17 changed files with 574 additions and 321 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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",

View File

@ -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

View File

@ -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

View File

@ -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)
}

View File

@ -1,304 +1,249 @@
package geth
/*
#include <stddef.h>
#include <stdbool.h>
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 := &eth.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)
}

289
geth/node_manager.go Normal file
View File

@ -0,0 +1,289 @@
package geth
/*
#include <stddef.h>
#include <stdbool.h>
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)
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}