diff --git a/cmd/devnet/args/node.go b/cmd/devnet/args/node.go index 932b28efbd5..0ab64a9e1ed 100644 --- a/cmd/devnet/args/node.go +++ b/cmd/devnet/args/node.go @@ -1,7 +1,11 @@ package args import ( + "crypto/ecdsa" + "encoding/hex" "fmt" + "github.com/ledgerwatch/erigon/crypto" + "github.com/ledgerwatch/erigon/p2p/enode" "math/big" "net" "path/filepath" @@ -46,6 +50,9 @@ type Node struct { HeimdallGRpc string `arg:"--bor.heimdallgRPC" json:"bor.heimdallgRPC,omitempty"` WithHeimdallMilestones bool `arg:"--bor.milestone" json:"bor.milestone"` VMDebug bool `arg:"--vmdebug" flag:"" default:"false" json:"dmdebug"` + + NodeKey *ecdsa.PrivateKey `arg:"-"` + NodeKeyHex string `arg:"--nodekeyhex" json:"nodekeyhex,omitempty"` } func (node *Node) configure(base Node, nodeNumber int) error { @@ -63,14 +70,19 @@ func (node *Node) configure(base Node, nodeNumber int) error { node.StaticPeers = base.StaticPeers + var err error + node.NodeKey, err = crypto.GenerateKey() + if err != nil { + return err + } + node.NodeKeyHex = hex.EncodeToString(crypto.FromECDSA(node.NodeKey)) + node.Metrics = base.Metrics node.MetricsPort = base.MetricsPort node.MetricsAddr = base.MetricsAddr node.Snapshots = base.Snapshots - var err error - node.PrivateApiAddr, _, err = portFromBase(base.PrivateApiAddr, nodeNumber, 1) if err != nil { @@ -92,10 +104,19 @@ func (node *Node) configure(base Node, nodeNumber int) error { return nil } -func (node Node) ChainID() *big.Int { +func (node *Node) ChainID() *big.Int { return &big.Int{} } +func (node *Node) GetHttpPort() int { + return node.HttpPort +} + +func (node *Node) GetEnodeURL() string { + port := node.Port + return enode.NewV4(&node.NodeKey.PublicKey, net.ParseIP("127.0.0.1"), port, port).URLv4() +} + type BlockProducer struct { Node Mine bool `arg:"--mine" flag:"true"` @@ -108,11 +129,10 @@ type BlockProducer struct { account *accounts.Account } -func (m BlockProducer) Configure(baseNode Node, nodeNumber int) (int, interface{}, error) { +func (m *BlockProducer) Configure(baseNode Node, nodeNumber int) (interface{}, error) { err := m.configure(baseNode, nodeNumber) - if err != nil { - return -1, nil, err + return nil, err } switch m.Chain { @@ -134,18 +154,18 @@ func (m BlockProducer) Configure(baseNode Node, nodeNumber int) (int, interface{ m.Etherbase = m.account.Address.Hex() } - return m.HttpPort, m, nil + return m, nil } -func (n BlockProducer) Name() string { +func (n *BlockProducer) Name() string { return n.Node.Name } -func (n BlockProducer) Account() *accounts.Account { +func (n *BlockProducer) Account() *accounts.Account { return n.account } -func (n BlockProducer) IsBlockProducer() bool { +func (n *BlockProducer) IsBlockProducer() bool { return true } @@ -156,25 +176,24 @@ type NonBlockProducer struct { NoDiscover string `arg:"--nodiscover" flag:"" default:"true" json:"nodiscover"` } -func (n NonBlockProducer) Configure(baseNode Node, nodeNumber int) (int, interface{}, error) { +func (n *NonBlockProducer) Configure(baseNode Node, nodeNumber int) (interface{}, error) { err := n.configure(baseNode, nodeNumber) - if err != nil { - return -1, nil, err + return nil, err } - return n.HttpPort, n, nil + return n, nil } -func (n NonBlockProducer) Name() string { +func (n *NonBlockProducer) Name() string { return n.Node.Name } -func (n NonBlockProducer) IsBlockProducer() bool { +func (n *NonBlockProducer) IsBlockProducer() bool { return false } -func (n NonBlockProducer) Account() *accounts.Account { +func (n *NonBlockProducer) Account() *accounts.Account { return nil } diff --git a/cmd/devnet/devnet/network.go b/cmd/devnet/devnet/network.go index a5584d085ee..76997bf3cb6 100644 --- a/cmd/devnet/devnet/network.go +++ b/cmd/devnet/devnet/network.go @@ -56,11 +56,6 @@ func (nw *Network) ChainID() *big.Int { // Start starts the process for multiple erigon nodes running on the dev chain func (nw *Network) Start(ctx context.Context) error { - - type configurable interface { - Configure(baseNode args.Node, nodeNumber int) (int, interface{}, error) - } - for _, service := range nw.Services { if err := service.Start(ctx); err != nil { nw.Stop() @@ -89,22 +84,25 @@ func (nw *Network) Start(ctx context.Context) error { metricsNode := cliCtx.Int("metrics.node") nw.namedNodes = map[string]Node{} - for i, node := range nw.Nodes { - if configurable, ok := node.(configurable); ok { - + for i, nodeConfig := range nw.Nodes { + { base := baseNode - if metricsEnabled && metricsNode == i { base.Metrics = true base.MetricsPort = cliCtx.Int("metrics.port") } + base.StaticPeers = strings.Join(nw.peers, ",") - nodePort, args, err := configurable.Configure(base, i) - - if err == nil { - node, err = nw.createNode(fmt.Sprintf("%s:%d", nw.BaseRPCHost, nodePort), args) + argsObj, err := nodeConfig.Configure(base, i) + if err != nil { + nw.Stop() + return err } + nodePort := nodeConfig.GetHttpPort() + nodeAddr := fmt.Sprintf("%s:%d", nw.BaseRPCHost, nodePort) + + node, err := nw.createNode(nodeAddr, argsObj) if err != nil { nw.Stop() return err @@ -112,6 +110,7 @@ func (nw *Network) Start(ctx context.Context) error { nw.Nodes[i] = node nw.namedNodes[node.Name()] = node + nw.peers = append(nw.peers, nodeConfig.GetEnodeURL()) for _, service := range nw.Services { service.NodeCreated(ctx, node) @@ -126,23 +125,6 @@ func (nw *Network) Start(ctx context.Context) error { return err } - // get the enode of the node - // - note this has the side effect of waiting for the node to start - enode, err := getEnode(node) - if err != nil { - if errors.Is(err, devnetutils.ErrInvalidEnodeString) { - continue - } - - nw.Stop() - return err - } - nw.peers = append(nw.peers, enode) - - // TODO do we need to call AddPeer to the nodes to make them aware of this one - // the current model only works for an appending node network where the peers gossip - // connections - not sure if this is the case ? - for _, service := range nw.Services { service.NodeStarted(ctx, node) } @@ -205,28 +187,10 @@ func (nw *Network) startNode(n Node) error { node := n.(*node) args, err := args.AsArgs(node.args) - if err != nil { return err } - if len(nw.peers) > 0 { - peersIndex := -1 - - for i, arg := range args { - if strings.HasPrefix(arg, "--staticpeers") { - peersIndex = i - break - } - } - - if peersIndex >= 0 { - args[peersIndex] = args[peersIndex] + "," + strings.Join(nw.peers, ",") - } else { - args = append(args, "--staticpeers="+strings.Join(nw.peers, ",")) - } - } - go func() { nw.Logger.Info("Running node", "name", node.Name(), "args", args) diff --git a/cmd/devnet/devnet/node.go b/cmd/devnet/devnet/node.go index b45a098f063..053f45b8d70 100644 --- a/cmd/devnet/devnet/node.go +++ b/cmd/devnet/devnet/node.go @@ -2,8 +2,10 @@ package devnet import ( "context" + "errors" "fmt" "math/big" + "net" "net/http" "sync" @@ -14,6 +16,7 @@ import ( "github.com/ledgerwatch/erigon/diagnostics" "github.com/ledgerwatch/erigon/eth/ethconfig" "github.com/ledgerwatch/erigon/node/nodecfg" + p2p_enode "github.com/ledgerwatch/erigon/p2p/enode" "github.com/ledgerwatch/erigon/params" "github.com/ledgerwatch/erigon/turbo/debug" enode "github.com/ledgerwatch/erigon/turbo/node" @@ -25,8 +28,11 @@ type Node interface { requests.RequestGenerator Name() string ChainID() *big.Int + GetHttpPort() int + GetEnodeURL() string Account() *accounts.Account IsBlockProducer() bool + Configure(baseNode args.Node, nodeNumber int) (interface{}, error) } type NodeSelector interface { @@ -98,6 +104,10 @@ func (n *node) done() { } } +func (n *node) Configure(args.Node, int) (interface{}, error) { + return nil, errors.New("N/A") +} + func (n *node) IsBlockProducer() bool { _, isBlockProducer := n.args.(args.BlockProducer) return isBlockProducer @@ -127,6 +137,15 @@ func (n *node) ChainID() *big.Int { return nil } +func (n *node) GetHttpPort() int { + return n.nodeCfg.HTTPPort +} + +func (n *node) GetEnodeURL() string { + port := n.nodeCfg.P2P.ListenPort() + return p2p_enode.NewV4(&n.nodeCfg.P2P.PrivateKey.PublicKey, net.ParseIP("127.0.0.1"), port, port).URLv4() +} + // run configures, creates and serves an erigon node func (n *node) run(ctx *cli.Context) error { var logger log.Logger diff --git a/cmd/devnet/main.go b/cmd/devnet/main.go index a381b16c4f1..12053b7aed8 100644 --- a/cmd/devnet/main.go +++ b/cmd/devnet/main.go @@ -345,7 +345,7 @@ func initDevnet(ctx *cli.Context, logger log.Logger) (devnet.Devnet, error) { account_services.NewFaucet(networkname.BorDevnetChainName, faucetSource), }, Nodes: []devnet.Node{ - args.BlockProducer{ + &args.BlockProducer{ Node: args.Node{ ConsoleVerbosity: "0", DirVerbosity: "5", @@ -353,7 +353,7 @@ func initDevnet(ctx *cli.Context, logger log.Logger) (devnet.Devnet, error) { }, AccountSlots: 200, }, - args.NonBlockProducer{ + &args.NonBlockProducer{ Node: args.Node{ ConsoleVerbosity: "0", DirVerbosity: "5", @@ -404,7 +404,7 @@ func initDevnet(ctx *cli.Context, logger log.Logger) (devnet.Devnet, error) { faucetSource.Address: {Balance: accounts.EtherAmount(200_000)}, }, Nodes: []devnet.Node{ - args.BlockProducer{ + &args.BlockProducer{ Node: args.Node{ ConsoleVerbosity: "0", DirVerbosity: "5", @@ -412,7 +412,7 @@ func initDevnet(ctx *cli.Context, logger log.Logger) (devnet.Devnet, error) { }, AccountSlots: 200, }, - args.BlockProducer{ + &args.BlockProducer{ Node: args.Node{ ConsoleVerbosity: "0", DirVerbosity: "5", @@ -420,7 +420,7 @@ func initDevnet(ctx *cli.Context, logger log.Logger) (devnet.Devnet, error) { }, AccountSlots: 200, }, - /*args.BlockProducer{ + /*&args.BlockProducer{ Node: args.Node{ ConsoleVerbosity: "0", DirVerbosity: "5", @@ -428,7 +428,7 @@ func initDevnet(ctx *cli.Context, logger log.Logger) (devnet.Devnet, error) { }, AccountSlots: 200, },*/ - args.NonBlockProducer{ + &args.NonBlockProducer{ Node: args.Node{ ConsoleVerbosity: "0", DirVerbosity: "5", @@ -451,7 +451,7 @@ func initDevnet(ctx *cli.Context, logger log.Logger) (devnet.Devnet, error) { checkpointOwner.Address: {Balance: accounts.EtherAmount(10_000)}, }, Nodes: []devnet.Node{ - args.BlockProducer{ + &args.BlockProducer{ Node: args.Node{ ConsoleVerbosity: "0", DirVerbosity: "5", @@ -461,7 +461,7 @@ func initDevnet(ctx *cli.Context, logger log.Logger) (devnet.Devnet, error) { DevPeriod: 5, AccountSlots: 200, }, - args.NonBlockProducer{ + &args.NonBlockProducer{ Node: args.Node{ ConsoleVerbosity: "0", DirVerbosity: "3", @@ -487,14 +487,14 @@ func initDevnet(ctx *cli.Context, logger log.Logger) (devnet.Devnet, error) { account_services.NewFaucet(networkname.DevChainName, faucetSource), }, Nodes: []devnet.Node{ - args.BlockProducer{ + &args.BlockProducer{ Node: args.Node{ ConsoleVerbosity: "0", DirVerbosity: "5", }, AccountSlots: 200, }, - args.NonBlockProducer{ + &args.NonBlockProducer{ Node: args.Node{ ConsoleVerbosity: "0", DirVerbosity: "5", diff --git a/p2p/server.go b/p2p/server.go index c4d15a2060d..bba6dae4fc6 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -26,6 +26,7 @@ import ( "fmt" "net" "sort" + "strconv" "sync" "sync/atomic" "time" @@ -173,6 +174,18 @@ type Config struct { MetricsEnabled bool } +func (config *Config) ListenPort() int { + _, portStr, err := net.SplitHostPort(config.ListenAddr) + if err != nil { + return 0 + } + port, err := strconv.Atoi(portStr) + if err != nil { + return 0 + } + return port +} + // Server manages all peer connections. type Server struct { // Config fields may not be modified while the server is running.