mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
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:
parent
9bf9211c9b
commit
9cd4879228
10 changed files with 531 additions and 489 deletions
100
p2p/dial.go
100
p2p/dial.go
|
|
@ -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
|
||||
|
|
|
|||
439
p2p/dial_test.go
439
p2p/dial_test.go
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
26
p2p/peer.go
26
p2p/peer.go
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
49
p2p/rlpx.go
49
p2p/rlpx.go
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
187
p2p/server.go
187
p2p/server.go
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue