瀏覽代碼

拿到了v4

skyfffire 2 年之前
父節點
當前提交
d688758c9e
共有 2 個文件被更改,包括 181 次插入14 次删除
  1. 178 4
      cmd/p2p/main.go
  2. 3 10
      cmd/p2p/one.go

+ 178 - 4
cmd/p2p/main.go

@@ -1,10 +1,22 @@
 package main
 
 import (
-	"fmt"
-	"gopkg.in/urfave/cli.v1"
-	"os"
-	"path/filepath"
+    "bytes"
+    "encoding/base64"
+    "encoding/hex"
+    "fmt"
+    "github.com/ethereum/go-ethereum/crypto"
+    "github.com/ethereum/go-ethereum/p2p/discover"
+    "github.com/ethereum/go-ethereum/p2p/enode"
+    "github.com/ethereum/go-ethereum/p2p/enr"
+    "github.com/ethereum/go-ethereum/params"
+    "github.com/ethereum/go-ethereum/rlp"
+    "gopkg.in/urfave/cli.v1"
+    "net"
+    "os"
+    "path/filepath"
+    "sort"
+    "strings"
 )
 
 var app = &cli.App{
@@ -13,6 +25,25 @@ var app = &cli.App{
 	Writer: os.Stdout,
 }
 
+var (
+    bootnodesFlag = cli.StringFlag{
+        Name:  "bootnodes",
+        Usage: "Comma separated nodes used for bootstrapping",
+    }
+    nodekeyFlag = cli.StringFlag{
+        Name:  "nodekey",
+        Usage: "Hex-encoded node key",
+    }
+    nodedbFlag = cli.StringFlag{
+        Name:  "nodedb",
+        Usage: "Nodes database location",
+    }
+    listenAddrFlag = cli.StringFlag{
+        Name:  "addr",
+        Usage: "Listening address",
+    }
+)
+
 func main() {
 	app.CommandNotFound = func(ctx *cli.Context, cmd string) {
 		fmt.Fprintf(os.Stderr, "No such command: %s\n", cmd)
@@ -33,3 +64,146 @@ func exit(err interface{}) {
 	fmt.Fprintln(os.Stderr, err)
 	os.Exit(1)
 }
+
+// commandHasFlag returns true if the current command supports the given flag.
+func commandHasFlag(ctx *cli.Context, flag cli.Flag) bool {
+    flags := ctx.FlagNames()
+    sort.Strings(flags)
+    i := sort.SearchStrings(flags, flag.GetName())
+    return i != len(flags) && flags[i] == flag.GetName()
+}
+
+// startV4 starts an ephemeral discovery V4 node.
+func startV4(ctx *cli.Context) *discover.UDPv4 {
+    ln, config := makeDiscoveryConfig(ctx)
+    socket := listen(ln, ctx.String(listenAddrFlag.Name))
+    disc, err := discover.ListenV4(socket, ln, config)
+    if err != nil {
+        exit(err)
+    }
+    return disc
+}
+
+func makeDiscoveryConfig(ctx *cli.Context) (*enode.LocalNode, discover.Config) {
+    var cfg discover.Config
+
+    if ctx.IsSet(nodekeyFlag.Name) {
+        key, err := crypto.HexToECDSA(ctx.String(nodekeyFlag.Name))
+        if err != nil {
+            exit(fmt.Errorf("-%s: %v", nodekeyFlag.Name, err))
+        }
+        cfg.PrivateKey = key
+    } else {
+        cfg.PrivateKey, _ = crypto.GenerateKey()
+    }
+
+    if commandHasFlag(ctx, bootnodesFlag) {
+        bn, err := parseBootnodes(ctx)
+        if err != nil {
+            exit(err)
+        }
+        cfg.Bootnodes = bn
+    }
+
+    dbpath := ctx.String(nodedbFlag.Name)
+    db, err := enode.OpenDB(dbpath)
+    if err != nil {
+        exit(err)
+    }
+    ln := enode.NewLocalNode(db, cfg.PrivateKey)
+    return ln, cfg
+}
+
+func listen(ln *enode.LocalNode, addr string) *net.UDPConn {
+    if addr == "" {
+        addr = "0.0.0.0:0"
+    }
+    socket, err := net.ListenPacket("udp4", addr)
+    if err != nil {
+        exit(err)
+    }
+    usocket := socket.(*net.UDPConn)
+    uaddr := socket.LocalAddr().(*net.UDPAddr)
+    if uaddr.IP.IsUnspecified() {
+        ln.SetFallbackIP(net.IP{127, 0, 0, 1})
+    } else {
+        ln.SetFallbackIP(uaddr.IP)
+    }
+    ln.SetFallbackUDP(uaddr.Port)
+    return usocket
+}
+
+func parseBootnodes(ctx *cli.Context) ([]*enode.Node, error) {
+    s := params.RinkebyBootnodes
+    if ctx.IsSet(bootnodesFlag.Name) {
+        input := ctx.String(bootnodesFlag.Name)
+        if input == "" {
+            return nil, nil
+        }
+        s = strings.Split(input, ",")
+    }
+    nodes := make([]*enode.Node, len(s))
+    var err error
+    for i, record := range s {
+        nodes[i], err = parseNode(record)
+        if err != nil {
+            return nil, fmt.Errorf("invalid bootstrap node: %v", err)
+        }
+    }
+    return nodes, nil
+}
+
+// parseNode parses a node record and verifies its signature.
+func parseNode(source string) (*enode.Node, error) {
+    if strings.HasPrefix(source, "enode://") {
+        return enode.ParseV4(source)
+    }
+    r, err := parseRecord(source)
+    if err != nil {
+        return nil, err
+    }
+    return enode.New(enode.ValidSchemes, r)
+}
+
+// parseRecord parses a node record from hex, base64, or raw binary input.
+func parseRecord(source string) (*enr.Record, error) {
+    bin := []byte(source)
+    if d, ok := decodeRecordHex(bytes.TrimSpace(bin)); ok {
+        bin = d
+    } else if d, ok := decodeRecordBase64(bytes.TrimSpace(bin)); ok {
+        bin = d
+    }
+    var r enr.Record
+    err := rlp.DecodeBytes(bin, &r)
+    return &r, err
+}
+
+func decodeRecordHex(b []byte) ([]byte, bool) {
+    if bytes.HasPrefix(b, []byte("0x")) {
+        b = b[2:]
+    }
+    dec := make([]byte, hex.DecodedLen(len(b)))
+    _, err := hex.Decode(dec, b)
+    return dec, err == nil
+}
+
+func decodeRecordBase64(b []byte) ([]byte, bool) {
+    if bytes.HasPrefix(b, []byte("enr:")) {
+        b = b[4:]
+    }
+    dec := make([]byte, base64.RawURLEncoding.DecodedLen(len(b)))
+    n, err := base64.RawURLEncoding.Decode(dec, b)
+    return dec[:n], err == nil
+}
+
+// getNodeArg handles the common case of a single node descriptor argument.
+func getNodeArg(ctx *cli.Context) *enode.Node {
+    if ctx.NArg() < 1 {
+        exit("missing node as command-line argument")
+    }
+    n, err := parseNode(ctx.Args()[0])
+    if err != nil {
+        exit(err)
+    }
+    return n
+}

+ 3 - 10
cmd/p2p/one.go

@@ -15,14 +15,7 @@ var onePeerCommand = cli.Command{
 
 func one(ctx *cli.Context) {
 	node := getNodeArg(ctx)
-
-	fmt.Fprintf(os.Stdout, "Hello one peer kit, node is %v.\n", node)
-}
-
-func getNodeArg(ctx *cli.Context) string {
-	if ctx.NArg() < 1 {
-		exit("missing node as command-line argument")
-	}
-
-	return ctx.Args()[0]
+    disc := startV4(ctx)
+    defer disc.Close()
+    fmt.Fprintf(os.Stdout, "Hello one peer kit, node is %v.\n", node)
 }