replaces dependency on go-ethereum "cmd/*" packages. Fixes #72
This commit is contained in:
parent
09d021e598
commit
e5bb6a24f7
5
Makefile
5
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
449
geth/node.go
449
geth/node.go
|
@ -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 := ð.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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue