Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions cmd/devnet/args/args.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package args

import (
"fmt"
"reflect"
"strings"
"unicode"
"unicode/utf8"
)

type Args []string

func AsArgs(args interface{}) (Args, error) {

argsValue := reflect.ValueOf(args)

if argsValue.Kind() == reflect.Ptr {
argsValue = argsValue.Elem()
}

if argsValue.Kind() != reflect.Struct {
return nil, fmt.Errorf("Args type must be struct or struc pointer, got %T", args)
}

return gatherArgs(argsValue, func(v reflect.Value, field reflect.StructField) (string, error) {
tag := field.Tag.Get("arg")

if tag == "-" {
return "", nil
}

// only process public fields (reflection won't return values of unsafe fields without unsafe operations)
if r, _ := utf8.DecodeRuneInString(field.Name); !(unicode.IsLetter(r) && unicode.IsUpper(r)) {
return "", nil
}

var key string
var positional bool

for _, key = range strings.Split(tag, ",") {
if key == "" {
continue
}

key = strings.TrimLeft(key, " ")

if pos := strings.Index(key, ":"); pos != -1 {
key = key[:pos]
}

switch {
case strings.HasPrefix(key, "---"):
return "", fmt.Errorf("%s.%s: too many hyphens", v.Type().Name(), field.Name)
case strings.HasPrefix(key, "--"):

case strings.HasPrefix(key, "-"):
if len(key) != 2 {
return "", fmt.Errorf("%s.%s: short arguments must be one character only", v.Type().Name(), field.Name)
}
case key == "positional":
key = ""
positional = true
default:
return "", fmt.Errorf("unrecognized tag '%s' on field %s", key, tag)
}
}

if len(key) == 0 && !positional {
key = "--" + strings.ToLower(field.Name)
}

var value string

switch fv := v.FieldByIndex(field.Index); fv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if fv.Int() == 0 {
break
}
fallthrough
default:
value = fmt.Sprintf("%v", fv.Interface())
}

flagValue, isFlag := field.Tag.Lookup("flag")

if isFlag {
if value != "true" {
if flagValue == "true" {
value = flagValue
}
}
}

if len(value) == 0 {
if defaultString, hasDefault := field.Tag.Lookup("default"); hasDefault {
value = defaultString
}

if len(value) == 0 {
return "", nil
}
}

if len(key) == 0 {
return value, nil
}

if isFlag {
if value == "true" {
return key, nil
}

return "", nil
}

if len(value) == 0 {
return key, nil
}

return fmt.Sprintf("%s=%s", key, value), nil
})
}

func gatherArgs(v reflect.Value, visit func(v reflect.Value, field reflect.StructField) (string, error)) (args Args, err error) {
for i := 0; i < v.NumField(); i++ {
field := v.Type().Field(i)

var gathered Args

fieldType := field.Type

if fieldType.Kind() == reflect.Ptr {
fieldType.Elem()
}

if fieldType.Kind() == reflect.Struct {
gathered, err = gatherArgs(v.FieldByIndex(field.Index), visit)
} else {
var value string

if value, err = visit(v, field); len(value) > 0 {
gathered = Args{value}
}
}

if err != nil {
return nil, err
}

args = append(args, gathered...)
}

return args, nil
}
137 changes: 137 additions & 0 deletions cmd/devnet/args/node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package args

import (
"fmt"
"net"
"path/filepath"
"strconv"

"github.com/ledgerwatch/erigon/cmd/devnet/requests"
"github.com/ledgerwatch/erigon/params/networkname"
)

