swarm/network, p2p: fixes

This commit is contained in:
zelig 2017-03-13 10:33:41 +07:00 committed by Lewis Marshall
parent 8cd9adcf38
commit 7f22abaead
13 changed files with 231 additions and 398 deletions

View file

@ -34,7 +34,6 @@ func newPeer(m Messenger) *Peer {
} }
type Peer struct { type Peer struct {
//RW p2p.MsgReadWriter
Messenger Messenger
Errc chan error Errc chan error
Flushc chan bool Flushc chan bool
@ -174,9 +173,9 @@ func (self *SimNode) RunProtocol(id *NodeId, rw, rrw p2p.MsgReadWriter, runc cha
p := p2p.NewPeer(id.NodeID, Name(id.Bytes()), []p2p.Cap{}) p := p2p.NewPeer(id.NodeID, Name(id.Bytes()), []p2p.Cap{})
go func() { go func() {
err := self.Run(p, rw) err := self.Run(p, rw)
glog.V(6).Infof("protocol quit on peer %v (connection with %v broken)", self.Id, id) glog.V(6).Infof("protocol quit on peer %v (connection with %v broken: %v)", self.Id, id, err)
<-runc <-runc
self.Disconnect(id.Bytes()) // self.Disconnect(id.Bytes())
peer.Errc <- err peer.Errc <- err
}() }()
return nil return nil

View file

@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/adapters" "github.com/ethereum/go-ethereum/p2p/adapters"
"github.com/ethereum/go-ethereum/p2p/discover"
) )
// error codes used by this protocol scheme // error codes used by this protocol scheme
@ -158,8 +159,11 @@ func (self *CodeMap) Register(msgs ...interface{}) {
} }
} }
func NewProtocol(protocolname string, protocolversion uint, run func(*Peer) error, na adapters.NodeAdapter, ct *CodeMap) *p2p.Protocol { func NewProtocol(protocolname string, protocolversion uint, run func(*Peer) error, na adapters.NodeAdapter, ct *CodeMap, peerInfo func(id discover.NodeID) interface{}, nodeInfo func() interface{}) *p2p.Protocol {
// PeerInfo is an optional helper method to retrieve protocol specific metadata
// about a certain peer in the network. If an info retrieval function is set,
// but returns nil, it is assumed that the protocol handshake is still running.
r := func(p *p2p.Peer, rw p2p.MsgReadWriter) error { r := func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
m := na.Messenger(rw) m := na.Messenger(rw)
@ -180,9 +184,15 @@ func NewProtocol(protocolname string, protocolversion uint, run func(*Peer) erro
Version: protocolversion, Version: protocolversion,
Length: ct.Length(), Length: ct.Length(),
Run: r, Run: r,
PeerInfo: peerInfo,
NodeInfo: nodeInfo,
} }
} }
type Disconnect struct {
err error
}
// A Peer represents a remote peer or protocol instance that is running on a peer connection with // A Peer represents a remote peer or protocol instance that is running on a peer connection with
// a remote peer // a remote peer
type Peer struct { type Peer struct {
@ -192,6 +202,7 @@ type Peer struct {
rw p2p.MsgReadWriter // p2p.MsgReadWriter to send messages to and read messages from rw p2p.MsgReadWriter // p2p.MsgReadWriter to send messages to and read messages from
handlers map[reflect.Type][]func(interface{}) error // message type -> message handler callback(s) map handlers map[reflect.Type][]func(interface{}) error // message type -> message handler callback(s) map
disconnect func() // Disconnect function set differently for testing disconnect func() // Disconnect function set differently for testing
Err error
} }
// NewPeer returns a new peer // NewPeer returns a new peer
@ -222,7 +233,7 @@ func (self *Peer) Register(msg interface{}, handler func(interface{}) error) uin
if !found { if !found {
panic(fmt.Sprintf("message type '%v' unknown ", typ)) panic(fmt.Sprintf("message type '%v' unknown ", typ))
} }
glog.V(logger.Detail).Infof("registered handle for %v %v", msg, typ) glog.V(logger.Detail).Infof("register handle for %v", typ)
self.handlers[typ] = append(self.handlers[typ], handler) self.handlers[typ] = append(self.handlers[typ], handler)
return code return code
} }
@ -233,9 +244,13 @@ func (self *Peer) Run() error {
var err error var err error
for { for {
_, err = self.handleIncoming() _, err = self.handleIncoming()
if err != nil { if self.Err == nil {
return err err = self.Err
} }
for _, f := range self.handlers[reflect.TypeOf(&Disconnect{})] {
f(err)
}
return err
} }
} }
@ -245,8 +260,8 @@ func (self *Peer) Run() error {
// TODO: may need to implement protocol drop only? don't want to kick off the peer // TODO: may need to implement protocol drop only? don't want to kick off the peer
// if they are useful for other protocols // if they are useful for other protocols
// overwrite Disconnect for testing, so that protocol readloop quits // overwrite Disconnect for testing, so that protocol readloop quits
func (self *Peer) Drop() { func (self *Peer) Drop(err error) {
self.disconnect() self.Err = err
} }
// Send takes a message, encodes it in RLP, finds the right message code and sends the // Send takes a message, encodes it in RLP, finds the right message code and sends the
@ -261,8 +276,9 @@ func (self *Peer) Send(msg interface{}) error {
glog.V(logger.Detail).Infof("=> %v (%d)", msg, code) glog.V(logger.Detail).Infof("=> %v (%d)", msg, code)
err := self.m.SendMsg(uint64(code), msg) err := self.m.SendMsg(uint64(code), msg)
if err != nil { if err != nil {
self.Drop() err = errorf(ErrWrite, "(msg code: %v): %v", code, err)
return errorf(ErrWrite, "(msg code: %v): %v", code, err) self.Drop(err)
return err
} }
return nil return nil
} }

View file

