geth/params: node settings implemented #116

This commit is contained in:
Victor Farazdagi 2017-03-16 00:03:01 +03:00
parent 34b19e6af9
commit 031eeb33b8
17 changed files with 963 additions and 197 deletions

View File

@ -49,6 +49,7 @@ statusgo-ios-simulator-mainnet: xgo
ci: ci:
build/env.sh go test -v -cover ./geth build/env.sh go test -v -cover ./geth
build/env.sh go test -v -cover ./geth/params
build/env.sh go test -v -cover ./geth/jail build/env.sh go test -v -cover ./geth/jail
build/env.sh go test -v -cover ./extkeys build/env.sh go test -v -cover ./extkeys
@ -56,6 +57,8 @@ test:
@build/env.sh echo "mode: set" > coverage-all.out @build/env.sh echo "mode: set" > coverage-all.out
build/env.sh go test -coverprofile=coverage.out -covermode=set ./geth build/env.sh go test -coverprofile=coverage.out -covermode=set ./geth
@build/env.sh tail -n +2 coverage.out >> coverage-all.out @build/env.sh tail -n +2 coverage.out >> coverage-all.out
build/env.sh go test -coverprofile=coverage.out -covermode=set ./geth/params
@build/env.sh tail -n +2 coverage.out >> coverage-all.out
build/env.sh go test -coverprofile=coverage.out -covermode=set ./geth/jail build/env.sh go test -coverprofile=coverage.out -covermode=set ./geth/jail
@build/env.sh tail -n +2 coverage.out >> coverage-all.out @build/env.sh tail -n +2 coverage.out >> coverage-all.out
build/env.sh go test -coverprofile=coverage.out -covermode=set ./extkeys build/env.sh go test -coverprofile=coverage.out -covermode=set ./extkeys
@ -70,6 +73,11 @@ test-geth:
@build/env.sh go tool cover -html=coverage.out -o coverage.html @build/env.sh go tool cover -html=coverage.out -o coverage.html
@build/env.sh go tool cover -func=coverage.out @build/env.sh go tool cover -func=coverage.out
test-config:
build/env.sh go test -v -coverprofile=coverage.out ./geth/params
@build/env.sh go tool cover -html=coverage.out -o coverage.html
@build/env.sh go tool cover -func=coverage.out
test-jail: test-jail:
build/env.sh go test -v -coverprofile=coverage.out ./geth/jail build/env.sh go test -v -coverprofile=coverage.out ./geth/jail
@build/env.sh go tool cover -html=coverage.out -o coverage.html @build/env.sh go tool cover -html=coverage.out -o coverage.html

View File

@ -9,5 +9,5 @@ fi
# set gitCommit when running from a Git checkout. # set gitCommit when running from a Git checkout.
if [ -f ".git/HEAD" ]; then if [ -f ".git/HEAD" ]; then
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)'"; echo "-ldflags '-X github.com/status-im/status-go/geth/params.UseMainnetFlag=true -X main.buildStamp=`date -u '+%Y-%m-%d.%H:%M:%S'` -X main.gitCommit=$(git rev-parse HEAD)'";
fi fi

View File

@ -9,5 +9,5 @@ fi
# set gitCommit when running from a Git checkout. # set gitCommit when running from a Git checkout.
if [ -f ".git/HEAD" ]; then if [ -f ".git/HEAD" ]; then
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)'"; echo "-ldflags '-X github.com/status-im/status-go/geth/params.UseMainnetFlag=false -X main.buildStamp=`date -u '+%Y-%m-%d.%H:%M:%S'` -X main.gitCommit=$(git rev-parse HEAD)'";
fi fi

View File

@ -9,6 +9,7 @@ import (
whisper "github.com/ethereum/go-ethereum/whisper/whisperv2" whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
"github.com/status-im/status-go/geth" "github.com/status-im/status-go/geth"
"github.com/status-im/status-go/geth/jail" "github.com/status-im/status-go/geth/jail"
"github.com/status-im/status-go/geth/params"
) )
//export CreateAccount //export CreateAccount
@ -197,18 +198,29 @@ func DiscardTransactions(ids *C.char) *C.char {
return C.CString(string(outBytes)) return C.CString(string(outBytes))
} }
//export StartNode //export GenerateConfig
func StartNode(datadir *C.char) *C.char { func GenerateConfig(datadir *C.char, networkId C.int) *C.char {
// This starts a geth node with the given datadir config, err := params.NewNodeConfig(C.GoString(datadir), int(networkId))
err := geth.CreateAndRunNode(&geth.NodeConfig{ if err != nil {
DataDir: C.GoString(datadir), return makeJSONErrorResponse(err)
IPCEnabled: false, }
HTTPPort: geth.HTTPPort,
WSEnabled: false,
WSPort: geth.WSPort,
TLSEnabled: false,
})
outBytes, err := json.Marshal(&config)
if err != nil {
return makeJSONErrorResponse(err)
}
return C.CString(string(outBytes))
}
//export StartNode
func StartNode(configJSON *C.char) *C.char {
config, err := params.LoadNodeConfig(C.GoString(configJSON))
if err != nil {
return makeJSONErrorResponse(err)
}
err = geth.CreateAndRunNode(config)
return makeJSONErrorResponse(err) return makeJSONErrorResponse(err)
} }
@ -230,19 +242,6 @@ func ResetChainData() *C.char {
return makeJSONErrorResponse(err) return makeJSONErrorResponse(err)
} }
//export StartTLSNode
func StartTLSNode(datadir *C.char) *C.char {
// This starts a geth node with the given datadir
err := geth.CreateAndRunNode(&geth.NodeConfig{
DataDir: C.GoString(datadir),
HTTPPort: geth.HTTPPort,
WSPort: geth.WSPort,
TLSEnabled: true,
})
return makeJSONErrorResponse(err)
}
//export StopNodeRPCServer //export StopNodeRPCServer
func StopNodeRPCServer() *C.char { func StopNodeRPCServer() *C.char {
_, err := geth.NodeManagerInstance().StopNodeRPCServer() _, err := geth.NodeManagerInstance().StopNodeRPCServer()

View File

@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"github.com/status-im/status-go/geth"
"github.com/status-im/status-go/geth/params" "github.com/status-im/status-go/geth/params"
) )
@ -12,10 +11,16 @@ var (
) )
func main() { func main() {
nodeConfig, err := params.NewNodeConfig(".ethereumcmd", params.TestNetworkId)
if err != nil {
panic(err)
}
netVersion := "mainnet" netVersion := "mainnet"
if geth.UseTestnet { if nodeConfig.TestNet {
netVersion = "testnet" netVersion = "testnet"
} }
fmt.Printf("%s\nVersion: %s\nGit Commit: %s\nBuild Date: %s\nNetwork: %s\n", fmt.Printf("%s\nVersion: %s\nGit Commit: %s\nBuild Date: %s\nNetwork: %s\n",
geth.ClientIdentifier, params.Version, gitCommit, buildStamp, netVersion) nodeConfig.Name, params.Version, gitCommit, buildStamp, netVersion)
} }