type Node struct {
requests.RequestGenerator `arg:"-"`
BuildDir string `arg:"positional" default:"./build/bin/devnet"`
DataDir string `arg:"--datadir" default:"./dev"`
Chain string `arg:"--chain" default:"dev"`
Port int `arg:"--port"`
AllowedPorts string `arg:"--p2p.allowed-ports"`
NAT string `arg:"--nat" default:"none"`
ConsoleVerbosity string `arg:"--log.console.verbosity" default:"0"`
DirVerbosity string `arg:"--log.dir.verbosity"`
LogDirPath string `arg:"--log.dir.path"`
LogDirPrefix string `arg:"--log.dir.prefix"`
P2PProtocol string `arg:"--p2p.protocol" default:"68"`
Downloader string `arg:"--no-downloader" default:"true"`
WS string `arg:"--ws" flag:"" default:"true"`
PrivateApiAddr string `arg:"--private.api.addr" default:"localhost:9090"`
HttpPort int `arg:"--http.port" default:"8545"`
HttpVHosts string `arg:"--http.vhosts"`
AuthRpcPort int `arg:"--authrpc.port" default:"8551"`
AuthRpcVHosts string `arg:"--authrpc.vhosts"`
WSPort int `arg:"-" default:"8546"` // flag not defined
GRPCPort int `arg:"-" default:"8547"` // flag not defined
TCPPort int `arg:"-" default:"8548"` // flag not defined
StaticPeers string `arg:"--staticpeers"`
WithoutHeimdall bool `arg:"--bor.withoutheimdall" flag:"" default:"false"`
}

func (node *Node) configure(base Node, nodeNumber int) error {
node.DataDir = filepath.Join(base.DataDir, fmt.Sprintf("%d", nodeNumber))

node.LogDirPath = filepath.Join(base.DataDir, "logs")
node.LogDirPrefix = fmt.Sprintf("node-%d", nodeNumber)

node.Chain = base.Chain

node.StaticPeers = base.StaticPeers

var err error

node.PrivateApiAddr, _, err = portFromBase(base.PrivateApiAddr, nodeNumber, 1)

if err != nil {
return err
}

apiPort := base.HttpPort + (nodeNumber * 5)

node.HttpPort = apiPort
node.WSPort = apiPort + 1
node.GRPCPort = apiPort + 2
node.TCPPort = apiPort + 3
node.AuthRpcPort = apiPort + 4

return nil
}

type Miner struct {
Node
Mine bool `arg:"--mine" flag:"true"`
DevPeriod int `arg:"--dev.period"`
BorPeriod int `arg:"--bor.period"`
BorMinBlockSize int `arg:"--bor.minblocksize"`
HttpApi string `arg:"--http.api" default:"admin,eth,erigon,web3,net,debug,trace,txpool,parity,ots"`
AccountSlots int `arg:"--txpool.accountslots" default:"16"`
}

func (m Miner) Configure(baseNode Node, nodeNumber int) (int, interface{}, error) {
err := m.configure(baseNode, nodeNumber)

if err != nil {
return -1, nil, err
}

switch m.Chain {
case networkname.DevChainName:
if m.DevPeriod == 0 {
m.DevPeriod = 30
}
}

return m.HttpPort, m, nil
}

func (n Miner) IsMiner() bool {
return true
}

type NonMiner struct {
Node
HttpApi string `arg:"--http.api" default:"admin,eth,debug,net,trace,web3,erigon,txpool"`
TorrentPort string `arg:"--torrent.port" default:"42070"`
NoDiscover string `arg:"--nodiscover" flag:"" default:"true"`
}

func (n NonMiner) Configure(baseNode Node, nodeNumber int) (int, interface{}, error) {
err := n.configure(baseNode, nodeNumber)

if err != nil {
return -1, nil, err
}

return n.HttpPort, n, nil
}

func (n NonMiner) IsMiner() bool {
return false
}

func portFromBase(baseAddr string, increment int, portCount int) (string, int, error) {
apiHost, apiPort, err := net.SplitHostPort(baseAddr)

if err != nil {
return "", -1, err
}

portNo, err := strconv.Atoi(apiPort)

if err != nil {
return "", -1, err
}

portNo += (increment * portCount)

return fmt.Sprintf("%s:%d", apiHost, portNo), portNo, nil
}
28 changes: 16 additions & 12 deletions cmd/devnet/node/node_test.go → cmd/devnet/args/node_test.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
package node_test
package args_test

