// 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 . // 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/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/whisper/whisperv2" ) // 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 // EthereumTestnetNonces specifies whether to use account nonces from the testnet // range (2^20) or from the mainnet one (0). EthereumTestnetNonces bool // EthereumDatabaseCache is the system memory in MB to allocate for database caching. // A minimum of 16MB is always reserved. EthereumDatabaseCache int // 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{ BootstrapNodes: FoundationBootnodes(), MaxPeers: 25, EthereumEnabled: true, EthereumNetworkID: 1, EthereumChainConfig: MainnetChainConfig(), 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. func NewNode(datadir string, config *NodeConfig) (*Node, error) { // If no or partial configurations were specified, use defaults if config == nil { config = NewNodeConfig() } if config.MaxPeers == 0 { config.MaxPeers = defaultNodeConfig.MaxPeers } if config.BootstrapNodes == nil || config.BootstrapNodes.Size() == 0 { config.BootstrapNodes = defaultNodeConfig.BootstrapNodes } // Create the empty networking stack nodeConf := &node.Config{ Name: clientIdentifier, 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, } stack, err := node.New(nodeConf) if err != nil { return nil, err } // Register the Ethereum protocol if requested if config.EthereumEnabled { ethConf := ð.Config{ ChainConfig: &core.ChainConfig{ HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock), DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock), DAOForkSupport: config.EthereumChainConfig.DAOForkSupport, HomesteadGasRepriceBlock: big.NewInt(config.EthereumChainConfig.HomesteadGasRepriceBlock), HomesteadGasRepriceHash: config.EthereumChainConfig.HomesteadGasRepriceHash.hash, }, Genesis: config.EthereumGenesis, LightMode: true, 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, } if config.EthereumTestnetNonces { state.StartingNonce = 1048576 // (2**20) light.StartingNonce = 1048576 // (2**20) } if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return les.New(ctx, ethConf) }); err != nil { return nil, fmt.Errorf("ethereum init: %v", err) } } // Register the Whisper protocol if requested if config.WhisperEnabled { if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisperv2.New(), nil }); err != nil { return nil, fmt.Errorf("whisper init: %v", err) } } return &Node{stack}, nil } // 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. func (n *Node) GetEthereumClient() (*EthereumClient, error) { 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()} }