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 (
|
import (
|
||||||
"container/heap"
|
"container/heap"
|
||||||
"crypto/rand"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"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"
|
"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
|
// NodeDialer is used to connect to nodes in the network, typically by using
|
||||||
// an underlying net.Dialer but also using net.Pipe in tests
|
// an underlying net.Dialer but also using net.Pipe in tests
|
||||||
type NodeDialer interface {
|
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
|
// 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
|
// Dial creates a TCP connection to the node
|
||||||
func (t TCPDialer) Dial(dest *discover.Node) (net.Conn, error) {
|
func (t TCPDialer) Dial(dest *enode.Node) (net.Conn, error) {
|
||||||
addr := &net.TCPAddr{IP: dest.IP, Port: int(dest.TCP)}
|
addr := &net.TCPAddr{IP: dest.IP(), Port: dest.TCP()}
|
||||||
return t.Dialer.Dial("tcp", addr.String())
|
return t.Dialer.Dial("tcp", addr.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,22 +73,22 @@ type dialstate struct {
|
||||||
netrestrict *netutil.Netlist
|
netrestrict *netutil.Netlist
|
||||||
|
|
||||||
lookupRunning bool
|
lookupRunning bool
|
||||||
dialing map[discover.NodeID]connFlag
|
dialing map[enode.ID]connFlag
|
||||||
lookupBuf []*discover.Node // current discovery lookup results
|
lookupBuf []*enode.Node // current discovery lookup results
|
||||||
randomNodes []*discover.Node // filled from Table
|
randomNodes []*enode.Node // filled from Table
|
||||||
static map[discover.NodeID]*dialTask
|
static map[enode.ID]*dialTask
|
||||||
hist *dialHistory
|
hist *dialHistory
|
||||||
|
|
||||||
start time.Time // time when the dialer was first used
|
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 {
|
type discoverTable interface {
|
||||||
Self() *discover.Node
|
Self() *enode.Node
|
||||||
Close()
|
Close()
|
||||||
Resolve(target discover.NodeID) *discover.Node
|
Resolve(*enode.Node) *enode.Node
|
||||||
Lookup(target discover.NodeID) []*discover.Node
|
LookupRandom() []*enode.Node
|
||||||
ReadRandomNodes([]*discover.Node) int
|
ReadRandomNodes([]*enode.Node) int
|
||||||
}
|
}
|
||||||
|
|
||||||
// the dial history remembers recent dials.
|
// the dial history remembers recent dials.
|
||||||
|
|
@ -97,7 +96,7 @@ type dialHistory []pastDial
|
||||||
|
|
||||||
// pastDial is an entry in the dial history.
|
// pastDial is an entry in the dial history.
|
||||||
type pastDial struct {
|
type pastDial struct {
|
||||||
id discover.NodeID
|
id enode.ID
|
||||||
exp time.Time
|
exp time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,7 +108,7 @@ type task interface {
|
||||||
// fields cannot be accessed while the task is running.
|
// fields cannot be accessed while the task is running.
|
||||||
type dialTask struct {
|
type dialTask struct {
|
||||||
flags connFlag
|
flags connFlag
|
||||||
dest *discover.Node
|
dest *enode.Node
|
||||||
lastResolved time.Time
|
lastResolved time.Time
|
||||||
resolveDelay time.Duration
|
resolveDelay time.Duration
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +117,7 @@ type dialTask struct {
|
||||||
// Only one discoverTask is active at any time.
|
// Only one discoverTask is active at any time.
|
||||||
// discoverTask.Do performs a random lookup.
|
// discoverTask.Do performs a random lookup.
|
||||||
type discoverTask struct {
|
type discoverTask struct {
|
||||||
results []*discover.Node
|
results []*enode.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// A waitExpireTask is generated if there are no other tasks
|
// A waitExpireTask is generated if there are no other tasks
|
||||||
|
|
@ -127,15 +126,15 @@ type waitExpireTask struct {
|
||||||
time.Duration
|
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{
|
s := &dialstate{
|
||||||
maxDynDials: maxdyn,
|
maxDynDials: maxdyn,
|
||||||
ntab: ntab,
|
ntab: ntab,
|
||||||
netrestrict: netrestrict,
|
netrestrict: netrestrict,
|
||||||
static: make(map[discover.NodeID]*dialTask),
|
static: make(map[enode.ID]*dialTask),
|
||||||
dialing: make(map[discover.NodeID]connFlag),
|
dialing: make(map[enode.ID]connFlag),
|
||||||
bootnodes: make([]*discover.Node, len(bootnodes)),
|
bootnodes: make([]*enode.Node, len(bootnodes)),
|
||||||
randomNodes: make([]*discover.Node, maxdyn/2),
|
randomNodes: make([]*enode.Node, maxdyn/2),
|
||||||
hist: new(dialHistory),
|
hist: new(dialHistory),
|
||||||
}
|
}
|
||||||
copy(s.bootnodes, bootnodes)
|
copy(s.bootnodes, bootnodes)
|
||||||
|
|
@ -145,32 +144,32 @@ func newDialState(static []*discover.Node, bootnodes []*discover.Node, ntab disc
|
||||||
return s
|
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
|
// This overwrites the task instead of updating an existing
|
||||||
// entry, giving users the opportunity to force a resolve operation.
|
// 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.
|
// 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
|
// This removes a previous dial timestamp so that application
|
||||||
// can force a server to reconnect with chosen peer immediately.
|
// 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() {
|
if s.start.IsZero() {
|
||||||
s.start = now
|
s.start = now
|
||||||
}
|
}
|
||||||
|
|
||||||
var newtasks []task
|
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 {
|
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
|
return false
|
||||||
}
|
}
|
||||||
s.dialing[n.ID] = flag
|
s.dialing[n.ID()] = flag
|
||||||
newtasks = append(newtasks, &dialTask{flags: flag, dest: n})
|
newtasks = append(newtasks, &dialTask{flags: flag, dest: n})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -196,8 +195,8 @@ func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now
|
||||||
err := s.checkDial(t.dest, peers)
|
err := s.checkDial(t.dest, peers)
|
||||||
switch err {
|
switch err {
|
||||||
case errNotWhitelisted, errSelf:
|
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)
|
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)
|
delete(s.static, t.dest.ID())
|
||||||
case nil:
|
case nil:
|
||||||
s.dialing[id] = t.flags
|
s.dialing[id] = t.flags
|
||||||
newtasks = append(newtasks, t)
|
newtasks = append(newtasks, t)
|
||||||
|
|
@ -260,18 +259,18 @@ var (
|
||||||
errNotWhitelisted = errors.New("not contained in netrestrict whitelist")
|
errNotWhitelisted = errors.New("not contained in netrestrict whitelist")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *dialstate) checkDial(n *discover.Node, peers map[discover.NodeID]*Peer) error {
|
func (s *dialstate) checkDial(n *enode.Node, peers map[enode.ID]*Peer) error {
|
||||||
_, dialing := s.dialing[n.ID]
|
_, dialing := s.dialing[n.ID()]
|
||||||
switch {
|
switch {
|
||||||
case dialing:
|
case dialing:
|
||||||
return errAlreadyDialing
|
return errAlreadyDialing
|
||||||
case peers[n.ID] != nil:
|
case peers[n.ID()] != nil:
|
||||||
return errAlreadyConnected
|
return errAlreadyConnected
|
||||||
case s.ntab != nil && n.ID == s.ntab.Self().ID:
|
case s.ntab != nil && n.ID() == s.ntab.Self().ID():
|
||||||
return errSelf
|
return errSelf
|
||||||
case s.netrestrict != nil && !s.netrestrict.Contains(n.IP):
|
case s.netrestrict != nil && !s.netrestrict.Contains(n.IP()):
|
||||||
return errNotWhitelisted
|
return errNotWhitelisted
|
||||||
case s.hist.contains(n.ID):
|
case s.hist.contains(n.ID()):
|
||||||
return errRecentlyDialed
|
return errRecentlyDialed
|
||||||
}
|
}
|
||||||
return nil
|
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) {
|
func (s *dialstate) taskDone(t task, now time.Time) {
|
||||||
switch t := t.(type) {
|
switch t := t.(type) {
|
||||||
case *dialTask:
|
case *dialTask:
|
||||||
s.hist.add(t.dest.ID, now.Add(dialHistoryExpiration))
|
s.hist.add(t.dest.ID(), now.Add(dialHistoryExpiration))
|
||||||
delete(s.dialing, t.dest.ID)
|
delete(s.dialing, t.dest.ID())
|
||||||
case *discoverTask:
|
case *discoverTask:
|
||||||
s.lookupRunning = false
|
s.lookupRunning = false
|
||||||
s.lookupBuf = append(s.lookupBuf, t.results...)
|
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 {
|
if time.Since(t.lastResolved) < t.resolveDelay {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
resolved := srv.ntab.Resolve(t.dest.ID)
|
resolved := srv.ntab.Resolve(t.dest)
|
||||||
t.lastResolved = time.Now()
|
t.lastResolved = time.Now()
|
||||||
if resolved == nil {
|
if resolved == nil {
|
||||||
t.resolveDelay *= 2
|
t.resolveDelay *= 2
|
||||||
|
|
@ -336,7 +335,7 @@ func (t *dialTask) resolve(srv *Server) bool {
|
||||||
// The node was found.
|
// The node was found.
|
||||||
t.resolveDelay = initialResolveDelay
|
t.resolveDelay = initialResolveDelay
|
||||||
t.dest = resolved
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -345,7 +344,7 @@ type dialError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// dial performs the actual connection attempt.
|
// 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)
|
fd, err := srv.Dialer.Dial(dest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &dialError{err}
|
return &dialError{err}
|
||||||
|
|
@ -355,7 +354,8 @@ func (t *dialTask) dial(srv *Server, dest *discover.Node) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dialTask) String() string {
|
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) {
|
func (t *discoverTask) Do(srv *Server) {
|
||||||
|
|
@ -367,9 +367,7 @@ func (t *discoverTask) Do(srv *Server) {
|
||||||
time.Sleep(next.Sub(now))
|
time.Sleep(next.Sub(now))
|
||||||
}
|
}
|
||||||
srv.lastLookup = time.Now()
|
srv.lastLookup = time.Now()
|
||||||
var target discover.NodeID
|
t.results = srv.ntab.LookupRandom()
|
||||||
rand.Read(target[:])
|
|
||||||
t.results = srv.ntab.Lookup(target)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *discoverTask) String() string {
|
func (t *discoverTask) String() string {
|
||||||
|
|
@ -391,11 +389,11 @@ func (t waitExpireTask) String() string {
|
||||||
func (h dialHistory) min() pastDial {
|
func (h dialHistory) min() pastDial {
|
||||||
return h[0]
|
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})
|
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 {
|
for i, v := range *h {
|
||||||
if v.id == id {
|
if v.id == id {
|
||||||
heap.Remove(h, i)
|
heap.Remove(h, i)
|
||||||
|
|
@ -404,7 +402,7 @@ func (h *dialHistory) remove(id discover.NodeID) bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
func (h dialHistory) contains(id discover.NodeID) bool {
|
func (h dialHistory) contains(id enode.ID) bool {
|
||||||
for _, v := range h {
|
for _, v := range h {
|
||||||
if v.id == id {
|
if v.id == id {
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
439
p2p/dial_test.go
439
p2p/dial_test.go
|
|
@ -24,7 +24,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"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"
|
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -48,10 +49,10 @@ func runDialTest(t *testing.T, test dialtest) {
|
||||||
vtime time.Time
|
vtime time.Time
|
||||||
running int
|
running int
|
||||||
)
|
)
|
||||||
pm := func(ps []*Peer) map[discover.NodeID]*Peer {
|
pm := func(ps []*Peer) map[enode.ID]*Peer {
|
||||||
m := make(map[discover.NodeID]*Peer)
|
m := make(map[enode.ID]*Peer)
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
m[p.rw.id] = p
|
m[p.ID()] = p
|
||||||
}
|
}
|
||||||
return m
|
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",
|
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))
|
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.
|
// Time advances by 16 seconds on every round.
|
||||||
vtime = vtime.Add(16 * time.Second)
|
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) Close() {}
|
||||||
func (t fakeTable) Lookup(discover.NodeID) []*discover.Node { return nil }
|
func (t fakeTable) LookupRandom() []*enode.Node { return nil }
|
||||||
func (t fakeTable) Resolve(discover.NodeID) *discover.Node { return nil }
|
func (t fakeTable) Resolve(*enode.Node) *enode.Node { return nil }
|
||||||
func (t fakeTable) ReadRandomNodes(buf []*discover.Node) int { return copy(buf, t) }
|
func (t fakeTable) ReadRandomNodes(buf []*enode.Node) int { return copy(buf, t) }
|
||||||
|
|
||||||
// This test checks that dynamic dials are launched from discovery results.
|
// This test checks that dynamic dials are launched from discovery results.
|
||||||
func TestDialStateDynDial(t *testing.T) {
|
func TestDialStateDynDial(t *testing.T) {
|
||||||
|
|
@ -92,63 +94,63 @@ func TestDialStateDynDial(t *testing.T) {
|
||||||
// A discovery query is launched.
|
// A discovery query is launched.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
},
|
},
|
||||||
new: []task{&discoverTask{}},
|
new: []task{&discoverTask{}},
|
||||||
},
|
},
|
||||||
// Dynamic dials are launched when it completes.
|
// Dynamic dials are launched when it completes.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
done: []task{
|
||||||
&discoverTask{results: []*discover.Node{
|
&discoverTask{results: []*enode.Node{
|
||||||
{ID: uintID(2)}, // this one is already connected and not dialed.
|
newNode(uintID(2), nil), // this one is already connected and not dialed.
|
||||||
{ID: uintID(3)},
|
newNode(uintID(3), nil),
|
||||||
{ID: uintID(4)},
|
newNode(uintID(4), nil),
|
||||||
{ID: uintID(5)},
|
newNode(uintID(5), nil),
|
||||||
{ID: uintID(6)}, // these are not tried because max dyn dials is 5
|
newNode(uintID(6), nil), // these are not tried because max dyn dials is 5
|
||||||
{ID: uintID(7)}, // ...
|
newNode(uintID(7), nil), // ...
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
new: []task{
|
new: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Some of the dials complete but no new ones are launched yet because
|
// 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.
|
// the sum of active dial count and dynamic peer count is == maxDynDials.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(3), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// No new dial tasks are launched in the this round because
|
// No new dial tasks are launched in the this round because
|
||||||
// maxDynDials has been reached.
|
// maxDynDials has been reached.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(3), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
|
||||||
},
|
},
|
||||||
new: []task{
|
new: []task{
|
||||||
&waitExpireTask{Duration: 14 * time.Second},
|
&waitExpireTask{Duration: 14 * time.Second},
|
||||||
|
|
@ -158,14 +160,14 @@ func TestDialStateDynDial(t *testing.T) {
|
||||||
// results from last discovery lookup are reused.
|
// results from last discovery lookup are reused.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(3), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}},
|
||||||
},
|
},
|
||||||
new: []task{
|
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.
|
// 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.
|
// and a new one is spawned because more candidates are needed.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(6), nil)},
|
||||||
},
|
},
|
||||||
new: []task{
|
new: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(7), nil)},
|
||||||
&discoverTask{},
|
&discoverTask{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -190,23 +192,23 @@ func TestDialStateDynDial(t *testing.T) {
|
||||||
// no new is started.
|
// no new is started.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(7)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(7), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
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
|
// Finish the running node discovery with an empty set. A new lookup
|
||||||
// should be immediately requested.
|
// should be immediately requested.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(7)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(7), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
done: []task{
|
||||||
&discoverTask{},
|
&discoverTask{},
|
||||||
|
|
@ -221,17 +223,17 @@ func TestDialStateDynDial(t *testing.T) {
|
||||||
|
|
||||||
// Tests that bootnodes are dialed if no peers are connectd, but not otherwise.
|
// Tests that bootnodes are dialed if no peers are connectd, but not otherwise.
|
||||||
func TestDialStateDynDialBootnode(t *testing.T) {
|
func TestDialStateDynDialBootnode(t *testing.T) {
|
||||||
bootnodes := []*discover.Node{
|
bootnodes := []*enode.Node{
|
||||||
{ID: uintID(1)},
|
newNode(uintID(1), nil),
|
||||||
{ID: uintID(2)},
|
newNode(uintID(2), nil),
|
||||||
{ID: uintID(3)},
|
newNode(uintID(3), nil),
|
||||||
}
|
}
|
||||||
table := fakeTable{
|
table := fakeTable{
|
||||||
{ID: uintID(4)},
|
newNode(uintID(4), nil),
|
||||||
{ID: uintID(5)},
|
newNode(uintID(5), nil),
|
||||||
{ID: uintID(6)},
|
newNode(uintID(6), nil),
|
||||||
{ID: uintID(7)},
|
newNode(uintID(7), nil),
|
||||||
{ID: uintID(8)},
|
newNode(uintID(8), nil),
|
||||||
}
|
}
|
||||||
runDialTest(t, dialtest{
|
runDialTest(t, dialtest{
|
||||||
init: newDialState(nil, bootnodes, table, 5, nil),
|
init: newDialState(nil, bootnodes, table, 5, nil),
|
||||||
|
|
@ -239,16 +241,16 @@ func TestDialStateDynDialBootnode(t *testing.T) {
|
||||||
// 2 dynamic dials attempted, bootnodes pending fallback interval
|
// 2 dynamic dials attempted, bootnodes pending fallback interval
|
||||||
{
|
{
|
||||||
new: []task{
|
new: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
|
||||||
&discoverTask{},
|
&discoverTask{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// No dials succeed, bootnodes still pending fallback interval
|
// No dials succeed, bootnodes still pending fallback interval
|
||||||
{
|
{
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// No dials succeed, bootnodes still pending fallback interval
|
// 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
|
// No dials succeed, 2 dynamic dials attempted and 1 bootnode too as fallback interval was reached
|
||||||
{
|
{
|
||||||
new: []task{
|
new: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// No dials succeed, 2nd bootnode is attempted
|
// No dials succeed, 2nd bootnode is attempted
|
||||||
{
|
{
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
|
||||||
},
|
},
|
||||||
new: []task{
|
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
|
// No dials succeed, 3rd bootnode is attempted
|
||||||
{
|
{
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)},
|
||||||
},
|
},
|
||||||
new: []task{
|
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
|
// No dials succeed, 1st bootnode is attempted again, expired random nodes retried
|
||||||
{
|
{
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
|
||||||
},
|
},
|
||||||
new: []task{
|
new: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Random dial succeeds, no more bootnodes are attempted
|
// Random dial succeeds, no more bootnodes are attempted
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
|
&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
|
// This table always returns the same random nodes
|
||||||
// in the order given below.
|
// in the order given below.
|
||||||
table := fakeTable{
|
table := fakeTable{
|
||||||
{ID: uintID(1)},
|
newNode(uintID(1), nil),
|
||||||
{ID: uintID(2)},
|
newNode(uintID(2), nil),
|
||||||
{ID: uintID(3)},
|
newNode(uintID(3), nil),
|
||||||
{ID: uintID(4)},
|
newNode(uintID(4), nil),
|
||||||
{ID: uintID(5)},
|
newNode(uintID(5), nil),
|
||||||
{ID: uintID(6)},
|
newNode(uintID(6), nil),
|
||||||
{ID: uintID(7)},
|
newNode(uintID(7), nil),
|
||||||
{ID: uintID(8)},
|
newNode(uintID(8), nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
runDialTest(t, dialtest{
|
runDialTest(t, dialtest{
|
||||||
|
|
@ -327,63 +329,63 @@ func TestDialStateDynDialFromTable(t *testing.T) {
|
||||||
// 5 out of 8 of the nodes returned by ReadRandomNodes are dialed.
|
// 5 out of 8 of the nodes returned by ReadRandomNodes are dialed.
|
||||||
{
|
{
|
||||||
new: []task{
|
new: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
|
||||||
&discoverTask{},
|
&discoverTask{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Dialing nodes 1,2 succeeds. Dials from the lookup are launched.
|
// Dialing nodes 1,2 succeeds. Dials from the lookup are launched.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)},
|
||||||
&discoverTask{results: []*discover.Node{
|
&discoverTask{results: []*enode.Node{
|
||||||
{ID: uintID(10)},
|
newNode(uintID(10), nil),
|
||||||
{ID: uintID(11)},
|
newNode(uintID(11), nil),
|
||||||
{ID: uintID(12)},
|
newNode(uintID(12), nil),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
new: []task{
|
new: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(10), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(11), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(12), nil)},
|
||||||
&discoverTask{},
|
&discoverTask{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Dialing nodes 3,4,5 fails. The dials from the lookup succeed.
|
// Dialing nodes 3,4,5 fails. The dials from the lookup succeed.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(10), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(11), nil)},
|
||||||
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
|
&dialTask{flags: dynDialedConn, dest: newNode(uintID(12), nil)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Waiting for expiry. No waitExpireTask is launched because the
|
// Waiting for expiry. No waitExpireTask is launched because the
|
||||||
// discovery query is still running.
|
// discovery query is still running.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Nodes 3,4 are not tried again because only the first two
|
// Nodes 3,4 are not tried again because only the first two
|
||||||
|
|
@ -391,30 +393,38 @@ func TestDialStateDynDialFromTable(t *testing.T) {
|
||||||
// already connected.
|
// already connected.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
|
{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.
|
// This test checks that candidates that do not match the netrestrict list are not dialed.
|
||||||
func TestDialStateNetRestrict(t *testing.T) {
|
func TestDialStateNetRestrict(t *testing.T) {
|
||||||
// This table always returns the same random nodes
|
// This table always returns the same random nodes
|
||||||
// in the order given below.
|
// in the order given below.
|
||||||
table := fakeTable{
|
table := fakeTable{
|
||||||
{ID: uintID(1), IP: net.ParseIP("127.0.0.1")},
|
newNode(uintID(1), net.ParseIP("127.0.0.1")),
|
||||||
{ID: uintID(2), IP: net.ParseIP("127.0.0.2")},
|
newNode(uintID(2), net.ParseIP("127.0.0.2")),
|
||||||
{ID: uintID(3), IP: net.ParseIP("127.0.0.3")},
|
newNode(uintID(3), net.ParseIP("127.0.0.3")),
|
||||||
{ID: uintID(4), IP: net.ParseIP("127.0.0.4")},
|
newNode(uintID(4), net.ParseIP("127.0.0.4")),
|
||||||
{ID: uintID(5), IP: net.ParseIP("127.0.2.5")},
|
newNode(uintID(5), net.ParseIP("127.0.2.5")),
|
||||||
{ID: uintID(6), IP: net.ParseIP("127.0.2.6")},
|
newNode(uintID(6), net.ParseIP("127.0.2.6")),
|
||||||
{ID: uintID(7), IP: net.ParseIP("127.0.2.7")},
|
newNode(uintID(7), net.ParseIP("127.0.2.7")),
|
||||||
{ID: uintID(8), IP: net.ParseIP("127.0.2.8")},
|
newNode(uintID(8), net.ParseIP("127.0.2.8")),
|
||||||
}
|
}
|
||||||
restrict := new(netutil.Netlist)
|
restrict := new(netutil.Netlist)
|
||||||
restrict.Add("127.0.2.0/24")
|
restrict.Add("127.0.2.0/24")
|
||||||
|
|
@ -434,12 +444,12 @@ func TestDialStateNetRestrict(t *testing.T) {
|
||||||
|
|
||||||
// This test checks that static dials are launched.
|
// This test checks that static dials are launched.
|
||||||
func TestDialStateStaticDial(t *testing.T) {
|
func TestDialStateStaticDial(t *testing.T) {
|
||||||
wantStatic := []*discover.Node{
|
wantStatic := []*enode.Node{
|
||||||
{ID: uintID(1)},
|
newNode(uintID(1), nil),
|
||||||
{ID: uintID(2)},
|
newNode(uintID(2), nil),
|
||||||
{ID: uintID(3)},
|
newNode(uintID(3), nil),
|
||||||
{ID: uintID(4)},
|
newNode(uintID(4), nil),
|
||||||
{ID: uintID(5)},
|
newNode(uintID(5), nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
runDialTest(t, dialtest{
|
runDialTest(t, dialtest{
|
||||||
|
|
@ -449,40 +459,40 @@ func TestDialStateStaticDial(t *testing.T) {
|
||||||
// aren't yet connected.
|
// aren't yet connected.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
},
|
},
|
||||||
new: []task{
|
new: []task{
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)},
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(4), nil)},
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(5), nil)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// No new tasks are launched in this round because all static
|
// No new tasks are launched in this round because all static
|
||||||
// nodes are either connected or still being dialed.
|
// nodes are either connected or still being dialed.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
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
|
// No new dial tasks are launched because all static
|
||||||
// nodes are now connected.
|
// nodes are now connected.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}},
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(4)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(4), nil)}},
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(5), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(4), nil)},
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(5), nil)},
|
||||||
},
|
},
|
||||||
new: []task{
|
new: []task{
|
||||||
&waitExpireTask{Duration: 14 * time.Second},
|
&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.
|
// Wait a round for dial history to expire, no new tasks should spawn.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}},
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(4)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(4), nil)}},
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(5), nil)}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// If a static node is dropped, it should be immediately redialed,
|
// If a static node is dropped, it should be immediately redialed,
|
||||||
// irrespective whether it was originally static or dynamic.
|
// irrespective whether it was originally static or dynamic.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}},
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(5), nil)}},
|
||||||
},
|
},
|
||||||
new: []task{
|
new: []task{
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)},
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
|
&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.
|
// This test checks that static peers will be redialed immediately if they were re-added to a static list.
|
||||||
func TestDialStaticAfterReset(t *testing.T) {
|
func TestDialStaticAfterReset(t *testing.T) {
|
||||||
wantStatic := []*discover.Node{
|
wantStatic := []*enode.Node{
|
||||||
{ID: uintID(1)},
|
newNode(uintID(1), nil),
|
||||||
{ID: uintID(2)},
|
newNode(uintID(2), nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
rounds := []round{
|
rounds := []round{
|
||||||
|
|
@ -527,19 +537,19 @@ func TestDialStaticAfterReset(t *testing.T) {
|
||||||
{
|
{
|
||||||
peers: nil,
|
peers: nil,
|
||||||
new: []task{
|
new: []task{
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)},
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// No new dial tasks, all peers are connected.
|
// No new dial tasks, all peers are connected.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)},
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)},
|
||||||
},
|
},
|
||||||
new: []task{
|
new: []task{
|
||||||
&waitExpireTask{Duration: 30 * time.Second},
|
&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.
|
// This test checks that past dials are not retried for some time.
|
||||||
func TestDialStateCache(t *testing.T) {
|
func TestDialStateCache(t *testing.T) {
|
||||||
wantStatic := []*discover.Node{
|
wantStatic := []*enode.Node{
|
||||||
{ID: uintID(1)},
|
newNode(uintID(1), nil),
|
||||||
{ID: uintID(2)},
|
newNode(uintID(2), nil),
|
||||||
{ID: uintID(3)},
|
newNode(uintID(3), nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
runDialTest(t, dialtest{
|
runDialTest(t, dialtest{
|
||||||
|
|
@ -575,32 +585,32 @@ func TestDialStateCache(t *testing.T) {
|
||||||
{
|
{
|
||||||
peers: nil,
|
peers: nil,
|
||||||
new: []task{
|
new: []task{
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)},
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)},
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// No new tasks are launched in this round because all static
|
// No new tasks are launched in this round because all static
|
||||||
// nodes are either connected or still being dialed.
|
// nodes are either connected or still being dialed.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: staticDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: staticDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)},
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// A salvage task is launched to wait for node 3's history
|
// A salvage task is launched to wait for node 3's history
|
||||||
// entry to expire.
|
// entry to expire.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
},
|
},
|
||||||
done: []task{
|
done: []task{
|
||||||
&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
|
&dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)},
|
||||||
},
|
},
|
||||||
new: []task{
|
new: []task{
|
||||||
&waitExpireTask{Duration: 14 * time.Second},
|
&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.
|
// Still waiting for node 3's entry to expire in the cache.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// The cache entry for node 3 has expired and is retried.
|
// The cache entry for node 3 has expired and is retried.
|
||||||
{
|
{
|
||||||
peers: []*Peer{
|
peers: []*Peer{
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
|
||||||
{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
|
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
|
||||||
},
|
},
|
||||||
new: []task{
|
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) {
|
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}
|
table := &resolveMock{answer: resolved}
|
||||||
state := newDialState(nil, nil, table, 0, nil)
|
state := newDialState(nil, nil, table, 0, nil)
|
||||||
|
|
||||||
// Check that the task is generated with an incomplete ID.
|
// 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)
|
state.addStatic(dest)
|
||||||
tasks := state.newTasks(0, nil, time.Time{})
|
tasks := state.newTasks(0, nil, time.Time{})
|
||||||
if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest}}) {
|
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)}}}
|
config := Config{Dialer: TCPDialer{&net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}}}
|
||||||
srv := &Server{ntab: table, Config: config}
|
srv := &Server{ntab: table, Config: config}
|
||||||
tasks[0].Do(srv)
|
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)
|
t.Fatalf("wrong resolve calls, got %v", table.resolveCalls)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -672,25 +682,24 @@ next:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func uintID(i uint32) discover.NodeID {
|
func uintID(i uint32) enode.ID {
|
||||||
var id discover.NodeID
|
var id enode.ID
|
||||||
binary.BigEndian.PutUint32(id[:], i)
|
binary.BigEndian.PutUint32(id[:], i)
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements discoverTable for TestDialResolve
|
// implements discoverTable for TestDialResolve
|
||||||
type resolveMock struct {
|
type resolveMock struct {
|
||||||
resolveCalls []discover.NodeID
|
resolveCalls []*enode.Node
|
||||||
answer *discover.Node
|
answer *enode.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *resolveMock) Resolve(id discover.NodeID) *discover.Node {
|
func (t *resolveMock) Resolve(n *enode.Node) *enode.Node {
|
||||||
t.resolveCalls = append(t.resolveCalls, id)
|
t.resolveCalls = append(t.resolveCalls, n)
|
||||||
return t.answer
|
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) Close() {}
|
||||||
func (t *resolveMock) Bootstrap([]*discover.Node) {}
|
func (t *resolveMock) LookupRandom() []*enode.Node { return nil }
|
||||||
func (t *resolveMock) Lookup(discover.NodeID) []*discover.Node { return nil }
|
func (t *resolveMock) ReadRandomNodes(buf []*enode.Node) int { return 0 }
|
||||||
func (t *resolveMock) ReadRandomNodes(buf []*discover.Node) int { return 0 }
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"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"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -253,13 +253,13 @@ type msgEventer struct {
|
||||||
MsgReadWriter
|
MsgReadWriter
|
||||||
|
|
||||||
feed *event.Feed
|
feed *event.Feed
|
||||||
peerID discover.NodeID
|
peerID enode.ID
|
||||||
Protocol string
|
Protocol string
|
||||||
}
|
}
|
||||||
|
|
||||||
// newMsgEventer returns a msgEventer which sends message events to the given
|
// newMsgEventer returns a msgEventer which sends message events to the given
|
||||||
// feed
|
// 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{
|
return &msgEventer{
|
||||||
MsgReadWriter: rw,
|
MsgReadWriter: rw,
|
||||||
feed: feed,
|
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/common/mclock"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"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"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -60,7 +61,7 @@ type protoHandshake struct {
|
||||||
Name string
|
Name string
|
||||||
Caps []Cap
|
Caps []Cap
|
||||||
ListenPort uint64
|
ListenPort uint64
|
||||||
ID discover.NodeID
|
ID []byte // secp256k1 public key
|
||||||
|
|
||||||
// Ignore additional fields (for forward compatibility).
|
// Ignore additional fields (for forward compatibility).
|
||||||
Rest []rlp.RawValue `rlp:"tail"`
|
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
|
// a p2p.Server or when a message is sent or received on a peer connection
|
||||||
type PeerEvent struct {
|
type PeerEvent struct {
|
||||||
Type PeerEventType `json:"type"`
|
Type PeerEventType `json:"type"`
|
||||||
Peer discover.NodeID `json:"peer"`
|
Peer enode.ID `json:"peer"`
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
Protocol string `json:"protocol,omitempty"`
|
Protocol string `json:"protocol,omitempty"`
|
||||||
MsgCode *uint64 `json:"msg_code,omitempty"`
|
MsgCode *uint64 `json:"msg_code,omitempty"`
|
||||||
|
|
@ -115,17 +116,23 @@ type Peer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPeer returns a peer for testing purposes.
|
// 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()
|
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)
|
peer := newPeer(conn, nil)
|
||||||
close(peer.closed) // ensures Disconnect doesn't block
|
close(peer.closed) // ensures Disconnect doesn't block
|
||||||
return peer
|
return peer
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID returns the node's public key.
|
// ID returns the node's public key.
|
||||||
func (p *Peer) ID() discover.NodeID {
|
func (p *Peer) ID() enode.ID {
|
||||||
return p.rw.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.
|
// Name returns the node name that the remote node advertised.
|
||||||
|
|
@ -160,7 +167,8 @@ func (p *Peer) Disconnect(reason DiscReason) {
|
||||||
|
|
||||||
// String implements fmt.Stringer.
|
// String implements fmt.Stringer.
|
||||||
func (p *Peer) String() string {
|
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
|
// 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),
|
disc: make(chan DiscReason),
|
||||||
protoErr: make(chan error, len(protomap)+1), // protocols + pingLoop
|
protoErr: make(chan error, len(protomap)+1), // protocols + pingLoop
|
||||||
closed: make(chan struct{}),
|
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
|
return p
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,8 @@ var discard = Protocol{
|
||||||
|
|
||||||
func testPeer(protos []Protocol) (func(), *conn, *Peer, <-chan error) {
|
func testPeer(protos []Protocol) (func(), *conn, *Peer, <-chan error) {
|
||||||
fd1, fd2 := net.Pipe()
|
fd1, fd2 := net.Pipe()
|
||||||
c1 := &conn{fd: fd1, transport: newTestTransport(randomID(), fd1)}
|
c1 := &conn{fd: fd1, node: newNode(randomID(), nil), transport: newTestTransport(&newkey().PublicKey, fd1)}
|
||||||
c2 := &conn{fd: fd2, transport: newTestTransport(randomID(), fd2)}
|
c2 := &conn{fd: fd2, node: newNode(randomID(), nil), transport: newTestTransport(&newkey().PublicKey, fd2)}
|
||||||
for _, p := range protos {
|
for _, p := range protos {
|
||||||
c1.caps = append(c1.caps, p.cap())
|
c1.caps = append(c1.caps, p.cap())
|
||||||
c2.caps = append(c2.caps, p.cap())
|
c2.caps = append(c2.caps, p.cap())
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ package p2p
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Protocol represents a P2P subprotocol implementation.
|
// Protocol represents a P2P subprotocol implementation.
|
||||||
|
|
@ -51,7 +51,7 @@ type Protocol struct {
|
||||||
// PeerInfo is an optional helper method to retrieve protocol specific metadata
|
// 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,
|
// 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.
|
// 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 {
|
func (p Protocol) cap() Cap {
|
||||||
|
|
|
||||||
49
p2p/rlpx.go
49
p2p/rlpx.go
|
|
@ -35,11 +35,11 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/bitutil"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/ecies"
|
"github.com/ethereum/go-ethereum/crypto/ecies"
|
||||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/golang/snappy"
|
"github.com/golang/snappy"
|
||||||
)
|
)
|
||||||
|
|
@ -165,7 +165,7 @@ func readProtocolHandshake(rw MsgReader, our *protoHandshake) (*protoHandshake,
|
||||||
if err := msg.Decode(&hs); err != nil {
|
if err := msg.Decode(&hs); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if (hs.ID == discover.NodeID{}) {
|
if len(hs.ID) != 64 || !bitutil.TestBytes(hs.ID) {
|
||||||
return nil, DiscInvalidIdentity
|
return nil, DiscInvalidIdentity
|
||||||
}
|
}
|
||||||
return &hs, nil
|
return &hs, nil
|
||||||
|
|
@ -175,7 +175,7 @@ func readProtocolHandshake(rw MsgReader, our *protoHandshake) (*protoHandshake,
|
||||||
// messages. the protocol handshake is the first authenticated message
|
// messages. the protocol handshake is the first authenticated message
|
||||||
// and also verifies whether the encryption handshake 'worked' and the
|
// and also verifies whether the encryption handshake 'worked' and the
|
||||||
// remote side actually provided the right public key.
|
// 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 (
|
var (
|
||||||
sec secrets
|
sec secrets
|
||||||
err error
|
err error
|
||||||
|
|
@ -183,23 +183,21 @@ func (t *rlpx) doEncHandshake(prv *ecdsa.PrivateKey, dial *discover.Node) (disco
|
||||||
if dial == nil {
|
if dial == nil {
|
||||||
sec, err = receiverEncHandshake(t.fd, prv)
|
sec, err = receiverEncHandshake(t.fd, prv)
|
||||||
} else {
|
} else {
|
||||||
sec, err = initiatorEncHandshake(t.fd, prv, dial.ID)
|
sec, err = initiatorEncHandshake(t.fd, prv, dial)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return discover.NodeID{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t.wmu.Lock()
|
t.wmu.Lock()
|
||||||
t.rw = newRLPXFrameRW(t.fd, sec)
|
t.rw = newRLPXFrameRW(t.fd, sec)
|
||||||
t.wmu.Unlock()
|
t.wmu.Unlock()
|
||||||
return sec.RemoteID, nil
|
return sec.Remote.ExportECDSA(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// encHandshake contains the state of the encryption handshake.
|
// encHandshake contains the state of the encryption handshake.
|
||||||
type encHandshake struct {
|
type encHandshake struct {
|
||||||
initiator bool
|
initiator bool
|
||||||
remoteID discover.NodeID
|
remote *ecies.PublicKey // remote-pubk
|
||||||
|
|
||||||
remotePub *ecies.PublicKey // remote-pubk
|
|
||||||
initNonce, respNonce []byte // nonce
|
initNonce, respNonce []byte // nonce
|
||||||
randomPrivKey *ecies.PrivateKey // ecdhe-random
|
randomPrivKey *ecies.PrivateKey // ecdhe-random
|
||||||
remoteRandomPub *ecies.PublicKey // ecdhe-random-pubk
|
remoteRandomPub *ecies.PublicKey // ecdhe-random-pubk
|
||||||
|
|
@ -208,7 +206,7 @@ type encHandshake struct {
|
||||||
// secrets represents the connection secrets
|
// secrets represents the connection secrets
|
||||||
// which are negotiated during the encryption handshake.
|
// which are negotiated during the encryption handshake.
|
||||||
type secrets struct {
|
type secrets struct {
|
||||||
RemoteID discover.NodeID
|
Remote *ecies.PublicKey
|
||||||
AES, MAC []byte
|
AES, MAC []byte
|
||||||
EgressMAC, IngressMAC hash.Hash
|
EgressMAC, IngressMAC hash.Hash
|
||||||
Token []byte
|
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))
|
sharedSecret := crypto.Keccak256(ecdheSecret, crypto.Keccak256(h.respNonce, h.initNonce))
|
||||||
aesSecret := crypto.Keccak256(ecdheSecret, sharedSecret)
|
aesSecret := crypto.Keccak256(ecdheSecret, sharedSecret)
|
||||||
s := secrets{
|
s := secrets{
|
||||||
RemoteID: h.remoteID,
|
Remote: h.remote,
|
||||||
AES: aesSecret,
|
AES: aesSecret,
|
||||||
MAC: crypto.Keccak256(ecdheSecret, 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
|
// staticSharedSecret returns the static shared secret, the result
|
||||||
// of key agreement between the local and remote static node key.
|
// of key agreement between the local and remote static node key.
|
||||||
func (h *encHandshake) staticSharedSecret(prv *ecdsa.PrivateKey) ([]byte, error) {
|
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.
|
// initiatorEncHandshake negotiates a session token on conn.
|
||||||
// it should be called on the dialing side of the connection.
|
// it should be called on the dialing side of the connection.
|
||||||
//
|
//
|
||||||
// prv is the local client's private key.
|
// prv is the local client's private key.
|
||||||
func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remoteID discover.NodeID) (s secrets, err error) {
|
func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remote *ecdsa.PublicKey) (s secrets, err error) {
|
||||||
h := &encHandshake{initiator: true, remoteID: remoteID}
|
h := &encHandshake{initiator: true, remote: ecies.ImportECDSAPublic(remote)}
|
||||||
authMsg, err := h.makeAuthMsg(prv)
|
authMsg, err := h.makeAuthMsg(prv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, err
|
return s, err
|
||||||
|
|
@ -307,14 +305,10 @@ func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remoteID d
|
||||||
|
|
||||||
// makeAuthMsg creates the initiator handshake message.
|
// makeAuthMsg creates the initiator handshake message.
|
||||||
func (h *encHandshake) makeAuthMsg(prv *ecdsa.PrivateKey) (*authMsgV4, error) {
|
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.
|
// Generate random initiator nonce.
|
||||||
h.initNonce = make([]byte, shaLen)
|
h.initNonce = make([]byte, shaLen)
|
||||||
if _, err := rand.Read(h.initNonce); err != nil {
|
_, err := rand.Read(h.initNonce)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Generate random keypair to for ECDH.
|
// 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 {
|
func (h *encHandshake) handleAuthMsg(msg *authMsgV4, prv *ecdsa.PrivateKey) error {
|
||||||
// Import the remote identity.
|
// Import the remote identity.
|
||||||
h.initNonce = msg.Nonce[:]
|
rpub, err := importPublicKey(msg.InitiatorPubkey[:])
|
||||||
h.remoteID = msg.InitiatorPubkey
|
|
||||||
rpub, err := h.remoteID.Pubkey()
|
|
||||||
if err != nil {
|
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.
|
// Generate random keypair for ECDH.
|
||||||
// If a private key is already set, use it instead of generating one (for testing).
|
// 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.InitiatorPubkey[:])
|
||||||
n += copy(buf[n:], msg.Nonce[:])
|
n += copy(buf[n:], msg.Nonce[:])
|
||||||
buf[n] = 0 // token-flag
|
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) {
|
func (msg *authMsgV4) decodePlain(input []byte) {
|
||||||
|
|
@ -452,7 +445,7 @@ func (msg *authRespV4) sealPlain(hs *encHandshake) ([]byte, error) {
|
||||||
buf := make([]byte, authRespLen)
|
buf := make([]byte, authRespLen)
|
||||||
n := copy(buf, msg.RandomPubkey[:])
|
n := copy(buf, msg.RandomPubkey[:])
|
||||||
copy(buf[n:], msg.Nonce[:])
|
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) {
|
func (msg *authRespV4) decodePlain(input []byte) {
|
||||||
|
|
@ -475,7 +468,7 @@ func sealEIP8(msg interface{}, h *encHandshake) ([]byte, error) {
|
||||||
prefix := make([]byte, 2)
|
prefix := make([]byte, 2)
|
||||||
binary.BigEndian.PutUint16(prefix, uint16(buf.Len()+eciesOverhead))
|
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
|
return append(prefix, enc...), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package p2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/ecdsa"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -34,7 +35,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/ecies"
|
"github.com/ethereum/go-ethereum/crypto/ecies"
|
||||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
"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/p2p/simulations/pipes"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
@ -81,7 +81,7 @@ func TestEncHandshake(t *testing.T) {
|
||||||
func testEncHandshake(token []byte) error {
|
func testEncHandshake(token []byte) error {
|
||||||
type result struct {
|
type result struct {
|
||||||
side string
|
side string
|
||||||
id discover.NodeID
|
pubkey *ecdsa.PublicKey
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
|
|
@ -97,14 +97,12 @@ func testEncHandshake(token []byte) error {
|
||||||
defer func() { output <- r }()
|
defer func() { output <- r }()
|
||||||
defer fd0.Close()
|
defer fd0.Close()
|
||||||
|
|
||||||
dest := &discover.Node{ID: discover.PubkeyID(&prv1.PublicKey)}
|
r.pubkey, r.err = c0.doEncHandshake(prv0, &prv1.PublicKey)
|
||||||
r.id, r.err = c0.doEncHandshake(prv0, dest)
|
|
||||||
if r.err != nil {
|
if r.err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id1 := discover.PubkeyID(&prv1.PublicKey)
|
if !reflect.DeepEqual(r.pubkey, &prv1.PublicKey) {
|
||||||
if r.id != id1 {
|
r.err = fmt.Errorf("remote pubkey mismatch: got %v, want: %v", r.pubkey, &prv1.PublicKey)
|
||||||
r.err = fmt.Errorf("remote ID mismatch: got %v, want: %v", r.id, id1)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -112,13 +110,12 @@ func testEncHandshake(token []byte) error {
|
||||||
defer func() { output <- r }()
|
defer func() { output <- r }()
|
||||||
defer fd1.Close()
|
defer fd1.Close()
|
||||||
|
|
||||||
r.id, r.err = c1.doEncHandshake(prv1, nil)
|
r.pubkey, r.err = c1.doEncHandshake(prv1, nil)
|
||||||
if r.err != nil {
|
if r.err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id0 := discover.PubkeyID(&prv0.PublicKey)
|
if !reflect.DeepEqual(r.pubkey, &prv0.PublicKey) {
|
||||||
if r.id != id0 {
|
r.err = fmt.Errorf("remote ID mismatch: got %v, want: %v", r.pubkey, &prv0.PublicKey)
|
||||||
r.err = fmt.Errorf("remote ID mismatch: got %v, want: %v", r.id, id0)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
@ -150,12 +147,12 @@ func testEncHandshake(token []byte) error {
|
||||||
func TestProtocolHandshake(t *testing.T) {
|
func TestProtocolHandshake(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
prv0, _ = crypto.GenerateKey()
|
prv0, _ = crypto.GenerateKey()
|
||||||
node0 = &discover.Node{ID: discover.PubkeyID(&prv0.PublicKey), IP: net.IP{1, 2, 3, 4}, TCP: 33}
|
pub0 = crypto.FromECDSAPub(&prv0.PublicKey)[1:]
|
||||||
hs0 = &protoHandshake{Version: 3, ID: node0.ID, Caps: []Cap{{"a", 0}, {"b", 2}}}
|
hs0 = &protoHandshake{Version: 3, ID: pub0, Caps: []Cap{{"a", 0}, {"b", 2}}}
|
||||||
|
|
||||||
prv1, _ = crypto.GenerateKey()
|
prv1, _ = crypto.GenerateKey()
|
||||||
node1 = &discover.Node{ID: discover.PubkeyID(&prv1.PublicKey), IP: net.IP{5, 6, 7, 8}, TCP: 44}
|
pub1 = crypto.FromECDSAPub(&prv1.PublicKey)[1:]
|
||||||
hs1 = &protoHandshake{Version: 3, ID: node1.ID, Caps: []Cap{{"c", 1}, {"d", 3}}}
|
hs1 = &protoHandshake{Version: 3, ID: pub1, Caps: []Cap{{"c", 1}, {"d", 3}}}
|
||||||
|
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
)
|
)
|
||||||
|
|
@ -170,13 +167,13 @@ func TestProtocolHandshake(t *testing.T) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
defer fd0.Close()
|
defer fd0.Close()
|
||||||
rlpx := newRLPX(fd0)
|
rlpx := newRLPX(fd0)
|
||||||
remid, err := rlpx.doEncHandshake(prv0, node1)
|
rpubkey, err := rlpx.doEncHandshake(prv0, &prv1.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("dial side enc handshake failed: %v", err)
|
t.Errorf("dial side enc handshake failed: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if remid != node1.ID {
|
if !reflect.DeepEqual(rpubkey, &prv1.PublicKey) {
|
||||||
t.Errorf("dial side remote id mismatch: got %v, want %v", remid, node1.ID)
|
t.Errorf("dial side remote pubkey mismatch: got %v, want %v", rpubkey, &prv1.PublicKey)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,13 +193,13 @@ func TestProtocolHandshake(t *testing.T) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
defer fd1.Close()
|
defer fd1.Close()
|
||||||
rlpx := newRLPX(fd1)
|
rlpx := newRLPX(fd1)
|
||||||
remid, err := rlpx.doEncHandshake(prv1, nil)
|
rpubkey, err := rlpx.doEncHandshake(prv1, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("listen side enc handshake failed: %v", err)
|
t.Errorf("listen side enc handshake failed: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if remid != node0.ID {
|
if !reflect.DeepEqual(rpubkey, &prv0.PublicKey) {
|
||||||
t.Errorf("listen side remote id mismatch: got %v, want %v", remid, node0.ID)
|
t.Errorf("listen side remote pubkey mismatch: got %v, want %v", rpubkey, &prv0.PublicKey)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
187
p2p/server.go
187
p2p/server.go
|
|
@ -18,6 +18,7 @@
|
||||||
package p2p
|
package p2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -28,10 +29,12 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
"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/nat"
|
||||||
"github.com/ethereum/go-ethereum/p2p/netutil"
|
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||||
)
|
)
|
||||||
|
|
@ -87,7 +90,7 @@ type Config struct {
|
||||||
|
|
||||||
// BootstrapNodes are used to establish connectivity
|
// BootstrapNodes are used to establish connectivity
|
||||||
// with the rest of the network.
|
// with the rest of the network.
|
||||||
BootstrapNodes []*discover.Node
|
BootstrapNodes []*enode.Node
|
||||||
|
|
||||||
// BootstrapNodesV5 are used to establish connectivity
|
// BootstrapNodesV5 are used to establish connectivity
|
||||||
// with the rest of the network using the V5 discovery
|
// 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
|
// Static nodes are used as pre-configured connections which are always
|
||||||
// maintained and re-connected on disconnects.
|
// maintained and re-connected on disconnects.
|
||||||
StaticNodes []*discover.Node
|
StaticNodes []*enode.Node
|
||||||
|
|
||||||
// Trusted nodes are used as pre-configured connections which are always
|
// Trusted nodes are used as pre-configured connections which are always
|
||||||
// allowed to connect, even above the peer limit.
|
// allowed to connect, even above the peer limit.
|
||||||
TrustedNodes []*discover.Node
|
TrustedNodes []*enode.Node
|
||||||
|
|
||||||
// Connectivity can be restricted to certain IP networks.
|
// 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
|
// 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{}
|
peerOpDone chan struct{}
|
||||||
|
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
addstatic chan *discover.Node
|
addstatic chan *enode.Node
|
||||||
removestatic chan *discover.Node
|
removestatic chan *enode.Node
|
||||||
addtrusted chan *discover.Node
|
addtrusted chan *enode.Node
|
||||||
removetrusted chan *discover.Node
|
removetrusted chan *enode.Node
|
||||||
posthandshake chan *conn
|
posthandshake chan *conn
|
||||||
addpeer chan *conn
|
addpeer chan *conn
|
||||||
delpeer chan peerDrop
|
delpeer chan peerDrop
|
||||||
|
|
@ -180,7 +183,7 @@ type Server struct {
|
||||||
log log.Logger
|
log log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type peerOpFunc func(map[discover.NodeID]*Peer)
|
type peerOpFunc func(map[enode.ID]*Peer)
|
||||||
|
|
||||||
type peerDrop struct {
|
type peerDrop struct {
|
||||||
*Peer
|
*Peer
|
||||||
|
|
@ -202,16 +205,16 @@ const (
|
||||||
type conn struct {
|
type conn struct {
|
||||||
fd net.Conn
|
fd net.Conn
|
||||||
transport
|
transport
|
||||||
|
node *enode.Node
|
||||||
flags connFlag
|
flags connFlag
|
||||||
cont chan error // The run loop uses cont to signal errors to SetupConn.
|
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
|
caps []Cap // valid after the protocol handshake
|
||||||
name string // valid after the protocol handshake
|
name string // valid after the protocol handshake
|
||||||
}
|
}
|
||||||
|
|
||||||
type transport interface {
|
type transport interface {
|
||||||
// The two handshakes.
|
// 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)
|
doProtoHandshake(our *protoHandshake) (*protoHandshake, error)
|
||||||
// The MsgReadWriter can only be used after the encryption
|
// The MsgReadWriter can only be used after the encryption
|
||||||
// handshake has completed. The code uses conn.id to track this
|
// handshake has completed. The code uses conn.id to track this
|
||||||
|
|
@ -225,8 +228,8 @@ type transport interface {
|
||||||
|
|
||||||
func (c *conn) String() string {
|
func (c *conn) String() string {
|
||||||
s := c.flags.String()
|
s := c.flags.String()
|
||||||
if (c.id != discover.NodeID{}) {
|
if (c.node.ID() != enode.ID{}) {
|
||||||
s += " " + c.id.String()
|
s += " " + c.node.ID().String()
|
||||||
}
|
}
|
||||||
s += " " + c.fd.RemoteAddr().String()
|
s += " " + c.fd.RemoteAddr().String()
|
||||||
return s
|
return s
|
||||||
|
|
@ -279,7 +282,7 @@ func (srv *Server) Peers() []*Peer {
|
||||||
// Note: We'd love to put this function into a variable but
|
// Note: We'd love to put this function into a variable but
|
||||||
// that seems to cause a weird compiler error in some
|
// that seems to cause a weird compiler error in some
|
||||||
// environments.
|
// environments.
|
||||||
case srv.peerOp <- func(peers map[discover.NodeID]*Peer) {
|
case srv.peerOp <- func(peers map[enode.ID]*Peer) {
|
||||||
for _, p := range peers {
|
for _, p := range peers {
|
||||||
ps = append(ps, p)
|
ps = append(ps, p)
|
||||||
}
|
}
|
||||||
|
|
@ -294,7 +297,7 @@ func (srv *Server) Peers() []*Peer {
|
||||||
func (srv *Server) PeerCount() int {
|
func (srv *Server) PeerCount() int {
|
||||||
var count int
|
var count int
|
||||||
select {
|
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
|
<-srv.peerOpDone
|
||||||
case <-srv.quit:
|
case <-srv.quit:
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +307,7 @@ func (srv *Server) PeerCount() int {
|
||||||
// AddPeer connects to the given node and maintains the connection until the
|
// 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
|
// server is shut down. If the connection fails for any reason, the server will
|
||||||
// attempt to reconnect the peer.
|
// attempt to reconnect the peer.
|
||||||
func (srv *Server) AddPeer(node *discover.Node) {
|
func (srv *Server) AddPeer(node *enode.Node) {
|
||||||
select {
|
select {
|
||||||
case srv.addstatic <- node:
|
case srv.addstatic <- node:
|
||||||
case <-srv.quit:
|
case <-srv.quit:
|
||||||
|
|
@ -312,7 +315,7 @@ func (srv *Server) AddPeer(node *discover.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemovePeer disconnects from the given node
|
// RemovePeer disconnects from the given node
|
||||||
func (srv *Server) RemovePeer(node *discover.Node) {
|
func (srv *Server) RemovePeer(node *enode.Node) {
|
||||||
select {
|
select {
|
||||||
case srv.removestatic <- node:
|
case srv.removestatic <- node:
|
||||||
case <-srv.quit:
|
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
|
// AddTrustedPeer adds the given node to a reserved whitelist which allows the
|
||||||
// node to always connect, even if the slot are full.
|
// 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 {
|
select {
|
||||||
case srv.addtrusted <- node:
|
case srv.addtrusted <- node:
|
||||||
case <-srv.quit:
|
case <-srv.quit:
|
||||||
|
|
@ -329,7 +332,7 @@ func (srv *Server) AddTrustedPeer(node *discover.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTrustedPeer removes the given node from the trusted peer set.
|
// 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 {
|
select {
|
||||||
case srv.removetrusted <- node:
|
case srv.removetrusted <- node:
|
||||||
case <-srv.quit:
|
case <-srv.quit:
|
||||||
|
|
@ -342,36 +345,47 @@ func (srv *Server) SubscribeEvents(ch chan *PeerEvent) event.Subscription {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Self returns the local node's endpoint information.
|
// Self returns the local node's endpoint information.
|
||||||
func (srv *Server) Self() *discover.Node {
|
func (srv *Server) Self() *enode.Node {
|
||||||
srv.lock.Lock()
|
srv.lock.Lock()
|
||||||
defer srv.lock.Unlock()
|
running, listener, ntab := srv.running, srv.listener, srv.ntab
|
||||||
|
srv.lock.Unlock()
|
||||||
|
|
||||||
if !srv.running {
|
if !running {
|
||||||
return &discover.Node{IP: net.ParseIP("0.0.0.0")}
|
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 {
|
func (srv *Server) makeSelf(listener net.Listener, ntab discoverTable) *enode.Node {
|
||||||
// If the server's not running, return an empty node.
|
|
||||||
// If the node is running but discovery is off, manually assemble the node infos.
|
// If the node is running but discovery is off, manually assemble the node infos.
|
||||||
if ntab == nil {
|
if ntab == nil {
|
||||||
// Inbound connections disabled, use zero address.
|
addr := srv.tcpAddr(listener)
|
||||||
if listener == nil {
|
return enode.NewV4(&srv.PrivateKey.PublicKey, addr.IP, addr.Port, 0)
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Otherwise return the discovery node.
|
// Otherwise return the discovery node.
|
||||||
return ntab.Self()
|
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.
|
// Stop terminates the server and all active peer connections.
|
||||||
// It blocks until all active connections have been closed.
|
// It blocks until all active connections have been closed.
|
||||||
func (srv *Server) Stop() {
|
func (srv *Server) Stop() {
|
||||||
|
|
@ -445,10 +459,10 @@ func (srv *Server) Start() (err error) {
|
||||||
srv.addpeer = make(chan *conn)
|
srv.addpeer = make(chan *conn)
|
||||||
srv.delpeer = make(chan peerDrop)
|
srv.delpeer = make(chan peerDrop)
|
||||||
srv.posthandshake = make(chan *conn)
|
srv.posthandshake = make(chan *conn)
|
||||||
srv.addstatic = make(chan *discover.Node)
|
srv.addstatic = make(chan *enode.Node)
|
||||||
srv.removestatic = make(chan *discover.Node)
|
srv.removestatic = make(chan *enode.Node)
|
||||||
srv.addtrusted = make(chan *discover.Node)
|
srv.addtrusted = make(chan *enode.Node)
|
||||||
srv.removetrusted = make(chan *discover.Node)
|
srv.removetrusted = make(chan *enode.Node)
|
||||||
srv.peerOp = make(chan peerOpFunc)
|
srv.peerOp = make(chan peerOpFunc)
|
||||||
srv.peerOpDone = make(chan struct{})
|
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)
|
dialer := newDialState(srv.StaticNodes, srv.BootstrapNodes, srv.ntab, dynPeers, srv.NetRestrict)
|
||||||
|
|
||||||
// handshake
|
// 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 {
|
for _, p := range srv.Protocols {
|
||||||
srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap())
|
srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap())
|
||||||
}
|
}
|
||||||
|
|
@ -541,7 +556,6 @@ func (srv *Server) Start() (err error) {
|
||||||
|
|
||||||
srv.loopWG.Add(1)
|
srv.loopWG.Add(1)
|
||||||
go srv.run(dialer)
|
go srv.run(dialer)
|
||||||
srv.running = true
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -568,18 +582,18 @@ func (srv *Server) startListening() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type dialer interface {
|
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)
|
taskDone(task, time.Time)
|
||||||
addStatic(*discover.Node)
|
addStatic(*enode.Node)
|
||||||
removeStatic(*discover.Node)
|
removeStatic(*enode.Node)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) run(dialstate dialer) {
|
func (srv *Server) run(dialstate dialer) {
|
||||||
defer srv.loopWG.Done()
|
defer srv.loopWG.Done()
|
||||||
var (
|
var (
|
||||||
peers = make(map[discover.NodeID]*Peer)
|
peers = make(map[enode.ID]*Peer)
|
||||||
inboundCount = 0
|
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)
|
taskdone = make(chan task, maxActiveDialTasks)
|
||||||
runningTasks []task
|
runningTasks []task
|
||||||
queuedTasks []task // tasks that can't run yet
|
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.
|
// Put trusted nodes into a map to speed up checks.
|
||||||
// Trusted peers are loaded on startup or added via AddTrustedPeer RPC.
|
// Trusted peers are loaded on startup or added via AddTrustedPeer RPC.
|
||||||
for _, n := range srv.TrustedNodes {
|
for _, n := range srv.TrustedNodes {
|
||||||
trusted[n.ID] = true
|
trusted[n.ID()] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// removes t from runningTasks
|
// removes t from runningTasks
|
||||||
|
|
@ -640,27 +654,27 @@ running:
|
||||||
// stop keeping the node connected.
|
// stop keeping the node connected.
|
||||||
srv.log.Trace("Removing static node", "node", n)
|
srv.log.Trace("Removing static node", "node", n)
|
||||||
dialstate.removeStatic(n)
|
dialstate.removeStatic(n)
|
||||||
if p, ok := peers[n.ID]; ok {
|
if p, ok := peers[n.ID()]; ok {
|
||||||
p.Disconnect(DiscRequested)
|
p.Disconnect(DiscRequested)
|
||||||
}
|
}
|
||||||
case n := <-srv.addtrusted:
|
case n := <-srv.addtrusted:
|
||||||
// This channel is used by AddTrustedPeer to add an enode
|
// This channel is used by AddTrustedPeer to add an enode
|
||||||
// to the trusted node set.
|
// to the trusted node set.
|
||||||
srv.log.Trace("Adding trusted node", "node", n)
|
srv.log.Trace("Adding trusted node", "node", n)
|
||||||
trusted[n.ID] = true
|
trusted[n.ID()] = true
|
||||||
// Mark any already-connected peer as trusted
|
// 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)
|
p.rw.set(trustedConn, true)
|
||||||
}
|
}
|
||||||
case n := <-srv.removetrusted:
|
case n := <-srv.removetrusted:
|
||||||
// This channel is used by RemoveTrustedPeer to remove an enode
|
// This channel is used by RemoveTrustedPeer to remove an enode
|
||||||
// from the trusted node set.
|
// from the trusted node set.
|
||||||
srv.log.Trace("Removing trusted node", "node", n)
|
srv.log.Trace("Removing trusted node", "node", n)
|
||||||
if _, ok := trusted[n.ID]; ok {
|
if _, ok := trusted[n.ID()]; ok {
|
||||||
delete(trusted, n.ID)
|
delete(trusted, n.ID())
|
||||||
}
|
}
|
||||||
// Unmark any already-connected peer as trusted
|
// 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)
|
p.rw.set(trustedConn, false)
|
||||||
}
|
}
|
||||||
case op := <-srv.peerOp:
|
case op := <-srv.peerOp:
|
||||||
|
|
@ -677,7 +691,7 @@ running:
|
||||||
case c := <-srv.posthandshake:
|
case c := <-srv.posthandshake:
|
||||||
// A connection has passed the encryption handshake so
|
// A connection has passed the encryption handshake so
|
||||||
// the remote identity is known (but hasn't been verified yet).
|
// 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.
|
// Ensure that the trusted flag is set before checking against MaxPeers.
|
||||||
c.flags |= trustedConn
|
c.flags |= trustedConn
|
||||||
}
|
}
|
||||||
|
|
@ -702,7 +716,7 @@ running:
|
||||||
name := truncateName(c.name)
|
name := truncateName(c.name)
|
||||||
srv.log.Debug("Adding p2p peer", "name", name, "addr", c.fd.RemoteAddr(), "peers", len(peers)+1)
|
srv.log.Debug("Adding p2p peer", "name", name, "addr", c.fd.RemoteAddr(), "peers", len(peers)+1)
|
||||||
go srv.runPeer(p)
|
go srv.runPeer(p)
|
||||||
peers[c.id] = p
|
peers[c.node.ID()] = p
|
||||||
if p.Inbound() {
|
if p.Inbound() {
|
||||||
inboundCount++
|
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.
|
// Drop connections with no matching protocols.
|
||||||
if len(srv.Protocols) > 0 && countMatchingProtocols(srv.Protocols, c.caps) == 0 {
|
if len(srv.Protocols) > 0 && countMatchingProtocols(srv.Protocols, c.caps) == 0 {
|
||||||
return DiscUselessPeer
|
return DiscUselessPeer
|
||||||
|
|
@ -759,15 +773,15 @@ func (srv *Server) protoHandshakeChecks(peers map[discover.NodeID]*Peer, inbound
|
||||||
return srv.encHandshakeChecks(peers, inboundCount, c)
|
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 {
|
switch {
|
||||||
case !c.is(trustedConn|staticDialedConn) && len(peers) >= srv.MaxPeers:
|
case !c.is(trustedConn|staticDialedConn) && len(peers) >= srv.MaxPeers:
|
||||||
return DiscTooManyPeers
|
return DiscTooManyPeers
|
||||||
case !c.is(trustedConn) && c.is(inboundConn) && inboundCount >= srv.maxInboundConns():
|
case !c.is(trustedConn) && c.is(inboundConn) && inboundCount >= srv.maxInboundConns():
|
||||||
return DiscTooManyPeers
|
return DiscTooManyPeers
|
||||||
case peers[c.id] != nil:
|
case peers[c.node.ID()] != nil:
|
||||||
return DiscAlreadyConnected
|
return DiscAlreadyConnected
|
||||||
case c.id == srv.Self().ID:
|
case c.node.ID() == srv.Self().ID():
|
||||||
return DiscSelf
|
return DiscSelf
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -777,7 +791,6 @@ func (srv *Server) encHandshakeChecks(peers map[discover.NodeID]*Peer, inboundCo
|
||||||
func (srv *Server) maxInboundConns() int {
|
func (srv *Server) maxInboundConns() int {
|
||||||
return srv.MaxPeers - srv.maxDialedConns()
|
return srv.MaxPeers - srv.maxDialedConns()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) maxDialedConns() int {
|
func (srv *Server) maxDialedConns() int {
|
||||||
if srv.NoDiscovery || srv.NoDial {
|
if srv.NoDiscovery || srv.NoDial {
|
||||||
return 0
|
return 0
|
||||||
|
|
@ -797,7 +810,7 @@ type tempError interface {
|
||||||
// inbound connections.
|
// inbound connections.
|
||||||
func (srv *Server) listenLoop() {
|
func (srv *Server) listenLoop() {
|
||||||
defer srv.loopWG.Done()
|
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
|
tokens := defaultMaxPendingPeers
|
||||||
if srv.MaxPendingPeers > 0 {
|
if srv.MaxPendingPeers > 0 {
|
||||||
|
|
@ -850,7 +863,7 @@ func (srv *Server) listenLoop() {
|
||||||
// SetupConn runs the handshakes and attempts to add the connection
|
// SetupConn runs the handshakes and attempts to add the connection
|
||||||
// as a peer. It returns when the connection has been added as a peer
|
// as a peer. It returns when the connection has been added as a peer
|
||||||
// or the handshakes have failed.
|
// 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()
|
self := srv.Self()
|
||||||
if self == nil {
|
if self == nil {
|
||||||
return errors.New("shutdown")
|
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)
|
err := srv.setupConn(c, flags, dialDest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.close(err)
|
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
|
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.
|
// Prevent leftover pending conns from entering the handshake.
|
||||||
srv.lock.Lock()
|
srv.lock.Lock()
|
||||||
running := srv.running
|
running := srv.running
|
||||||
|
|
@ -872,18 +885,30 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *discover.Node) e
|
||||||
if !running {
|
if !running {
|
||||||
return errServerStopped
|
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.
|
// Run the encryption handshake.
|
||||||
var err error
|
remotePubkey, err := c.doEncHandshake(srv.PrivateKey, dialPubkey)
|
||||||
if c.id, err = c.doEncHandshake(srv.PrivateKey, dialDest); err != nil {
|
if err != nil {
|
||||||
srv.log.Trace("Failed RLPx handshake", "addr", c.fd.RemoteAddr(), "conn", c.flags, "err", err)
|
srv.log.Trace("Failed RLPx handshake", "addr", c.fd.RemoteAddr(), "conn", c.flags, "err", err)
|
||||||
return 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.
|
// For dialed connections, check that the remote public key matches.
|
||||||
if dialDest != nil && c.id != dialDest.ID {
|
if dialPubkey.X.Cmp(remotePubkey.X) != 0 || dialPubkey.Y.Cmp(remotePubkey.Y) != 0 {
|
||||||
clog.Trace("Dialed identity mismatch", "want", c, dialDest.ID)
|
|
||||||
return DiscUnexpectedIdentity
|
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)
|
err = srv.checkpoint(c, srv.posthandshake)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
clog.Trace("Rejected peer before protocol handshake", "err", err)
|
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)
|
clog.Trace("Failed proto handshake", "err", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if phs.ID != c.id {
|
if id := c.node.ID(); !bytes.Equal(crypto.Keccak256(phs.ID), id[:]) {
|
||||||
clog.Trace("Wrong devp2p handshake identity", "err", phs.ID)
|
clog.Trace("Wrong devp2p handshake identity", "phsid", fmt.Sprintf("%x", phs.ID))
|
||||||
return DiscUnexpectedIdentity
|
return DiscUnexpectedIdentity
|
||||||
}
|
}
|
||||||
c.caps, c.name = phs.Caps, phs.Name
|
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
|
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 {
|
func truncateName(s string) string {
|
||||||
if len(s) > 20 {
|
if len(s) > 20 {
|
||||||
return s[:20] + "..."
|
return s[:20] + "..."
|
||||||
|
|
@ -985,13 +1020,13 @@ func (srv *Server) NodeInfo() *NodeInfo {
|
||||||
info := &NodeInfo{
|
info := &NodeInfo{
|
||||||
Name: srv.Name,
|
Name: srv.Name,
|
||||||
Enode: node.String(),
|
Enode: node.String(),
|
||||||
ID: node.ID.String(),
|
ID: node.ID().String(),
|
||||||
IP: node.IP.String(),
|
IP: node.IP().String(),
|
||||||
ListenAddr: srv.ListenAddr,
|
ListenAddr: srv.ListenAddr,
|
||||||
Protocols: make(map[string]interface{}),
|
Protocols: make(map[string]interface{}),
|
||||||
}
|
}
|
||||||
info.Ports.Discovery = int(node.UDP)
|
info.Ports.Discovery = node.UDP()
|
||||||
info.Ports.Listener = int(node.TCP)
|
info.Ports.Listener = node.TCP()
|
||||||
|
|
||||||
// Gather all the running protocol infos (only once per protocol type)
|
// Gather all the running protocol infos (only once per protocol type)
|
||||||
for _, proto := range srv.Protocols {
|
for _, proto := range srv.Protocols {
|
||||||
|
|
|
||||||
|
|
@ -28,21 +28,22 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"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() {
|
// func init() {
|
||||||
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlError, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
|
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
|
||||||
}
|
// }
|
||||||
|
|
||||||
type testTransport struct {
|
type testTransport struct {
|
||||||
id discover.NodeID
|
rpub *ecdsa.PublicKey
|
||||||
*rlpx
|
*rlpx
|
||||||
|
|
||||||
closeErr error
|
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 := newRLPX(fd).(*rlpx)
|
||||||
wrapped.rw = newRLPXFrameRW(fd, secrets{
|
wrapped.rw = newRLPXFrameRW(fd, secrets{
|
||||||
MAC: zero16,
|
MAC: zero16,
|
||||||
|
|
@ -50,15 +51,16 @@ func newTestTransport(id discover.NodeID, fd net.Conn) transport {
|
||||||
IngressMAC: sha3.NewKeccak256(),
|
IngressMAC: sha3.NewKeccak256(),
|
||||||
EgressMAC: 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) {
|
func (c *testTransport) doEncHandshake(prv *ecdsa.PrivateKey, dialDest *ecdsa.PublicKey) (*ecdsa.PublicKey, error) {
|
||||||
return c.id, nil
|
return c.rpub, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *testTransport) doProtoHandshake(our *protoHandshake) (*protoHandshake, error) {
|
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) {
|
func (c *testTransport) close(err error) {
|
||||||
|
|
@ -66,7 +68,7 @@ func (c *testTransport) close(err error) {
|
||||||
c.closeErr = err
|
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{
|
config := Config{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
MaxPeers: 10,
|
MaxPeers: 10,
|
||||||
|
|
@ -76,7 +78,7 @@ func startTestServer(t *testing.T, id discover.NodeID, pf func(*Peer)) *Server {
|
||||||
server := &Server{
|
server := &Server{
|
||||||
Config: config,
|
Config: config,
|
||||||
newPeerHook: pf,
|
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 {
|
if err := server.Start(); err != nil {
|
||||||
t.Fatalf("Could not start server: %v", err)
|
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) {
|
func TestServerListen(t *testing.T) {
|
||||||
// start the test server
|
// start the test server
|
||||||
connected := make(chan *Peer)
|
connected := make(chan *Peer)
|
||||||
remid := randomID()
|
remid := &newkey().PublicKey
|
||||||
srv := startTestServer(t, remid, func(p *Peer) {
|
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")
|
t.Error("peer func called with wrong node id")
|
||||||
}
|
}
|
||||||
if p == nil {
|
|
||||||
t.Error("peer func called with nil conn")
|
|
||||||
}
|
|
||||||
connected <- p
|
connected <- p
|
||||||
})
|
})
|
||||||
defer close(connected)
|
defer close(connected)
|
||||||
|
|
@ -141,14 +140,14 @@ func TestServerDial(t *testing.T) {
|
||||||
|
|
||||||
// start the server
|
// start the server
|
||||||
connected := make(chan *Peer)
|
connected := make(chan *Peer)
|
||||||
remid := randomID()
|
remid := &newkey().PublicKey
|
||||||
srv := startTestServer(t, remid, func(p *Peer) { connected <- p })
|
srv := startTestServer(t, remid, func(p *Peer) { connected <- p })
|
||||||
defer close(connected)
|
defer close(connected)
|
||||||
defer srv.Stop()
|
defer srv.Stop()
|
||||||
|
|
||||||
// tell the server to connect
|
// tell the server to connect
|
||||||
tcpAddr := listener.Addr().(*net.TCPAddr)
|
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)
|
srv.AddPeer(node)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
|
@ -157,7 +156,7 @@ func TestServerDial(t *testing.T) {
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case peer := <-connected:
|
case peer := <-connected:
|
||||||
if peer.ID() != remid {
|
if peer.ID() != enode.PubkeyToIDV4(remid) {
|
||||||
t.Errorf("peer has wrong id")
|
t.Errorf("peer has wrong id")
|
||||||
}
|
}
|
||||||
if peer.Name() != "test" {
|
if peer.Name() != "test" {
|
||||||
|
|
@ -211,7 +210,7 @@ func TestServerTaskScheduling(t *testing.T) {
|
||||||
quit, returned = make(chan struct{}), make(chan struct{})
|
quit, returned = make(chan struct{}), make(chan struct{})
|
||||||
tc = 0
|
tc = 0
|
||||||
tg = taskgen{
|
tg = taskgen{
|
||||||
newFunc: func(running int, peers map[discover.NodeID]*Peer) []task {
|
newFunc: func(running int, peers map[enode.ID]*Peer) []task {
|
||||||
tc++
|
tc++
|
||||||
return []task{&testTask{index: tc - 1}}
|
return []task{&testTask{index: tc - 1}}
|
||||||
},
|
},
|
||||||
|
|
@ -284,7 +283,7 @@ func TestServerManyTasks(t *testing.T) {
|
||||||
defer srv.Stop()
|
defer srv.Stop()
|
||||||
srv.loopWG.Add(1)
|
srv.loopWG.Add(1)
|
||||||
go srv.run(taskgen{
|
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
|
start, end = end, end+maxActiveDialTasks+10
|
||||||
if end > len(alltasks) {
|
if end > len(alltasks) {
|
||||||
end = len(alltasks)
|
end = len(alltasks)
|
||||||
|
|
@ -319,19 +318,19 @@ func TestServerManyTasks(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type taskgen struct {
|
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)
|
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)
|
return tg.newFunc(running, peers)
|
||||||
}
|
}
|
||||||
func (tg taskgen) taskDone(t task, now time.Time) {
|
func (tg taskgen) taskDone(t task, now time.Time) {
|
||||||
tg.doneFunc(t)
|
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 {
|
type testTask struct {
|
||||||
|
|
@ -347,13 +346,14 @@ func (t *testTask) Do(srv *Server) {
|
||||||
// just after the encryption handshake when the server is
|
// just after the encryption handshake when the server is
|
||||||
// at capacity. Trusted connections should still be accepted.
|
// at capacity. Trusted connections should still be accepted.
|
||||||
func TestServerAtCap(t *testing.T) {
|
func TestServerAtCap(t *testing.T) {
|
||||||
trustedID := randomID()
|
trustedNode := newkey()
|
||||||
|
trustedID := enode.PubkeyToIDV4(&trustedNode.PublicKey)
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
Config: Config{
|
Config: Config{
|
||||||
PrivateKey: newkey(),
|
PrivateKey: newkey(),
|
||||||
MaxPeers: 10,
|
MaxPeers: 10,
|
||||||
NoDial: true,
|
NoDial: true,
|
||||||
TrustedNodes: []*discover.Node{{ID: trustedID}},
|
TrustedNodes: []*enode.Node{newNode(trustedID, nil)},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if err := srv.Start(); err != nil {
|
if err := srv.Start(); err != nil {
|
||||||
|
|
@ -361,10 +361,11 @@ func TestServerAtCap(t *testing.T) {
|
||||||
}
|
}
|
||||||
defer srv.Stop()
|
defer srv.Stop()
|
||||||
|
|
||||||
newconn := func(id discover.NodeID) *conn {
|
newconn := func(id enode.ID) *conn {
|
||||||
fd, _ := net.Pipe()
|
fd, _ := net.Pipe()
|
||||||
tx := newTestTransport(id, fd)
|
tx := newTestTransport(&trustedNode.PublicKey, fd)
|
||||||
return &conn{fd: fd, transport: tx, flags: inboundConn, id: id, cont: make(chan error)}
|
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.
|
// 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
|
// Remove from trusted set and try again
|
||||||
srv.RemoveTrustedPeer(&discover.Node{ID: trustedID})
|
srv.RemoveTrustedPeer(newNode(trustedID, nil))
|
||||||
c = newconn(trustedID)
|
c = newconn(trustedID)
|
||||||
if err := srv.checkpoint(c, srv.posthandshake); err != DiscTooManyPeers {
|
if err := srv.checkpoint(c, srv.posthandshake); err != DiscTooManyPeers {
|
||||||
t.Error("wrong error for insert:", err)
|
t.Error("wrong error for insert:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add anotherID to trusted set and try again
|
// Add anotherID to trusted set and try again
|
||||||
srv.AddTrustedPeer(&discover.Node{ID: anotherID})
|
srv.AddTrustedPeer(newNode(anotherID, nil))
|
||||||
c = newconn(anotherID)
|
c = newconn(anotherID)
|
||||||
if err := srv.checkpoint(c, srv.posthandshake); err != nil {
|
if err := srv.checkpoint(c, srv.posthandshake); err != nil {
|
||||||
t.Error("unexpected error for trusted conn @posthandshake:", err)
|
t.Error("unexpected error for trusted conn @posthandshake:", err)
|
||||||
|
|
@ -409,20 +410,17 @@ func TestServerAtCap(t *testing.T) {
|
||||||
|
|
||||||
func TestServerPeerLimits(t *testing.T) {
|
func TestServerPeerLimits(t *testing.T) {
|
||||||
srvkey := newkey()
|
srvkey := newkey()
|
||||||
|
clientkey := newkey()
|
||||||
|
clientnode := enode.NewV4(&clientkey.PublicKey, nil, 0, 0)
|
||||||
|
|
||||||
clientid := randomID()
|
var tp = &setupTransport{
|
||||||
clientnode := &discover.Node{ID: clientid}
|
pubkey: &clientkey.PublicKey,
|
||||||
|
phs: protoHandshake{
|
||||||
var tp *setupTransport = &setupTransport{
|
ID: crypto.FromECDSAPub(&clientkey.PublicKey)[1:],
|
||||||
id: clientid,
|
|
||||||
phs: &protoHandshake{
|
|
||||||
ID: clientid,
|
|
||||||
// Force "DiscUselessPeer" due to unmatching caps
|
// Force "DiscUselessPeer" due to unmatching caps
|
||||||
// Caps: []Cap{discard.cap()},
|
// Caps: []Cap{discard.cap()},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
var flags connFlag = dynDialedConn
|
|
||||||
var dialDest *discover.Node = &discover.Node{ID: clientid}
|
|
||||||
|
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
Config: Config{
|
Config: Config{
|
||||||
|
|
@ -440,6 +438,8 @@ func TestServerPeerLimits(t *testing.T) {
|
||||||
defer srv.Stop()
|
defer srv.Stop()
|
||||||
|
|
||||||
// Check that server is full (MaxPeers=0)
|
// Check that server is full (MaxPeers=0)
|
||||||
|
flags := dynDialedConn
|
||||||
|
dialDest := clientnode
|
||||||
conn, _ := net.Pipe()
|
conn, _ := net.Pipe()
|
||||||
srv.SetupConn(conn, flags, dialDest)
|
srv.SetupConn(conn, flags, dialDest)
|
||||||
if tp.closeErr != DiscTooManyPeers {
|
if tp.closeErr != DiscTooManyPeers {
|
||||||
|
|
@ -473,59 +473,61 @@ func TestServerPeerLimits(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerSetupConn(t *testing.T) {
|
func TestServerSetupConn(t *testing.T) {
|
||||||
id := randomID()
|
var (
|
||||||
srvkey := newkey()
|
clientkey, srvkey = newkey(), newkey()
|
||||||
srvid := discover.PubkeyID(&srvkey.PublicKey)
|
clientpub = &clientkey.PublicKey
|
||||||
|
srvpub = &srvkey.PublicKey
|
||||||
|
)
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
dontstart bool
|
dontstart bool
|
||||||
tt *setupTransport
|
tt *setupTransport
|
||||||
flags connFlag
|
flags connFlag
|
||||||
dialDest *discover.Node
|
dialDest *enode.Node
|
||||||
|
|
||||||
wantCloseErr error
|
wantCloseErr error
|
||||||
wantCalls string
|
wantCalls string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
dontstart: true,
|
dontstart: true,
|
||||||
tt: &setupTransport{id: id},
|
tt: &setupTransport{pubkey: clientpub},
|
||||||
wantCalls: "close,",
|
wantCalls: "close,",
|
||||||
wantCloseErr: errServerStopped,
|
wantCloseErr: errServerStopped,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tt: &setupTransport{id: id, encHandshakeErr: errors.New("read error")},
|
tt: &setupTransport{pubkey: clientpub, encHandshakeErr: errors.New("read error")},
|
||||||
flags: inboundConn,
|
flags: inboundConn,
|
||||||
wantCalls: "doEncHandshake,close,",
|
wantCalls: "doEncHandshake,close,",
|
||||||
wantCloseErr: errors.New("read error"),
|
wantCloseErr: errors.New("read error"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tt: &setupTransport{id: id},
|
tt: &setupTransport{pubkey: clientpub},
|
||||||
dialDest: &discover.Node{ID: randomID()},
|
dialDest: enode.NewV4(&newkey().PublicKey, nil, 0, 0),
|
||||||
flags: dynDialedConn,
|
flags: dynDialedConn,
|
||||||
wantCalls: "doEncHandshake,close,",
|
wantCalls: "doEncHandshake,close,",
|
||||||
wantCloseErr: DiscUnexpectedIdentity,
|
wantCloseErr: DiscUnexpectedIdentity,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tt: &setupTransport{id: id, phs: &protoHandshake{ID: randomID()}},
|
tt: &setupTransport{pubkey: clientpub, phs: protoHandshake{ID: randomID().Bytes()}},
|
||||||
dialDest: &discover.Node{ID: id},
|
dialDest: enode.NewV4(clientpub, nil, 0, 0),
|
||||||
flags: dynDialedConn,
|
flags: dynDialedConn,
|
||||||
wantCalls: "doEncHandshake,doProtoHandshake,close,",
|
wantCalls: "doEncHandshake,doProtoHandshake,close,",
|
||||||
wantCloseErr: DiscUnexpectedIdentity,
|
wantCloseErr: DiscUnexpectedIdentity,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tt: &setupTransport{id: id, protoHandshakeErr: errors.New("foo")},
|
tt: &setupTransport{pubkey: clientpub, protoHandshakeErr: errors.New("foo")},
|
||||||
dialDest: &discover.Node{ID: id},
|
dialDest: enode.NewV4(clientpub, nil, 0, 0),
|
||||||
flags: dynDialedConn,
|
flags: dynDialedConn,
|
||||||
wantCalls: "doEncHandshake,doProtoHandshake,close,",
|
wantCalls: "doEncHandshake,doProtoHandshake,close,",
|
||||||
wantCloseErr: errors.New("foo"),
|
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,
|
flags: inboundConn,
|
||||||
wantCalls: "doEncHandshake,close,",
|
wantCalls: "doEncHandshake,close,",
|
||||||
wantCloseErr: DiscSelf,
|
wantCloseErr: DiscSelf,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tt: &setupTransport{id: id, phs: &protoHandshake{ID: id}},
|
tt: &setupTransport{pubkey: clientpub, phs: protoHandshake{ID: crypto.FromECDSAPub(clientpub)[1:]}},
|
||||||
flags: inboundConn,
|
flags: inboundConn,
|
||||||
wantCalls: "doEncHandshake,doProtoHandshake,close,",
|
wantCalls: "doEncHandshake,doProtoHandshake,close,",
|
||||||
wantCloseErr: DiscUselessPeer,
|
wantCloseErr: DiscUselessPeer,
|
||||||
|
|
@ -560,26 +562,26 @@ func TestServerSetupConn(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type setupTransport struct {
|
type setupTransport struct {
|
||||||
id discover.NodeID
|
pubkey *ecdsa.PublicKey
|
||||||
encHandshakeErr error
|
encHandshakeErr error
|
||||||
|
phs protoHandshake
|
||||||
phs *protoHandshake
|
|
||||||
protoHandshakeErr error
|
protoHandshakeErr error
|
||||||
|
|
||||||
calls string
|
calls string
|
||||||
closeErr error
|
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,"
|
c.calls += "doEncHandshake,"
|
||||||
return c.id, c.encHandshakeErr
|
return c.pubkey, c.encHandshakeErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *setupTransport) doProtoHandshake(our *protoHandshake) (*protoHandshake, error) {
|
func (c *setupTransport) doProtoHandshake(our *protoHandshake) (*protoHandshake, error) {
|
||||||
c.calls += "doProtoHandshake,"
|
c.calls += "doProtoHandshake,"
|
||||||
if c.protoHandshakeErr != nil {
|
if c.protoHandshakeErr != nil {
|
||||||
return nil, c.protoHandshakeErr
|
return nil, c.protoHandshakeErr
|
||||||
}
|
}
|
||||||
return c.phs, nil
|
return &c.phs, nil
|
||||||
}
|
}
|
||||||
func (c *setupTransport) close(err error) {
|
func (c *setupTransport) close(err error) {
|
||||||
c.calls += "close,"
|
c.calls += "close,"
|
||||||
|
|
@ -602,7 +604,7 @@ func newkey() *ecdsa.PrivateKey {
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
func randomID() (id discover.NodeID) {
|
func randomID() (id enode.ID) {
|
||||||
for i := range id {
|
for i := range id {
|
||||||
id[i] = byte(rand.Intn(255))
|
id[i] = byte(rand.Intn(255))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue