2016-09-05 16:07:57 +00:00
|
|
|
// Copyright 2016 The go-ethereum Authors
|
|
|
|
// This file is part of the go-ethereum library.
|
|
|
|
//
|
|
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
// Contains all the wrappers from the node package to support client side node
|
|
|
|
// management on mobile platforms.
|
|
|
|
|
|
|
|
package geth
|
|
|
|
|
|
|
|
import (
|
2017-03-02 13:03:33 +00:00
|
|
|
"encoding/json"
|
2016-09-05 16:07:57 +00:00
|
|
|
"fmt"
|
|
|
|
"math/big"
|
|
|
|
"path/filepath"
|
|
|
|
|
2017-03-02 13:03:33 +00:00
|
|
|
"github.com/ethereum/go-ethereum/core"
|
2016-09-05 16:07:57 +00:00
|
|
|
"github.com/ethereum/go-ethereum/eth"
|
|
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
2016-11-25 15:55:06 +00:00
|
|
|
"github.com/ethereum/go-ethereum/ethstats"
|
2016-11-09 14:19:19 +00:00
|
|
|
"github.com/ethereum/go-ethereum/les"
|
2016-09-05 16:07:57 +00:00
|
|
|
"github.com/ethereum/go-ethereum/node"
|
|
|
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
2016-11-14 11:03:29 +00:00
|
|
|
"github.com/ethereum/go-ethereum/params"
|
2017-02-14 14:44:47 +00:00
|
|
|
whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
|
2016-09-05 16:07:57 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// NodeConfig represents the collection of configuration values to fine tune the Geth
|
|
|
|
// node embedded into a mobile process. The available values are a subset of the
|
|
|
|
// entire API provided by go-ethereum to reduce the maintenance surface and dev
|
|
|
|
// complexity.
|
|
|
|
type NodeConfig struct {
|
|
|
|
// Bootstrap nodes used to establish connectivity with the rest of the network.
|
|
|
|
BootstrapNodes *Enodes
|
|
|
|
|
|
|
|
// MaxPeers is the maximum number of peers that can be connected. If this is
|
|
|
|
// set to zero, then only the configured static and trusted peers can connect.
|
|
|
|
MaxPeers int
|
|
|
|
|
|
|
|
// EthereumEnabled specifies whether the node should run the Ethereum protocol.
|
|
|
|
EthereumEnabled bool
|
|
|
|
|
|
|
|
// EthereumNetworkID is the network identifier used by the Ethereum protocol to
|
|
|
|
// decide if remote peers should be accepted or not.
|
|
|
|
EthereumNetworkID int
|
|
|
|
|
|
|
|
// EthereumChainConfig is the default parameters of the blockchain to use. If no
|
|
|
|
// configuration is specified, it defaults to the main network.
|
|
|
|
EthereumChainConfig *ChainConfig
|
|
|
|
|
|
|
|
// EthereumGenesis is the genesis JSON to use to seed the blockchain with. An
|
|
|
|
// empty genesis state is equivalent to using the mainnet's state.
|
|
|
|
EthereumGenesis string
|
|
|
|
|
|
|
|
// EthereumDatabaseCache is the system memory in MB to allocate for database caching.
|
|
|
|
// A minimum of 16MB is always reserved.
|
|
|
|
EthereumDatabaseCache int
|
|
|
|
|
2016-11-25 15:55:06 +00:00
|
|
|
// EthereumNetStats is a netstats connection string to use to report various
|
|
|
|
// chain, transaction and node stats to a monitoring server.
|
|
|
|
//
|
|
|
|
// It has the form "nodename:secret@host:port"
|
|
|
|
EthereumNetStats string
|
|
|
|
|
2016-09-05 16:07:57 +00:00
|
|
|
// WhisperEnabled specifies whether the node should run the Whisper protocol.
|
|
|
|
WhisperEnabled bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// defaultNodeConfig contains the default node configuration values to use if all
|
|
|
|
// or some fields are missing from the user's specified list.
|
|
|
|
var defaultNodeConfig = &NodeConfig{
|
2016-11-09 14:35:04 +00:00
|
|
|
BootstrapNodes: FoundationBootnodes(),
|
2016-09-05 16:07:57 +00:00
|
|
|
MaxPeers: 25,
|
|
|
|
EthereumEnabled: true,
|
|
|
|
EthereumNetworkID: 1,
|
2016-11-09 14:35:04 +00:00
|
|
|
EthereumChainConfig: MainnetChainConfig(),
|
2016-09-05 16:07:57 +00:00
|
|
|
EthereumDatabaseCache: 16,
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewNodeConfig creates a new node option set, initialized to the default values.
|
|
|
|
func NewNodeConfig() *NodeConfig {
|
|
|
|
config := *defaultNodeConfig
|
|
|
|
return &config
|
|
|
|
}
|
|
|
|
|
2017-03-02 13:03:33 +00:00
|
|
|
// SetMainnet sets up the node for use on the Ethereum mainnet.
|
|
|
|
func (cfg *NodeConfig) SetMainnet() {
|
|
|
|
cfg.EthereumGenesis = ""
|
|
|
|
cfg.EthereumChainConfig = MainnetChainConfig()
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetTestnet sets up the node for use on the Ethereum testnet.
|
|
|
|
func (cfg *NodeConfig) SetTestnet() {
|
|
|
|
cfg.EthereumGenesis = TestnetGenesis()
|
|
|
|
cfg.EthereumChainConfig = TestnetChainConfig()
|
|
|
|
}
|
|
|
|
|
2016-09-05 16:07:57 +00:00
|
|
|
// Node represents a Geth Ethereum node instance.
|
|
|
|
type Node struct {
|
|
|
|
node *node.Node
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewNode creates and configures a new Geth node.
|
2016-12-08 12:09:26 +00:00
|
|
|
func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
|
2016-09-05 16:07:57 +00:00
|
|
|
// If no or partial configurations were specified, use defaults
|
|
|
|
if config == nil {
|
|
|
|
config = NewNodeConfig()
|
|
|
|
}
|
|
|
|
if config.MaxPeers == 0 {
|
|
|
|
config.MaxPeers = defaultNodeConfig.MaxPeers
|
|
|
|
}
|
2016-11-09 14:35:04 +00:00
|
|
|
if config.BootstrapNodes == nil || config.BootstrapNodes.Size() == 0 {
|
|
|
|
config.BootstrapNodes = defaultNodeConfig.BootstrapNodes
|
|
|
|
}
|
2016-09-05 16:07:57 +00:00
|
|
|
// Create the empty networking stack
|
|
|
|
nodeConf := &node.Config{
|
2016-11-09 14:35:04 +00:00
|
|
|
Name: clientIdentifier,
|
2016-11-25 15:55:06 +00:00
|
|
|
Version: params.Version,
|
2016-11-09 14:35:04 +00:00
|
|
|
DataDir: datadir,
|
|
|
|
KeyStoreDir: filepath.Join(datadir, "keystore"), // Mobile should never use internal keystores!
|
|
|
|
NoDiscovery: true,
|
|
|
|
DiscoveryV5: true,
|
|
|
|
DiscoveryV5Addr: ":0",
|
|
|
|
BootstrapNodesV5: config.BootstrapNodes.nodes,
|
|
|
|
ListenAddr: ":0",
|
|
|
|
NAT: nat.Any(),
|
|
|
|
MaxPeers: config.MaxPeers,
|
2016-09-05 16:07:57 +00:00
|
|
|
}
|
2016-12-08 12:09:26 +00:00
|
|
|
rawStack, err := node.New(nodeConf)
|
2016-09-05 16:07:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-03-02 13:03:33 +00:00
|
|
|
|
|
|
|
var genesis *core.Genesis
|
|
|
|
if config.EthereumGenesis != "" {
|
|
|
|
genesis = new(core.Genesis)
|
|
|
|
if err := json.Unmarshal([]byte(config.EthereumGenesis), genesis); err != nil {
|
|
|
|
return nil, fmt.Errorf("invalid EthereumGenesis: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if config.EthereumChainConfig != nil {
|
|
|
|
if genesis == nil {
|
|
|
|
genesis = core.DefaultGenesisBlock()
|
|
|
|
}
|
|
|
|
genesis.Config = ¶ms.ChainConfig{
|
|
|
|
ChainId: big.NewInt(config.EthereumChainConfig.ChainID),
|
|
|
|
HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
|
|
|
|
DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock),
|
|
|
|
DAOForkSupport: config.EthereumChainConfig.DAOForkSupport,
|
|
|
|
EIP150Block: big.NewInt(config.EthereumChainConfig.EIP150Block),
|
|
|
|
EIP150Hash: config.EthereumChainConfig.EIP150Hash.hash,
|
|
|
|
EIP155Block: big.NewInt(config.EthereumChainConfig.EIP155Block),
|
|
|
|
EIP158Block: big.NewInt(config.EthereumChainConfig.EIP158Block),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-05 16:07:57 +00:00
|
|
|
// Register the Ethereum protocol if requested
|
|
|
|
if config.EthereumEnabled {
|
|
|
|
ethConf := ð.Config{
|
2017-04-06 14:20:42 +00:00
|
|
|
Genesis: genesis,
|
|
|
|
LightMode: true,
|
|
|
|
DatabaseCache: config.EthereumDatabaseCache,
|
|
|
|
NetworkId: config.EthereumNetworkID,
|
|
|
|
GasPrice: new(big.Int).SetUint64(20 * params.Shannon),
|
|
|
|
GpoBlocks: 5,
|
|
|
|
GpoPercentile: 50,
|
|
|
|
EthashCacheDir: "ethash",
|
|
|
|
EthashCachesInMem: 2,
|
|
|
|
EthashCachesOnDisk: 3,
|
2016-09-05 16:07:57 +00:00
|
|
|
}
|
2016-12-08 12:09:26 +00:00
|
|
|
if err := rawStack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
2016-11-09 14:19:19 +00:00
|
|
|
return les.New(ctx, ethConf)
|
2016-09-05 16:07:57 +00:00
|
|
|
}); err != nil {
|
|
|
|
return nil, fmt.Errorf("ethereum init: %v", err)
|
|
|
|
}
|
2016-11-25 15:55:06 +00:00
|
|
|
// If netstats reporting is requested, do it
|
|
|
|
if config.EthereumNetStats != "" {
|
2016-12-08 12:09:26 +00:00
|
|
|
if err := rawStack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
2016-11-25 15:55:06 +00:00
|
|
|
var lesServ *les.LightEthereum
|
|
|
|
ctx.Service(&lesServ)
|
|
|
|
|
|
|
|
return ethstats.New(config.EthereumNetStats, nil, lesServ)
|
|
|
|
}); err != nil {
|
|
|
|
return nil, fmt.Errorf("netstats init: %v", err)
|
|
|
|
}
|
|
|
|
}
|
2016-09-05 16:07:57 +00:00
|
|
|
}
|
|
|
|
// Register the Whisper protocol if requested
|
|
|
|
if config.WhisperEnabled {
|
2017-02-14 14:44:47 +00:00
|
|
|
if err := rawStack.Register(func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil {
|
2016-09-05 16:07:57 +00:00
|
|
|
return nil, fmt.Errorf("whisper init: %v", err)
|
|
|
|
}
|
|
|
|
}
|
2016-12-08 12:09:26 +00:00
|
|
|
return &Node{rawStack}, nil
|
2016-09-05 16:07:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Start creates a live P2P node and starts running it.
|
|
|
|
func (n *Node) Start() error {
|
|
|
|
return n.node.Start()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop terminates a running node along with all it's services. In the node was
|
|
|
|
// not started, an error is returned.
|
|
|
|
func (n *Node) Stop() error {
|
|
|
|
return n.node.Stop()
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetEthereumClient retrieves a client to access the Ethereum subsystem.
|
2016-12-08 12:09:26 +00:00
|
|
|
func (n *Node) GetEthereumClient() (client *EthereumClient, _ error) {
|
2016-09-05 16:07:57 +00:00
|
|
|
rpc, err := n.node.Attach()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &EthereumClient{ethclient.NewClient(rpc)}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetNodeInfo gathers and returns a collection of metadata known about the host.
|
|
|
|
func (n *Node) GetNodeInfo() *NodeInfo {
|
|
|
|
return &NodeInfo{n.node.Server().NodeInfo()}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetPeersInfo returns an array of metadata objects describing connected peers.
|
|
|
|
func (n *Node) GetPeersInfo() *PeerInfos {
|
|
|
|
return &PeerInfos{n.node.Server().PeersInfo()}
|
|
|
|
}
|