View File

@ -7,6 +7,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"strconv"
"testing" "testing"
"time" "time"
@ -14,18 +15,17 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/les/status" "github.com/ethereum/go-ethereum/les/status"
gethparams "github.com/ethereum/go-ethereum/params"
"github.com/status-im/status-go/geth" "github.com/status-im/status-go/geth"
"github.com/status-im/status-go/geth/params"
) )
var testConfig *geth.TestConfig var testConfig *geth.TestConfig
func init() { func init() {
// load shared test configuration // error is ignored, as it will occur on non-test compilation only, and there testConfig is not used at all
var err error // (we have to use "main" package due to restrictions on including C imports into *_test packages)
testConfig, err = geth.LoadTestConfig() testConfig, _ = geth.LoadTestConfig()
if err != nil {
panic(err)
}
} }
func testExportedAPI(t *testing.T, done chan struct{}) { func testExportedAPI(t *testing.T, done chan struct{}) {
@ -35,6 +35,10 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
name string name string
fn func(t *testing.T) bool fn func(t *testing.T) bool
}{ }{
{
"check default configuration",
testGetDefaultConfig,
},
{ {
"reset blockchain data", "reset blockchain data",
testResetChainData, testResetChainData,
@ -98,6 +102,97 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
done <- struct{}{} done <- struct{}{}
} }
func testGetDefaultConfig(t *testing.T) bool {
// test Mainnet config
nodeConfig := params.NodeConfig{}
rawResponse := GenerateConfig(C.CString("/tmp/data-folder"), 1)
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &nodeConfig); err != nil {
t.Errorf("cannot decode reponse (%s): %v", C.GoString(rawResponse), err)
return false
}
chainConfig := nodeConfig.ChainConfig
if chainConfig.HomesteadBlock.Cmp(gethparams.MainNetHomesteadBlock) != 0 {
t.Error("invalid chainConfig.HomesteadBlock")
return false
}
if chainConfig.DAOForkBlock.Cmp(gethparams.MainNetDAOForkBlock) != 0 {
t.Error("invalid chainConfig.DAOForkBlock")
return false
}
if chainConfig.DAOForkSupport != true {
t.Error("invalid chainConfig.DAOForkSupport")
return false
}
if chainConfig.EIP150Block.Cmp(gethparams.MainNetHomesteadGasRepriceBlock) != 0 {
t.Error("invalid chainConfig.EIP150Block")
return false
}
if chainConfig.EIP150Hash != gethparams.MainNetHomesteadGasRepriceHash {
t.Error("invalid chainConfig.EIP150Hash")
return false
}
if chainConfig.EIP155Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 {
t.Error("invalid chainConfig.EIP155Block")
return false
}
if chainConfig.EIP158Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 {
t.Error("invalid chainConfig.EIP158Block")
return false
}
if chainConfig.ChainId.Cmp(gethparams.MainNetChainID) != 0 {
t.Error("invalid chainConfig.ChainId")
return false
}
// test Testnet
nodeConfig = params.NodeConfig{}
rawResponse = GenerateConfig(C.CString("/tmp/data-folder"), 3)
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &nodeConfig); err != nil {
t.Errorf("cannot decode reponse (%s): %v", C.GoString(rawResponse), err)
return false
}
chainConfig = nodeConfig.ChainConfig
refChainConfig := gethparams.TestnetChainConfig
if chainConfig.HomesteadBlock.Cmp(refChainConfig.HomesteadBlock) != 0 {
t.Error("invalid chainConfig.HomesteadBlock")
return false
}
if chainConfig.DAOForkBlock != nil { // already forked
t.Error("invalid chainConfig.DAOForkBlock")
return false
}
if chainConfig.DAOForkSupport != refChainConfig.DAOForkSupport {
t.Error("invalid chainConfig.DAOForkSupport")
return false
}
if chainConfig.EIP150Block.Cmp(refChainConfig.EIP150Block) != 0 {
t.Error("invalid chainConfig.EIP150Block")
return false
}
if chainConfig.EIP150Hash != refChainConfig.EIP150Hash {
t.Error("invalid chainConfig.EIP150Hash")
return false
}
if chainConfig.EIP155Block.Cmp(refChainConfig.EIP155Block) != 0 {
t.Error("invalid chainConfig.EIP155Block")
return false
}
if chainConfig.EIP158Block.Cmp(refChainConfig.EIP158Block) != 0 {
t.Error("invalid chainConfig.EIP158Block")
return false
}
if chainConfig.ChainId.Cmp(refChainConfig.ChainId) != 0 {
t.Error("invalid chainConfig.ChainId")
return false
}
return true
}
func testResetChainData(t *testing.T) bool { func testResetChainData(t *testing.T) bool {
resetChainDataResponse := geth.JSONError{} resetChainDataResponse := geth.JSONError{}
rawResponse := ResetChainData() rawResponse := ResetChainData()
@ -246,7 +341,7 @@ func testRestartNodeRPC(t *testing.T) bool {
t.Errorf("cannot decode StartNodeRPCServer reponse (%s): %v", C.GoString(rawResponse), err) t.Errorf("cannot decode StartNodeRPCServer reponse (%s): %v", C.GoString(rawResponse), err)
return false return false
} }
expectedError := "HTTP RPC already running on localhost:8545" expectedError := "HTTP RPC already running on localhost:8645"
if startNodeRPCServerResponse.Error != expectedError { if startNodeRPCServerResponse.Error != expectedError {
t.Errorf("expected error not thrown: %s", expectedError) t.Errorf("expected error not thrown: %s", expectedError)
return false return false
@ -1213,6 +1308,20 @@ func startTestNode(t *testing.T) <-chan struct{} {
syncRequired = true syncRequired = true
} }
// prepare node directory
if err := os.MkdirAll(filepath.Join(geth.TestDataDir, "testnet", "keystore"), os.ModePerm); err != nil {
panic(err)
}
// import test account (with test ether on it)
dst := filepath.Join(geth.TestDataDir, "testnet", "keystore", "test-account.pk")
if _, err := os.Stat(dst); os.IsNotExist(err) {
err = geth.CopyFile(dst, filepath.Join(geth.RootDir, "data", "test-account.pk"))
if err != nil {
panic(err)
}
}
waitForNodeStart := make(chan struct{}, 1) waitForNodeStart := make(chan struct{}, 1)
geth.SetDefaultNodeNotificationHandler(func(jsonEvent string) { geth.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
t.Log(jsonEvent) t.Log(jsonEvent)
@ -1246,12 +1355,18 @@ func startTestNode(t *testing.T) <-chan struct{} {
}) })
go func() { go func() {
response := StartNode(C.CString(geth.TestDataDir)) configJSON := `{
"NetworkId": ` + strconv.Itoa(params.TestNetworkId) + `,
"DataDir": "` + geth.TestDataDir + `",
"HTTPPort": ` + strconv.Itoa(testConfig.Node.HTTPPort) + `,
"WSPort": ` + strconv.Itoa(testConfig.Node.WSPort) + `
}`
response := StartNode(C.CString(configJSON))
err := geth.JSONError{} err := geth.JSONError{}
json.Unmarshal([]byte(C.GoString(response)), &err) json.Unmarshal([]byte(C.GoString(response)), &err)
if err.Error != "" { if err.Error != "" {
t.Error("cannot start node") panic("cannot start node: " + err.Error)
} }
}() }()

View File

@ -1,6 +1,6 @@
{ {
"Node": { "Node": {
"SyncSeconds": 45, "SyncSeconds": 90,
"HTTPPort": 8645, "HTTPPort": 8645,
"WSPort": 8646 "WSPort": 8646
}, },

View File

@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/geth" "github.com/status-im/status-go/geth"
"github.com/status-im/status-go/geth/params"
"github.com/status-im/status-go/geth/jail" "github.com/status-im/status-go/geth/jail"
) )
@ -636,7 +637,7 @@ func TestContractDeployment(t *testing.T) {
{ {
from: '` + testConfig.Account1.Address + `', from: '` + testConfig.Account1.Address + `',
data: '0x6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636ffa1caa14603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60008160020290505b9190505600a165627a7a72305820ccdadd737e4ac7039963b54cee5e5afb25fa859a275252bdcf06f653155228210029', data: '0x6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636ffa1caa14603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60008160020290505b9190505600a165627a7a72305820ccdadd737e4ac7039963b54cee5e5afb25fa859a275252bdcf06f653155228210029',
gas: '` + strconv.Itoa(geth.DefaultGas) + `' gas: '` + strconv.Itoa(params.DefaultGas) + `'
}, function (e, contract){ }, function (e, contract){
if (!e) { if (!e) {
responseValue = contract.transactionHash responseValue = contract.transactionHash

View File

@ -4,10 +4,8 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math/big"
"os" "os"
"path" "path"
"path/filepath"
"reflect" "reflect"
"runtime" "runtime"
"runtime/debug" "runtime/debug"
@ -15,60 +13,23 @@ import (
"syscall" "syscall"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5" "github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/params" gethparams "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv2" whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
"github.com/status-im/status-go/geth/params"
) )
const ( const (
ClientIdentifier = "StatusIM" // Client identifier to advertise over the network
IPCFile = "geth.ipc" // Filename of exposed IPC-RPC Server
HTTPPort = 8545 // HTTP-RPC port (replaced in unit tests)
WSPort = 8546 // WS-RPC port (replaced in unit tests)
MaxPeers = 25
MaxLightPeers = 20
MaxPendingPeers = 0
DefaultGas = 180000
ProcessFileDescriptorLimit = uint64(2048)
DatabaseCacheSize = 128 // Megabytes of memory allocated to internal caching (min 16MB / database forced)
EventNodeStarted = "node.started" EventNodeStarted = "node.started"
EventNodeCrashed = "node.crashed" EventNodeCrashed = "node.crashed"
) )
// Gas price settings
var (
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 (%)
)
// default node configuration options
var (
UseTestnetFlag = "true" // to be overridden via -ldflags '-X geth.UseTestnetFlag'
UseTestnet = false
)
func init() {
if UseTestnetFlag == "true" { // set at compile time, here we make sure to set corresponding boolean flag
UseTestnet = true
}
}
// node-related errors // node-related errors
var ( var (
ErrEthServiceRegistrationFailure = errors.New("failed to register the Ethereum service") ErrEthServiceRegistrationFailure = errors.New("failed to register the Ethereum service")
@ -76,22 +37,12 @@ var (
ErrLightEthRegistrationFailure = errors.New("failed to register the LES service") ErrLightEthRegistrationFailure = errors.New("failed to register the LES service")
) )
// NodeConfig stores configuration options for a node
type NodeConfig struct {
DataDir string // base data directory
IPCEnabled bool // whether IPC-RPC Server is enabled or not
HTTPPort int // HTTP-RPC Server port
WSPort int // WS-RPC Server port
WSEnabled bool // whether WS-RPC Server is enabled or not
TLSEnabled bool // whether TLS support should be enabled on node or not
}
// Node represents running node (serves as a wrapper around P2P node) // Node represents running node (serves as a wrapper around P2P node)
type Node struct { type Node struct {
config *NodeConfig // configuration used to create Status node config *params.NodeConfig // configuration used to create Status node
geth *node.Node // reference to the running Geth node geth *node.Node // reference to the running Geth node
gethConfig *node.Config // configuration used to create P2P node gethConfig *node.Config // configuration used to create P2P node
started chan struct{} // channel to wait for node to start started chan struct{} // channel to wait for node to start
} }
// Inited checks whether status node has been properly initialized // Inited checks whether status node has been properly initialized
@ -105,24 +56,16 @@ func (n *Node) GethStack() *node.Node {
} }
// MakeNode create a geth node entity // MakeNode create a geth node entity
func MakeNode(config *NodeConfig) *Node { func MakeNode(config *params.NodeConfig) *Node {
glog.CopyStandardLogTo("INFO") glog.CopyStandardLogTo("INFO")
glog.SetToStderr(true) glog.SetToStderr(true)
dataDir := config.DataDir
if UseTestnet {
dataDir = filepath.Join(config.DataDir, "testnet")
}
// exposed RPC APIs
exposedAPIs := "db,eth,net,web3,shh,personal,admin" // TODO remove "admin" on main net
// configure required node (should you need to update node's config, e.g. add bootstrap nodes, see node.Config) // configure required node (should you need to update node's config, e.g. add bootstrap nodes, see node.Config)
stackConfig := &node.Config{ stackConfig := &node.Config{
DataDir: dataDir, DataDir: config.DataDir,
UseLightweightKDF: true, UseLightweightKDF: true,
Name: ClientIdentifier, Name: config.Name,
Version: params.Version, Version: config.Version,
NoDiscovery: true, NoDiscovery: true,
DiscoveryV5: false, DiscoveryV5: false,
DiscoveryV5Addr: ":0", DiscoveryV5Addr: ":0",
@ -130,17 +73,17 @@ func MakeNode(config *NodeConfig) *Node {
BootstrapNodesV5: makeBootstrapNodesV5(), BootstrapNodesV5: makeBootstrapNodesV5(),
ListenAddr: ":0", ListenAddr: ":0",
NAT: nat.Any(), NAT: nat.Any(),
MaxPeers: MaxPeers, MaxPeers: config.MaxPeers,
MaxPendingPeers: MaxPendingPeers, MaxPendingPeers: config.MaxPendingPeers,
IPCPath: makeIPCPath(dataDir, config.IPCEnabled), IPCPath: makeIPCPath(config),
HTTPHost: node.DefaultHTTPHost, HTTPHost: config.HTTPHost,
HTTPPort: config.HTTPPort, HTTPPort: config.HTTPPort,
HTTPCors: "*", HTTPCors: "*",
HTTPModules: strings.Split(exposedAPIs, ","), HTTPModules: strings.Split(config.APIModules, ","),
WSHost: makeWSHost(config.WSEnabled), WSHost: makeWSHost(config),
WSPort: config.WSPort, WSPort: config.WSPort,
WSOrigins: "*", WSOrigins: "*",
WSModules: strings.Split(exposedAPIs, ","), WSModules: strings.Split(config.APIModules, ","),
} }
stack, err := node.New(stackConfig) stack, err := node.New(stackConfig)
@ -149,12 +92,12 @@ func MakeNode(config *NodeConfig) *Node {
} }
// start Ethereum service // start Ethereum service
if err := activateEthService(stack, makeDefaultExtra()); err != nil { if err := activateEthService(stack, config); err != nil {
Fatalf(fmt.Errorf("%v: %v", ErrEthServiceRegistrationFailure, err)) Fatalf(fmt.Errorf("%v: %v", ErrEthServiceRegistrationFailure, err))
} }
// start Whisper service // start Whisper service
if err := activateShhService(stack); err != nil { if err := activateShhService(stack, config); err != nil {
Fatalf(fmt.Errorf("%v: %v", ErrSshServiceRegistrationFailure, err)) Fatalf(fmt.Errorf("%v: %v", ErrSshServiceRegistrationFailure, err))
} }
@ -167,35 +110,29 @@ func MakeNode(config *NodeConfig) *Node {
} }
// activateEthService configures and registers the eth.Ethereum service with a given node. // activateEthService configures and registers the eth.Ethereum service with a given node.
func activateEthService(stack *node.Node, extra []byte) error { func activateEthService(stack *node.Node, config *params.NodeConfig) error {
ethConf := &eth.Config{ ethConf := &eth.Config{
Etherbase: common.Address{}, Etherbase: common.Address{},
ChainConfig: makeChainConfig(stack), ChainConfig: makeChainConfig(config),
FastSync: false, FastSync: false,
LightMode: true, LightMode: true,
LightServ: 60, MaxPeers: config.MaxPeers,
LightPeers: MaxLightPeers, DatabaseCache: config.LightEthConfig.DatabaseCache,
MaxPeers: MaxPeers,
DatabaseCache: DatabaseCacheSize,
DatabaseHandles: makeDatabaseHandles(), DatabaseHandles: makeDatabaseHandles(),
NetworkId: 1, // Olympic NetworkId: config.NetworkId,
Genesis: config.LightEthConfig.Genesis,
MinerThreads: runtime.NumCPU(), MinerThreads: runtime.NumCPU(),
GasPrice: GasPrice, GasPrice: params.GasPrice,
GpoMinGasPrice: GpoMinGasPrice, GpoMinGasPrice: params.GpoMinGasPrice,
GpoMaxGasPrice: GpoMaxGasPrice, GpoMaxGasPrice: params.GpoMaxGasPrice,
GpoFullBlockRatio: GpoFullBlockRatio, GpoFullBlockRatio: params.GpoFullBlockRatio,
GpobaseStepDown: GpobaseStepDown, GpobaseStepDown: params.GpobaseStepDown,
GpobaseStepUp: GpobaseStepUp, GpobaseStepUp: params.GpobaseStepUp,
GpobaseCorrectionFactor: GpobaseCorrectionFactor, GpobaseCorrectionFactor: params.GpobaseCorrectionFactor,
SolcPath: "solc", SolcPath: "solc",
AutoDAG: false, AutoDAG: false,
} }
if UseTestnet {
ethConf.NetworkId = 3
ethConf.Genesis = core.DefaultTestnetGenesisBlock()
}
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
return les.New(ctx, ethConf) return les.New(ctx, ethConf)
}); err != nil { }); err != nil {
@ -206,7 +143,7 @@ func activateEthService(stack *node.Node, extra []byte) error {
} }
// activateShhService configures Whisper and adds it to the given node. // activateShhService configures Whisper and adds it to the given node.
func activateShhService(stack *node.Node) error { func activateShhService(stack *node.Node, config *params.NodeConfig) error {
serviceConstructor := func(*node.ServiceContext) (node.Service, error) { serviceConstructor := func(*node.ServiceContext) (node.Service, error) {
return whisper.New(), nil return whisper.New(), nil
} }
@ -218,47 +155,44 @@ func activateShhService(stack *node.Node) error {
} }
// makeIPCPath returns IPC-RPC filename // makeIPCPath returns IPC-RPC filename
func makeIPCPath(dataDir string, ipcEnabled bool) string { func makeIPCPath(config *params.NodeConfig) string {
if !ipcEnabled { if !config.IPCEnabled {
return "" return ""
} }
return path.Join(dataDir, IPCFile) return path.Join(config.DataDir, config.IPCFile)
} }
// makeWSHost returns WS-RPC Server host, given enabled/disabled flag // makeWSHost returns WS-RPC Server host, given enabled/disabled flag
func makeWSHost(wsEnabled bool) string { func makeWSHost(config *params.NodeConfig) string {
if !wsEnabled { if !config.WSEnabled {
return "" return ""
} }
return node.DefaultWSHost return config.WSHost
} }
// makeChainConfig reads the chain configuration from the database in the datadir. // makeChainConfig reads the chain configuration from the database in the datadir.
func makeChainConfig(stack *node.Node) *params.ChainConfig { func makeChainConfig(config *params.NodeConfig) *gethparams.ChainConfig {
config := new(params.ChainConfig) chainConfig := new(gethparams.ChainConfig)
if UseTestnet { // Homestead fork
config = params.TestnetChainConfig chainConfig.HomesteadBlock = config.HomesteadBlock
} else {
// Homestead fork
config.HomesteadBlock = params.MainNetHomesteadBlock
// DAO fork
config.DAOForkBlock = params.MainNetDAOForkBlock
config.DAOForkSupport = true
// DoS reprice fork // DAO fork
config.EIP150Block = params.MainNetHomesteadGasRepriceBlock chainConfig.DAOForkBlock = config.DAOForkBlock
config.EIP150Hash = params.MainNetHomesteadGasRepriceHash chainConfig.DAOForkSupport = config.DAOForkSupport
// DoS state cleanup fork // DoS reprice fork
config.EIP155Block = params.MainNetSpuriousDragon chainConfig.EIP150Block = config.EIP150Block
config.EIP158Block = params.MainNetSpuriousDragon chainConfig.EIP150Hash = config.EIP150Hash
config.ChainId = params.MainNetChainID
}
return config // DoS state cleanup fork
chainConfig.EIP155Block = config.EIP155Block
chainConfig.EIP158Block = config.EIP158Block
chainConfig.ChainId = config.ChainId
return chainConfig
} }
// makeDatabaseHandles makes sure that enough file descriptors are available to the process // makeDatabaseHandles makes sure that enough file descriptors are available to the process
@ -272,8 +206,8 @@ func makeDatabaseHandles() int {
// increase limit // increase limit
limit.Cur = limit.Max limit.Cur = limit.Max
if limit.Cur > ProcessFileDescriptorLimit { if limit.Cur > params.DefaultFileDescriptorLimit {
limit.Cur = ProcessFileDescriptorLimit limit.Cur = params.DefaultFileDescriptorLimit
} }
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
Fatalf(err) Fatalf(err)
@ -285,34 +219,13 @@ func makeDatabaseHandles() int {
} }
// cap limit // cap limit
if limit.Cur > ProcessFileDescriptorLimit { if limit.Cur > params.DefaultFileDescriptorLimit {
limit.Cur = ProcessFileDescriptorLimit limit.Cur = params.DefaultFileDescriptorLimit
} }
return int(limit.Cur) / 2 return int(limit.Cur) / 2
} }
func makeDefaultExtra() []byte {
var clientInfo = struct {
Version uint
Name string
GoVersion string
Os string
}{uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.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)
}
if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
glog.V(logger.Debug).Infof("extra: %x\n", extra)
return nil
}
return extra
}
// makeBootstrapNodes returns default (hence bootstrap) list of peers // makeBootstrapNodes returns default (hence bootstrap) list of peers
func makeBootstrapNodes() []*discover.Node { func makeBootstrapNodes() []*discover.Node {
// on desktops params.TestnetBootnodes and params.MainBootnodes, // on desktops params.TestnetBootnodes and params.MainBootnodes,

View File

@ -64,7 +64,7 @@ var (
) )
// CreateAndRunNode creates and starts running Geth node locally (exposing given RPC port along the way) // CreateAndRunNode creates and starts running Geth node locally (exposing given RPC port along the way)
func CreateAndRunNode(config *NodeConfig) error { func CreateAndRunNode(config *params.NodeConfig) error {
defer HaltOnPanic() defer HaltOnPanic()
nodeManager := NewNodeManager(config) nodeManager := NewNodeManager(config)
@ -79,7 +79,7 @@ func CreateAndRunNode(config *NodeConfig) error {
} }
// NewNodeManager makes new instance of node manager // NewNodeManager makes new instance of node manager
func NewNodeManager(config *NodeConfig) *NodeManager { func NewNodeManager(config *params.NodeConfig) *NodeManager {
createOnce.Do(func() { createOnce.Do(func() {
nodeManagerInstance = &NodeManager{ nodeManagerInstance = &NodeManager{
services: &NodeServiceStack{ services: &NodeServiceStack{

275
geth/params/config.go Normal file
View File

@ -0,0 +1,275 @@
package params
import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"strings"
"math/big"
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
)
// default node configuration options
var (
UseMainnetFlag = "false" // to be overridden via -ldflags '-X geth/params.UseMainnetFlag'
UseMainnet = false
)
func init() {
if UseMainnetFlag == "true" { // set at compile time, here we make sure to set corresponding boolean flag
UseMainnet = true
}
}
var (
ErrMissingDataDir = errors.New("missing required 'DataDir' parameter")
ErrMissingNetworkId = errors.New("missing required 'NetworkId' parameter")
)
// ChainConfig holds core blockchain settings. It is stored in the database on a per block basis.
type ChainConfig struct {
// ChainId identifies the current chain and is used for replay protection
ChainId *big.Int
// HomesteadBlock is Homestead switch block (nil = no fork, 0 = already homestead)
HomesteadBlock *big.Int
// DAOForkBlock TheDAO hard-fork switch block (nil = no fork)
DAOForkBlock *big.Int
// DAOForkSupport Whether the nodes supports or opposes the DAO hard-fork
DAOForkSupport bool
// EIP150Block is EIP150 HF block (nil = no fork)
EIP150Block *big.Int
// EIP150Hash is EIP150 HF hash (fast sync aid)
EIP150Hash common.Hash
// EIP155Block is EIP155 HF block
EIP155Block *big.Int
// EIP158Block is EIP158 HF block
EIP158Block *big.Int
}
// LightEthConfig holds LES-related configuration
// Status nodes are always lightweight clients (due to mobile platform constraints)
type LightEthConfig struct {
// Genesis is JSON to seed the chain database with
Genesis string
// DatabaseCache is memory (in MBs) allocated to internal caching (min 16MB / database forced)
DatabaseCache int
}
// WhisperConfig holds SHH-related configuration
type WhisperConfig struct{}
// SwarmConfig holds Swarm-related configuration
type SwarmConfig struct{}
// NodeConfig stores configuration options for a node
type NodeConfig struct {
// TestNet flag whether given configuration describes a test or mainnet
TestNet bool
// NetworkId sets network to use for selecting peers to connect to
NetworkId int
// DataDir is the file system folder the node should use for any data storage needs.
DataDir string
// Name sets the instance name of the node. It must not contain the / character.
Name string
// Version exposes program's version. It is used in the devp2p node identifier.
Version string
// APIModules is a comma-separated list of API modules exposed via *any* (HTTP/WS/IPC) RPC interface.
APIModules string
// HTTPHost is the host interface on which to start the HTTP RPC server.
// Pass empty string if no HTTP RPC interface needs to be started.
HTTPHost string
// HTTPPort is the TCP port number on which to start the Geth's HTTP RPC server.
HTTPPort int
// WSHost is a host interface for the WebSocket RPC server
WSHost string
// WSPort is the TCP port number on which to start the Geth's WebSocket RPC server.
WSPort int
// WSEnabled specifies whether WS-RPC Server is enabled or not
WSEnabled bool
// IPCFile is filename of exposed IPC RPC Server
IPCFile string
// IPCEnabled specifies whether IPC-RPC Server is enabled or not
IPCEnabled bool
// TLSEnabled specifies whether TLS support should be enabled on node or not
// TLS support is only planned in go-ethereum, so we are using our own patch.
TLSEnabled bool
// MaxPeers is the maximum number of (global) peers that can be connected.
// Set to zero, if only static or trusted peers are allowed to connect.
MaxPeers int
// MaxPendingPeers is the maximum number of peers that can be pending in the
// handshake phase, counted separately for inbound and outbound connections.
MaxPendingPeers int
// ChainConfig extra configuration for blockchain
*ChainConfig `json:"ChainConfig,"`
// LightEthConfig extra configuration for LES
*LightEthConfig `json:"LightEthConfig,"`
// WhisperConfig extra configuration for SHH
*WhisperConfig `json:"WhisperConfig,"`
// SwarmConfig extra configuration for Swarm and ENS
*SwarmConfig `json:"SwarmConfig,"`
}
// NewNodeConfig creates new node configuration object
func NewNodeConfig(dataDir string, networkId int) (*NodeConfig, error) {
nodeConfig := &NodeConfig{
NetworkId: networkId,
DataDir: dataDir,
Name: DefaultClientIdentifier,
Version: Version,
HTTPHost: DefaultHTTPHost,
HTTPPort: DefaultHTTPPort,
APIModules: DefaultAPIModules,
WSHost: DefaultWSHost,
WSPort: DefaultWSPort,
MaxPeers: DefaultMaxPeers,
MaxPendingPeers: DefaultMaxPendingPeers,
IPCFile: DefaultIPCFile,
ChainConfig: &ChainConfig{},
LightEthConfig: &LightEthConfig{
DatabaseCache: DefaultDatabaseCache,
},
WhisperConfig: &WhisperConfig{},
SwarmConfig: &SwarmConfig{},
}
nodeConfig.populateChainConfig()
return nodeConfig, nil
}
// populateChainConfig does necessary adjustments to config object (depending on network node will be runnin on)
func (c *NodeConfig) populateChainConfig() {
c.TestNet = false
if c.NetworkId == TestNetworkId {
c.TestNet = true
}
if c.TestNet {
// Homestead fork
c.ChainConfig.HomesteadBlock = params.TestnetChainConfig.HomesteadBlock
// DAO fork
c.ChainConfig.DAOForkBlock = params.TestnetChainConfig.DAOForkBlock
c.ChainConfig.DAOForkSupport = params.TestnetChainConfig.DAOForkSupport
// DoS reprice fork
c.ChainConfig.EIP150Block = params.TestnetChainConfig.EIP150Block
c.ChainConfig.EIP150Hash = params.TestnetChainConfig.EIP150Hash
// DoS state cleanup fork
c.ChainConfig.EIP155Block = params.TestnetChainConfig.EIP155Block
c.ChainConfig.EIP158Block = params.TestnetChainConfig.EIP158Block
c.ChainConfig.ChainId = params.TestnetChainConfig.ChainId
if len(c.DataDir) > 0 {
c.DataDir = filepath.Join(c.DataDir, "testnet")
}
c.Genesis = core.DefaultTestnetGenesisBlock()
} else {
// Homestead fork
c.ChainConfig.HomesteadBlock = params.MainNetHomesteadBlock
// DAO fork
c.ChainConfig.DAOForkBlock = params.MainNetDAOForkBlock
c.ChainConfig.DAOForkSupport = true
// DoS reprice fork
c.ChainConfig.EIP150Block = params.MainNetHomesteadGasRepriceBlock
c.ChainConfig.EIP150Hash = params.MainNetHomesteadGasRepriceHash
// DoS state cleanup fork
c.ChainConfig.EIP155Block = params.MainNetSpuriousDragon
c.ChainConfig.EIP158Block = params.MainNetSpuriousDragon
c.ChainConfig.ChainId = params.MainNetChainID
c.Genesis = core.DefaultGenesisBlock()
}
}
// LoadNodeConfig parses incoming JSON and returned it as Config
func LoadNodeConfig(configJSON string) (*NodeConfig, error) {
nodeConfig, err := NewNodeConfig("", 0)
if err != nil {
return nil, err
}
decoder := json.NewDecoder(strings.NewReader(configJSON))
//decoder.UseNumber()
// override default configuration with values by JSON input
if err := decoder.Decode(&nodeConfig); err != nil {
return nil, err
}
// repopulate
nodeConfig.populateChainConfig()
if len(nodeConfig.DataDir) == 0 {
return nil, ErrMissingDataDir
}
if nodeConfig.NetworkId <= 0 {
return nil, ErrMissingNetworkId
}
return nodeConfig, nil
}
// Save dumps configuration to the disk
func (c *NodeConfig) Save() error {
data, err := json.MarshalIndent(c, "", " ")
if err != nil {
return err
}
if err := os.MkdirAll(c.DataDir, os.ModePerm); err != nil {
return err
}
configFilePath := filepath.Join(c.DataDir, "config.json")
if err := ioutil.WriteFile(configFilePath, data, os.ModePerm); err != nil {
return err
}
glog.V(logger.Info).Infof("config file saved: %v", configFilePath)
return nil
}
// String dumps config object as nicely indented JSON
func (c *NodeConfig) String() string {
data, _ := json.MarshalIndent(c, "", " ")
return string(data)
}

319
geth/params/config_test.go Normal file
View File

@ -0,0 +1,319 @@
package params_test
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/status-im/status-go/geth"
"github.com/status-im/status-go/geth/params"
gethparams "github.com/ethereum/go-ethereum/params"
)
var loadConfigTestCases = []struct {
name string
configJSON string
validator func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error)
}{
{
`invalid input configuration`,
`{
"NetworkId": 3
"DataDir": "$TMPDIR",
"Name": "TestStatusNode",
"WSPort": 8546,
"IPCEnabled": true,
"WSEnabled": false,
"LightEthConfig": {
"DatabaseCache": 64
}
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err == nil {
t.Fatal("error is expected, not thrown")
}
},
},
{
`missing required field (DataDir)`,
`{
"NetworkId": 3,
"Name": "TestStatusNode"
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != params.ErrMissingDataDir {
t.Fatalf("expected error not thrown, expected: %v, thrown: %v", params.ErrMissingDataDir, err)
}
},
},
{
`missing required field (NetworkId)`,
`{
"DataDir": "$TMPDIR"
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != params.ErrMissingNetworkId {
t.Fatalf("expected error not thrown, expected: %v, thrown: %v", params.ErrMissingNetworkId, err)
}
},
},
{
`testnet subdirectory not used (while we are on Network = 3)`,
`{
"NetworkId": 3,
"DataDir": "$TMPDIR"
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if nodeConfig.DataDir != filepath.Join(dataDir, "testnet") {
t.Fatal("'testnet' subdirectory not used")
}
if !strings.Contains(nodeConfig.LightEthConfig.Genesis, "\"chainId\": 3") {
t.Fatal("wrong genesis")
}
},
},
{
`testnet subdirectory used (while we are on Network != 3)`,
`{
"NetworkId": 1,
"DataDir": "$TMPDIR"
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if nodeConfig.DataDir != dataDir {
t.Fatal("'testnet' subdirectory used")
}
if strings.Contains(nodeConfig.LightEthConfig.Genesis, "\"chainId\": 3") {
t.Fatal("wrong genesis")
}
},
},
{
`test parameter overriding`,
`{
"NetworkId": 3,
"DataDir": "$TMPDIR",
"Name": "TestStatusNode",
"WSPort": 4242,
"IPCEnabled": true,
"WSEnabled": false,
"LightEthConfig": {
"DatabaseCache": 64
}
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if nodeConfig.NetworkId != 3 {
t.Fatal("wrong NetworkId")
}
if nodeConfig.Name != "TestStatusNode" {
t.Fatal("wrong Name")
}
if nodeConfig.HTTPPort != params.DefaultHTTPPort {
t.Fatal("wrong HTTPPort")
}
if nodeConfig.HTTPHost != params.DefaultHTTPHost {
t.Fatal("wrong HTTPHost")
}
if nodeConfig.WSPort != 4242 {
t.Fatal("wrong WSPort")
}
if nodeConfig.WSEnabled != false {
t.Fatal("wrong WSEnabled")
}
if nodeConfig.IPCEnabled != true{
t.Fatal("wrong IPCEnabled")
}
if nodeConfig.LightEthConfig.DatabaseCache != 64 {
t.Fatal("wrong LightEthConfig.DatabaseCache")
}
},
},
{
`test loading Testnet config`,
`{
"NetworkId": 3,
"DataDir": "$TMPDIR",
"Name": "TestStatusNode",
"WSPort": 8546,
"IPCEnabled": true,
"WSEnabled": false,
"LightEthConfig": {
"DatabaseCache": 64
}
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
chainConfig := nodeConfig.ChainConfig
refChainConfig := gethparams.TestnetChainConfig
if chainConfig.HomesteadBlock.Cmp(refChainConfig.HomesteadBlock) != 0 {
t.Fatal("invalid chainConfig.HomesteadBlock")
}
if chainConfig.DAOForkBlock != nil { // already forked
t.Fatal("invalid chainConfig.DAOForkBlock")
}
if chainConfig.DAOForkSupport != refChainConfig.DAOForkSupport {
t.Fatal("invalid chainConfig.DAOForkSupport")
}
if chainConfig.EIP150Block.Cmp(refChainConfig.EIP150Block) != 0 {
t.Fatal("invalid chainConfig.EIP150Block")
}
if chainConfig.EIP150Hash != refChainConfig.EIP150Hash {
t.Fatal("invalid chainConfig.EIP150Hash")
}
if chainConfig.EIP155Block.Cmp(refChainConfig.EIP155Block) != 0 {
t.Fatal("invalid chainConfig.EIP155Block")
}
if chainConfig.EIP158Block.Cmp(refChainConfig.EIP158Block) != 0 {
t.Fatal("invalid chainConfig.EIP158Block")
}
if chainConfig.ChainId.Cmp(refChainConfig.ChainId) != 0 {
t.Fatal("invalid chainConfig.ChainId")
}
},
},
{
`test loading Mainnet config`,
`{
"NetworkId": 1,
"DataDir": "$TMPDIR",
"Name": "TestStatusNode",
"WSPort": 8546,
"IPCEnabled": true,
"WSEnabled": false,
"LightEthConfig": {
"DatabaseCache": 64
}
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
chainConfig := nodeConfig.ChainConfig
if chainConfig.HomesteadBlock.Cmp(gethparams.MainNetHomesteadBlock) != 0 {
t.Fatal("invalid chainConfig.HomesteadBlock")
}
if chainConfig.DAOForkBlock.Cmp(gethparams.MainNetDAOForkBlock) != 0 {
t.Fatal("invalid chainConfig.DAOForkBlock")
}
if chainConfig.DAOForkSupport != true {
t.Fatal("invalid chainConfig.DAOForkSupport")
}
if chainConfig.EIP150Block.Cmp(gethparams.MainNetHomesteadGasRepriceBlock) != 0 {
t.Fatal("invalid chainConfig.EIP150Block")
}
if chainConfig.EIP150Hash != gethparams.MainNetHomesteadGasRepriceHash {
t.Fatal("invalid chainConfig.EIP150Hash")
}
if chainConfig.EIP155Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 {
t.Fatal("invalid chainConfig.EIP155Block")
}
if chainConfig.EIP158Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 {
t.Fatal("invalid chainConfig.EIP158Block")
}
if chainConfig.ChainId.Cmp(gethparams.MainNetChainID) != 0 {
t.Fatal("invalid chainConfig.ChainId")
}
},
},
{
`test loading Privatenet config`,
`{
"NetworkId": 311,
"DataDir": "$TMPDIR",
"Name": "TestStatusNode",
"WSPort": 8546,
"IPCEnabled": true,
"WSEnabled": false,
"ChainConfig": {
"ChainId": 311
}
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
//nodeConfig.LightEthConfig.Genesis = nodeConfig.LightEthConfig.Genesis[:125]
//fmt.Println(nodeConfig)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
networkId := 311
if nodeConfig.NetworkId != networkId {
t.Fatalf("unexpected NetworkId, expected: %v, got: %v", networkId, nodeConfig.NetworkId)
}
if nodeConfig.ChainId.Int64() != int64(networkId) {
t.Fatalf("unexpected ChainConfig.ChainId, expected: %v, got: %v", networkId, nodeConfig.ChainId)
}
},
},
}
func TestLoadNodeConfig(t *testing.T) {
tmpDir, err := ioutil.TempDir(os.TempDir(), "geth-config-tests")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
for _, testCase := range loadConfigTestCases {
t.Log("test: " + testCase.name)
testCase.configJSON = strings.Replace(testCase.configJSON, "$TMPDIR", tmpDir, -1)
nodeConfig, err := params.LoadNodeConfig(testCase.configJSON)
testCase.validator(t, tmpDir, nodeConfig, err)
}
}
func TestConfigWriteRead(t *testing.T) {
tmpDir, err := ioutil.TempDir(os.TempDir(), "geth-config-tests")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
nodeConfig, err := params.NewNodeConfig(tmpDir, params.TestNetworkId)
if err != nil {
t.Fatalf("cannot create new config object: %v", err)
}
if err := nodeConfig.Save(); err != nil {
t.Fatalf("cannot persist configuration: %v", err)
}
loadedConfigData, err := ioutil.ReadFile(filepath.Join(nodeConfig.DataDir, "config.json"))
if err != nil {
t.Fatalf("cannot read configuration from disk: %v", err)
}
refConfigData := geth.LoadFromFile("testdata/config.testnet.json")
refConfigData = strings.Replace(refConfigData, "$TMPDIR", nodeConfig.DataDir, -1)
refConfigData = strings.Replace(refConfigData, "$VERSION", params.Version, -1)
if string(loadedConfigData) != refConfigData {
t.Fatalf("configuration mismatch,\nexpected: %v\ngot: %v", refConfigData, string(loadedConfigData))
}
}

61
geth/params/defaults.go Normal file
View File

@ -0,0 +1,61 @@
package params
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
)
const (
// DefaultClientIdentifier is client identifier to advertise over the network
DefaultClientIdentifier = "status"
// DefaultIPCFile is filename of exposed IPC RPC Server
DefaultIPCFile = "geth.ipc"
// DefaultHTTPHost is host interface for the HTTP RPC server
DefaultHTTPHost = "localhost"
// DefaultHTTPPort is HTTP-RPC port (replaced in unit tests)
DefaultHTTPPort = 8545
// DefaultAPIModules is a list of modules to expose vie HTTP RPC
// TODO remove "admin" on main net
DefaultAPIModules = "db,eth,net,web3,shh,personal,admin"
// DefaultWSHost is a host interface for the websocket RPC server
DefaultWSHost = "localhost"
// DefaultWSPort is a WS-RPC port (replaced in unit tests)
DefaultWSPort = 8546
// DefaultMaxPeers is the maximum number of global peers
DefaultMaxPeers = 25
// DefaultMaxPendingPeers is the maximum number of peers that can be pending in the
// handshake phase, counted separately for inbound and outbound connections.
DefaultMaxPendingPeers = 0
// DefaultGas default amount of gas used for transactions
DefaultGas = 180000
// DefaultFileDescriptorLimit is fd limit that database can use
DefaultFileDescriptorLimit = uint64(2048)
// DefaultDatabaseCache is memory (in MBs) allocated to internal caching (min 16MB / database forced)
DefaultDatabaseCache = 128
// TestNetworkId is id of a test network
TestNetworkId = 3
)
// Gas price settings
var (
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 (%)
)

34
geth/params/testdata/config.mainnet.json vendored Executable file

File diff suppressed because one or more lines are too long

34
geth/params/testdata/config.testnet.json vendored Executable file

File diff suppressed because one or more lines are too long

View File

@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/les/status" "github.com/ethereum/go-ethereum/les/status"
"github.com/status-im/status-go/geth" "github.com/status-im/status-go/geth"
"github.com/status-im/status-go/geth/params"
) )
func TestQueuedContracts(t *testing.T) { func TestQueuedContracts(t *testing.T) {
@ -95,7 +96,7 @@ func TestQueuedContracts(t *testing.T) {
From: geth.FromAddress(testConfig.Account1.Address), From: geth.FromAddress(testConfig.Account1.Address),
To: nil, // marker, contract creation is expected To: nil, // marker, contract creation is expected
//Value: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(1), common.Ether)), //Value: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(1), common.Ether)),
Gas: (*hexutil.Big)(big.NewInt(geth.DefaultGas)), Gas: (*hexutil.Big)(big.NewInt(params.DefaultGas)),
Data: byteCode, Data: byteCode,
}) })
if err != nil { if err != nil {

View File

@ -20,6 +20,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/status-im/status-go/geth/params"
) )
var ( var (
@ -177,14 +178,14 @@ func PrepareTestNode() (err error) {
} }
// start geth node and wait for it to initialize // start geth node and wait for it to initialize
err = CreateAndRunNode(&NodeConfig{ config, err := params.NewNodeConfig(TestDataDir, params.TestNetworkId)
DataDir: TestDataDir, if err != nil {
IPCEnabled: false, return err
HTTPPort: testConfig.Node.HTTPPort, // to avoid conflicts with running app, using different port in tests }
WSEnabled: false, config.HTTPPort = testConfig.Node.HTTPPort // to avoid conflicts with running app, using different port in tests
WSPort: testConfig.Node.WSPort, // ditto config.WSPort = testConfig.Node.WSPort // ditto
TLSEnabled: false,
}) err = CreateAndRunNode(config)
if err != nil { if err != nil {
panic(err) panic(err)
} }