github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/cmd/devp2p/keycmd.go (about)

     1  // Copyright 2020 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"fmt"
    21  	"net"
    22  
    23  	"github.com/tirogen/go-ethereum/crypto"
    24  	"github.com/tirogen/go-ethereum/p2p/enode"
    25  	"github.com/tirogen/go-ethereum/p2p/enr"
    26  	"github.com/urfave/cli/v2"
    27  )
    28  
    29  var (
    30  	keyCommand = &cli.Command{
    31  		Name:  "key",
    32  		Usage: "Operations on node keys",
    33  		Subcommands: []*cli.Command{
    34  			keyGenerateCommand,
    35  			keyToIDCommand,
    36  			keyToNodeCommand,
    37  			keyToRecordCommand,
    38  		},
    39  	}
    40  	keyGenerateCommand = &cli.Command{
    41  		Name:      "generate",
    42  		Usage:     "Generates node key files",
    43  		ArgsUsage: "keyfile",
    44  		Action:    genkey,
    45  	}
    46  	keyToIDCommand = &cli.Command{
    47  		Name:      "to-id",
    48  		Usage:     "Creates a node ID from a node key file",
    49  		ArgsUsage: "keyfile",
    50  		Action:    keyToID,
    51  		Flags:     []cli.Flag{},
    52  	}
    53  	keyToNodeCommand = &cli.Command{
    54  		Name:      "to-enode",
    55  		Usage:     "Creates an enode URL from a node key file",
    56  		ArgsUsage: "keyfile",
    57  		Action:    keyToURL,
    58  		Flags:     []cli.Flag{hostFlag, tcpPortFlag, udpPortFlag},
    59  	}
    60  	keyToRecordCommand = &cli.Command{
    61  		Name:      "to-enr",
    62  		Usage:     "Creates an ENR from a node key file",
    63  		ArgsUsage: "keyfile",
    64  		Action:    keyToRecord,
    65  		Flags:     []cli.Flag{hostFlag, tcpPortFlag, udpPortFlag},
    66  	}
    67  )
    68  
    69  var (
    70  	hostFlag = &cli.StringFlag{
    71  		Name:  "ip",
    72  		Usage: "IP address of the node",
    73  		Value: "127.0.0.1",
    74  	}
    75  	tcpPortFlag = &cli.IntFlag{
    76  		Name:  "tcp",
    77  		Usage: "TCP port of the node",
    78  		Value: 30303,
    79  	}
    80  	udpPortFlag = &cli.IntFlag{
    81  		Name:  "udp",
    82  		Usage: "UDP port of the node",
    83  		Value: 30303,
    84  	}
    85  )
    86  
    87  func genkey(ctx *cli.Context) error {
    88  	if ctx.NArg() != 1 {
    89  		return fmt.Errorf("need key file as argument")
    90  	}
    91  	file := ctx.Args().Get(0)
    92  
    93  	key, err := crypto.GenerateKey()
    94  	if err != nil {
    95  		return fmt.Errorf("could not generate key: %v", err)
    96  	}
    97  	return crypto.SaveECDSA(file, key)
    98  }
    99  
   100  func keyToID(ctx *cli.Context) error {
   101  	n, err := makeRecord(ctx)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	fmt.Println(n.ID())
   106  	return nil
   107  }
   108  
   109  func keyToURL(ctx *cli.Context) error {
   110  	n, err := makeRecord(ctx)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	fmt.Println(n.URLv4())
   115  	return nil
   116  }
   117  
   118  func keyToRecord(ctx *cli.Context) error {
   119  	n, err := makeRecord(ctx)
   120  	if err != nil {
   121  		return err
   122  	}
   123  	fmt.Println(n.String())
   124  	return nil
   125  }
   126  
   127  func makeRecord(ctx *cli.Context) (*enode.Node, error) {
   128  	if ctx.NArg() != 1 {
   129  		return nil, fmt.Errorf("need key file as argument")
   130  	}
   131  
   132  	var (
   133  		file = ctx.Args().Get(0)
   134  		host = ctx.String(hostFlag.Name)
   135  		tcp  = ctx.Int(tcpPortFlag.Name)
   136  		udp  = ctx.Int(udpPortFlag.Name)
   137  	)
   138  	key, err := crypto.LoadECDSA(file)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	var r enr.Record
   144  	if host != "" {
   145  		ip := net.ParseIP(host)
   146  		if ip == nil {
   147  			return nil, fmt.Errorf("invalid IP address %q", host)
   148  		}
   149  		r.Set(enr.IP(ip))
   150  	}
   151  	if udp != 0 {
   152  		r.Set(enr.UDP(udp))
   153  	}
   154  	if tcp != 0 {
   155  		r.Set(enr.TCP(tcp))
   156  	}
   157  
   158  	if err := enode.SignV4(&r, key); err != nil {
   159  		return nil, err
   160  	}
   161  	return enode.New(enode.ValidSchemes, &r)
   162  }