cmd/devp2p: add devp2p debug tool (#19657)
* p2p/discover: export Ping and RequestENR These two are useful for checking the status of a node. * cmd/devp2p: add devp2p debug tool This is a new tool for debugging p2p issues. It supports a few basic tasks for now, but many more things can and will be added in the near future. devp2p enrdump -- prints ENRs readably devp2p discv4 ping -- checks if a node is up devp2p discv4 requestenr -- gets a node's record devp2p discv4 resolve -- finds a node through the DHT
This commit is contained in:
		
							parent
							
								
									1b15c6da33
								
							
						
					
					
						commit
						896322bf88
					
				
							
								
								
									
										166
									
								
								cmd/devp2p/discv4cmd.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								cmd/devp2p/discv4cmd.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | |||||||
|  | // Copyright 2019 The go-ethereum Authors
 | ||||||
|  | // This file is part of go-ethereum.
 | ||||||
|  | //
 | ||||||
|  | // go-ethereum is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | //
 | ||||||
|  | // go-ethereum is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||||
|  | // GNU General Public License for more details.
 | ||||||
|  | //
 | ||||||
|  | // You should have received a copy of the GNU General Public License
 | ||||||
|  | // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"net" | ||||||
|  | 	"sort" | ||||||
|  | 	"strings" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"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/params" | ||||||
|  | 	"gopkg.in/urfave/cli.v1" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	discv4Command = cli.Command{ | ||||||
|  | 		Name:  "discv4", | ||||||
|  | 		Usage: "Node Discovery v4 tools", | ||||||
|  | 		Subcommands: []cli.Command{ | ||||||
|  | 			discv4PingCommand, | ||||||
|  | 			discv4RequestRecordCommand, | ||||||
|  | 			discv4ResolveCommand, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	discv4PingCommand = cli.Command{ | ||||||
|  | 		Name:   "ping", | ||||||
|  | 		Usage:  "Sends ping to a node", | ||||||
|  | 		Action: discv4Ping, | ||||||
|  | 	} | ||||||
|  | 	discv4RequestRecordCommand = cli.Command{ | ||||||
|  | 		Name:   "requestenr", | ||||||
|  | 		Usage:  "Requests a node record using EIP-868 enrRequest", | ||||||
|  | 		Action: discv4RequestRecord, | ||||||
|  | 	} | ||||||
|  | 	discv4ResolveCommand = cli.Command{ | ||||||
|  | 		Name:   "resolve", | ||||||
|  | 		Usage:  "Finds a node in the DHT", | ||||||
|  | 		Action: discv4Resolve, | ||||||
|  | 		Flags:  []cli.Flag{bootnodesFlag}, | ||||||
|  | 	} | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var bootnodesFlag = cli.StringFlag{ | ||||||
|  | 	Name:  "bootnodes", | ||||||
|  | 	Usage: "Comma separated nodes used for bootstrapping", | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func discv4Ping(ctx *cli.Context) error { | ||||||
|  | 	n, disc, err := getNodeArgAndStartV4(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer disc.Close() | ||||||
|  | 
 | ||||||
|  | 	start := time.Now() | ||||||
|  | 	if err := disc.Ping(n); err != nil { | ||||||
|  | 		return fmt.Errorf("node didn't respond: %v", err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Printf("node responded to ping (RTT %v).\n", time.Since(start)) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func discv4RequestRecord(ctx *cli.Context) error { | ||||||
|  | 	n, disc, err := getNodeArgAndStartV4(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer disc.Close() | ||||||
|  | 
 | ||||||
|  | 	respN, err := disc.RequestENR(n) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("can't retrieve record: %v", err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Println(respN.String()) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func discv4Resolve(ctx *cli.Context) error { | ||||||
|  | 	n, disc, err := getNodeArgAndStartV4(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer disc.Close() | ||||||
|  | 
 | ||||||
|  | 	fmt.Println(disc.Resolve(n).String()) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func getNodeArgAndStartV4(ctx *cli.Context) (*enode.Node, *discover.UDPv4, error) { | ||||||
|  | 	if ctx.NArg() != 1 { | ||||||
|  | 		return nil, nil, fmt.Errorf("missing node as command-line argument") | ||||||
|  | 	} | ||||||
|  | 	n, err := parseNode(ctx.Args()[0]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  | 	var bootnodes []*enode.Node | ||||||
|  | 	if commandHasFlag(ctx, bootnodesFlag) { | ||||||
|  | 		bootnodes, err = parseBootnodes(ctx) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	disc, err := startV4(bootnodes) | ||||||
|  | 	return n, disc, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func parseBootnodes(ctx *cli.Context) ([]*enode.Node, error) { | ||||||
|  | 	s := params.RinkebyBootnodes | ||||||
|  | 	if ctx.IsSet(bootnodesFlag.Name) { | ||||||
|  | 		s = strings.Split(ctx.String(bootnodesFlag.Name), ",") | ||||||
|  | 	} | ||||||
|  | 	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 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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(bootnodes []*enode.Node) (*discover.UDPv4, error) { | ||||||
|  | 	var cfg discover.Config | ||||||
|  | 	cfg.Bootnodes = bootnodes | ||||||
|  | 	cfg.PrivateKey, _ = crypto.GenerateKey() | ||||||
|  | 	db, _ := enode.OpenDB("") | ||||||
|  | 	ln := enode.NewLocalNode(db, cfg.PrivateKey) | ||||||
|  | 
 | ||||||
|  | 	socket, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IP{0, 0, 0, 0}}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	addr := socket.LocalAddr().(*net.UDPAddr) | ||||||
|  | 	ln.SetFallbackIP(net.IP{127, 0, 0, 1}) | ||||||
|  | 	ln.SetFallbackUDP(addr.Port) | ||||||
|  | 	return discover.ListenUDP(socket, ln, cfg) | ||||||
|  | } | ||||||
							
								
								
									
										198
									
								
								cmd/devp2p/enrcmd.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								cmd/devp2p/enrcmd.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,198 @@ | |||||||
|  | // Copyright 2019 The go-ethereum Authors
 | ||||||
|  | // This file is part of go-ethereum.
 | ||||||
|  | //
 | ||||||
|  | // go-ethereum is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | //
 | ||||||
|  | // go-ethereum is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||||
|  | // GNU General Public License for more details.
 | ||||||
|  | //
 | ||||||
|  | // You should have received a copy of the GNU General Public License
 | ||||||
|  | // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/base64" | ||||||
|  | 	"encoding/hex" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"net" | ||||||
|  | 	"os" | ||||||
|  | 	"strconv" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"github.com/ethereum/go-ethereum/p2p/enode" | ||||||
|  | 	"github.com/ethereum/go-ethereum/p2p/enr" | ||||||
|  | 	"github.com/ethereum/go-ethereum/rlp" | ||||||
|  | 	"gopkg.in/urfave/cli.v1" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var enrdumpCommand = cli.Command{ | ||||||
|  | 	Name:   "enrdump", | ||||||
|  | 	Usage:  "Pretty-prints node records", | ||||||
|  | 	Action: enrdump, | ||||||
|  | 	Flags: []cli.Flag{ | ||||||
|  | 		cli.StringFlag{Name: "file"}, | ||||||
|  | 	}, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func enrdump(ctx *cli.Context) error { | ||||||
|  | 	var source string | ||||||
|  | 	if file := ctx.String("file"); file != "" { | ||||||
|  | 		if ctx.NArg() != 0 { | ||||||
|  | 			return fmt.Errorf("can't dump record from command-line argument in -file mode") | ||||||
|  | 		} | ||||||
|  | 		var b []byte | ||||||
|  | 		var err error | ||||||
|  | 		if file == "-" { | ||||||
|  | 			b, err = ioutil.ReadAll(os.Stdin) | ||||||
|  | 		} else { | ||||||
|  | 			b, err = ioutil.ReadFile(file) | ||||||
|  | 		} | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		source = string(b) | ||||||
|  | 	} else if ctx.NArg() == 1 { | ||||||
|  | 		source = ctx.Args()[0] | ||||||
|  | 	} else { | ||||||
|  | 		return fmt.Errorf("need record as argument") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	r, err := parseRecord(source) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("INVALID: %v", err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Print(dumpRecord(r)) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // dumpRecord creates a human-readable description of the given node record.
 | ||||||
|  | func dumpRecord(r *enr.Record) string { | ||||||
|  | 	out := new(bytes.Buffer) | ||||||
|  | 	if n, err := enode.New(enode.ValidSchemes, r); err != nil { | ||||||
|  | 		fmt.Fprintf(out, "INVALID: %v\n", err) | ||||||
|  | 	} else { | ||||||
|  | 		fmt.Fprintf(out, "Node ID: %v\n", n.ID()) | ||||||
|  | 	} | ||||||
|  | 	kv := r.AppendElements(nil)[1:] | ||||||
|  | 	fmt.Fprintf(out, "Record has sequence number %d and %d key/value pairs.\n", r.Seq(), len(kv)/2) | ||||||
|  | 	fmt.Fprint(out, dumpRecordKV(kv, 2)) | ||||||
|  | 	return out.String() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func dumpRecordKV(kv []interface{}, indent int) string { | ||||||
|  | 	// Determine the longest key name for alignment.
 | ||||||
|  | 	var out string | ||||||
|  | 	var longestKey = 0 | ||||||
|  | 	for i := 0; i < len(kv); i += 2 { | ||||||
|  | 		key := kv[i].(string) | ||||||
|  | 		if len(key) > longestKey { | ||||||
|  | 			longestKey = len(key) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// Print the keys, invoking formatters for known keys.
 | ||||||
|  | 	for i := 0; i < len(kv); i += 2 { | ||||||
|  | 		key := kv[i].(string) | ||||||
|  | 		val := kv[i+1].(rlp.RawValue) | ||||||
|  | 		pad := longestKey - len(key) | ||||||
|  | 		out += strings.Repeat(" ", indent) + strconv.Quote(key) + strings.Repeat(" ", pad+1) | ||||||
|  | 		formatter := attrFormatters[key] | ||||||
|  | 		if formatter == nil { | ||||||
|  | 			formatter = formatAttrRaw | ||||||
|  | 		} | ||||||
|  | 		fmtval, ok := formatter(val) | ||||||
|  | 		if ok { | ||||||
|  | 			out += fmtval + "\n" | ||||||
|  | 		} else { | ||||||
|  | 			out += hex.EncodeToString(val) + " (!)\n" | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // attrFormatters contains formatting functions for well-known ENR keys.
 | ||||||
|  | var attrFormatters = map[string]func(rlp.RawValue) (string, bool){ | ||||||
|  | 	"id":   formatAttrString, | ||||||
|  | 	"ip":   formatAttrIP, | ||||||
|  | 	"ip6":  formatAttrIP, | ||||||
|  | 	"tcp":  formatAttrUint, | ||||||
|  | 	"tcp6": formatAttrUint, | ||||||
|  | 	"udp":  formatAttrUint, | ||||||
|  | 	"udp6": formatAttrUint, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func formatAttrRaw(v rlp.RawValue) (string, bool) { | ||||||
|  | 	s := hex.EncodeToString(v) | ||||||
|  | 	return s, true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func formatAttrString(v rlp.RawValue) (string, bool) { | ||||||
|  | 	content, _, err := rlp.SplitString(v) | ||||||
|  | 	return strconv.Quote(string(content)), err == nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func formatAttrIP(v rlp.RawValue) (string, bool) { | ||||||
|  | 	content, _, err := rlp.SplitString(v) | ||||||
|  | 	if err != nil || len(content) != 4 && len(content) != 6 { | ||||||
|  | 		return "", false | ||||||
|  | 	} | ||||||
|  | 	return net.IP(content).String(), true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func formatAttrUint(v rlp.RawValue) (string, bool) { | ||||||
|  | 	var x uint64 | ||||||
|  | 	if err := rlp.DecodeBytes(v, &x); err != nil { | ||||||
|  | 		return "", false | ||||||
|  | 	} | ||||||
|  | 	return strconv.FormatUint(x, 10), true | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								cmd/devp2p/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								cmd/devp2p/main.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | |||||||
|  | // Copyright 2019 The go-ethereum Authors
 | ||||||
|  | // This file is part of go-ethereum.
 | ||||||
|  | //
 | ||||||
|  | // go-ethereum is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | //
 | ||||||
|  | // go-ethereum is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||||
|  | // GNU General Public License for more details.
 | ||||||
|  | //
 | ||||||
|  | // You should have received a copy of the GNU General Public License
 | ||||||
|  | // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | 
 | ||||||
|  | 	"github.com/ethereum/go-ethereum/internal/debug" | ||||||
|  | 	"github.com/ethereum/go-ethereum/params" | ||||||
|  | 	"gopkg.in/urfave/cli.v1" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// Git information set by linker when building with ci.go.
 | ||||||
|  | 	gitCommit string | ||||||
|  | 	gitDate   string | ||||||
|  | 	app       = &cli.App{ | ||||||
|  | 		Name:        filepath.Base(os.Args[0]), | ||||||
|  | 		Usage:       "go-ethereum devp2p tool", | ||||||
|  | 		Version:     params.VersionWithCommit(gitCommit, gitDate), | ||||||
|  | 		Writer:      os.Stdout, | ||||||
|  | 		HideVersion: true, | ||||||
|  | 	} | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func init() { | ||||||
|  | 	// Set up the CLI app.
 | ||||||
|  | 	app.Flags = append(app.Flags, debug.Flags...) | ||||||
|  | 	app.Before = func(ctx *cli.Context) error { | ||||||
|  | 		return debug.Setup(ctx, "") | ||||||
|  | 	} | ||||||
|  | 	app.After = func(ctx *cli.Context) error { | ||||||
|  | 		debug.Exit() | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	app.CommandNotFound = func(ctx *cli.Context, cmd string) { | ||||||
|  | 		fmt.Fprintf(os.Stderr, "No such command: %s\n", cmd) | ||||||
|  | 		os.Exit(1) | ||||||
|  | 	} | ||||||
|  | 	// Add subcommands.
 | ||||||
|  | 	app.Commands = []cli.Command{ | ||||||
|  | 		enrdumpCommand, | ||||||
|  | 		discv4Command, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func main() { | ||||||
|  | 	if err := app.Run(os.Args); err != nil { | ||||||
|  | 		fmt.Fprintln(os.Stderr, err) | ||||||
|  | 		os.Exit(1) | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -85,10 +85,10 @@ type Table struct { | |||||||
| // transport is implemented by the UDP transports.
 | // transport is implemented by the UDP transports.
 | ||||||
| type transport interface { | type transport interface { | ||||||
| 	Self() *enode.Node | 	Self() *enode.Node | ||||||
|  | 	RequestENR(*enode.Node) (*enode.Node, error) | ||||||
| 	lookupRandom() []*enode.Node | 	lookupRandom() []*enode.Node | ||||||
| 	lookupSelf() []*enode.Node | 	lookupSelf() []*enode.Node | ||||||
| 	ping(*enode.Node) (seq uint64, err error) | 	ping(*enode.Node) (seq uint64, err error) | ||||||
| 	requestENR(*enode.Node) (*enode.Node, error) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // bucket contains nodes, ordered by their last activity. the entry
 | // bucket contains nodes, ordered by their last activity. the entry
 | ||||||
| @ -344,7 +344,7 @@ func (tab *Table) doRevalidate(done chan<- struct{}) { | |||||||
| 
 | 
 | ||||||
| 	// Also fetch record if the node replied and returned a higher sequence number.
 | 	// Also fetch record if the node replied and returned a higher sequence number.
 | ||||||
| 	if last.Seq() < remoteSeq { | 	if last.Seq() < remoteSeq { | ||||||
| 		n, err := tab.net.requestENR(unwrapNode(last)) | 		n, err := tab.net.RequestENR(unwrapNode(last)) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			tab.log.Debug("ENR request failed", "id", last.ID(), "addr", last.addr(), "err", err) | 			tab.log.Debug("ENR request failed", "id", last.ID(), "addr", last.addr(), "err", err) | ||||||
| 		} else { | 		} else { | ||||||
|  | |||||||
| @ -145,7 +145,7 @@ func (t *pingRecorder) ping(n *enode.Node) (seq uint64, err error) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // requestENR simulates an ENR request.
 | // requestENR simulates an ENR request.
 | ||||||
| func (t *pingRecorder) requestENR(n *enode.Node) (*enode.Node, error) { | func (t *pingRecorder) RequestENR(n *enode.Node) (*enode.Node, error) { | ||||||
| 	t.mu.Lock() | 	t.mu.Lock() | ||||||
| 	defer t.mu.Unlock() | 	defer t.mu.Unlock() | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -415,13 +415,13 @@ func (t *UDPv4) lookupWorker(n *node, targetKey encPubkey, reply chan<- []*node) | |||||||
| // version of the node record for it. It returns n if the node could not be resolved.
 | // version of the node record for it. It returns n if the node could not be resolved.
 | ||||||
| func (t *UDPv4) Resolve(n *enode.Node) *enode.Node { | func (t *UDPv4) Resolve(n *enode.Node) *enode.Node { | ||||||
| 	// Try asking directly. This works if the node is still responding on the endpoint we have.
 | 	// Try asking directly. This works if the node is still responding on the endpoint we have.
 | ||||||
| 	if rn, err := t.requestENR(n); err == nil { | 	if rn, err := t.RequestENR(n); err == nil { | ||||||
| 		return rn | 		return rn | ||||||
| 	} | 	} | ||||||
| 	// Check table for the ID, we might have a newer version there.
 | 	// Check table for the ID, we might have a newer version there.
 | ||||||
| 	if intable := t.tab.getNode(n.ID()); intable != nil && intable.Seq() > n.Seq() { | 	if intable := t.tab.getNode(n.ID()); intable != nil && intable.Seq() > n.Seq() { | ||||||
| 		n = intable | 		n = intable | ||||||
| 		if rn, err := t.requestENR(n); err == nil { | 		if rn, err := t.RequestENR(n); err == nil { | ||||||
| 			return rn | 			return rn | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -433,7 +433,7 @@ func (t *UDPv4) Resolve(n *enode.Node) *enode.Node { | |||||||
| 	result := t.LookupPubkey((*ecdsa.PublicKey)(&key)) | 	result := t.LookupPubkey((*ecdsa.PublicKey)(&key)) | ||||||
| 	for _, rn := range result { | 	for _, rn := range result { | ||||||
| 		if rn.ID() == n.ID() { | 		if rn.ID() == n.ID() { | ||||||
| 			if rn, err := t.requestENR(rn); err == nil { | 			if rn, err := t.RequestENR(rn); err == nil { | ||||||
| 				return rn | 				return rn | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -447,6 +447,12 @@ func (t *UDPv4) ourEndpoint() rpcEndpoint { | |||||||
| 	return makeEndpoint(a, uint16(n.TCP())) | 	return makeEndpoint(a, uint16(n.TCP())) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Ping sends a ping message to the given node.
 | ||||||
|  | func (t *UDPv4) Ping(n *enode.Node) error { | ||||||
|  | 	_, err := t.ping(n) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // ping sends a ping message to the given node and waits for a reply.
 | // ping sends a ping message to the given node and waits for a reply.
 | ||||||
| func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) { | func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) { | ||||||
| 	rm := t.sendPing(n.ID(), &net.UDPAddr{IP: n.IP(), Port: n.UDP()}, nil) | 	rm := t.sendPing(n.ID(), &net.UDPAddr{IP: n.IP(), Port: n.UDP()}, nil) | ||||||
| @ -521,8 +527,8 @@ func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target encPubkey) ( | |||||||
| 	return nodes, <-rm.errc | 	return nodes, <-rm.errc | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // requestENR sends enrRequest to the given node and waits for a response.
 | // RequestENR sends enrRequest to the given node and waits for a response.
 | ||||||
| func (t *UDPv4) requestENR(n *enode.Node) (*enode.Node, error) { | func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { | ||||||
| 	addr := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} | 	addr := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} | ||||||
| 	t.ensureBond(n.ID(), addr) | 	t.ensureBond(n.ID(), addr) | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user