@ -4,7 +4,9 @@ import (
"fmt" "fmt"
"sync" "sync"
"testing" "testing"
"time"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/adapters" "github.com/ethereum/go-ethereum/p2p/adapters"
@ -12,7 +14,7 @@ import (
) )
func init() { func init() {
glog.SetV(6) glog.SetV(logger.Detail)
glog.SetToStderr(true) glog.SetToStderr(true)
} }
@ -55,9 +57,8 @@ const networkId = "420"
// newProtocol sets up a protocol // newProtocol sets up a protocol
// the run function here demonstrates a typical protocol using peerPool, handshake // the run function here demonstrates a typical protocol using peerPool, handshake
// and messages registered to handlers // and messages registered to handlers
func newProtocol(pp *p2ptest.TestPeerPool, wg *sync.WaitGroup) func(adapters.NodeAdapter) adapters.ProtoCall { func newProtocol(pp *TestPeerPool, wg *sync.WaitGroup) func(adapters.NodeAdapter) adapters.ProtoCall {
ct := NewCodeMap("test", 42, 1024, &protoHandshake{}, &hs0{}, &kill{}, &drop{}) ct := NewCodeMap("test", 42, 1024, &protoHandshake{}, &hs0{}, &kill{}, &drop{})
return func(na adapters.NodeAdapter) adapters.ProtoCall { return func(na adapters.NodeAdapter) adapters.ProtoCall {
return func(p *p2p.Peer, rw p2p.MsgReadWriter) error { return func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
if wg != nil { if wg != nil {
@ -69,13 +70,16 @@ func newProtocol(pp *p2ptest.TestPeerPool, wg *sync.WaitGroup) func(adapters.Nod
// demonstrates use of peerPool, killing another peer connection as a response to a message // demonstrates use of peerPool, killing another peer connection as a response to a message
peer.Register(&kill{}, func(msg interface{}) error { peer.Register(&kill{}, func(msg interface{}) error {
id := msg.(*kill).C id := msg.(*kill).C
pp.Get(id).Drop() // pp.Get(id).Drop(fmt.Errorf("killed"))
glog.V(logger.Detail).Infof("id %v killed", id)
return nil return nil
}) })
// for testing we can trigger self induced disconnect upon receiving drop message // for testing we can trigger self induced disconnect upon receiving drop message
peer.Register(&drop{}, func(msg interface{}) error { peer.Register(&drop{}, func(msg interface{}) error {
return fmt.Errorf("received disconnect request") glog.V(logger.Detail).Infof("dropped")
// return fmt.Errorf("dropped")
return
}) })
// initiate one-off protohandshake and check validity // initiate one-off protohandshake and check validity
@ -110,20 +114,21 @@ func newProtocol(pp *p2ptest.TestPeerPool, wg *sync.WaitGroup) func(adapters.Nod
return peer.Send(lhs) return peer.Send(lhs)
}) })
// add/remove peer from pool glog.V(logger.Detail).Infof("adding peer %v", peer)
pp.Add(peer) pp.Add(peer)
defer pp.Remove(peer) defer pp.Remove(peer)
// this launches a forever read loop
err = peer.Run() err = peer.Run()
if wg != nil { if wg != nil {
wg.Done() wg.Done()
} }
glog.V(logger.Detail).Infof("peer %v protocol quitting: %v", peer, err)
return err return err
} }
} }
} }
func protocolTester(t *testing.T, pp *p2ptest.TestPeerPool, wg *sync.WaitGroup) *p2ptest.ExchangeSession { func protocolTester(t *testing.T, pp *TestPeerPool, wg *sync.WaitGroup) *p2ptest.ExchangeSession {
id := p2ptest.RandomNodeId() id := p2ptest.RandomNodeId()
return p2ptest.NewProtocolTester(t, id, 2, newProtocol(pp, wg)) return p2ptest.NewProtocolTester(t, id, 2, newProtocol(pp, wg))
} }
@ -153,7 +158,7 @@ func protoHandshakeExchange(id *adapters.NodeId, proto *protoHandshake) []p2ptes
} }
func runProtoHandshake(t *testing.T, proto *protoHandshake, errs ...error) { func runProtoHandshake(t *testing.T, proto *protoHandshake, errs ...error) {
pp := p2ptest.NewTestPeerPool() pp := NewTestPeerPool()
s := protocolTester(t, pp, nil) s := protocolTester(t, pp, nil)
// TODO: make this more than one handshake // TODO: make this more than one handshake
id := s.Ids[0] id := s.Ids[0]
@ -202,7 +207,7 @@ func moduleHandshakeExchange(id *adapters.NodeId, resp uint) []p2ptest.Exchange
} }
func runModuleHandshake(t *testing.T, resp uint, errs ...error) { func runModuleHandshake(t *testing.T, resp uint, errs ...error) {
pp := p2ptest.NewTestPeerPool() pp := NewTestPeerPool()
s := protocolTester(t, pp, nil) s := protocolTester(t, pp, nil)
id := s.Ids[0] id := s.Ids[0]
s.TestExchanges(protoHandshakeExchange(id, &protoHandshake{42, "420"})...) s.TestExchanges(protoHandshakeExchange(id, &protoHandshake{42, "420"})...)
@ -227,6 +232,7 @@ func testMultiPeerSetup(a, b *adapters.NodeId) []p2ptest.Exchange {
return []p2ptest.Exchange{ return []p2ptest.Exchange{
p2ptest.Exchange{ p2ptest.Exchange{
Label: "primary handshake",
Expects: []p2ptest.Expect{ Expects: []p2ptest.Expect{
p2ptest.Expect{ p2ptest.Expect{
Code: 0, Code: 0,
@ -241,6 +247,7 @@ func testMultiPeerSetup(a, b *adapters.NodeId) []p2ptest.Exchange {
}, },
}, },
p2ptest.Exchange{ p2ptest.Exchange{
Label: "module handshake",
Triggers: []p2ptest.Trigger{ Triggers: []p2ptest.Trigger{
p2ptest.Trigger{ p2ptest.Trigger{
Code: 0, Code: 0,
@ -266,53 +273,30 @@ func testMultiPeerSetup(a, b *adapters.NodeId) []p2ptest.Exchange {
}, },
}, },
}, },
p2ptest.Exchange{
Triggers: []p2ptest.Trigger{ p2ptest.Exchange{Label: "alternative module handshake", Triggers: []p2ptest.Trigger{p2ptest.Trigger{Code: 1, Msg: &hs0{41}, Peer: a},
p2ptest.Trigger{ p2ptest.Trigger{Code: 1, Msg: &hs0{41}, Peer: b}}},
Code: 1, p2ptest.Exchange{Label: "repeated module handshake", Triggers: []p2ptest.Trigger{p2ptest.Trigger{Code: 1, Msg: &hs0{1}, Peer: a}}},
Msg: &hs0{41}, p2ptest.Exchange{Label: "receiving repeated module handshake", Expects: []p2ptest.Expect{p2ptest.Expect{Code: 1, Msg: &hs0{43}, Peer: a}}}}
Peer: a,
},
p2ptest.Trigger{
Code: 1,
Msg: &hs0{41},
Peer: b,
},
},
},
p2ptest.Exchange{
Triggers: []p2ptest.Trigger{
p2ptest.Trigger{
Code: 1,
Msg: &hs0{1},
Peer: a,
},
},
},
p2ptest.Exchange{
Expects: []p2ptest.Expect{
p2ptest.Expect{
Code: 1,
Msg: &hs0{43},
Peer: a,
},
},
},
}
} }
func runMultiplePeers(t *testing.T, peer int, errs ...error) { func runMultiplePeers(t *testing.T, peer int, errs ...error) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
pp := p2ptest.NewTestPeerPool() pp := NewTestPeerPool()
s := protocolTester(t, pp, wg) s := protocolTester(t, pp, wg)
s.TestExchanges(testMultiPeerSetup(s.Ids[0], s.Ids[1])...) s.TestExchanges(testMultiPeerSetup(s.Ids[0], s.Ids[1])...)
// after some exchanges of messages, we can test state changes // after some exchanges of messages, we can test state changes
// here this is simply demonstrated by the peerPool // here this is simply demonstrated by the peerPool
// after the handshake negotiations peers must be addded to the pool // after the handshake negotiations peers must be added to the pool
if !pp.Has(s.Ids[0]) { // time.Sleep(1)
t.Fatalf("missing peer test-0: %v (%v)", pp, s.Ids) for !pp.Has(s.Ids[0]) {
time.Sleep(1)
glog.V(logger.Detail).Infof("missing peer test-0: %v (%v)", pp, s.Ids)
} }
// if !pp.Has(s.Ids[0]) {
// t.Fatalf("missing peer test-0: %v (%v)", pp, s.Ids)
// }
if !pp.Has(s.Ids[1]) { if !pp.Has(s.Ids[1]) {
t.Fatalf("missing peer test-1: %v (%v)", pp, s.Ids) t.Fatalf("missing peer test-1: %v (%v)", pp, s.Ids)
} }
@ -355,13 +339,13 @@ func runMultiplePeers(t *testing.T, peer int, errs ...error) {
func TestMultiplePeersDropSelf(t *testing.T) { func TestMultiplePeersDropSelf(t *testing.T) {
runMultiplePeers(t, 0, runMultiplePeers(t, 0,
fmt.Errorf("p2p: read or write on closed message pipe"), fmt.Errorf("p2p: read or write on closed message pipe"),
fmt.Errorf("Message handler error: (msg code 3): received disconnect request"), fmt.Errorf("Message handler error: (msg code 3): killed"),
) )
} }
func TestMultiplePeersDropOther(t *testing.T) { func TestMultiplePeersDropOther(t *testing.T) {
runMultiplePeers(t, 1, runMultiplePeers(t, 1,
fmt.Errorf("Message handler error: (msg code 3): received disconnect request"), fmt.Errorf("Message handler error: (msg code 3): dropped"),
fmt.Errorf("p2p: read or write on closed message pipe"), fmt.Errorf("p2p: read or write on closed message pipe"),
) )
} }

View file

@ -1,7 +1,3 @@
// Package protocols helpers_test make it easier to
// write protocol tests by providing convenience functions and structures
// protocols uses these helpers for its own tests
// but ideally should sit in p2p/protocols/testing/ subpackage
package testing package testing
import ( import (
@ -34,7 +30,6 @@ type TestNetAdapter interface {
} }
type TestMessenger interface { type TestMessenger interface {
// MsgPipe([]byte, []byte) p2p,MsgPipe
ExpectMsg(uint64, interface{}) error ExpectMsg(uint64, interface{}) error
TriggerMsg(uint64, interface{}) error TriggerMsg(uint64, interface{}) error
} }
@ -42,6 +37,7 @@ type TestMessenger interface {
// exchanges are the basic units of protocol tests // exchanges are the basic units of protocol tests
// an exchange is defined on a session // an exchange is defined on a session
type Exchange struct { type Exchange struct {
Label string
Triggers []Trigger Triggers []Trigger
Expects []Expect Expects []Expect
} }
@ -62,8 +58,8 @@ type Expect struct {
} }
type Disconnect struct { type Disconnect struct {
Peer *adapters.NodeId // the peer that expects the message Peer *adapters.NodeId // discconnected peer
Error error Error error // disconnect reason
} }
// NewExchangeTestSession takes a network session and Messenger // NewExchangeTestSession takes a network session and Messenger
@ -81,12 +77,11 @@ func NewExchangeTestSession(t *testing.T, n TestNetAdapter, ids []*adapters.Node
} }
} }
type TestPeerInfo struct { // type PeerTester struct {
//RW p2p.MsgReadWriter // Messenger TestMessenger
Messenger TestMessenger // Flushc chan bool
Flushc chan bool // Errc chan error
Errc chan error // }
}
// trigger sends messages from peers // trigger sends messages from peers
func (self *ExchangeTestSession) trigger(trig Trigger) error { func (self *ExchangeTestSession) trigger(trig Trigger) error {
@ -102,10 +97,10 @@ func (self *ExchangeTestSession) trigger(trig Trigger) error {
errc := make(chan error) errc := make(chan error)
go func() { go func() {
glog.V(6).Infof("trigger....") glog.V(6).Infof("trigger %v (%v)....", trig.Msg, trig.Code)
//errc <- self.TriggerMsg(rw, trig.Code, trig.Msg) //errc <- self.TriggerMsg(rw, trig.Code, trig.Msg)
errc <- m.(TestMessenger).TriggerMsg(trig.Code, trig.Msg) errc <- m.(TestMessenger).TriggerMsg(trig.Code, trig.Msg)
glog.V(6).Infof("triggered") glog.V(6).Infof("triggered %v (%v)", trig.Msg, trig.Code)
}() }()
t := trig.Timeout t := trig.Timeout
@ -168,18 +163,13 @@ func (self *ExchangeTestSession) TestExchanges(exchanges ...Exchange) {
// launch all triggers of this exchanges // launch all triggers of this exchanges
for i, e := range exchanges { for i, e := range exchanges {
errc := make(chan error) errc := make(chan error, 1)
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
for _, trig := range e.Triggers { for _, trig := range e.Triggers {
wg.Add(1) err := self.trigger(trig)
// separate go routing to allow parallel requests
go func(t Trigger) {
defer wg.Done()
err := self.trigger(t)
if err != nil { if err != nil {
errc <- err errc <- err
} }
}(trig)
} }
// each expectation is spawned in separate go-routine // each expectation is spawned in separate go-routine
@ -217,40 +207,16 @@ func (self *ExchangeTestSession) TestExchanges(exchanges ...Exchange) {
if err != nil { if err != nil {
self.t.Fatalf("exchange failed with: %v", err) self.t.Fatalf("exchange failed with: %v", err)
} else { } else {
glog.V(6).Infof("exchange %v run successfully", i) glog.V(6).Infof("exchange %v: '%v' run successfully", i, e.Label)
} }
case <-alarm.C: case <-alarm.C:
self.t.Fatalf("exchange timed out") self.t.Fatalf("exchange %v: '%v' timed out", i, e.Label)
} }
} }
} }
type flushMsg struct{} func (self *ExchangeTestSession) TestConnected(peers ...*adapters.NodeId) {
func flushExchange(c int, ids ...*adapters.NodeId) Exchange {
var triggers []Trigger
for _, id := range ids {
triggers = append(triggers,
Trigger{
Code: uint64(c),
Msg: &flushMsg{},
Peer: id,
})
}
return Exchange{
Triggers: triggers,
}
}
var FlushMsg = &flushMsg{}
func (self *ExchangeTestSession) TestConnected(flush bool, peers ...*adapters.NodeId) {
timeout := time.NewTimer(1000 * time.Millisecond) timeout := time.NewTimer(1000 * time.Millisecond)
var flushc chan bool
if !flush {
flushc = make(chan bool)
close(flushc)
}
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(len(peers)) wg.Add(len(peers))
for _, id := range peers { for _, id := range peers {
@ -260,15 +226,12 @@ func (self *ExchangeTestSession) TestConnected(flush bool, peers ...*adapters.No
for { for {
peer := self.GetPeer(p) peer := self.GetPeer(p)
if peer != nil { if peer != nil {
if flush {
flushc = peer.Flushc
}
select { select {
case <-timeout.C: case <-timeout.C:
self.t.Fatalf("exchange timed out waiting for peer %v to flush", p) self.t.Fatalf("exchange timed out waiting for peer %v to flush", p)
case err := <-peer.Errc: case err := <-peer.Errc:
self.t.Fatalf("peer %v disconnected with error %v", p, err) self.t.Fatalf("peer %v disconnected with error %v", p, err)
case <-flushc: case <-peer.Flushc:
glog.V(6).Infof("peer %v is connected", p) glog.V(6).Infof("peer %v is connected", p)
return return
} }

View file

@ -1,48 +0,0 @@
package testing
import (
"sync"
"github.com/ethereum/go-ethereum/p2p/adapters"
"github.com/ethereum/go-ethereum/p2p/discover"
)
type TestPeer interface {
ID() discover.NodeID
Drop()
}
// TestPeerPool is an example peerPool to demonstrate registration of peer connections
type TestPeerPool struct {
lock sync.Mutex
peers map[discover.NodeID]TestPeer
}
func NewTestPeerPool() *TestPeerPool {
return &TestPeerPool{peers: make(map[discover.NodeID]TestPeer)}
}
func (self *TestPeerPool) Add(p TestPeer) {
self.lock.Lock()
defer self.lock.Unlock()
self.peers[p.ID()] = p
}
func (self *TestPeerPool) Remove(p TestPeer) {
self.lock.Lock()
defer self.lock.Unlock()
delete(self.peers, p.ID())
}
func (self *TestPeerPool) Has(n *adapters.NodeId) bool {
self.lock.Lock()
defer self.lock.Unlock()
_, ok := self.peers[n.NodeID]
return ok
}
func (self *TestPeerPool) Get(n *adapters.NodeId) TestPeer {
self.lock.Lock()
defer self.lock.Unlock()
return self.peers[n.NodeID]
}

View file

@ -62,13 +62,7 @@ func NewProtocolTester(t *testing.T, id *adapters.NodeId, n int, run func(id ada
return self return self
} }
func (self *ExchangeTestSession) Flush(code int, ids ...*adapters.NodeId) { //
self.TestConnected(false, ids...)
glog.V(6).Infof("flushing peers %v (code %v)", ids, code)
self.TestExchanges(flushExchange(code, ids...))
self.TestConnected(true, ids...)
}
func (self *ExchangeSession) Start(id *adapters.NodeId) error { func (self *ExchangeSession) Start(id *adapters.NodeId) error {
err := self.network.NewNode(&simulations.NodeConfig{Id: id}) err := self.network.NewNode(&simulations.NodeConfig{Id: id})
if err != nil { if err != nil {
@ -103,6 +97,10 @@ func (self *ExchangeSession) Connect(ids ...*adapters.NodeId) {
} }
// func (self *ExchangeSession) Id(i int) *adapters.NodeId {
// return self.network.Nodes[i].Id
// }
func RandomNodeId() *adapters.NodeId { func RandomNodeId() *adapters.NodeId {
key, err := crypto.GenerateKey() key, err := crypto.GenerateKey()
if err != nil { if err != nil {

View file

@ -1,56 +1,57 @@
package network package network
import ( import (
"bytes"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p/discover"
) )
// discovery bzz hive extension for efficient peer relaying // discovery bzz hive extension doing peer relaying
// this will be triggered by p2p/protocol already // can be switched off
type discPeer struct { type discPeer struct {
Peer Peer
hive Hive hive *Hive
sub overlaySubscription proxLimit uint8
peers map[discover.NodeID]bool peers map[discover.NodeID]bool
} }
type overlaySubscription interface { // NotifyPeer notifies the receiver remote end of a peer p or PO po.
Subscribe(proxLimit uint) chan interface{} // callback for overlay driver
SubscribeProxChange(proxLimit uint) chan interface{} func (self *discPeer) NotifyPeer(p Peer, po uint8) error {
if po < self.proxLimit || self.peers[p.ID()] {
return nil
}
resp := &peersMsg{
Peers: []*peerAddr{p.(*bzzPeer).peerAddr},
}
return p.Send(resp)
}
// NotifyProx sends a subPeers Msg to the receiver notifying them about
// a change in the prox limit (radius of the set including the nearest X peers
// or first empty row)
// callback for overlay driver
func (self *discPeer) NotifyProx(po uint8) error {
return self.Send(&SubPeersMsg{ProxLimit: po, MinProxBinSize: 8})
} }
// new discovery contructor // new discovery contructor
func NewDiscovery(p Peer, h Hive) error { func NewDiscovery(p Peer, h *Hive) *discPeer {
overlay, ok := h.Overlay.(overlaySubscription)
if !ok {
return fmt.Errorf("overlay does not support subscription")
}
self := &discPeer{ self := &discPeer{
sub: overlay,
hive: h, hive: h,
Peer: p, Peer: p,
peers: make(map[discover.NodeID]Peer), peers: make(map[discover.NodeID]bool),
} }
c := sub.SubscribeProxChange()
go func() {
for {
select {
case <-h.quit:
return
case p := <-c:
resp := &peersMsg{
Peers: []*peerAddr{p.PeerAddr.(*peerAddr)},
}
p.Send(resp)
}
}
}()
p.Register(&subPeersMsg{}, self.handleSubPeersMsg)
p.Register(&peersMsg{}, self.handlePeersMsg) p.Register(&peersMsg{}, self.handlePeersMsg)
p.Register(&getPeersMsg{}, self.handleGetPeersMsg) p.Register(&getPeersMsg{}, self.handleGetPeersMsg)
p.Register(&SubPeersMsg{}, self.handleSubPeersMsg)
return nil return self
} }
/* /*
@ -61,6 +62,7 @@ The encoding of a peer is identical to that in the devp2p base protocol peers
messages: [IP, Port, NodeID] messages: [IP, Port, NodeID]
note that a node's DPA address is not the NodeID but the hash of the NodeID. note that a node's DPA address is not the NodeID but the hash of the NodeID.
TODO:
To mitigate against spurious peers messages, requests should be remembered To mitigate against spurious peers messages, requests should be remembered
and correctness of responses should be checked and correctness of responses should be checked
@ -70,7 +72,7 @@ disconnected
// peersMsg encapsulates an array of peer addresses // peersMsg encapsulates an array of peer addresses
// used for communicating about known peers // used for communicating about known peers
// relevvant for bootstrapping connectivity and updating peersets // relevant for bootstrapping connectivity and updating peersets
type peersMsg struct { type peersMsg struct {
Peers []*peerAddr Peers []*peerAddr
} }
@ -81,8 +83,8 @@ func (self peersMsg) String() string {
// getPeersMsg is sent to (random) peers to request (Max) peers of a specific order // getPeersMsg is sent to (random) peers to request (Max) peers of a specific order
type getPeersMsg struct { type getPeersMsg struct {
Order uint Order uint8
Max uint Max uint8
} }
func (self getPeersMsg) String() string { func (self getPeersMsg) String() string {
@ -90,20 +92,19 @@ func (self getPeersMsg) String() string {
} }
// subPeers msg is communicating the depth/sharpness/focus of the overlay table of a peer // subPeers msg is communicating the depth/sharpness/focus of the overlay table of a peer
type subPeersMsg struct { type SubPeersMsg struct {
MinProxBinSize uint MinProxBinSize uint8
ProxLimit uint ProxLimit uint8
// Offset uint
// Batch uint
} }
func (self subPeersMsg) String() string { func (self SubPeersMsg) String() string {
return fmt.Sprintf("request peers > PO%02d. ProxLimit: %02d", self.Request, self.ProxLimit) return fmt.Sprintf("%T: request peers > PO%02d. ", self, self.ProxLimit)
} }
func (self *discPeer) handleSubPeersMsg(msg interface{}) error { func (self *discPeer) handleSubPeersMsg(msg interface{}) error {
spm := msg.(*subPeersMsg) spm := msg.(*SubPeersMsg)
self.sub.Subscribe(spm.ProxLimit) self.proxLimit = spm.ProxLimit
return nil
} }
// handlePeersMsg called by the protocol when receiving peerset (for target address) // handlePeersMsg called by the protocol when receiving peerset (for target address)
@ -115,7 +116,7 @@ func (p *discPeer) handlePeersMsg(msg interface{}) error {
for _, na := range msg.(*peersMsg).Peers { for _, na := range msg.(*peersMsg).Peers {
addr := PeerAddr(na) addr := PeerAddr(na)
nas = append(nas, addr) nas = append(nas, addr)
p.peers[NodeId(addr)] = true p.peers[NodeId(addr).NodeID] = true
} }
return p.hive.Register(nas...) return p.hive.Register(nas...)
} }
@ -130,7 +131,7 @@ func (p *discPeer) handleGetPeersMsg(msg interface{}) error {
var peers []*peerAddr var peers []*peerAddr
alreadySent := p.peers alreadySent := p.peers
i := 0 i := 0
p.Overlay.EachLivePeer(p.OverlayAddr(), int(req.Order), func(n Peer, po int) bool { p.hive.EachLivePeer(p.OverlayAddr(), int(req.Order), func(n Peer, po int) bool {
i++ i++
if bytes.Compare(n.OverlayAddr(), p.OverlayAddr()) != 0 && if bytes.Compare(n.OverlayAddr(), p.OverlayAddr()) != 0 &&
// only send peers we have not sent before in this session // only send peers we have not sent before in this session
@ -149,9 +150,5 @@ func (p *discPeer) handleGetPeersMsg(msg interface{}) error {
resp := &peersMsg{ resp := &peersMsg{
Peers: peers, Peers: peers,
} }
err := p.Send(resp) return p.Send(resp)
if err != nil {
return err
}
return nil
} }

View file

@ -1,30 +1,25 @@
package network package network
import ( import (
"sync"
"testing" "testing"
"time"
"github.com/ethereum/go-ethereum/p2p/adapters"
// "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p/protocols"
p2ptest "github.com/ethereum/go-ethereum/p2p/testing" p2ptest "github.com/ethereum/go-ethereum/p2p/testing"
) )
func TestDiscovery(t *testing.T) { func TestDiscovery(t *testing.T) {
addr := RandomAddr() addr := RandomAddr()
to := NewTestOverlay(addr.OverlayAddr()) to := NewKademlia(addr.OAddr, NewKadParams())
pp := NewHive(NewHiveParams(), to) pp := NewHive(NewHiveParams(), to)
ct := BzzCodeMap(HiveMsgs...) ct := BzzCodeMap(HiveMsgs...)
s := newDiscoveryTester(t, 0, addr, pp, ct, nil) s := newBzzTester(t, 1, addr, pp, ct, nil)
s.runHandshakes()
s.TestExchanges(p2ptest.Exchange{ s.TestExchanges(p2ptest.Exchange{
Expects: []p2ptest.Expect{ Expects: []p2ptest.Expect{
p2ptest.Expect{ p2ptest.Expect{
Code: 1, Code: 3,
Msg: &subPeersMsg{uint(o)}, Msg: &SubPeersMsg{ProxLimit: 0, MinProxBinSize: 8},
Peer: id, Peer: s.ExchangeSession.Id(1),
}, },
}, },
}) })

View file

@ -17,13 +17,12 @@
package network package network
import ( import (
"bytes"
"fmt"
"sync" "sync"
"time" "time"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p/adapters"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
) )
@ -57,7 +56,7 @@ type Overlay interface {
type Hive struct { type Hive struct {
*HiveParams // settings *HiveParams // settings
Overlay // the overlay topology driver Overlay // the overlay topology driver
disc Discovery // disc Discovery
lock sync.Mutex lock sync.Mutex
quit chan bool quit chan bool
@ -72,8 +71,8 @@ const (
) )
type HiveParams struct { type HiveParams struct {
PeersBroadcastSetSize uint PeersBroadcastSetSize uint8
MaxPeersPerRequest uint MaxPeersPerRequest uint8
CallInterval uint CallInterval uint
} }
@ -95,18 +94,17 @@ func NewHive(params *HiveParams, overlay Overlay) *Hive {
} }
} }
// messages that hive regusters handles for // messages that hive handles
var HiveMsgs = []interface{}{ var HiveMsgs = []interface{}{
&getPeersMsg{}, &getPeersMsg{},
&peersMsg{}, &peersMsg{},
&subPeersMsg{}, &SubPeersMsg{},
} }
// Start receives network info only at startup // Start receives network info only at startup
// listedAddr is a function to retrieve listening address to advertise to peers
// connectPeer is a function to connect to a peer based on its NodeID or enode URL // connectPeer is a function to connect to a peer based on its NodeID or enode URL
// these are called on the p2p.Server which runs on the node
// af() returns an arbitrary ticker channel // af() returns an arbitrary ticker channel
// there are called on the p2p.Server which runs on the node
func (self *Hive) Start(connectPeer func(string) error, af func() <-chan time.Time) error { func (self *Hive) Start(connectPeer func(string) error, af func() <-chan time.Time) error {
self.toggle = make(chan bool) self.toggle = make(chan bool)
@ -137,10 +135,10 @@ func (self *Hive) Start(connectPeer func(string) error, af func() <-chan time.Ti
} }
if want { if want {
req := &getPeersMsg{ req := &getPeersMsg{
Order: uint(order), Order: uint8(order),
Max: self.MaxPeersPerRequest, Max: self.MaxPeersPerRequest,
} }
var i uint var i uint8
var err error var err error
self.EachLivePeer(nil, order, func(n Peer, po int) bool { self.EachLivePeer(nil, order, func(n Peer, po int) bool {
glog.V(logger.Detail).Infof("%T sent to %v", req, n.ID()) glog.V(logger.Detail).Infof("%T sent to %v", req, n.ID())
@ -218,15 +216,12 @@ func (self *Hive) wake() {
// to register a connected (live) peer // to register a connected (live) peer
func (self *Hive) Add(p Peer) error { func (self *Hive) Add(p Peer) error {
defer self.wake() defer self.wake()
dp := NewDiscovery(p, self)
glog.V(logger.Debug).Infof("to add new bee %v", p) glog.V(logger.Debug).Infof("to add new bee %v", p)
self.On(p) self.On(dp)
glog.V(logger.Warn).Infof("%v", self) glog.V(logger.Warn).Infof("%v", self)
dp.NotifyProx(0)
// self.lock.Lock() return nil
// self.peers[p.ID()] = p
// self.lock.Unlock()
return NewDiscovery(p, self)
} }
// Remove called after peer is disconnected // Remove called after peer is disconnected
@ -234,9 +229,6 @@ func (self *Hive) Remove(p Peer) {
defer self.wake() defer self.wake()
glog.V(logger.Debug).Infof("remove bee %v", p) glog.V(logger.Debug).Infof("remove bee %v", p)
self.Off(p) self.Off(p)
self.lock.Lock()
delete(self.peers, p.ID())
self.lock.Unlock()
} }
func (self *Hive) NodeInfo() interface{} { func (self *Hive) NodeInfo() interface{} {
@ -246,11 +238,8 @@ func (self *Hive) NodeInfo() interface{} {
func (self *Hive) PeerInfo(id discover.NodeID) interface{} { func (self *Hive) PeerInfo(id discover.NodeID) interface{} {
self.lock.Lock() self.lock.Lock()
defer self.lock.Unlock() defer self.lock.Unlock()
p, ok := self.peers[id] addr := NewPeerAddrFromNodeId(adapters.NewNodeId(id[:]))
if !ok { return interface{}(addr)
return nil
}
return interface{}(&peerAddr{p.OverlayAddr(), p.UnderlayAddr()})
} }
func HexToBytes(s string) []byte { func HexToBytes(s string) []byte {

View file

@ -9,7 +9,7 @@ import (
// "github.com/ethereum/go-ethereum/p2p/discover" // "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p/protocols" // "github.com/ethereum/go-ethereum/p2p/protocols"
p2ptest "github.com/ethereum/go-ethereum/p2p/testing" p2ptest "github.com/ethereum/go-ethereum/p2p/testing"
) )
@ -37,22 +37,14 @@ func (self *testConnect) connect(na string) error {
return nil return nil
} }
func newBzzHiveTester(t *testing.T, n int, addr *peerAddr, pp PeerPool, ct *protocols.CodeMap, services func(Peer) error) *bzzTester {
s := p2ptest.NewProtocolTester(t, NodeId(addr), n, newTestBzzProtocol(addr, pp, ct, services))
return &bzzTester{
addr: addr,
flushCode: 3,
ExchangeSession: s,
}
}
func TestOverlayRegistration(t *testing.T) { func TestOverlayRegistration(t *testing.T) {
// setup // setup
addr := RandomAddr() // tested peers peer address addr := RandomAddr() // tested peers peer address
to := NewTestOverlay(addr.OverlayAddr()) // overlay topology driver to := NewTestOverlay(addr.OverlayAddr()) // overlay topology driver
pp := NewHive(NewHiveParams(), to) // hive pp := NewHive(NewHiveParams(), to) // hive
ct := BzzCodeMap(HiveMsgs...) // bzz protocol code map ct := BzzCodeMap(HiveMsgs...) // bzz protocol code map
s := newBzzHiveTester(t, 1, addr, pp, ct, nil)
s := newBzzTester(t, 1, addr, ct, nil)
// connect to the other peer // connect to the other peer
id := s.Ids[0] id := s.Ids[0]
@ -70,14 +62,18 @@ func TestRegisterAndConnect(t *testing.T) {
to := NewTestOverlay(addr.OverlayAddr()) to := NewTestOverlay(addr.OverlayAddr())
pp := NewHive(NewHiveParams(), to) pp := NewHive(NewHiveParams(), to)
ct := BzzCodeMap(HiveMsgs...) ct := BzzCodeMap(HiveMsgs...)
s := newBzzHiveTester(t, 0, addr, pp, ct, nil) s := newBzzTester(t, 0, addr, pp, ct, nil)
// register the node with the peerPool // register the node with the peerPool
id := p2ptest.RandomNodeId() id := p2ptest.RandomNodeId()
// pretend to start the node
s.Start(id) s.Start(id)
// register another address
raddr := NewPeerAddrFromNodeId(id) raddr := NewPeerAddrFromNodeId(id)
pp.Register(raddr) pp.Register(raddr)
glog.V(5).Infof("%v", pp) glog.V(5).Infof("%v", pp)
// start the hive and wait for the connection // start the hive and wait for the connection
tc := &testConnect{ tc := &testConnect{
connectf: func(c string) error { connectf: func(c string) error {
@ -88,42 +84,36 @@ func TestRegisterAndConnect(t *testing.T) {
} }
pp.Start(tc.connect, tc.ping) pp.Start(tc.connect, tc.ping)
tc.ticker <- time.Now() tc.ticker <- time.Now()
// run bzz handshake
s.runHandshakes() s.runHandshakes()
if to.posMap[string(raddr.OverlayAddr())] == nil { if to.posMap[string(raddr.OverlayAddr())] == nil {
t.Fatalf("Overlay#On not called on new peer") t.Fatalf("Overlay#On not called on new peer")
} }
glog.V(6).Infof("check peer requests for %v", id)
// tc.ticker <- time.Now()
// shakeHands(s, addr, id) // retrieve and broadcast
// s.Flush(int(ct.Length())-1, 0) glog.V(6).Infof("check peer requests for %v", id)
// time.Sleep(3)
ord := order(raddr.OverlayAddr()) ord := order(raddr.OverlayAddr())
o := 0 o := 0
if ord == 0 { if ord == 0 {
o = 1 o = 1
} }
s.TestExchanges(p2ptest.Exchange{
Expects: []p2ptest.Expect{
p2ptest.Expect{
Code: 3,
Msg: &SubPeersMsg{ProxLimit: 0, MinProxBinSize: 8},
Peer: s.ExchangeSession.Id(1),
},
},
})
s.TestExchanges(p2ptest.Exchange{ s.TestExchanges(p2ptest.Exchange{
Expects: []p2ptest.Expect{ Expects: []p2ptest.Expect{
p2ptest.Expect{ p2ptest.Expect{
Code: 1, Code: 1,
Msg: &getPeersMsg{uint(o), 5}, Msg: &getPeersMsg{uint8(o), 5},
Peer: id, Peer: id,
}, },
}, },
// Triggers: []p2ptest.Trigger{
// p2ptest.Trigger{
// Code: 1,
// Msg: &getPeersMsg{0, 1},
// Peer: 0,
// },
// },
// Expects: []p2ptest.Expect{
// p2ptest.Expect{
// Code: 1,
// Msg: &peersMsg{[]*peerAddr{RandomAddr()}},
// Peer: 0,
// },
// },
}) })
} }

View file

@ -50,6 +50,10 @@ adjust Prox (proxLimit and proxSize after an insertion/removal of nodes)
caller holds the lock caller holds the lock
*/ */
type KadDiscovery interface {
NotifyPeer(Peer, uint8) error
NotifyProx(uint8) error
}
type KadParams struct { type KadParams struct {
// adjustable parameters // adjustable parameters
@ -199,12 +203,21 @@ func (self *Kademlia) On(p Peer) {
}) })
kp.seenAt = time.Now() kp.seenAt = time.Now()
kp.retries = 0 kp.retries = 0
f := func(val pot.PotVal, po int) { prox := self.proxLimit()
vp := val.(*KadPeer).Peer
dp.NotifyPeer(kp.PeerAddr, po)
}
self.conns.EachNeighbourAsync(pp, 256, 256, f, nil) vp, ok := kp.Peer.(KadDiscovery)
if !ok {
glog.V(logger.Detail).Infof("not discovery peer")
return
}
// vp.NotifyProx(uint8(prox))
f := func(val pot.PotVal, po int) {
glog.V(logger.Detail).Infof("peer %v nofified", vp)
dp := val.(KadDiscovery)
dp.NotifyPeer(kp.Peer, uint8(po))
dp.NotifyProx(uint8(prox))
}
self.conns.EachNeighbourAsync(pp, 255, 255, f, false)
} }
// Off removes a peer from among live peers // Off removes a peer from among live peers

View file

@ -39,7 +39,6 @@ const (
// bzz is the bzz protocol view of a protocols.Peer (itself an extension of p2p.Peer) // bzz is the bzz protocol view of a protocols.Peer (itself an extension of p2p.Peer)
type bzzPeer struct { type bzzPeer struct {
*protocols.Peer *protocols.Peer
hive PeerPool
network adapters.NodeAdapter network adapters.NodeAdapter
localAddr *peerAddr localAddr *peerAddr
*peerAddr // remote address *peerAddr // remote address
@ -68,22 +67,10 @@ type Peer interface {
ID() discover.NodeID // the key that uniquely identifies the Node for the peerPool ID() discover.NodeID // the key that uniquely identifies the Node for the peerPool
Peers() map[discover.NodeID]bool Peers() map[discover.NodeID]bool
Send(interface{}) error // can send messages Send(interface{}) error // can send messages
Drop() // disconnect this peer Drop(error) // disconnect this peer
Register(interface{}, func(interface{}) error) uint64 // register message-handler callbacks Register(interface{}, func(interface{}) error) uint64 // register message-handler callbacks
} }
// PeerPool is the interface for the connectivity manager
// directly interacts with the p2p server to suggest connections
type PeerPool interface {
Add(Peer) error
Remove(Peer)
}
type PeerInfo interface {
NodeInfo() interface{}
PeerInfo(discover.NodeID) interface{}
}
func BzzCodeMap(msgs ...interface{}) *protocols.CodeMap { func BzzCodeMap(msgs ...interface{}) *protocols.CodeMap {
ct := protocols.NewCodeMap(ProtocolName, Version, ProtocolMaxMsgSize) ct := protocols.NewCodeMap(ProtocolName, Version, ProtocolMaxMsgSize)
ct.Register(&bzzHandshake{}) ct.Register(&bzzHandshake{})
@ -93,13 +80,12 @@ func BzzCodeMap(msgs ...interface{}) *protocols.CodeMap {
// Bzz is the protocol constructor // Bzz is the protocol constructor
// returns p2p.Protocol that is to be offered by the node.Service // returns p2p.Protocol that is to be offered by the node.Service
func Bzz(localAddr []byte, hive PeerPool, na adapters.NodeAdapter, ct *protocols.CodeMap, services func(Peer) error) *p2p.Protocol { func Bzz(localAddr []byte, na adapters.NodeAdapter, ct *protocols.CodeMap, services func(Peer) error) *p2p.Protocol {
run := func(p *protocols.Peer) error { run := func(p *protocols.Peer) error {
addr := &peerAddr{localAddr, na.LocalAddr()} addr := &peerAddr{localAddr, na.LocalAddr()}
bee := &bzzPeer{ bee := &bzzPeer{
Peer: p, Peer: p,
hive: hive,
network: na, network: na,
localAddr: addr, localAddr: addr,
peers: make(map[discover.NodeID]bool), peers: make(map[discover.NodeID]bool),
@ -121,24 +107,10 @@ func Bzz(localAddr []byte, hive PeerPool, na adapters.NodeAdapter, ct *protocols
} }
} }
err = hive.Add(bee)
if err != nil {
glog.V(6).Infof("failed to add peer '%v' to hive: %v", bee.ID(), err)
return err
}
defer hive.Remove(bee)
return bee.Run() return bee.Run()
} }
proto := protocols.NewProtocol(ProtocolName, Version, run, na, ct) return protocols.NewProtocol(ProtocolName, Version, run, na, ct, peerInfo, nodeInfo)
if o, ok := hive.(PeerInfo); ok {
proto.NodeInfo = o.NodeInfo
proto.PeerInfo = o.PeerInfo
}
return proto
} }
/* /*

View file

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"sync" "sync"
"testing" "testing"
"time"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p/adapters" "github.com/ethereum/go-ethereum/p2p/adapters"
@ -37,11 +36,11 @@ func bzzHandshakeExchange(lhs, rhs *bzzHandshake, id *adapters.NodeId) []p2ptest
} }
} }
func newTestBzzProtocol(addr *peerAddr, pp PeerPool, ct *protocols.CodeMap, services func(Peer) error) func(adapters.NodeAdapter) adapters.ProtoCall { func newTestBzzProtocol(addr *peerAddr, ct *protocols.CodeMap, services func(Peer) error) func(adapters.NodeAdapter) adapters.ProtoCall {
if ct == nil { if ct == nil {
ct = BzzCodeMap() ct = BzzCodeMap()
} }
ct.Register(p2ptest.FlushMsg) // ct.Register(p2ptest.FlushMsg)
return func(na adapters.NodeAdapter) adapters.ProtoCall { return func(na adapters.NodeAdapter) adapters.ProtoCall {
srv := func(p Peer) error { srv := func(p Peer) error {
if services != nil { if services != nil {
@ -50,12 +49,12 @@ func newTestBzzProtocol(addr *peerAddr, pp PeerPool, ct *protocols.CodeMap, serv
return err return err
} }
} }
id := p.ID() // id := p.ID()
p.Register(p2ptest.FlushMsg, func(interface{}) error { // p.Register(p2ptest.FlushMsg, func(interface{}) error {
flushc := na.(p2ptest.TestNetAdapter).GetPeer(&adapters.NodeId{id}).Flushc // flushc := na.(p2ptest.TestNetAdapter).GetPeer(&adapters.NodeId{id}).Flushc
flushc <- true // flushc <- true
return nil // return nil
}) // })
return nil return nil
} }
@ -66,7 +65,7 @@ func newTestBzzProtocol(addr *peerAddr, pp PeerPool, ct *protocols.CodeMap, serv
type bzzTester struct { type bzzTester struct {
*p2ptest.ExchangeSession *p2ptest.ExchangeSession
flushCode int // flushCode int
addr *peerAddr addr *peerAddr
} }
@ -81,27 +80,23 @@ func (s *bzzTester) testHandshake(lhs, rhs *bzzHandshake, disconnects ...*p2ptes
} else { } else {
peers = []*adapters.NodeId{id} peers = []*adapters.NodeId{id}
} }
s.TestConnected(false, peers...) s.TestConnected(peers...)
s.TestExchanges(bzzHandshakeExchange(lhs, rhs, id)...) s.TestExchanges(bzzHandshakeExchange(lhs, rhs, id)...)
s.TestDisconnected(disconnects...) s.TestDisconnected(disconnects...)
} }
func (s *bzzTester) flush(ids ...*adapters.NodeId) { // func (s *bzzTester) flush(ids ...*adapters.NodeId) {
s.Flush(s.flushCode, ids...) // s.Flush(s.flushCode, ids...)
} // }
func (s *bzzTester) runHandshakes(ids ...*adapters.NodeId) { func (s *bzzTester) runHandshakes(ids ...*adapters.NodeId) {
if len(ids) == 0 { if len(ids) == 0 {
ids = s.Ids ids = s.Ids
} }
for _, id := range ids { for _, id := range ids {
glog.V(6).Infof("\n\n\nrun handshake with %v", id)
time.Sleep(1)
s.testHandshake(correctBzzHandshake(s.addr), correctBzzHandshake(NewPeerAddrFromNodeId(id))) s.testHandshake(correctBzzHandshake(s.addr), correctBzzHandshake(NewPeerAddrFromNodeId(id)))
time.Sleep(1)
} }
glog.V(6).Infof("flush %v", ids)
s.flush(ids...)
} }
func correctBzzHandshake(addr *peerAddr) *bzzHandshake { func correctBzzHandshake(addr *peerAddr) *bzzHandshake {
@ -109,16 +104,22 @@ func correctBzzHandshake(addr *peerAddr) *bzzHandshake {
} }
func newBzzTester(t *testing.T, addr *peerAddr, pp PeerPool, ct *protocols.CodeMap, services func(Peer) error) *bzzTester { func newBzzTester(t *testing.T, addr *peerAddr, pp PeerPool, ct *protocols.CodeMap, services func(Peer) error) *bzzTester {
s := p2ptest.NewProtocolTester(t, NodeId(addr), 1, newTestBzzProtocol(addr, pp, ct, services))
extraservices := func(p Peer) error {
pp.Add(p)
p.Register(&protocols.Disconnect{}, func(e interface{}) error { pp.Remove(p) })
return services(p)
}
s := p2ptest.NewProtocolTester(t, NodeId(addr), 1, newTestBzzProtocol(addr, pp, ct, extarservices))
return &bzzTester{ return &bzzTester{
addr: addr, addr: addr,
flushCode: 1, // flushCode: 4,
ExchangeSession: s, ExchangeSession: s,
} }
} }
func TestBzzHandshakeNetworkIdMismatch(t *testing.T) { func TestBzzHandshakeNetworkIdMismatch(t *testing.T) {
pp := NewTestPeerPool() pp := p2ptest.NewTestPeerPool()
addr := RandomAddr() addr := RandomAddr()
s := newBzzTester(t, addr, pp, nil, nil) s := newBzzTester(t, addr, pp, nil, nil)
id := s.Ids[0] id := s.Ids[0]
@ -130,7 +131,7 @@ func TestBzzHandshakeNetworkIdMismatch(t *testing.T) {
} }
func TestBzzHandshakeVersionMismatch(t *testing.T) { func TestBzzHandshakeVersionMismatch(t *testing.T) {
pp := NewTestPeerPool() pp := p2ptest.NewTestPeerPool()
addr := RandomAddr() addr := RandomAddr()
s := newBzzTester(t, addr, pp, nil, nil) s := newBzzTester(t, addr, pp, nil, nil)
id := s.Ids[0] id := s.Ids[0]
@ -142,7 +143,7 @@ func TestBzzHandshakeVersionMismatch(t *testing.T) {
} }
func TestBzzHandshakeSuccess(t *testing.T) { func TestBzzHandshakeSuccess(t *testing.T) {
pp := NewTestPeerPool() pp := p2ptest.NewTestPeerPool()
addr := RandomAddr() addr := RandomAddr()
s := newBzzTester(t, addr, pp, nil, nil) s := newBzzTester(t, addr, pp, nil, nil)
id := s.Ids[0] id := s.Ids[0]
@ -153,13 +154,14 @@ func TestBzzHandshakeSuccess(t *testing.T) {
} }
func TestBzzPeerPoolAdd(t *testing.T) { func TestBzzPeerPoolAdd(t *testing.T) {
pp := NewTestPeerPool() pp := p2ptest.NewTestPeerPool()
addr := RandomAddr() addr := RandomAddr()
s := newBzzTester(t, addr, pp, nil, nil) s := newBzzTester(t, addr, pp, nil, nil)
id := s.Ids[0] id := s.Ids[0]
glog.V(6).Infof("handshake with %v", id) glog.V(6).Infof("handshake with %v", id)
s.runHandshakes() s.runHandshakes()
// s.TestConnected()
if !pp.Has(id) { if !pp.Has(id) {
t.Fatalf("peer '%v' not added: %v", id, pp) t.Fatalf("peer '%v' not added: %v", id, pp)
} }
@ -167,7 +169,7 @@ func TestBzzPeerPoolAdd(t *testing.T) {
func TestBzzPeerPoolRemove(t *testing.T) { func TestBzzPeerPoolRemove(t *testing.T) {
addr := RandomAddr() addr := RandomAddr()
pp := NewTestPeerPool() pp := p2ptest.NewTestPeerPool()
s := newBzzTester(t, addr, pp, nil, nil) s := newBzzTester(t, addr, pp, nil, nil)
s.runHandshakes() s.runHandshakes()
@ -181,7 +183,7 @@ func TestBzzPeerPoolRemove(t *testing.T) {
func TestBzzPeerPoolBothAddRemove(t *testing.T) { func TestBzzPeerPoolBothAddRemove(t *testing.T) {
addr := RandomAddr() addr := RandomAddr()
pp := NewTestPeerPool() pp := p2ptest.NewTestPeerPool()
s := newBzzTester(t, addr, pp, nil, nil) s := newBzzTester(t, addr, pp, nil, nil)
s.runHandshakes() s.runHandshakes()
@ -199,7 +201,7 @@ func TestBzzPeerPoolBothAddRemove(t *testing.T) {
func TestBzzPeerPoolNotAdd(t *testing.T) { func TestBzzPeerPoolNotAdd(t *testing.T) {
addr := RandomAddr() addr := RandomAddr()
pp := NewTestPeerPool() pp := p2ptest.NewTestPeerPool()
s := newBzzTester(t, addr, pp, nil, nil) s := newBzzTester(t, addr, pp, nil, nil)
id := s.Ids[0] id := s.Ids[0]
@ -208,40 +210,3 @@ func TestBzzPeerPoolNotAdd(t *testing.T) {
t.Fatalf("peer %v incorrectly added: %v", id, pp) t.Fatalf("peer %v incorrectly added: %v", id, pp)
} }
} }
// TestPeerPool is an example peerPool to demonstrate registration of peer connections
type TestPeerPool struct {
lock sync.Mutex
peers map[discover.NodeID]Peer
}
func NewTestPeerPool() *TestPeerPool {
return &TestPeerPool{peers: make(map[discover.NodeID]Peer)}
}
func (self *TestPeerPool) Add(p Peer) error {
self.lock.Lock()
defer self.lock.Unlock()
self.peers[p.ID()] = p
return nil
}
func (self *TestPeerPool) Remove(p Peer) {
self.lock.Lock()
defer self.lock.Unlock()
// glog.V(6).Infof("removing peer %v", p.ID())
delete(self.peers, p.ID())
}
func (self *TestPeerPool) Has(n *adapters.NodeId) bool {
self.lock.Lock()
defer self.lock.Unlock()
_, ok := self.peers[n.NodeID]
return ok
}
func (self *TestPeerPool) Get(n *adapters.NodeId) Peer {
self.lock.Lock()
defer self.lock.Unlock()
return self.peers[n.NodeID]
}