import (
"errors"
"fmt"
"path/filepath"
"testing"

"github.com/ledgerwatch/erigon/cmd/devnet/devnetutils"
"github.com/ledgerwatch/erigon/cmd/devnet/node"
"github.com/ledgerwatch/erigon/cmd/devnet/args"
)

func TestNodeArgs(t *testing.T) {
asMap := map[string]struct{}{}

args, _ := devnetutils.AsArgs(node.Miner{
Node: node.Node{
nodeArgs, _ := args.AsArgs(args.Miner{
Node: args.Node{
DataDir: filepath.Join("data", fmt.Sprintf("%d", 1)),
PrivateApiAddr: "localhost:9092",
},
DevPeriod: 30,
})

for _, arg := range args {
for _, arg := range nodeArgs {
asMap[arg] = struct{}{}
}

Expand All @@ -36,15 +36,15 @@ func TestNodeArgs(t *testing.T) {
t.Fatal(asMap, "not found")
}

args, _ = devnetutils.AsArgs(node.NonMiner{
Node: node.Node{
nodeArgs, _ = args.AsArgs(args.NonMiner{
Node: args.Node{
DataDir: filepath.Join("data", fmt.Sprintf("%d", 2)),
StaticPeers: "enode",
PrivateApiAddr: "localhost:9091",
},
})

for _, arg := range args {
for _, arg := range nodeArgs {
asMap[arg] = struct{}{}
}

Expand Down Expand Up @@ -160,8 +160,10 @@ func miningNodeArgs(dataDir string, nodeNumber int) []string {
downloaderArg, _ := parameterFromArgument("--no-downloader", "true")
httpPortArg, _ := parameterFromArgument("--http.port", "8545")
authrpcPortArg, _ := parameterFromArgument("--authrpc.port", "8551")
natArg, _ := parameterFromArgument("--nat", "none")
accountSlotsArg, _ := parameterFromArgument("--txpool.accountslots", "16")

return []string{buildDirArg, dataDirArg, chainType, privateApiAddr, httpPortArg, authrpcPortArg, mine, httpApi, ws, devPeriod, consoleVerbosity, p2pProtocol, downloaderArg}
return []string{buildDirArg, dataDirArg, chainType, privateApiAddr, httpPortArg, authrpcPortArg, mine, httpApi, ws, natArg, devPeriod, consoleVerbosity, p2pProtocol, downloaderArg, accountSlotsArg}
}

// nonMiningNodeArgs returns custom args for starting a non-mining node
Expand All @@ -176,8 +178,10 @@ func nonMiningNodeArgs(dataDir string, nodeNumber int, enode string) []string {
p2pProtocol, _ := parameterFromArgument("--p2p.protocol", "68")
downloaderArg, _ := parameterFromArgument("--no-downloader", "true")
httpPortArg, _ := parameterFromArgument("--http.port", "8545")
httpApi, _ := parameterFromArgument(httpApiArg, "eth,debug,net,trace,web3,erigon")
httpApi, _ := parameterFromArgument(httpApiArg, "admin,eth,debug,net,trace,web3,erigon,txpool")
authrpcPortArg, _ := parameterFromArgument("--authrpc.port", "8551")
natArg, _ := parameterFromArgument("--nat", "none")
ws := wsArg

return []string{buildDirArg, dataDirArg, chainType, privateApiAddr, httpPortArg, authrpcPortArg, httpApi, staticPeers, noDiscover, consoleVerbosity, torrentPort, p2pProtocol, downloaderArg}
return []string{buildDirArg, dataDirArg, chainType, privateApiAddr, httpPortArg, authrpcPortArg, httpApi, ws, natArg, staticPeers, noDiscover, consoleVerbosity, torrentPort, p2pProtocol, downloaderArg}
}
Loading