geth.go 7.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// 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 (
	"fmt"
	"math/big"
	"path/filepath"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/eth"
	"github.com/ethereum/go-ethereum/ethclient"
30
	"github.com/ethereum/go-ethereum/ethstats"
31
	"github.com/ethereum/go-ethereum/les"
32 33
	"github.com/ethereum/go-ethereum/node"
	"github.com/ethereum/go-ethereum/p2p/nat"
34
	"github.com/ethereum/go-ethereum/params"
35
	"github.com/ethereum/go-ethereum/whisper/whisperv2"
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
)

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

69 70 71 72 73 74
	// 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

75 76 77 78 79 80 81
	// 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{
82
	BootstrapNodes:        FoundationBootnodes(),
83 84 85
	MaxPeers:              25,
	EthereumEnabled:       true,
	EthereumNetworkID:     1,
86
	EthereumChainConfig:   MainnetChainConfig(),
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
	EthereumDatabaseCache: 16,
}

// NewNodeConfig creates a new node option set, initialized to the default values.
func NewNodeConfig() *NodeConfig {
	config := *defaultNodeConfig
	return &config
}

// Node represents a Geth Ethereum node instance.
type Node struct {
	node *node.Node
}

// NewNode creates and configures a new Geth node.
102
func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
103 104 105 106 107 108 109
	// If no or partial configurations were specified, use defaults
	if config == nil {
		config = NewNodeConfig()
	}
	if config.MaxPeers == 0 {
		config.MaxPeers = defaultNodeConfig.MaxPeers
	}
110 111 112
	if config.BootstrapNodes == nil || config.BootstrapNodes.Size() == 0 {
		config.BootstrapNodes = defaultNodeConfig.BootstrapNodes
	}
113 114
	// Create the empty networking stack
	nodeConf := &node.Config{
115
		Name:             clientIdentifier,
116
		Version:          params.Version,
117 118 119 120 121 122 123 124 125
		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,
126
	}
127
	rawStack, err := node.New(nodeConf)
128 129 130 131 132 133
	if err != nil {
		return nil, err
	}
	// Register the Ethereum protocol if requested
	if config.EthereumEnabled {
		ethConf := &eth.Config{
134
			ChainConfig: &params.ChainConfig{
135
				ChainId:        big.NewInt(config.EthereumChainConfig.ChainID),
136 137 138 139 140 141 142
				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),
143 144
			},
			Genesis:                 config.EthereumGenesis,
145
			LightMode:               true,
146 147 148 149 150 151 152 153 154 155
			DatabaseCache:           config.EthereumDatabaseCache,
			NetworkId:               config.EthereumNetworkID,
			GasPrice:                new(big.Int).Mul(big.NewInt(20), common.Shannon),
			GpoMinGasPrice:          new(big.Int).Mul(big.NewInt(20), common.Shannon),
			GpoMaxGasPrice:          new(big.Int).Mul(big.NewInt(500), common.Shannon),
			GpoFullBlockRatio:       80,
			GpobaseStepDown:         10,
			GpobaseStepUp:           100,
			GpobaseCorrectionFactor: 110,
		}
156
		if err := rawStack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
157
			return les.New(ctx, ethConf)
158 159 160
		}); err != nil {
			return nil, fmt.Errorf("ethereum init: %v", err)
		}
161 162
		// If netstats reporting is requested, do it
		if config.EthereumNetStats != "" {
163
			if err := rawStack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
164 165 166 167 168 169 170 171
				var lesServ *les.LightEthereum
				ctx.Service(&lesServ)

				return ethstats.New(config.EthereumNetStats, nil, lesServ)
			}); err != nil {
				return nil, fmt.Errorf("netstats init: %v", err)
			}
		}
172 173 174
	}
	// Register the Whisper protocol if requested
	if config.WhisperEnabled {
175
		if err := rawStack.Register(func(*node.ServiceContext) (node.Service, error) { return whisperv2.New(), nil }); err != nil {
176 177 178
			return nil, fmt.Errorf("whisper init: %v", err)
		}
	}
179
	return &Node{rawStack}, nil
180 181 182 183 184 185 186 187 188 189 190 191 192 193
}

// 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.
194
func (n *Node) GetEthereumClient() (client *EthereumClient, _ error) {
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
	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()}
}