p2p: port to p2p/enode and discovery changes

This adapts package p2p to the changes in p2p/discover. All uses of
discover.Node and discover.NodeID are replaced by their equivalents from
p2p/enode.

New API is added to retrieve the enode.Node instance of a peer. The
behavior of Server.Self with discovery disabled is improved. It now
tries much harder to report a working IP address, falling back to
127.0.0.1 if no suitable address can be determined through other means.
These changes were needed for tests of other packages later in the
series.
This commit is contained in:
Felix Lange 2018-09-11 16:56:15 +02:00
parent 9bf9211c9b
commit 9cd4879228
10 changed files with 531 additions and 489 deletions

View file

@ -18,14 +18,13 @@ package p2p
import (
"container/heap"
"crypto/rand"
"errors"
"fmt"
"net"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/netutil"
)
@ -50,7 +49,7 @@ const (
// NodeDialer is used to connect to nodes in the network, typically by using
// an underlying net.Dialer but also using net.Pipe in tests
type NodeDialer interface {
Dial(*discover.Node) (net.Conn, error)
Dial(*enode.Node) (net.Conn, error)
}
// TCPDialer implements the NodeDialer interface by using a net.Dialer to
@ -60,8 +59,8 @@ type TCPDialer struct {
}
// Dial creates a TCP connection to the node
func (t TCPDialer) Dial(dest *discover.Node) (net.Conn, error) {
addr := &net.TCPAddr{IP: dest.IP, Port: int(dest.TCP)}
func (t TCPDialer) Dial(dest *enode.Node) (net.Conn, error) {
addr := &net.TCPAddr{IP: dest.IP(), Port: dest.TCP()}
return t.Dialer.Dial("tcp", addr.String())
}
@ -74,22 +73,22 @@ type dialstate struct {
netrestrict *netutil.Netlist
lookupRunning bool
dialing map[discover.NodeID]connFlag
lookupBuf []*discover.Node // current discovery lookup results
randomNodes []*discover.Node // filled from Table
static map[discover.NodeID]*dialTask
dialing map[enode.ID]connFlag
lookupBuf []*enode.Node // current discovery lookup results
randomNodes []*enode.Node // filled from Table
static map[enode.ID]*dialTask
hist *dialHistory
start time.Time // time when the dialer was first used
bootnodes []*discover.Node // default dials when there are no peers
bootnodes []*enode.Node // default dials when there are no peers
}
type discoverTable interface {
Self() *discover.Node
Self() *enode.Node
Close()
Resolve(target discover.NodeID) *discover.Node
Lookup(target discover.NodeID) []*discover.Node
ReadRandomNodes([]*discover.Node) int
Resolve(*enode.Node) *enode.Node
LookupRandom() []*enode.Node
ReadRandomNodes([]*enode.Node) int
}
// the dial history remembers recent dials.
@ -97,7 +96,7 @@ type dialHistory []pastDial
// pastDial is an entry in the dial history.
type pastDial struct {
id discover.NodeID
id enode.ID
exp time.Time
}
@ -109,7 +108,7 @@ type task interface {
// fields cannot be accessed while the task is running.
type dialTask struct {
flags connFlag
dest *discover.Node
dest *enode.Node
lastResolved time.Time
resolveDelay time.Duration
}
@ -118,7 +117,7 @@ type dialTask struct {
// Only one discoverTask is active at any time.
// discoverTask.Do performs a random lookup.
type discoverTask struct {
results []*discover.Node
results []*enode.Node
}
// A waitExpireTask is generated if there are no other tasks
@ -127,15 +126,15 @@ type waitExpireTask struct {
time.Duration
}
func newDialState(static []*discover.Node, bootnodes []*discover.Node, ntab discoverTable, maxdyn int, netrestrict *netutil.Netlist) *dialstate {
func newDialState(static []*enode.Node, bootnodes []*enode.Node, ntab discoverTable, maxdyn int, netrestrict *netutil.Netlist) *dialstate {
s := &dialstate{
maxDynDials: maxdyn,
ntab: ntab,
netrestrict: netrestrict,
static: make(map[discover.NodeID]*dialTask),
dialing: make(map[discover.NodeID]connFlag),
bootnodes: make([]*discover.Node, len(bootnodes)),
randomNodes: make([]*discover.Node, maxdyn/2),
static: make(map[enode.ID]*dialTask),
dialing: make(map[enode.ID]connFlag),
bootnodes: make([]*enode.Node, len(bootnodes)),
randomNodes: make([]*enode.Node, maxdyn/2),
hist: new(dialHistory),
}
copy(s.bootnodes, bootnodes)
@ -145,32 +144,32 @@ func newDialState(static []*discover.Node, bootnodes []*discover.Node, ntab disc
return s
}
func (s *dialstate) addStatic(n *discover.Node) {
func (s *dialstate) addStatic(n *enode.Node) {
// This overwrites the task instead of updating an existing
// entry, giving users the opportunity to force a resolve operation.
s.static[n.ID] = &dialTask{flags: staticDialedConn, dest: n}
s.static[n.ID()] = &dialTask{flags: staticDialedConn, dest: n}
}
func (s *dialstate) removeStatic(n *discover.Node) {
func (s *dialstate) removeStatic(n *enode.Node) {
// This removes a task so future attempts to connect will not be made.
delete(s.static, n.ID)
delete(s.static, n.ID())
// This removes a previous dial timestamp so that application
// can force a server to reconnect with chosen peer immediately.
s.hist.remove(n.ID)
s.hist.remove(n.ID())
}
func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now time.Time) []task {
func (s *dialstate) newTasks(nRunning int, peers map[enode.ID]*Peer, now time.Time) []task {
if s.start.IsZero() {
s.start = now
}
var newtasks []task
addDial := func(flag connFlag, n *discover.Node) bool {
addDial := func(flag connFlag, n *enode.Node) bool {
if err := s.checkDial(n, peers); err != nil {
log.Trace("Skipping dial candidate", "id", n.ID, "addr", &net.TCPAddr{IP: n.IP, Port: int(n.TCP)}, "err", err)
log.Trace("Skipping dial candidate", "id", n.ID(), "addr", &net.TCPAddr{IP: n.IP(), Port: n.TCP()}, "err", err)
return false
}
s.dialing[n.ID] = flag
s.dialing[n.ID()] = flag
newtasks = append(newtasks, &dialTask{flags: flag, dest: n})
return true
}
@ -196,8 +195,8 @@ func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now
err := s.checkDial(t.dest, peers)
switch err {
case errNotWhitelisted, errSelf:
log.Warn("Removing static dial candidate", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)}, "err", err)
delete(s.static, t.dest.ID)
log.Warn("Removing static dial candidate", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP(), Port: t.dest.TCP()}, "err", err)
delete(s.static, t.dest.ID())
case nil:
s.dialing[id] = t.flags
newtasks = append(newtasks, t)
@ -260,18 +259,18 @@ var (
errNotWhitelisted = errors.New("not contained in netrestrict whitelist")
)
func (s *dialstate) checkDial(n *discover.Node, peers map[discover.NodeID]*Peer) error {
_, dialing := s.dialing[n.ID]
func (s *dialstate) checkDial(n *enode.Node, peers map[enode.ID]*Peer) error {
_, dialing := s.dialing[n.ID()]
switch {
case dialing:
return errAlreadyDialing
case peers[n.ID] != nil:
case peers[n.ID()] != nil:
return errAlreadyConnected
case s.ntab != nil && n.ID == s.ntab.Self().ID:
case s.ntab != nil && n.ID() == s.ntab.Self().ID():
return errSelf
case s.netrestrict != nil && !s.netrestrict.Contains(n.IP):
case s.netrestrict != nil && !s.netrestrict.Contains(n.IP()):
return errNotWhitelisted
case s.hist.contains(n.ID):
case s.hist.contains(n.ID()):
return errRecentlyDialed
}
return nil
@ -280,8 +279,8 @@ func (s *dialstate) checkDial(n *discover.Node, peers map[discover.NodeID]*Peer)
func (s *dialstate) taskDone(t task, now time.Time) {
switch t := t.(type) {
case *dialTask:
s.hist.add(t.dest.ID, now.Add(dialHistoryExpiration))
delete(s.dialing, t.dest.ID)
s.hist.add(t.dest.ID(), now.Add(dialHistoryExpiration))
delete(s.dialing, t.dest.ID())
case *discoverTask:
s.lookupRunning = false
s.lookupBuf = append(s.lookupBuf, t.results...)
@ -323,7 +322,7 @@ func (t *dialTask) resolve(srv *Server) bool {
if time.Since(t.lastResolved) < t.resolveDelay {
return false
}
resolved := srv.ntab.Resolve(t.dest.ID)
resolved := srv.ntab.Resolve(t.dest)
t.lastResolved = time.Now()
if resolved == nil {
t.resolveDelay *= 2
@ -336,7 +335,7 @@ func (t *dialTask) resolve(srv *Server) bool {
// The node was found.
t.resolveDelay = initialResolveDelay
t.dest = resolved
log.Debug("Resolved node", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)})
log.Debug("Resolved node", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP(), Port: t.dest.TCP()})
return true
}
@ -345,7 +344,7 @@ type dialError struct {
}
// dial performs the actual connection attempt.
func (t *dialTask) dial(srv *Server, dest *discover.Node) error {
func (t *dialTask) dial(srv *Server, dest *enode.Node) error {
fd, err := srv.Dialer.Dial(dest)
if err != nil {
return &dialError{err}
@ -355,7 +354,8 @@ func (t *dialTask) dial(srv *Server, dest *discover.Node) error {
}
func (t *dialTask) String() string {
return fmt.Sprintf("%v %x %v:%d", t.flags, t.dest.ID[:8], t.dest.IP, t.dest.TCP)
id := t.dest.ID()
return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], t.dest.IP(), t.dest.TCP())
}
func (t *discoverTask) Do(srv *Server) {
@ -367,9 +367,7 @@ func (t *discoverTask) Do(srv *Server) {
time.Sleep(next.Sub(now))
}
srv.lastLookup = time.Now()
var target discover.NodeID
rand.Read(target[:])
t.results = srv.ntab.Lookup(target)
t.results = srv.ntab.LookupRandom()
}
func (t *discoverTask) String() string {
@ -391,11 +389,11 @@ func (t waitExpireTask) String() string {
func (h dialHistory) min() pastDial {
return h[0]
}
func (h *dialHistory) add(id discover.NodeID, exp time.Time) {
func (h *dialHistory) add(id enode.ID, exp time.Time) {
heap.Push(h, pastDial{id, exp})
}
func (h *dialHistory) remove(id discover.NodeID) bool {
func (h *dialHistory) remove(id enode.ID) bool {
for i, v := range *h {
if v.id == id {
heap.Remove(h, i)
@ -404,7 +402,7 @@ func (h *dialHistory) remove(id discover.NodeID) bool {
}
return false
}
func (h dialHistory) contains(id discover.NodeID) bool {
func (h dialHistory) contains(id enode.ID) bool {
for _, v := range h {
if v.id == id {
return true

View file

@ -24,7 +24,8 @@ import (
"time"
"github.com/davecgh/go-spew/spew"
"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/p2p/netutil"
)
@ -48,10 +49,10 @@ func runDialTest(t *testing.T, test dialtest) {
vtime time.Time
running int
)
pm := func(ps []*Peer) map[discover.NodeID]*Peer {
m := make(map[discover.NodeID]*Peer)
pm := func(ps []*Peer) map[enode.ID]*Peer {
m := make(map[enode.ID]*Peer)
for _, p := range ps {
m[p.rw.id] = p
m[p.ID()] = p
}
return m
}
@ -69,6 +70,7 @@ func runDialTest(t *testing.T, test dialtest) {
t.Errorf("round %d: new tasks mismatch:\ngot %v\nwant %v\nstate: %v\nrunning: %v\n",
i, spew.Sdump(new), spew.Sdump(round.new), spew.Sdump(test.init), spew.Sdump(running))
}
t.Log("tasks:", spew.Sdump(new))
// Time advances by 16 seconds on every round.
vtime = vtime.Add(16 * time.Second)
@ -76,13 +78,13 @@ func runDialTest(t *testing.T, test dialtest) {
}
}
type fakeTable []*discover.Node
type fakeTable []*enode.Node
func (t fakeTable) Self() *discover.Node { return new(discover.Node) }
func (t fakeTable) Self() *enode.Node { return new(enode.Node) }
func (t fakeTable) Close() {}
func (t fakeTable) Lookup(discover.NodeID) []*discover.Node { return nil }
func (t fakeTable) Resolve(discover.NodeID) *discover.Node { return nil }
func (t fakeTable) ReadRandomNodes(buf []*discover.Node) int { return copy(buf, t) }
func (t fakeTable) LookupRandom() []*enode.Node { return nil }
func (t fakeTable) Resolve(*enode.Node) *enode.Node { return nil }
func (t fakeTable) ReadRandomNodes(buf []*enode.Node) int { return copy(buf, t) }
// This test checks that dynamic dials are launched from discovery results.
func TestDialStateDynDial(t *testing.T) {
@ -92,63 +94,63 @@ func TestDialStateDynDial(t *testing.T) {
// A discovery query is launched.
{
peers: []*Peer{
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
},
new: []task{&discoverTask{}},
},
// Dynamic dials are launched when it completes.
{
peers: []*Peer{
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
},
done: []task{
&discoverTask{results: []*discover.Node{
{ID: uintID(2)}, // this one is already connected and not dialed.
{ID: uintID(3)},
{ID: uintID(4)},
{ID: uintID(5)},
{ID: uintID(6)}, // these are not tried because max dyn dials is 5
{ID: uintID(7)}, // ...
&discoverTask{results: []*enode.Node{
newNode(uintID(2), nil), // this one is already connected and not dialed.
newNode(uintID(3), nil),
newNode(uintID(4), nil),
newNode(uintID(5), nil),
newNode(uintID(6), nil), // these are not tried because max dyn dials is 5
newNode(uintID(7), nil), // ...
}},
},
new: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
},
},
// Some of the dials complete but no new ones are launched yet because
// the sum of active dial count and dynamic peer count is == maxDynDials.
{
peers: []*Peer{
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(3), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}},
},
done: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
},
},
// No new dial tasks are launched in the this round because
// maxDynDials has been reached.
{
peers: []*Peer{
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(3), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}},
},
done: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
},
new: []task{
&waitExpireTask{Duration: 14 * time.Second},
@ -158,14 +160,14 @@ func TestDialStateDynDial(t *testing.T) {
// results from last discovery lookup are reused.
{
peers: []*Peer{
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(3), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}},
},
new: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(6), nil)},
},
},
// More peers (3,4) drop off and dial for ID 6 completes.
@ -173,15 +175,15 @@ func TestDialStateDynDial(t *testing.T) {
// and a new one is spawned because more candidates are needed.
{
peers: []*Peer{
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}},
},
done: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(6), nil)},
},
new: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(7), nil)},
&discoverTask{},
},
},
@ -190,23 +192,23 @@ func TestDialStateDynDial(t *testing.T) {
// no new is started.
{
peers: []*Peer{
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
{rw: &conn{flags: dynDialedConn, id: uintID(7)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(7), nil)}},
},
done: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(7), nil)},
},
},
// Finish the running node discovery with an empty set. A new lookup
// should be immediately requested.
{
peers: []*Peer{
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
{rw: &conn{flags: dynDialedConn, id: uintID(7)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(7), nil)}},
},
done: []task{
&discoverTask{},
@ -221,17 +223,17 @@ func TestDialStateDynDial(t *testing.T) {
// Tests that bootnodes are dialed if no peers are connectd, but not otherwise.
func TestDialStateDynDialBootnode(t *testing.T) {
bootnodes := []*discover.Node{
{ID: uintID(1)},
{ID: uintID(2)},
{ID: uintID(3)},
bootnodes := []*enode.Node{
newNode(uintID(1), nil),
newNode(uintID(2), nil),
newNode(uintID(3), nil),
}
table := fakeTable{
{ID: uintID(4)},
{ID: uintID(5)},
{ID: uintID(6)},
{ID: uintID(7)},
{ID: uintID(8)},
newNode(uintID(4), nil),
newNode(uintID(5), nil),
newNode(uintID(6), nil),
newNode(uintID(7), nil),
newNode(uintID(8), nil),
}
runDialTest(t, dialtest{
init: newDialState(nil, bootnodes, table, 5, nil),
@ -239,16 +241,16 @@ func TestDialStateDynDialBootnode(t *testing.T) {
// 2 dynamic dials attempted, bootnodes pending fallback interval
{
new: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
&discoverTask{},
},
},
// No dials succeed, bootnodes still pending fallback interval
{
done: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
},
},
// No dials succeed, bootnodes still pending fallback interval
@ -256,51 +258,51 @@ func TestDialStateDynDialBootnode(t *testing.T) {
// No dials succeed, 2 dynamic dials attempted and 1 bootnode too as fallback interval was reached
{
new: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
},
},
// No dials succeed, 2nd bootnode is attempted
{
done: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
},
new: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)},
},
},
// No dials succeed, 3rd bootnode is attempted
{
done: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)},
},
new: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
},
},
// No dials succeed, 1st bootnode is attempted again, expired random nodes retried
{
done: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
},
new: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
},
},
// Random dial succeeds, no more bootnodes are attempted
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}},
},
done: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
},
},
},
@ -311,14 +313,14 @@ func TestDialStateDynDialFromTable(t *testing.T) {
// This table always returns the same random nodes
// in the order given below.
table := fakeTable{
{ID: uintID(1)},
{ID: uintID(2)},
{ID: uintID(3)},
{ID: uintID(4)},
{ID: uintID(5)},
{ID: uintID(6)},
{ID: uintID(7)},
{ID: uintID(8)},
newNode(uintID(1), nil),
newNode(uintID(2), nil),
newNode(uintID(3), nil),
newNode(uintID(4), nil),
newNode(uintID(5), nil),
newNode(uintID(6), nil),
newNode(uintID(7), nil),
newNode(uintID(8), nil),
}
runDialTest(t, dialtest{
@ -327,63 +329,63 @@ func TestDialStateDynDialFromTable(t *testing.T) {
// 5 out of 8 of the nodes returned by ReadRandomNodes are dialed.
{
new: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
&discoverTask{},
},
},
// Dialing nodes 1,2 succeeds. Dials from the lookup are launched.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
},
done: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
&discoverTask{results: []*discover.Node{
{ID: uintID(10)},
{ID: uintID(11)},
{ID: uintID(12)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)},
&discoverTask{results: []*enode.Node{
newNode(uintID(10), nil),
newNode(uintID(11), nil),
newNode(uintID(12), nil),
}},
},
new: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(10), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(11), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(12), nil)},
&discoverTask{},
},
},
// Dialing nodes 3,4,5 fails. The dials from the lookup succeed.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}},
},
done: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(10), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(11), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(12), nil)},
},
},
// Waiting for expiry. No waitExpireTask is launched because the
// discovery query is still running.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}},
},
},
// Nodes 3,4 are not tried again because only the first two
@ -391,30 +393,38 @@ func TestDialStateDynDialFromTable(t *testing.T) {
// already connected.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}},
},
},
},
})
}
func newNode(id enode.ID, ip net.IP) *enode.Node {
var r enr.Record
if ip != nil {
r.Set(enr.IP(ip))
}
return enode.SignNull(&r, id)
}
// This test checks that candidates that do not match the netrestrict list are not dialed.
func TestDialStateNetRestrict(t *testing.T) {
// This table always returns the same random nodes
// in the order given below.
table := fakeTable{
{ID: uintID(1), IP: net.ParseIP("127.0.0.1")},
{ID: uintID(2), IP: net.ParseIP("127.0.0.2")},
{ID: uintID(3), IP: net.ParseIP("127.0.0.3")},
{ID: uintID(4), IP: net.ParseIP("127.0.0.4")},
{ID: uintID(5), IP: net.ParseIP("127.0.2.5")},
{ID: uintID(6), IP: net.ParseIP("127.0.2.6")},
{ID: uintID(7), IP: net.ParseIP("127.0.2.7")},
{ID: uintID(8), IP: net.ParseIP("127.0.2.8")},
newNode(uintID(1), net.ParseIP("127.0.0.1")),
newNode(uintID(2), net.ParseIP("127.0.0.2")),
newNode(uintID(3), net.ParseIP("127.0.0.3")),
newNode(uintID(4), net.ParseIP("127.0.0.4")),
newNode(uintID(5), net.ParseIP("127.0.2.5")),
newNode(uintID(6), net.ParseIP("127.0.2.6")),
newNode(uintID(7), net.ParseIP("127.0.2.7")),
newNode(uintID(8), net.ParseIP("127.0.2.8")),
}
restrict := new(netutil.Netlist)
restrict.Add("127.0.2.0/24")
@ -434,12 +444,12 @@ func TestDialStateNetRestrict(t *testing.T) {
// This test checks that static dials are launched.
func TestDialStateStaticDial(t *testing.T) {
wantStatic := []*discover.Node{
{ID: uintID(1)},
{ID: uintID(2)},
{ID: uintID(3)},
{ID: uintID(4)},
{ID: uintID(5)},
wantStatic := []*enode.Node{
newNode(uintID(1), nil),
newNode(uintID(2), nil),
newNode(uintID(3), nil),
newNode(uintID(4), nil),
newNode(uintID(5), nil),
}
runDialTest(t, dialtest{
@ -449,40 +459,40 @@ func TestDialStateStaticDial(t *testing.T) {
// aren't yet connected.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
},
new: []task{
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(5), nil)},
},
},
// No new tasks are launched in this round because all static
// nodes are either connected or still being dialed.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}},
},
done: []task{
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)},
},
},
// No new dial tasks are launched because all static
// nodes are now connected.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
{rw: &conn{flags: staticDialedConn, id: uintID(4)}},
{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(4), nil)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(5), nil)}},
},
done: []task{
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(5), nil)},
},
new: []task{
&waitExpireTask{Duration: 14 * time.Second},
@ -491,24 +501,24 @@ func TestDialStateStaticDial(t *testing.T) {
// Wait a round for dial history to expire, no new tasks should spawn.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
{rw: &conn{flags: staticDialedConn, id: uintID(4)}},
{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(4), nil)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(5), nil)}},
},
},
// If a static node is dropped, it should be immediately redialed,
// irrespective whether it was originally static or dynamic.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(5), nil)}},
},
new: []task{
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(4), nil)},
},
},
},
@ -517,9 +527,9 @@ func TestDialStateStaticDial(t *testing.T) {
// This test checks that static peers will be redialed immediately if they were re-added to a static list.
func TestDialStaticAfterReset(t *testing.T) {
wantStatic := []*discover.Node{
{ID: uintID(1)},
{ID: uintID(2)},
wantStatic := []*enode.Node{
newNode(uintID(1), nil),
newNode(uintID(2), nil),
}
rounds := []round{
@ -527,19 +537,19 @@ func TestDialStaticAfterReset(t *testing.T) {
{
peers: nil,
new: []task{
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)},
},
},
// No new dial tasks, all peers are connected.
{
peers: []*Peer{
{rw: &conn{flags: staticDialedConn, id: uintID(1)}},
{rw: &conn{flags: staticDialedConn, id: uintID(2)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(2), nil)}},
},
done: []task{
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)},
},
new: []task{
&waitExpireTask{Duration: 30 * time.Second},
@ -561,10 +571,10 @@ func TestDialStaticAfterReset(t *testing.T) {
// This test checks that past dials are not retried for some time.
func TestDialStateCache(t *testing.T) {
wantStatic := []*discover.Node{
{ID: uintID(1)},
{ID: uintID(2)},
{ID: uintID(3)},
wantStatic := []*enode.Node{
newNode(uintID(1), nil),
newNode(uintID(2), nil),
newNode(uintID(3), nil),
}
runDialTest(t, dialtest{
@ -575,32 +585,32 @@ func TestDialStateCache(t *testing.T) {
{
peers: nil,
new: []task{
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)},
},
},
// No new tasks are launched in this round because all static
// nodes are either connected or still being dialed.
{
peers: []*Peer{
{rw: &conn{flags: staticDialedConn, id: uintID(1)}},
{rw: &conn{flags: staticDialedConn, id: uintID(2)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(2), nil)}},
},
done: []task{
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)},
},
},
// A salvage task is launched to wait for node 3's history
// entry to expire.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
},
done: []task{
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)},
},
new: []task{
&waitExpireTask{Duration: 14 * time.Second},
@ -609,18 +619,18 @@ func TestDialStateCache(t *testing.T) {
// Still waiting for node 3's entry to expire in the cache.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
},
},
// The cache entry for node 3 has expired and is retried.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
},
new: []task{
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
&dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)},
},
},
},
@ -628,12 +638,12 @@ func TestDialStateCache(t *testing.T) {
}
func TestDialResolve(t *testing.T) {
resolved := discover.NewNode(uintID(1), net.IP{127, 0, 55, 234}, 3333, 4444)
resolved := newNode(uintID(1), net.IP{127, 0, 55, 234})
table := &resolveMock{answer: resolved}
state := newDialState(nil, nil, table, 0, nil)
// Check that the task is generated with an incomplete ID.
dest := discover.NewNode(uintID(1), nil, 0, 0)
dest := newNode(uintID(1), nil)
state.addStatic(dest)
tasks := state.newTasks(0, nil, time.Time{})
if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest}}) {
@ -644,7 +654,7 @@ func TestDialResolve(t *testing.T) {
config := Config{Dialer: TCPDialer{&net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}}}
srv := &Server{ntab: table, Config: config}
tasks[0].Do(srv)
if !reflect.DeepEqual(table.resolveCalls, []discover.NodeID{dest.ID}) {
if !reflect.DeepEqual(table.resolveCalls, []*enode.Node{dest}) {
t.Fatalf("wrong resolve calls, got %v", table.resolveCalls)
}
@ -672,25 +682,24 @@ next:
return true
}
func uintID(i uint32) discover.NodeID {
var id discover.NodeID
func uintID(i uint32) enode.ID {
var id enode.ID
binary.BigEndian.PutUint32(id[:], i)
return id
}
// implements discoverTable for TestDialResolve
type resolveMock struct {
resolveCalls []discover.NodeID
answer *discover.Node
resolveCalls []*enode.Node
answer *enode.Node
}
func (t *resolveMock) Resolve(id discover.NodeID) *discover.Node {
t.resolveCalls = append(t.resolveCalls, id)
func (t *resolveMock) Resolve(n *enode.Node) *enode.Node {
t.resolveCalls = append(t.resolveCalls, n)
return t.answer
}
func (t *resolveMock) Self() *discover.Node { return new(discover.Node) }
func (t *resolveMock) Self() *enode.Node { return new(enode.Node) }
func (t *resolveMock) Close() {}
func (t *resolveMock) Bootstrap([]*discover.Node) {}
func (t *resolveMock) Lookup(discover.NodeID) []*discover.Node { return nil }
func (t *resolveMock) ReadRandomNodes(buf []*discover.Node) int { return 0 }
func (t *resolveMock) LookupRandom() []*enode.Node { return nil }
func (t *resolveMock) ReadRandomNodes(buf []*enode.Node) int { return 0 }

View file

@ -26,7 +26,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/rlp"
)
@ -253,13 +253,13 @@ type msgEventer struct {
MsgReadWriter
feed *event.Feed
peerID discover.NodeID
peerID enode.ID
Protocol string
}
// newMsgEventer returns a msgEventer which sends message events to the given
// feed
func newMsgEventer(rw MsgReadWriter, feed *event.Feed, peerID discover.NodeID, proto string) *msgEventer {
func newMsgEventer(rw MsgReadWriter, feed *event.Feed, peerID enode.ID, proto string) *msgEventer {
return &msgEventer{
MsgReadWriter: rw,
feed: feed,

View file

@ -28,7 +28,8 @@ import (
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"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/rlp"
)
@ -60,7 +61,7 @@ type protoHandshake struct {
Name string
Caps []Cap
ListenPort uint64
ID discover.NodeID
ID []byte // secp256k1 public key
// Ignore additional fields (for forward compatibility).
Rest []rlp.RawValue `rlp:"tail"`
@ -91,7 +92,7 @@ const (
// a p2p.Server or when a message is sent or received on a peer connection
type PeerEvent struct {
Type PeerEventType `json:"type"`
Peer discover.NodeID `json:"peer"`
Peer enode.ID `json:"peer"`
Error string `json:"error,omitempty"`
Protocol string `json:"protocol,omitempty"`
MsgCode *uint64 `json:"msg_code,omitempty"`
@ -115,17 +116,23 @@ type Peer struct {
}
// NewPeer returns a peer for testing purposes.
func NewPeer(id discover.NodeID, name string, caps []Cap) *Peer {
func NewPeer(id enode.ID, name string, caps []Cap) *Peer {
pipe, _ := net.Pipe()
conn := &conn{fd: pipe, transport: nil, id: id, caps: caps, name: name}
node := enode.SignNull(new(enr.Record), id)
conn := &conn{fd: pipe, transport: nil, node: node, caps: caps, name: name}
peer := newPeer(conn, nil)
close(peer.closed) // ensures Disconnect doesn't block
return peer
}
// ID returns the node's public key.
func (p *Peer) ID() discover.NodeID {
return p.rw.id
func (p *Peer) ID() enode.ID {
return p.rw.node.ID()
}
// Node returns the peer's node descriptor.
func (p *Peer) Node() *enode.Node {
return p.rw.node
}
// Name returns the node name that the remote node advertised.
@ -160,7 +167,8 @@ func (p *Peer) Disconnect(reason DiscReason) {
// String implements fmt.Stringer.
func (p *Peer) String() string {
return fmt.Sprintf("Peer %x %v", p.rw.id[:8], p.RemoteAddr())
id := p.ID()
return fmt.Sprintf("Peer %x %v", id[:8], p.RemoteAddr())
}
// Inbound returns true if the peer is an inbound connection
@ -177,7 +185,7 @@ func newPeer(conn *conn, protocols []Protocol) *Peer {
disc: make(chan DiscReason),
protoErr: make(chan error, len(protomap)+1), // protocols + pingLoop
closed: make(chan struct{}),
log: log.New("id", conn.id, "conn", conn.flags),
log: log.New("id", conn.node.ID(), "conn", conn.flags),
}
return p
}

View file

@ -45,8 +45,8 @@ var discard = Protocol{
func testPeer(protos []Protocol) (func(), *conn, *Peer, <-chan error) {
fd1, fd2 := net.Pipe()
c1 := &conn{fd: fd1, transport: newTestTransport(randomID(), fd1)}
c2 := &conn{fd: fd2, transport: newTestTransport(randomID(), fd2)}
c1 := &conn{fd: fd1, node: newNode(randomID(), nil), transport: newTestTransport(&newkey().PublicKey, fd1)}
c2 := &conn{fd: fd2, node: newNode(randomID(), nil), transport: newTestTransport(&newkey().PublicKey, fd2)}
for _, p := range protos {
c1.caps = append(c1.caps, p.cap())
c2.caps = append(c2.caps, p.cap())

View file

@ -19,7 +19,7 @@ package p2p
import (
"fmt"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
)
// Protocol represents a P2P subprotocol implementation.
@ -51,7 +51,7 @@ type Protocol struct {
// PeerInfo is an optional helper method to retrieve protocol specific metadata
// about a certain peer in the network. If an info retrieval function is set,
// but returns nil, it is assumed that the protocol handshake is still running.
PeerInfo func(id discover.NodeID) interface{}
PeerInfo func(id enode.ID) interface{}
}
func (p Protocol) cap() Cap {

View file

@ -35,11 +35,11 @@ import (
"sync"
"time"
"github.com/ethereum/go-ethereum/common/bitutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/rlp"
"github.com/golang/snappy"
)
@ -165,7 +165,7 @@ func readProtocolHandshake(rw MsgReader, our *protoHandshake) (*protoHandshake,
if err := msg.Decode(&hs); err != nil {
return nil, err
}
if (hs.ID == discover.NodeID{}) {
if len(hs.ID) != 64 || !bitutil.TestBytes(hs.ID) {
return nil, DiscInvalidIdentity
}
return &hs, nil
@ -175,7 +175,7 @@ func readProtocolHandshake(rw MsgReader, our *protoHandshake) (*protoHandshake,
// messages. the protocol handshake is the first authenticated message
// and also verifies whether the encryption handshake 'worked' and the
// remote side actually provided the right public key.
func (t *rlpx) doEncHandshake(prv *ecdsa.PrivateKey, dial *discover.Node) (discover.NodeID, error) {
func (t *rlpx) doEncHandshake(prv *ecdsa.PrivateKey, dial *ecdsa.PublicKey) (*ecdsa.PublicKey, error) {
var (
sec secrets
err error
@ -183,23 +183,21 @@ func (t *rlpx) doEncHandshake(prv *ecdsa.PrivateKey, dial *discover.Node) (disco
if dial == nil {
sec, err = receiverEncHandshake(t.fd, prv)
} else {
sec, err = initiatorEncHandshake(t.fd, prv, dial.ID)
sec, err = initiatorEncHandshake(t.fd, prv, dial)
}
if err != nil {
return discover.NodeID{}, err
return nil, err
}
t.wmu.Lock()
t.rw = newRLPXFrameRW(t.fd, sec)
t.wmu.Unlock()
return sec.RemoteID, nil
return sec.Remote.ExportECDSA(), nil
}
// encHandshake contains the state of the encryption handshake.
type encHandshake struct {
initiator bool
remoteID discover.NodeID
remotePub *ecies.PublicKey // remote-pubk
remote *ecies.PublicKey // remote-pubk
initNonce, respNonce []byte // nonce
randomPrivKey *ecies.PrivateKey // ecdhe-random
remoteRandomPub *ecies.PublicKey // ecdhe-random-pubk
@ -208,7 +206,7 @@ type encHandshake struct {
// secrets represents the connection secrets
// which are negotiated during the encryption handshake.
type secrets struct {
RemoteID discover.NodeID
Remote *ecies.PublicKey
AES, MAC []byte
EgressMAC, IngressMAC hash.Hash
Token []byte
@ -249,7 +247,7 @@ func (h *encHandshake) secrets(auth, authResp []byte) (secrets, error) {
sharedSecret := crypto.Keccak256(ecdheSecret, crypto.Keccak256(h.respNonce, h.initNonce))
aesSecret := crypto.Keccak256(ecdheSecret, sharedSecret)
s := secrets{
RemoteID: h.remoteID,
Remote: h.remote,
AES: aesSecret,
MAC: crypto.Keccak256(ecdheSecret, aesSecret),
}
@ -273,15 +271,15 @@ func (h *encHandshake) secrets(auth, authResp []byte) (secrets, error) {
// staticSharedSecret returns the static shared secret, the result
// of key agreement between the local and remote static node key.
func (h *encHandshake) staticSharedSecret(prv *ecdsa.PrivateKey) ([]byte, error) {
return ecies.ImportECDSA(prv).GenerateShared(h.remotePub, sskLen, sskLen)
return ecies.ImportECDSA(prv).GenerateShared(h.remote, sskLen, sskLen)
}
// initiatorEncHandshake negotiates a session token on conn.
// it should be called on the dialing side of the connection.
//
// prv is the local client's private key.
func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remoteID discover.NodeID) (s secrets, err error) {
h := &encHandshake{initiator: true, remoteID: remoteID}
func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remote *ecdsa.PublicKey) (s secrets, err error) {
h := &encHandshake{initiator: true, remote: ecies.ImportECDSAPublic(remote)}
authMsg, err := h.makeAuthMsg(prv)
if err != nil {
return s, err
@ -307,14 +305,10 @@ func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remoteID d
// makeAuthMsg creates the initiator handshake message.
func (h *encHandshake) makeAuthMsg(prv *ecdsa.PrivateKey) (*authMsgV4, error) {
rpub, err := h.remoteID.Pubkey()
if err != nil {
return nil, fmt.Errorf("bad remoteID: %v", err)
}
h.remotePub = ecies.ImportECDSAPublic(rpub)
// Generate random initiator nonce.
h.initNonce = make([]byte, shaLen)
if _, err := rand.Read(h.initNonce); err != nil {
_, err := rand.Read(h.initNonce)
if err != nil {
return nil, err
}
// Generate random keypair to for ECDH.
@ -384,13 +378,12 @@ func receiverEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey) (s secrets,
func (h *encHandshake) handleAuthMsg(msg *authMsgV4, prv *ecdsa.PrivateKey) error {
// Import the remote identity.
h.initNonce = msg.Nonce[:]
h.remoteID = msg.InitiatorPubkey
rpub, err := h.remoteID.Pubkey()
rpub, err := importPublicKey(msg.InitiatorPubkey[:])
if err != nil {
return fmt.Errorf("bad remoteID: %#v", err)
return err
}
h.remotePub = ecies.ImportECDSAPublic(rpub)
h.initNonce = msg.Nonce[:]
h.remote = rpub
// Generate random keypair for ECDH.
// If a private key is already set, use it instead of generating one (for testing).
@ -436,7 +429,7 @@ func (msg *authMsgV4) sealPlain(h *encHandshake) ([]byte, error) {
n += copy(buf[n:], msg.InitiatorPubkey[:])
n += copy(buf[n:], msg.Nonce[:])
buf[n] = 0 // token-flag
return ecies.Encrypt(rand.Reader, h.remotePub, buf, nil, nil)
return ecies.Encrypt(rand.Reader, h.remote, buf, nil, nil)
}
func (msg *authMsgV4) decodePlain(input []byte) {
@ -452,7 +445,7 @@ func (msg *authRespV4) sealPlain(hs *encHandshake) ([]byte, error) {
buf := make([]byte, authRespLen)
n := copy(buf, msg.RandomPubkey[:])
copy(buf[n:], msg.Nonce[:])
return ecies.Encrypt(rand.Reader, hs.remotePub, buf, nil, nil)
return ecies.Encrypt(rand.Reader, hs.remote, buf, nil, nil)
}
func (msg *authRespV4) decodePlain(input []byte) {
@ -475,7 +468,7 @@ func sealEIP8(msg interface{}, h *encHandshake) ([]byte, error) {
prefix := make([]byte, 2)
binary.BigEndian.PutUint16(prefix, uint16(buf.Len()+eciesOverhead))
enc, err := ecies.Encrypt(rand.Reader, h.remotePub, buf.Bytes(), nil, prefix)
enc, err := ecies.Encrypt(rand.Reader, h.remote, buf.Bytes(), nil, prefix)
return append(prefix, enc...), err
}

View file

@ -18,6 +18,7 @@ package p2p
import (
"bytes"
"crypto/ecdsa"
"crypto/rand"
"errors"
"fmt"
@ -34,7 +35,6 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/simulations/pipes"
"github.com/ethereum/go-ethereum/rlp"
)
@ -81,7 +81,7 @@ func TestEncHandshake(t *testing.T) {
func testEncHandshake(token []byte) error {
type result struct {
side string
id discover.NodeID
pubkey *ecdsa.PublicKey
err error
}
var (
@ -97,14 +97,12 @@ func testEncHandshake(token []byte) error {
defer func() { output <- r }()
defer fd0.Close()
dest := &discover.Node{ID: discover.PubkeyID(&prv1.PublicKey)}
r.id, r.err = c0.doEncHandshake(prv0, dest)
r.pubkey, r.err = c0.doEncHandshake(prv0, &prv1.PublicKey)
if r.err != nil {
return
}
id1 := discover.PubkeyID(&prv1.PublicKey)
if r.id != id1 {
r.err = fmt.Errorf("remote ID mismatch: got %v, want: %v", r.id, id1)
if !reflect.DeepEqual(r.pubkey, &prv1.PublicKey) {
r.err = fmt.Errorf("remote pubkey mismatch: got %v, want: %v", r.pubkey, &prv1.PublicKey)
}
}()
go func() {
@ -112,13 +110,12 @@ func testEncHandshake(token []byte) error {
defer func() { output <- r }()
defer fd1.Close()
r.id, r.err = c1.doEncHandshake(prv1, nil)
r.pubkey, r.err = c1.doEncHandshake(prv1, nil)
if r.err != nil {
return
}
id0 := discover.PubkeyID(&prv0.PublicKey)
if r.id != id0 {
r.err = fmt.Errorf("remote ID mismatch: got %v, want: %v", r.id, id0)
if !reflect.DeepEqual(r.pubkey, &prv0.PublicKey) {
r.err = fmt.Errorf("remote ID mismatch: got %v, want: %v", r.pubkey, &prv0.PublicKey)
}
}()
@ -150,12 +147,12 @@ func testEncHandshake(token []byte) error {
func TestProtocolHandshake(t *testing.T) {
var (
prv0, _ = crypto.GenerateKey()
node0 = &discover.Node{ID: discover.PubkeyID(&prv0.PublicKey), IP: net.IP{1, 2, 3, 4}, TCP: 33}
hs0 = &protoHandshake{Version: 3, ID: node0.ID, Caps: []Cap{{"a", 0}, {"b", 2}}}
pub0 = crypto.FromECDSAPub(&prv0.PublicKey)[1:]
hs0 = &protoHandshake{Version: 3, ID: pub0, Caps: []Cap{{"a", 0}, {"b", 2}}}
prv1, _ = crypto.GenerateKey()
node1 = &discover.Node{ID: discover.PubkeyID(&prv1.PublicKey), IP: net.IP{5, 6, 7, 8}, TCP: 44}
hs1 = &protoHandshake{Version: 3, ID: node1.ID, Caps: []Cap{{"c", 1}, {"d", 3}}}
pub1 = crypto.FromECDSAPub(&prv1.PublicKey)[1:]
hs1 = &protoHandshake{Version: 3, ID: pub1, Caps: []Cap{{"c", 1}, {"d", 3}}}
wg sync.WaitGroup
)
@ -170,13 +167,13 @@ func TestProtocolHandshake(t *testing.T) {
defer wg.Done()
defer fd0.Close()
rlpx := newRLPX(fd0)
remid, err := rlpx.doEncHandshake(prv0, node1)
rpubkey, err := rlpx.doEncHandshake(prv0, &prv1.PublicKey)
if err != nil {
t.Errorf("dial side enc handshake failed: %v", err)
return
}
if remid != node1.ID {
t.Errorf("dial side remote id mismatch: got %v, want %v", remid, node1.ID)
if !reflect.DeepEqual(rpubkey, &prv1.PublicKey) {
t.Errorf("dial side remote pubkey mismatch: got %v, want %v", rpubkey, &prv1.PublicKey)
return
}
@ -196,13 +193,13 @@ func TestProtocolHandshake(t *testing.T) {
defer wg.Done()
defer fd1.Close()
rlpx := newRLPX(fd1)
remid, err := rlpx.doEncHandshake(prv1, nil)
rpubkey, err := rlpx.doEncHandshake(prv1, nil)
if err != nil {
t.Errorf("listen side enc handshake failed: %v", err)
return
}
if remid != node0.ID {
t.Errorf("listen side remote id mismatch: got %v, want %v", remid, node0.ID)
if !reflect.DeepEqual(rpubkey, &prv0.PublicKey) {
t.Errorf("listen side remote pubkey mismatch: got %v, want %v", rpubkey, &prv0.PublicKey)
return
}

View file

@ -18,6 +18,7 @@
package p2p
import (
"bytes"
"crypto/ecdsa"
"errors"
"fmt"
@ -28,10 +29,12 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil"
)
@ -87,7 +90,7 @@ type Config struct {
// BootstrapNodes are used to establish connectivity
// with the rest of the network.
BootstrapNodes []*discover.Node
BootstrapNodes []*enode.Node
// BootstrapNodesV5 are used to establish connectivity
// with the rest of the network using the V5 discovery
@ -96,11 +99,11 @@ type Config struct {
// Static nodes are used as pre-configured connections which are always
// maintained and re-connected on disconnects.
StaticNodes []*discover.Node
StaticNodes []*enode.Node
// Trusted nodes are used as pre-configured connections which are always
// allowed to connect, even above the peer limit.
TrustedNodes []*discover.Node
TrustedNodes []*enode.Node
// Connectivity can be restricted to certain IP networks.
// If this option is set to a non-nil value, only hosts which match one of the
@ -168,10 +171,10 @@ type Server struct {
peerOpDone chan struct{}
quit chan struct{}
addstatic chan *discover.Node
removestatic chan *discover.Node
addtrusted chan *discover.Node
removetrusted chan *discover.Node
addstatic chan *enode.Node
removestatic chan *enode.Node
addtrusted chan *enode.Node
removetrusted chan *enode.Node
posthandshake chan *conn
addpeer chan *conn
delpeer chan peerDrop
@ -180,7 +183,7 @@ type Server struct {
log log.Logger
}
type peerOpFunc func(map[discover.NodeID]*Peer)
type peerOpFunc func(map[enode.ID]*Peer)
type peerDrop struct {
*Peer
@ -202,16 +205,16 @@ const (
type conn struct {
fd net.Conn
transport
node *enode.Node
flags connFlag
cont chan error // The run loop uses cont to signal errors to SetupConn.
id discover.NodeID // valid after the encryption handshake
caps []Cap // valid after the protocol handshake
name string // valid after the protocol handshake
}
type transport interface {
// The two handshakes.
doEncHandshake(prv *ecdsa.PrivateKey, dialDest *discover.Node) (discover.NodeID, error)
doEncHandshake(prv *ecdsa.PrivateKey, dialDest *ecdsa.PublicKey) (*ecdsa.PublicKey, error)
doProtoHandshake(our *protoHandshake) (*protoHandshake, error)
// The MsgReadWriter can only be used after the encryption
// handshake has completed. The code uses conn.id to track this
@ -225,8 +228,8 @@ type transport interface {
func (c *conn) String() string {
s := c.flags.String()
if (c.id != discover.NodeID{}) {
s += " " + c.id.String()
if (c.node.ID() != enode.ID{}) {
s += " " + c.node.ID().String()
}
s += " " + c.fd.RemoteAddr().String()
return s
@ -279,7 +282,7 @@ func (srv *Server) Peers() []*Peer {
// Note: We'd love to put this function into a variable but
// that seems to cause a weird compiler error in some
// environments.
case srv.peerOp <- func(peers map[discover.NodeID]*Peer) {
case srv.peerOp <- func(peers map[enode.ID]*Peer) {
for _, p := range peers {
ps = append(ps, p)
}
@ -294,7 +297,7 @@ func (srv *Server) Peers() []*Peer {
func (srv *Server) PeerCount() int {
var count int
select {
case srv.peerOp <- func(ps map[discover.NodeID]*Peer) { count = len(ps) }:
case srv.peerOp <- func(ps map[enode.ID]*Peer) { count = len(ps) }:
<-srv.peerOpDone
case <-srv.quit:
}
@ -304,7 +307,7 @@ func (srv *Server) PeerCount() int {
// AddPeer connects to the given node and maintains the connection until the
// server is shut down. If the connection fails for any reason, the server will
// attempt to reconnect the peer.
func (srv *Server) AddPeer(node *discover.Node) {
func (srv *Server) AddPeer(node *enode.Node) {
select {
case srv.addstatic <- node:
case <-srv.quit:
@ -312,7 +315,7 @@ func (srv *Server) AddPeer(node *discover.Node) {
}
// RemovePeer disconnects from the given node
func (srv *Server) RemovePeer(node *discover.Node) {
func (srv *Server) RemovePeer(node *enode.Node) {
select {
case srv.removestatic <- node:
case <-srv.quit:
@ -321,7 +324,7 @@ func (srv *Server) RemovePeer(node *discover.Node) {
// AddTrustedPeer adds the given node to a reserved whitelist which allows the
// node to always connect, even if the slot are full.
func (srv *Server) AddTrustedPeer(node *discover.Node) {
func (srv *Server) AddTrustedPeer(node *enode.Node) {
select {
case srv.addtrusted <- node:
case <-srv.quit:
@ -329,7 +332,7 @@ func (srv *Server) AddTrustedPeer(node *discover.Node) {
}
// RemoveTrustedPeer removes the given node from the trusted peer set.
func (srv *Server) RemoveTrustedPeer(node *discover.Node) {
func (srv *Server) RemoveTrustedPeer(node *enode.Node) {
select {
case srv.removetrusted <- node:
case <-srv.quit:
@ -342,36 +345,47 @@ func (srv *Server) SubscribeEvents(ch chan *PeerEvent) event.Subscription {
}
// Self returns the local node's endpoint information.
func (srv *Server) Self() *discover.Node {
func (srv *Server) Self() *enode.Node {
srv.lock.Lock()
defer srv.lock.Unlock()
running, listener, ntab := srv.running, srv.listener, srv.ntab
srv.lock.Unlock()
if !srv.running {
return &discover.Node{IP: net.ParseIP("0.0.0.0")}
if !running {
return enode.NewV4(&srv.PrivateKey.PublicKey, net.ParseIP("0.0.0.0"), 0, 0)
}
return srv.makeSelf(srv.listener, srv.ntab)
return srv.makeSelf(listener, ntab)
}
func (srv *Server) makeSelf(listener net.Listener, ntab discoverTable) *discover.Node {
// If the server's not running, return an empty node.
func (srv *Server) makeSelf(listener net.Listener, ntab discoverTable) *enode.Node {
// If the node is running but discovery is off, manually assemble the node infos.
if ntab == nil {
// Inbound connections disabled, use zero address.
if listener == nil {
return &discover.Node{IP: net.ParseIP("0.0.0.0"), ID: discover.PubkeyID(&srv.PrivateKey.PublicKey)}
}
// Otherwise inject the listener address too
addr := listener.Addr().(*net.TCPAddr)
return &discover.Node{
ID: discover.PubkeyID(&srv.PrivateKey.PublicKey),
IP: addr.IP,
TCP: uint16(addr.Port),
}
addr := srv.tcpAddr(listener)
return enode.NewV4(&srv.PrivateKey.PublicKey, addr.IP, addr.Port, 0)
}
// Otherwise return the discovery node.
return ntab.Self()
}
func (srv *Server) tcpAddr(listener net.Listener) net.TCPAddr {
addr := net.TCPAddr{IP: net.IP{0, 0, 0, 0}}
if listener == nil {
return addr // Inbound connections disabled, use zero address.
}
// Otherwise inject the listener address too.
if a, ok := listener.Addr().(*net.TCPAddr); ok {
addr = *a
}
if srv.NAT != nil {
if ip, err := srv.NAT.ExternalIP(); err == nil {
addr.IP = ip
}
}
if addr.IP.IsUnspecified() {
addr.IP = net.IP{127, 0, 0, 1}
}
return addr
}
// Stop terminates the server and all active peer connections.
// It blocks until all active connections have been closed.
func (srv *Server) Stop() {
@ -445,10 +459,10 @@ func (srv *Server) Start() (err error) {
srv.addpeer = make(chan *conn)
srv.delpeer = make(chan peerDrop)
srv.posthandshake = make(chan *conn)
srv.addstatic = make(chan *discover.Node)
srv.removestatic = make(chan *discover.Node)
srv.addtrusted = make(chan *discover.Node)
srv.removetrusted = make(chan *discover.Node)
srv.addstatic = make(chan *enode.Node)
srv.removestatic = make(chan *enode.Node)
srv.addtrusted = make(chan *enode.Node)
srv.removetrusted = make(chan *enode.Node)
srv.peerOp = make(chan peerOpFunc)
srv.peerOpDone = make(chan struct{})
@ -525,7 +539,8 @@ func (srv *Server) Start() (err error) {
dialer := newDialState(srv.StaticNodes, srv.BootstrapNodes, srv.ntab, dynPeers, srv.NetRestrict)
// handshake
srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: discover.PubkeyID(&srv.PrivateKey.PublicKey)}
pubkey := crypto.FromECDSAPub(&srv.PrivateKey.PublicKey)
srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: pubkey[1:]}
for _, p := range srv.Protocols {
srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap())
}
@ -541,7 +556,6 @@ func (srv *Server) Start() (err error) {
srv.loopWG.Add(1)
go srv.run(dialer)
srv.running = true
return nil
}
@ -568,18 +582,18 @@ func (srv *Server) startListening() error {
}
type dialer interface {
newTasks(running int, peers map[discover.NodeID]*Peer, now time.Time) []task
newTasks(running int, peers map[enode.ID]*Peer, now time.Time) []task
taskDone(task, time.Time)
addStatic(*discover.Node)
removeStatic(*discover.Node)
addStatic(*enode.Node)
removeStatic(*enode.Node)
}
func (srv *Server) run(dialstate dialer) {
defer srv.loopWG.Done()
var (
peers = make(map[discover.NodeID]*Peer)
peers = make(map[enode.ID]*Peer)
inboundCount = 0
trusted = make(map[discover.NodeID]bool, len(srv.TrustedNodes))
trusted = make(map[enode.ID]bool, len(srv.TrustedNodes))
taskdone = make(chan task, maxActiveDialTasks)
runningTasks []task
queuedTasks []task // tasks that can't run yet
@ -587,7 +601,7 @@ func (srv *Server) run(dialstate dialer) {
// Put trusted nodes into a map to speed up checks.
// Trusted peers are loaded on startup or added via AddTrustedPeer RPC.
for _, n := range srv.TrustedNodes {
trusted[n.ID] = true
trusted[n.ID()] = true
}
// removes t from runningTasks
@ -640,27 +654,27 @@ running:
// stop keeping the node connected.
srv.log.Trace("Removing static node", "node", n)
dialstate.removeStatic(n)
if p, ok := peers[n.ID]; ok {
if p, ok := peers[n.ID()]; ok {
p.Disconnect(DiscRequested)
}
case n := <-srv.addtrusted:
// This channel is used by AddTrustedPeer to add an enode
// to the trusted node set.
srv.log.Trace("Adding trusted node", "node", n)
trusted[n.ID] = true
trusted[n.ID()] = true
// Mark any already-connected peer as trusted
if p, ok := peers[n.ID]; ok {
if p, ok := peers[n.ID()]; ok {
p.rw.set(trustedConn, true)
}
case n := <-srv.removetrusted:
// This channel is used by RemoveTrustedPeer to remove an enode
// from the trusted node set.
srv.log.Trace("Removing trusted node", "node", n)
if _, ok := trusted[n.ID]; ok {
delete(trusted, n.ID)
if _, ok := trusted[n.ID()]; ok {
delete(trusted, n.ID())
}
// Unmark any already-connected peer as trusted
if p, ok := peers[n.ID]; ok {
if p, ok := peers[n.ID()]; ok {
p.rw.set(trustedConn, false)
}
case op := <-srv.peerOp:
@ -677,7 +691,7 @@ running:
case c := <-srv.posthandshake:
// A connection has passed the encryption handshake so
// the remote identity is known (but hasn't been verified yet).
if trusted[c.id] {
if trusted[c.node.ID()] {
// Ensure that the trusted flag is set before checking against MaxPeers.
c.flags |= trustedConn
}
@ -702,7 +716,7 @@ running:
name := truncateName(c.name)
srv.log.Debug("Adding p2p peer", "name", name, "addr", c.fd.RemoteAddr(), "peers", len(peers)+1)
go srv.runPeer(p)
peers[c.id] = p
peers[c.node.ID()] = p
if p.Inbound() {
inboundCount++
}
@ -749,7 +763,7 @@ running:
}
}
func (srv *Server) protoHandshakeChecks(peers map[discover.NodeID]*Peer, inboundCount int, c *conn) error {
func (srv *Server) protoHandshakeChecks(peers map[enode.ID]*Peer, inboundCount int, c *conn) error {
// Drop connections with no matching protocols.
if len(srv.Protocols) > 0 && countMatchingProtocols(srv.Protocols, c.caps) == 0 {
return DiscUselessPeer
@ -759,15 +773,15 @@ func (srv *Server) protoHandshakeChecks(peers map[discover.NodeID]*Peer, inbound
return srv.encHandshakeChecks(peers, inboundCount, c)
}
func (srv *Server) encHandshakeChecks(peers map[discover.NodeID]*Peer, inboundCount int, c *conn) error {
func (srv *Server) encHandshakeChecks(peers map[enode.ID]*Peer, inboundCount int, c *conn) error {
switch {
case !c.is(trustedConn|staticDialedConn) && len(peers) >= srv.MaxPeers:
return DiscTooManyPeers
case !c.is(trustedConn) && c.is(inboundConn) && inboundCount >= srv.maxInboundConns():
return DiscTooManyPeers
case peers[c.id] != nil:
case peers[c.node.ID()] != nil:
return DiscAlreadyConnected
case c.id == srv.Self().ID:
case c.node.ID() == srv.Self().ID():
return DiscSelf
default:
return nil
@ -777,7 +791,6 @@ func (srv *Server) encHandshakeChecks(peers map[discover.NodeID]*Peer, inboundCo
func (srv *Server) maxInboundConns() int {
return srv.MaxPeers - srv.maxDialedConns()
}
func (srv *Server) maxDialedConns() int {
if srv.NoDiscovery || srv.NoDial {
return 0
@ -797,7 +810,7 @@ type tempError interface {
// inbound connections.
func (srv *Server) listenLoop() {
defer srv.loopWG.Done()
srv.log.Info("RLPx listener up", "self", srv.makeSelf(srv.listener, srv.ntab))
srv.log.Info("RLPx listener up", "self", srv.Self())
tokens := defaultMaxPendingPeers
if srv.MaxPendingPeers > 0 {
@ -850,7 +863,7 @@ func (srv *Server) listenLoop() {
// SetupConn runs the handshakes and attempts to add the connection
// as a peer. It returns when the connection has been added as a peer
// or the handshakes have failed.
func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *discover.Node) error {
func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *enode.Node) error {
self := srv.Self()
if self == nil {
return errors.New("shutdown")
@ -859,12 +872,12 @@ func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *discover.Nod
err := srv.setupConn(c, flags, dialDest)
if err != nil {
c.close(err)
srv.log.Trace("Setting up connection failed", "id", c.id, "err", err)
srv.log.Trace("Setting up connection failed", "addr", fd.RemoteAddr(), "err", err)
}
return err
}
func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *discover.Node) error {
func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) error {
// Prevent leftover pending conns from entering the handshake.
srv.lock.Lock()
running := srv.running
@ -872,18 +885,30 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *discover.Node) e
if !running {
return errServerStopped
}
// If dialing, figure out the remote public key.
var dialPubkey *ecdsa.PublicKey
if dialDest != nil {
dialPubkey = new(ecdsa.PublicKey)
if err := dialDest.Load((*enode.Secp256k1)(dialPubkey)); err != nil {
return fmt.Errorf("dial destination doesn't have a secp256k1 public key")
}
}
// Run the encryption handshake.
var err error
if c.id, err = c.doEncHandshake(srv.PrivateKey, dialDest); err != nil {
remotePubkey, err := c.doEncHandshake(srv.PrivateKey, dialPubkey)
if err != nil {
srv.log.Trace("Failed RLPx handshake", "addr", c.fd.RemoteAddr(), "conn", c.flags, "err", err)
return err
}
clog := srv.log.New("id", c.id, "addr", c.fd.RemoteAddr(), "conn", c.flags)
if dialDest != nil {
// For dialed connections, check that the remote public key matches.
if dialDest != nil && c.id != dialDest.ID {
clog.Trace("Dialed identity mismatch", "want", c, dialDest.ID)
if dialPubkey.X.Cmp(remotePubkey.X) != 0 || dialPubkey.Y.Cmp(remotePubkey.Y) != 0 {
return DiscUnexpectedIdentity
}
c.node = dialDest
} else {
c.node = nodeFromConn(remotePubkey, c.fd)
}
clog := srv.log.New("id", c.node.ID(), "addr", c.fd.RemoteAddr(), "conn", c.flags)
err = srv.checkpoint(c, srv.posthandshake)
if err != nil {
clog.Trace("Rejected peer before protocol handshake", "err", err)
@ -895,8 +920,8 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *discover.Node) e
clog.Trace("Failed proto handshake", "err", err)
return err
}
if phs.ID != c.id {
clog.Trace("Wrong devp2p handshake identity", "err", phs.ID)
if id := c.node.ID(); !bytes.Equal(crypto.Keccak256(phs.ID), id[:]) {
clog.Trace("Wrong devp2p handshake identity", "phsid", fmt.Sprintf("%x", phs.ID))
return DiscUnexpectedIdentity
}
c.caps, c.name = phs.Caps, phs.Name
@ -911,6 +936,16 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *discover.Node) e
return nil
}
func nodeFromConn(pubkey *ecdsa.PublicKey, conn net.Conn) *enode.Node {
var ip net.IP
var port int
if tcp, ok := conn.RemoteAddr().(*net.TCPAddr); ok {
ip = tcp.IP
port = tcp.Port
}
return enode.NewV4(pubkey, ip, port, port)
}
func truncateName(s string) string {
if len(s) > 20 {
return s[:20] + "..."
@ -985,13 +1020,13 @@ func (srv *Server) NodeInfo() *NodeInfo {
info := &NodeInfo{
Name: srv.Name,
Enode: node.String(),
ID: node.ID.String(),
IP: node.IP.String(),
ID: node.ID().String(),
IP: node.IP().String(),
ListenAddr: srv.ListenAddr,
Protocols: make(map[string]interface{}),
}
info.Ports.Discovery = int(node.UDP)
info.Ports.Listener = int(node.TCP)
info.Ports.Discovery = node.UDP()
info.Ports.Listener = node.TCP()
// Gather all the running protocol infos (only once per protocol type)
for _, proto := range srv.Protocols {

View file

@ -28,21 +28,22 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
)
func init() {
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlError, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
}
// func init() {
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
// }
type testTransport struct {
id discover.NodeID
rpub *ecdsa.PublicKey
*rlpx
closeErr error
}
func newTestTransport(id discover.NodeID, fd net.Conn) transport {
func newTestTransport(rpub *ecdsa.PublicKey, fd net.Conn) transport {
wrapped := newRLPX(fd).(*rlpx)
wrapped.rw = newRLPXFrameRW(fd, secrets{
MAC: zero16,
@ -50,15 +51,16 @@ func newTestTransport(id discover.NodeID, fd net.Conn) transport {
IngressMAC: sha3.NewKeccak256(),
EgressMAC: sha3.NewKeccak256(),
})
return &testTransport{id: id, rlpx: wrapped}
return &testTransport{rpub: rpub, rlpx: wrapped}
}
func (c *testTransport) doEncHandshake(prv *ecdsa.PrivateKey, dialDest *discover.Node) (discover.NodeID, error) {
return c.id, nil
func (c *testTransport) doEncHandshake(prv *ecdsa.PrivateKey, dialDest *ecdsa.PublicKey) (*ecdsa.PublicKey, error) {
return c.rpub, nil
}
func (c *testTransport) doProtoHandshake(our *protoHandshake) (*protoHandshake, error) {
return &protoHandshake{ID: c.id, Name: "test"}, nil
pubkey := crypto.FromECDSAPub(c.rpub)[1:]
return &protoHandshake{ID: pubkey, Name: "test"}, nil
}
func (c *testTransport) close(err error) {
@ -66,7 +68,7 @@ func (c *testTransport) close(err error) {
c.closeErr = err
}
func startTestServer(t *testing.T, id discover.NodeID, pf func(*Peer)) *Server {
func startTestServer(t *testing.T, remoteKey *ecdsa.PublicKey, pf func(*Peer)) *Server {
config := Config{
Name: "test",
MaxPeers: 10,
@ -76,7 +78,7 @@ func startTestServer(t *testing.T, id discover.NodeID, pf func(*Peer)) *Server {
server := &Server{
Config: config,
newPeerHook: pf,
newTransport: func(fd net.Conn) transport { return newTestTransport(id, fd) },
newTransport: func(fd net.Conn) transport { return newTestTransport(remoteKey, fd) },
}
if err := server.Start(); err != nil {
t.Fatalf("Could not start server: %v", err)
@ -87,14 +89,11 @@ func startTestServer(t *testing.T, id discover.NodeID, pf func(*Peer)) *Server {
func TestServerListen(t *testing.T) {
// start the test server
connected := make(chan *Peer)
remid := randomID()
remid := &newkey().PublicKey
srv := startTestServer(t, remid, func(p *Peer) {
if p.ID() != remid {
if p.ID() != enode.PubkeyToIDV4(remid) {
t.Error("peer func called with wrong node id")
}
if p == nil {
t.Error("peer func called with nil conn")
}
connected <- p
})
defer close(connected)
@ -141,14 +140,14 @@ func TestServerDial(t *testing.T) {
// start the server
connected := make(chan *Peer)
remid := randomID()
remid := &newkey().PublicKey
srv := startTestServer(t, remid, func(p *Peer) { connected <- p })
defer close(connected)
defer srv.Stop()
// tell the server to connect
tcpAddr := listener.Addr().(*net.TCPAddr)
node := &discover.Node{ID: remid, IP: tcpAddr.IP, TCP: uint16(tcpAddr.Port)}
node := enode.NewV4(remid, tcpAddr.IP, tcpAddr.Port, 0)
srv.AddPeer(node)
select {
@ -157,7 +156,7 @@ func TestServerDial(t *testing.T) {
select {
case peer := <-connected:
if peer.ID() != remid {
if peer.ID() != enode.PubkeyToIDV4(remid) {
t.Errorf("peer has wrong id")
}
if peer.Name() != "test" {
@ -211,7 +210,7 @@ func TestServerTaskScheduling(t *testing.T) {
quit, returned = make(chan struct{}), make(chan struct{})
tc = 0
tg = taskgen{
newFunc: func(running int, peers map[discover.NodeID]*Peer) []task {
newFunc: func(running int, peers map[enode.ID]*Peer) []task {
tc++
return []task{&testTask{index: tc - 1}}
},
@ -284,7 +283,7 @@ func TestServerManyTasks(t *testing.T) {
defer srv.Stop()
srv.loopWG.Add(1)
go srv.run(taskgen{
newFunc: func(running int, peers map[discover.NodeID]*Peer) []task {
newFunc: func(running int, peers map[enode.ID]*Peer) []task {
start, end = end, end+maxActiveDialTasks+10
if end > len(alltasks) {
end = len(alltasks)
@ -319,19 +318,19 @@ func TestServerManyTasks(t *testing.T) {
}
type taskgen struct {
newFunc func(running int, peers map[discover.NodeID]*Peer) []task
newFunc func(running int, peers map[enode.ID]*Peer) []task
doneFunc func(task)
}
func (tg taskgen) newTasks(running int, peers map[discover.NodeID]*Peer, now time.Time) []task {
func (tg taskgen) newTasks(running int, peers map[enode.ID]*Peer, now time.Time) []task {
return tg.newFunc(running, peers)
}
func (tg taskgen) taskDone(t task, now time.Time) {
tg.doneFunc(t)
}
func (tg taskgen) addStatic(*discover.Node) {
func (tg taskgen) addStatic(*enode.Node) {
}
func (tg taskgen) removeStatic(*discover.Node) {
func (tg taskgen) removeStatic(*enode.Node) {
}
type testTask struct {
@ -347,13 +346,14 @@ func (t *testTask) Do(srv *Server) {
// just after the encryption handshake when the server is
// at capacity. Trusted connections should still be accepted.
func TestServerAtCap(t *testing.T) {
trustedID := randomID()
trustedNode := newkey()
trustedID := enode.PubkeyToIDV4(&trustedNode.PublicKey)
srv := &Server{
Config: Config{
PrivateKey: newkey(),
MaxPeers: 10,
NoDial: true,
TrustedNodes: []*discover.Node{{ID: trustedID}},
TrustedNodes: []*enode.Node{newNode(trustedID, nil)},
},
}
if err := srv.Start(); err != nil {
@ -361,10 +361,11 @@ func TestServerAtCap(t *testing.T) {
}
defer srv.Stop()
newconn := func(id discover.NodeID) *conn {
newconn := func(id enode.ID) *conn {
fd, _ := net.Pipe()
tx := newTestTransport(id, fd)
return &conn{fd: fd, transport: tx, flags: inboundConn, id: id, cont: make(chan error)}
tx := newTestTransport(&trustedNode.PublicKey, fd)
node := enode.SignNull(new(enr.Record), id)
return &conn{fd: fd, transport: tx, flags: inboundConn, node: node, cont: make(chan error)}
}
// Inject a few connections to fill up the peer set.
@ -390,14 +391,14 @@ func TestServerAtCap(t *testing.T) {
}
// Remove from trusted set and try again
srv.RemoveTrustedPeer(&discover.Node{ID: trustedID})
srv.RemoveTrustedPeer(newNode(trustedID, nil))
c = newconn(trustedID)
if err := srv.checkpoint(c, srv.posthandshake); err != DiscTooManyPeers {
t.Error("wrong error for insert:", err)
}
// Add anotherID to trusted set and try again
srv.AddTrustedPeer(&discover.Node{ID: anotherID})
srv.AddTrustedPeer(newNode(anotherID, nil))
c = newconn(anotherID)
if err := srv.checkpoint(c, srv.posthandshake); err != nil {
t.Error("unexpected error for trusted conn @posthandshake:", err)
@ -409,20 +410,17 @@ func TestServerAtCap(t *testing.T) {
func TestServerPeerLimits(t *testing.T) {
srvkey := newkey()
clientkey := newkey()
clientnode := enode.NewV4(&clientkey.PublicKey, nil, 0, 0)
clientid := randomID()
clientnode := &discover.Node{ID: clientid}
var tp *setupTransport = &setupTransport{
id: clientid,
phs: &protoHandshake{
ID: clientid,
var tp = &setupTransport{
pubkey: &clientkey.PublicKey,
phs: protoHandshake{
ID: crypto.FromECDSAPub(&clientkey.PublicKey)[1:],
// Force "DiscUselessPeer" due to unmatching caps
// Caps: []Cap{discard.cap()},
},
}
var flags connFlag = dynDialedConn
var dialDest *discover.Node = &discover.Node{ID: clientid}
srv := &Server{
Config: Config{
@ -440,6 +438,8 @@ func TestServerPeerLimits(t *testing.T) {
defer srv.Stop()
// Check that server is full (MaxPeers=0)
flags := dynDialedConn
dialDest := clientnode
conn, _ := net.Pipe()
srv.SetupConn(conn, flags, dialDest)
if tp.closeErr != DiscTooManyPeers {
@ -473,59 +473,61 @@ func TestServerPeerLimits(t *testing.T) {
}
func TestServerSetupConn(t *testing.T) {
id := randomID()
srvkey := newkey()
srvid := discover.PubkeyID(&srvkey.PublicKey)
var (
clientkey, srvkey = newkey(), newkey()
clientpub = &clientkey.PublicKey
srvpub = &srvkey.PublicKey
)
tests := []struct {
dontstart bool
tt *setupTransport
flags connFlag
dialDest *discover.Node
dialDest *enode.Node
wantCloseErr error
wantCalls string
}{
{
dontstart: true,
tt: &setupTransport{id: id},
tt: &setupTransport{pubkey: clientpub},
wantCalls: "close,",
wantCloseErr: errServerStopped,
},
{
tt: &setupTransport{id: id, encHandshakeErr: errors.New("read error")},
tt: &setupTransport{pubkey: clientpub, encHandshakeErr: errors.New("read error")},
flags: inboundConn,
wantCalls: "doEncHandshake,close,",
wantCloseErr: errors.New("read error"),
},
{
tt: &setupTransport{id: id},
dialDest: &discover.Node{ID: randomID()},
tt: &setupTransport{pubkey: clientpub},
dialDest: enode.NewV4(&newkey().PublicKey, nil, 0, 0),
flags: dynDialedConn,
wantCalls: "doEncHandshake,close,",
wantCloseErr: DiscUnexpectedIdentity,
},
{
tt: &setupTransport{id: id, phs: &protoHandshake{ID: randomID()}},
dialDest: &discover.Node{ID: id},
tt: &setupTransport{pubkey: clientpub, phs: protoHandshake{ID: randomID().Bytes()}},
dialDest: enode.NewV4(clientpub, nil, 0, 0),
flags: dynDialedConn,
wantCalls: "doEncHandshake,doProtoHandshake,close,",
wantCloseErr: DiscUnexpectedIdentity,
},
{
tt: &setupTransport{id: id, protoHandshakeErr: errors.New("foo")},
dialDest: &discover.Node{ID: id},
tt: &setupTransport{pubkey: clientpub, protoHandshakeErr: errors.New("foo")},
dialDest: enode.NewV4(clientpub, nil, 0, 0),
flags: dynDialedConn,
wantCalls: "doEncHandshake,doProtoHandshake,close,",
wantCloseErr: errors.New("foo"),
},
{
tt: &setupTransport{id: srvid, phs: &protoHandshake{ID: srvid}},
tt: &setupTransport{pubkey: srvpub, phs: protoHandshake{ID: crypto.FromECDSAPub(srvpub)[1:]}},
flags: inboundConn,
wantCalls: "doEncHandshake,close,",
wantCloseErr: DiscSelf,
},
{
tt: &setupTransport{id: id, phs: &protoHandshake{ID: id}},
tt: &setupTransport{pubkey: clientpub, phs: protoHandshake{ID: crypto.FromECDSAPub(clientpub)[1:]}},
flags: inboundConn,
wantCalls: "doEncHandshake,doProtoHandshake,close,",
wantCloseErr: DiscUselessPeer,
@ -560,26 +562,26 @@ func TestServerSetupConn(t *testing.T) {
}
type setupTransport struct {
id discover.NodeID
pubkey *ecdsa.PublicKey
encHandshakeErr error
phs *protoHandshake
phs protoHandshake
protoHandshakeErr error
calls string
closeErr error
}
func (c *setupTransport) doEncHandshake(prv *ecdsa.PrivateKey, dialDest *discover.Node) (discover.NodeID, error) {
func (c *setupTransport) doEncHandshake(prv *ecdsa.PrivateKey, dialDest *ecdsa.PublicKey) (*ecdsa.PublicKey, error) {
c.calls += "doEncHandshake,"
return c.id, c.encHandshakeErr
return c.pubkey, c.encHandshakeErr
}
func (c *setupTransport) doProtoHandshake(our *protoHandshake) (*protoHandshake, error) {
c.calls += "doProtoHandshake,"
if c.protoHandshakeErr != nil {
return nil, c.protoHandshakeErr
}
return c.phs, nil
return &c.phs, nil
}
func (c *setupTransport) close(err error) {
c.calls += "close,"
@ -602,7 +604,7 @@ func newkey() *ecdsa.PrivateKey {
return key
}
func randomID() (id discover.NodeID) {
func randomID() (id enode.ID) {
for i := range id {
id[i] = byte(rand.Intn(255))
}