WIP network rewrite

This commit is contained in:
zelig 2017-05-11 18:07:10 -07:00 committed by Lewis Marshall
parent b77b855f2c
commit c870e2be26
18 changed files with 1024 additions and 835 deletions

View file

@ -135,21 +135,25 @@ func (self *CodeMap) GetCode(msg interface{}) (uint64, bool) {
return code, found return code, found
} }
// NewCodeMap construct the code to type map for the protocol
func NewCodeMap(name string, version uint, maxMsgSize int) *CodeMap { func NewCodeMap(name string, version uint, maxMsgSize int) *CodeMap {
return &CodeMap{ return &CodeMap{
Name: name, Name: name,
Version: version, Version: version,
MaxMsgSize: maxMsgSize, MaxMsgSize: maxMsgSize,
messages: make(map[reflect.Type]uint64), messages: make(map[reflect.Type]uint64),
codes: make(map[uint64]reflect.Type),
} }
} }
// Length returns the current highes codepos + 1
func (self *CodeMap) Length() uint64 { func (self *CodeMap) Length() uint64 {
return uint64(self.codepos) return uint64(self.codepos)
} }
// Register defines a new series of codes starting on series, incrementing
func (self *CodeMap) Register(series int, msgs ...interface{}) { func (self *CodeMap) Register(series int, msgs ...interface{}) {
code := series self.codepos = series
for _, msg := range msgs { for _, msg := range msgs {
typ := reflect.TypeOf(msg) typ := reflect.TypeOf(msg)
_, found := self.messages[typ] _, found := self.messages[typ]
@ -196,7 +200,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
Errc chan error Errc chan error
wErrc chan error // write error channel ready chan bool // blocking send until handshake finishes
} }
// NewPeer returns a new peer // NewPeer returns a new peer
@ -204,12 +208,14 @@ type Peer struct {
// the first two arguments are comming the arguments passed to p2p.Protocol.Run function // the first two arguments are comming the arguments passed to p2p.Protocol.Run function
// the third argument is the CodeMap describing the protocol messages and options // the third argument is the CodeMap describing the protocol messages and options
func NewPeer(p *p2p.Peer, ct *CodeMap, rw p2p.MsgReadWriter) *Peer { func NewPeer(p *p2p.Peer, ct *CodeMap, rw p2p.MsgReadWriter) *Peer {
ready := make(chan bool)
defer close(ready)
return &Peer{ return &Peer{
ct: ct, ct: ct,
Peer: p, Peer: p,
rw: rw, rw: rw,
Errc: make(chan error), Errc: make(chan error),
wErrc: make(chan error), ready: ready,
handlers: make(map[reflect.Type][]func(interface{}) error), handlers: make(map[reflect.Type][]func(interface{}) error),
} }
} }
@ -269,11 +275,17 @@ func (self *Peer) Drop(err error) {
// this low level call will be wrapped by libraries providing routed or broadcast sends // this low level call will be wrapped by libraries providing routed or broadcast sends
// but often just used to forward and push messages to directly connected peers // but often just used to forward and push messages to directly connected peers
func (self *Peer) Send(msg interface{}) error { func (self *Peer) Send(msg interface{}) error {
<-self.ready
return self.send(msg)
}
func (self *Peer) send(msg interface{}) error {
code, found := self.ct.GetCode(msg) code, found := self.ct.GetCode(msg)
if !found { if !found {
return errorf(ErrInvalidMsgType, "%v", code) return errorf(ErrInvalidMsgType, "%v", code)
} }
log.Trace(fmt.Sprintf("=> msg #%d TO %v : %v", code, self.ID(), msg)) log.Trace(fmt.Sprintf("=> msg #%d TO %v : %v", code, self.ID(), msg))
return p2p.Send(self.rw, uint64(code), msg) return p2p.Send(self.rw, uint64(code), msg)
} }
@ -350,29 +362,25 @@ func (self *Peer) Handshake(hs interface{}, handshakeTimeout time.Duration) (rhs
if !found { if !found {
return nil, errorf(ErrHandshake, "unknown handshake message type: %v", typ) return nil, errorf(ErrHandshake, "unknown handshake message type: %v", typ)
} }
errc := make(chan error, 1) self.ready = make(chan bool)
go func() { received := make(chan bool)
if err := self.Send(hs); err != nil { defer close(self.ready)
errc <- errorf(ErrHandshake, "cannot send: %v", err)
}
}()
hsc := make(chan interface{})
go func() { go func() {
defer close(received)
// receiving and validating remote handshake, expect code // receiving and validating remote handshake, expect code
rhs, err := self.handleIncoming() rhs, err = self.handleIncoming()
if err != nil { if err != nil {
errc <- errorf(ErrHandshake, "'%v': %v", self.ct.Name, err) err = errorf(ErrHandshake, "'%v': %v", self.ct.Name, err)
return
} }
hsc <- rhs
}() }()
if e := self.send(hs); e != nil {
return nil, errorf(ErrHandshake, "cannot send: %v", e)
}
select { select {
case err = <-errc: case <-received:
case rhs = <-hsc:
case <-time.NewTimer(handshakeTimeout).C: case <-time.NewTimer(handshakeTimeout).C:
err = errorf(ErrHandshake, "timeout") err = errorf(ErrHandshake, "timeout after %v", handshakeTimeout)
} }
return rhs, err return rhs, err
} }

View file

@ -211,7 +211,8 @@ func (self *SimNode) startRPC(service node.Service) error {
self.lock.Lock() self.lock.Lock()
defer self.lock.Unlock() defer self.lock.Unlock()
if self.client != nil { if self.client != nil {
return errors.New("RPC already started") return nil
// return errors.New("RPC already started")
} }
// add SimAdminAPI so that the network can call the // add SimAdminAPI so that the network can call the

View file

@ -275,6 +275,7 @@ func (self *Network) startWithSnapshot(id *adapters.NodeId, snapshot []byte) err
} }
log.Trace(fmt.Sprintf("starting node %v: %v using %v", id, node.Up, self.nodeAdapter.Name())) log.Trace(fmt.Sprintf("starting node %v: %v using %v", id, node.Up, self.nodeAdapter.Name()))
if err := node.Start(snapshot); err != nil { if err := node.Start(snapshot); err != nil {
log.Warn(fmt.Sprintf("start up failed: %v", err))
return err return err
} }
node.Up = true node.Up = true

View file

@ -287,3 +287,62 @@ func (self *BoolAddress) PO(val PotVal, pos int) (po int, eq bool) {
} }
return po, true return po, true
} }
type BytesAddress interface {
Bytes() []byte
}
type bytesAddress struct {
bytes []byte
toBytes func(v AnyVal) []byte
}
func NewBytesVal(v AnyVal, f func(v AnyVal) []byte) *bytesAddress {
if f == nil {
f = ToBytes
}
b := f(v)
return &bytesAddress{b, f}
}
func ToBytes(v AnyVal) []byte {
b, ok := v.([]byte)
if !ok {
ba, ok := v.(BytesAddress)
if !ok {
panic(fmt.Sprintf("unsupported value type %T", v))
}
b = ba.Bytes()
}
return b
}
func (a *bytesAddress) String() string {
return fmt.Sprintf("%08b", a.bytes)
}
func (a *bytesAddress) Bytes() []byte {
return a.bytes
}
func (a *bytesAddress) PO(val PotVal, i int) (int, bool) {
return proximityOrder(a.bytes, a.toBytes(val), i)
}
func proximityOrder(one, other []byte, pos int) (int, bool) {
for i := pos / 8; i < len(one); i++ {
if one[i] == other[i] {
continue
}
oxo := one[i] ^ other[i]
start := 0
if i == pos/8 {
start = pos % 8
}
for j := start; j < 8; j++ {
if (uint8(oxo)>>uint8(7-j))&0x01 != 0 {
return i*8 + j, false
}
}
}
return len(one) * 8, true
}

View file

@ -45,6 +45,8 @@ type PotVal interface {
String() string String() string
} }
type AnyVal interface{}
// Pot constructor. Requires value of type PotVal to pin // Pot constructor. Requires value of type PotVal to pin
// and po to point to a span in the PotVal key // and po to point to a span in the PotVal key
// The pinned item counts towards the size // The pinned item counts towards the size
@ -245,11 +247,12 @@ func remove(t *pot, val PotVal) (r *pot, po int, found bool) {
// if f returns v' <> v then v' is inserted into the Pot // if f returns v' <> v then v' is inserted into the Pot
// if v' == v the pot is not changed // if v' == v the pot is not changed
// it panics if v'.PO(k, 0) says v and k are not equal // it panics if v'.PO(k, 0) says v and k are not equal
func (t *Pot) Swap(val PotVal, f func(v PotVal) PotVal) (po int, found bool, change bool) { func (t *Pot) Swap(val AnyVal, f func(v PotVal) PotVal) (po int, found bool, change bool) {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
ba := NewBytesVal(val, nil)
var t0 *pot var t0 *pot
t0, po, found, change = swap(t.pot, val, f) t0, po, found, change = swap(t.pot, ba, f)
if change { if change {
t.pot = t0 t.pot = t0
} }

View file

@ -16,7 +16,7 @@ var DiscoveryMsgs = []interface{}{
} }
type discPeer struct { type discPeer struct {
Peer *bzzPeer
overlay Overlay overlay Overlay
peers map[string]bool peers map[string]bool
proxLimit uint8 // the proximity radius advertised by remote to subscribe to peers proxLimit uint8 // the proximity radius advertised by remote to subscribe to peers
@ -25,10 +25,10 @@ type discPeer struct {
// discovery peer contructor // discovery peer contructor
// registers the handlers for discovery messages // registers the handlers for discovery messages
func NewDiscovery(p Peer, o Overlay) *discPeer { func NewDiscovery(p *bzzPeer, o Overlay) *discPeer {
self := &discPeer{ self := &discPeer{
overlay: o, overlay: o,
Peer: p, bzzPeer: p,
peers: make(map[string]bool), peers: make(map[string]bool),
} }
self.seen(self) self.seen(self)
@ -42,15 +42,15 @@ func NewDiscovery(p Peer, o Overlay) *discPeer {
// NotifyPeer notifies the receiver remote end of a peer p or PO po. // NotifyPeer notifies the receiver remote end of a peer p or PO po.
// callback for overlay driver // callback for overlay driver
func (self *discPeer) NotifyPeer(p Peer, po uint8) error { func (self *discPeer) NotifyPeer(p OverlayPeer, po uint8) error {
log.Warn(fmt.Sprintf("peer %#v peers %v", p, self.peers)) log.Warn(fmt.Sprintf("peer %#v peers %v", p, self.peers))
if po < self.proxLimit || self.seen(p) { if po < self.proxLimit || self.seen(p) {
return nil return nil
} }
log.Warn(fmt.Sprintf("notification about %x", p.OverlayAddr())) log.Warn(fmt.Sprintf("notification about %x", p.Address()))
resp := &peersMsg{ resp := &peersMsg{
Peers: []*peerAddr{&peerAddr{OAddr: p.OverlayAddr(), UAddr: p.UnderlayAddr()}}, // perhaps the PeerAddr interface is unnecessary generalization Peers: []*bzzAddr{ToAddr(p)}, // perhaps the PeerAddr interface is unnecessary generalization
} }
return self.Send(resp) return self.Send(resp)
} }
@ -83,7 +83,7 @@ disconnected
// used for communicating about known peers // used for communicating about known peers
// relevant for bootstrapping connectivity and updating peersets // relevant for bootstrapping connectivity and updating peersets
type peersMsg struct { type peersMsg struct {
Peers []*peerAddr Peers []*bzzAddr
} }
func (self peersMsg) String() string { func (self peersMsg) String() string {
@ -113,14 +113,15 @@ func (self *discPeer) handleSubPeersMsg(msg interface{}) error {
spm := msg.(*subPeersMsg) spm := msg.(*subPeersMsg)
self.proxLimit = spm.ProxLimit self.proxLimit = spm.ProxLimit
if !self.sentPeers { if !self.sentPeers {
var peers []*peerAddr var peers []*bzzAddr
self.overlay.EachLivePeer(self.OverlayAddr(), 255, func(p Peer, po int, isproxbin bool) bool { self.overlay.EachConn(self.Over(), 255, func(p OverlayConn, po int, isproxbin bool) bool {
if uint8(po) < self.proxLimit { if uint8(po) < self.proxLimit {
return false return false
} }
log.Warn(fmt.Sprintf("peer %#v proxlimit %v", p, self.proxLimit)) log.Warn(fmt.Sprintf("peer %#v proxlimit %v", p, self.proxLimit))
self.seen(p.(*discPeer).Peer) if !self.seen(p) {
peers = append(peers, &peerAddr{p.OverlayAddr(), p.UnderlayAddr()}) peers = append(peers, ToAddr(p))
}
return true return true
}) })
log.Warn(fmt.Sprintf("found initial %v peers not farther than %v", len(peers), self.proxLimit)) log.Warn(fmt.Sprintf("found initial %v peers not farther than %v", len(peers), self.proxLimit))
@ -139,35 +140,37 @@ func (self *discPeer) handleSubPeersMsg(msg interface{}) error {
// Register interface method // Register interface method
func (self *discPeer) handlePeersMsg(msg interface{}) error { func (self *discPeer) handlePeersMsg(msg interface{}) error {
// register all addresses // register all addresses
var nas []PeerAddr as := msg.(*peersMsg).Peers
for _, na := range msg.(*peersMsg).Peers { if len(as) == 0 {
addr := PeerAddr(na)
nas = append(nas, addr)
self.seen(addr)
}
if len(nas) == 0 {
log.Debug(fmt.Sprintf("whoops, no peers in incoming peersMsg from %v", self)) log.Debug(fmt.Sprintf("whoops, no peers in incoming peersMsg from %v", self))
return nil return nil
} }
log.Debug(fmt.Sprintf("got peer addresses from %x, %v (%v)", self.OverlayAddr(), nas, len(nas)))
return self.overlay.Register(nas...) var c chan OverlayAddr
go func() {
for _, a := range as {
self.seen(a)
c <- a
}
}()
return self.overlay.Register(c)
} }
// handleGetPeersMsg is called by the protocol when receiving a // handleGetPeersMsg is called by the protocol when receiving a
// peerset (for target address) request // peerset (for target address) request
// peers suggestions are retrieved from the overlay topology driver // peers suggestions are retrieved from the overlay topology driver
// using the EachLivePeer interface iterator method // using the EachConn interface iterator method
// peers sent are remembered throughout a session and not sent twice // peers sent are remembered throughout a session and not sent twice
func (self *discPeer) handleGetPeersMsg(msg interface{}) error { func (self *discPeer) handleGetPeersMsg(msg interface{}) error {
var peers []*peerAddr var peers []*bzzAddr
req := msg.(*getPeersMsg) req := msg.(*getPeersMsg)
i := 0 i := 0
self.overlay.EachLivePeer(self.OverlayAddr(), int(req.Order), func(n Peer, po int, isproxbin bool) bool { self.overlay.EachConn(self.Over(), int(req.Order), func(p OverlayConn, po int, isproxbin bool) bool {
i++ i++
// only send peers we have not sent before in this session // only send peers we have not sent before in this session
if self.seen(n) { a := ToAddr(p)
peers = append(peers, &peerAddr{n.OverlayAddr(), n.UnderlayAddr()}) if self.seen(a) {
peers = append(peers, a)
} }
return len(peers) < int(req.Max) return len(peers) < int(req.Max)
}) })
@ -189,9 +192,8 @@ func RequestOrder(k Overlay, order, broadcastSize, maxPeers uint8) {
} }
var i uint8 var i uint8
//var err error //var err error
k.EachLivePeer(nil, 255, func(n Peer, po int, isproxbin bool) bool { k.EachConn(nil, 255, func(p OverlayConn, po int, isproxbin bool) bool {
log.Trace(fmt.Sprintf("%T sent to %v", req, n)) if err := p.(Conn).Send(req); err == nil {
if err := n.Send(req); err == nil {
i++ i++
if i >= broadcastSize { if i >= broadcastSize {
return false return false
@ -202,8 +204,8 @@ func RequestOrder(k Overlay, order, broadcastSize, maxPeers uint8) {
log.Info(fmt.Sprintf("requesting bees of PO%03d from %v/%v (each max %v)", order, i, broadcastSize, maxPeers)) log.Info(fmt.Sprintf("requesting bees of PO%03d from %v/%v (each max %v)", order, i, broadcastSize, maxPeers))
} }
func (self *discPeer) seen(p PeerAddr) bool { func (self *discPeer) seen(p OverlayPeer) bool {
k := NodeId(p).NodeID.String() k := string(p.Address())
if self.peers[k] { if self.peers[k] {
return true return true
} }

View file

@ -18,7 +18,7 @@ func TestDiscovery(t *testing.T) {
to := NewKademlia(addr.OAddr, NewKadParams()) to := NewKademlia(addr.OAddr, NewKadParams())
ct := BzzCodeMap(DiscoveryMsgs...) ct := BzzCodeMap(DiscoveryMsgs...)
services := func(p Peer) error { services := func(p *bzzPeer) error {
dp := NewDiscovery(p, to) dp := NewDiscovery(p, to)
to.On(dp) to.On(dp)
log.Trace(fmt.Sprintf("kademlia on %v", p)) log.Trace(fmt.Sprintf("kademlia on %v", p))
@ -32,7 +32,6 @@ func TestDiscovery(t *testing.T) {
defer s.Stop() defer s.Stop()
s.runHandshakes() s.runHandshakes()
// o := 0
s.TestExchanges(p2ptest.Exchange{ s.TestExchanges(p2ptest.Exchange{
Label: "outgoing SubPeersMsg", Label: "outgoing SubPeersMsg",
Expects: []p2ptest.Expect{ Expects: []p2ptest.Expect{

View file

@ -17,6 +17,7 @@
package network package network
import ( import (
"encoding/json"
"fmt" "fmt"
"sync" "sync"
"time" "time"
@ -39,38 +40,51 @@ and relay the peer request process to the Overlay module
peer connections and disconnections are reported and registered peer connections and disconnections are reported and registered
to keep the nodetable uptodate to keep the nodetable uptodate
*/ */
// Overlay is the interface to Jaak ahd ka)a
type Overlay interface { type Overlay interface {
Register(...PeerAddr) error Register(chan OverlayAddr) error
On(Peer) On(OverlayPeer)
Off(Peer) Off(OverlayConn)
EachLivePeer([]byte, int, func(Peer, int, bool) bool) EachConn([]byte, int, func(OverlayConn, int, bool) bool)
EachPeer([]byte, int, func(PeerAddr, int) bool) EachAddr([]byte, int, func(OverlayAddr, int) bool)
SuggestPeer() (PeerAddr, int, bool) SuggestPeer() (OverlayAddr, int, bool)
String() string String() string
GetAddr() PeerAddr BaseAddr() []byte
}
// ReadWriter interface to persist known peers, uses disk for real nodes
type ReadWriter interface {
ReadAll(string) ([]byte, error)
WriteAll(string, []byte) error
} }
// Hive implements the PeerPool interface // Hive implements the PeerPool interface
type Hive struct { type Hive struct {
*HiveParams // settings *HiveParams // settings
Overlay // the overlay topology driver Overlay // the overlay topology driver
lock sync.Mutex RW ReadWriter // ReadWriter
quit chan bool
toggle chan bool // bookkeeping
more chan bool lock sync.Mutex
quit chan bool
toggle chan bool
more chan bool
} }
// HiveParams holds the config options to hive
type HiveParams struct { type HiveParams struct {
Discovery bool Discovery bool // if want discovery of not
PeersBroadcastSetSize uint8 PeersBroadcastSetSize uint8 // how many peers to use when relaying
MaxPeersPerRequest uint8 MaxPeersPerRequest uint8 // max size for peer address batches
CallInterval uint CallInterval uint // polling interval fir===
} }
// NewHiveParams returns hive config with only the
func NewHiveParams() *HiveParams { func NewHiveParams() *HiveParams {
return &HiveParams{ return &HiveParams{
Discovery: true, Discovery: true,
@ -81,8 +95,8 @@ func NewHiveParams() *HiveParams {
} }
// Hive constructor embeds both arguments // Hive constructor embeds both arguments
// HiveParams config parameters // HiveParams: config parameters
// Overlay Topology Driver Interface // Overlay: Topology Driver Interface
func NewHive(params *HiveParams, overlay Overlay) *Hive { func NewHive(params *HiveParams, overlay Overlay) *Hive {
return &Hive{ return &Hive{
HiveParams: params, HiveParams: params,
@ -91,11 +105,16 @@ func NewHive(params *HiveParams, overlay Overlay) *Hive {
} }
// Start receives network info only at startup // Start receives network info only at startup
// connectPeer is a function to connect to a peer based on its NodeID or enode URL // server is used to connect to a peer based on its NodeID or enode URL
// these are called on the p2p.Server which runs on the node // these are called on the p2p.Server which runs on the node
// af() returns an arbitrary ticker channel // af() returns an arbitrary ticker channel
func (self *Hive) Start(server p2p.Server, af func() <-chan time.Time) error { // rw is a read writer for json configs
func (self *Hive) Start(server p2p.Server, af func() <-chan time.Time, rw ReadWriter) error {
if rw != nil {
if err := self.loadPeers(); err != nil {
return err
}
}
self.toggle = make(chan bool) self.toggle = make(chan bool)
self.more = make(chan bool, 1) self.more = make(chan bool, 1)
self.quit = make(chan bool) self.quit = make(chan bool)
@ -115,9 +134,9 @@ func (self *Hive) Start(server p2p.Server, af func() <-chan time.Time) error {
if addr != nil { if addr != nil {
log.Info(fmt.Sprintf("========> connect to bee %v", addr)) log.Info(fmt.Sprintf("========> connect to bee %v", addr))
node, err := discover.ParseNode(NodeId(addr).NodeID.String()) under, err := discover.ParseNode(string(addr.(Addr).Under()))
if err == nil { if err == nil {
server.AddPeer(node) server.AddPeer(under)
} else { } else {
log.Error(fmt.Sprintf("===X====> connect to bee %v failed: invalid node URL: %v", addr, err)) log.Error(fmt.Sprintf("===X====> connect to bee %v failed: invalid node URL: %v", addr, err))
} }
@ -127,7 +146,7 @@ func (self *Hive) Start(server p2p.Server, af func() <-chan time.Time) error {
want = want && self.Discovery want = want && self.Discovery
if want { if want {
go RequestOrder(self.Overlay, uint8(order), self.PeersBroadcastSetSize, self.MaxPeersPerRequest) RequestOrder(self.Overlay, uint8(order), self.PeersBroadcastSetSize, self.MaxPeersPerRequest)
} }
select { select {
@ -136,20 +155,98 @@ func (self *Hive) Start(server p2p.Server, af func() <-chan time.Time) error {
case <-self.quit: case <-self.quit:
return return
} }
log.Info(fmt.Sprintf("%v", self)) // log.Info(fmt.Sprintf("%v", self))
} }
}() }()
return nil return nil
} }
// Stop terminates the updateloop and saves the peers
func (self *Hive) Stop() {
if self.RW != nil {
self.savePeers()
}
// closing toggle channel quits the updateloop
close(self.quit)
}
// default ticker, tickinterval is taken from KadParams.CallInterval
func (self *Hive) ticker() <-chan time.Time { func (self *Hive) ticker() <-chan time.Time {
return time.NewTicker(time.Duration(self.CallInterval) * time.Millisecond).C return time.NewTicker(time.Duration(self.CallInterval) * time.Millisecond).C
} }
// Add is called at the end of a successful protocol handshake
// to register a connected (live) peer
func (self *Hive) Add(p *bzzPeer) error {
defer self.wake()
dp := NewDiscovery(p, self.Overlay)
log.Debug(fmt.Sprintf("to add new bee %v", p))
self.On(dp)
self.String()
log.Debug(fmt.Sprintf("%v", self))
return nil
}
// Remove called after peer is disconnected
func (self *Hive) Remove(p *bzzPeer) {
defer self.wake()
log.Debug(fmt.Sprintf("remove bee %v", p))
self.Off(p)
}
// NodeInfo function is used by the p2p.server RPC interface to display
// protocol specific node information
func (self *Hive) NodeInfo() interface{} {
return interface{}(self.String())
}
// PeerInfo function is used by the p2p.server RPC interface to display
// protocol specific information any connected peer referred to by their NodeID
func (self *Hive) PeerInfo(id discover.NodeID) interface{} {
self.lock.Lock()
defer self.lock.Unlock()
addr := NewAddrFromNodeId(adapters.NewNodeId(id[:]))
return interface{}(addr)
}
// Healthy reports the health state of the kademlia connectivity
//
func (self *Hive) Healthy() bool {
// TODO: determine if we have enough peers to consider the network
// to be healthy
return true
}
// wake triggers
func (self *Hive) wake() {
select {
case self.more <- true:
log.Trace("hive woken up")
case <-self.quit:
default:
log.Trace("hive already awake")
}
}
// HexToBytes reads a hex string ontp
func HexToBytes(s string) []byte {
id := discover.MustHexID(s)
return id[:]
}
// ToAddr returns the serialisable version of u
func ToAddr(pa OverlayPeer) *bzzAddr {
if addr, ok := pa.(*bzzAddr); ok {
return addr
}
return pa.(*bzzPeer).bzzAddr
}
// keepAlive is a forever loop // keepAlive is a forever loop
// in its awake state it periodically triggers connection attempts // in its awake state it periodically triggers connection attempts
// by writing to self.more until Kademlia Table is saturated // by writing to self.more until Kademlia Table is saturated
// wake state is toggled by writing to self.toggle // wake state is toggled by writing to self.toggle
// it goes to sleep mode if table is saturated
// it restarts if the table becomes non-full again due to disconnections // it restarts if the table becomes non-full again due to disconnections
func (self *Hive) keepAlive(af func() <-chan time.Time) { func (self *Hive) keepAlive(af func() <-chan time.Time) {
log.Trace("keep alive loop started") log.Trace("keep alive loop started")
@ -173,63 +270,48 @@ func (self *Hive) keepAlive(af func() <-chan time.Time) {
} }
} }
// Add is called at the end of a successful protocol handshake // loadPeers, savePeer implement persistence callback/
// to register a connected (live) peer func (self *Hive) loadPeers() error {
func (self *Hive) Add(p Peer) error { rw := self.RW
defer self.wake() data, err := rw.ReadAll("peers")
dp := NewDiscovery(p, self.Overlay) if err != nil {
log.Debug(fmt.Sprintf("to add new bee %v", p)) return err
self.On(dp) }
self.String() if data == nil {
log.Debug(fmt.Sprintf("%v", self)) return nil
}
var as []*bzzAddr
if err := json.Unmarshal(data, &as); err != nil {
return err
}
var c chan OverlayAddr
defer close(c)
go func() {
for _, a := range as {
c <- a
}
}()
return self.Overlay.Register(c)
}
// savePeers, savePeer implement persistence callback/
func (self *Hive) savePeers() error {
var peers []*bzzAddr
self.Overlay.EachAddr(nil, 256, func(pa OverlayAddr, i int) bool {
if pa == nil {
log.Warn(fmt.Sprintf("empty addr: %v", i))
return true
}
peers = append(peers, ToAddr(pa))
return true
})
data, err := json.Marshal(peers)
if err != nil {
return fmt.Errorf("could not encode peers: %v", err)
}
if err := self.RW.WriteAll("peers", data); err != nil {
return fmt.Errorf("could not save peers: %v", err)
}
return nil return nil
} }
// Remove called after peer is disconnected
func (self *Hive) Remove(p Peer) {
defer self.wake()
log.Debug(fmt.Sprintf("remove bee %v", p))
self.Off(p)
}
// NodeInfo function is used by the p2p.server RPC interface to display
// protocol specific node information
func (self *Hive) NodeInfo() interface{} {
return interface{}(self.String())
}
// PeerInfo function is used by the p2p.server RPC interface to display
// protocol specific information any connected peer referred to by their NodeID
func (self *Hive) PeerInfo(id discover.NodeID) interface{} {
self.lock.Lock()
defer self.lock.Unlock()
addr := NewPeerAddrFromNodeId(adapters.NewNodeId(id[:]))
return interface{}(addr)
}
// Stop terminates the updateloop
func (self *Hive) Stop() {
// closing toggle channel quits the updateloop
close(self.quit)
}
func (self *Hive) Healthy() bool {
// TODO: determine if we have enough peers to consider the network
// to be healthy
return true
}
func (self *Hive) wake() {
select {
case self.more <- true:
log.Trace("hive woken up")
case <-self.quit:
default:
log.Trace("hive already awake")
}
}
func HexToBytes(s string) []byte {
id := discover.MustHexID(s)
return id[:]
}

View file

@ -30,12 +30,13 @@ func (self *testConnect) connect(na string) error {
func newHiveTester(t *testing.T, params *HiveParams) (*bzzTester, *Hive) { func newHiveTester(t *testing.T, params *HiveParams) (*bzzTester, *Hive) {
// setup // setup
addr := RandomAddr() // tested peers peer address addr := RandomAddr() // tested peers peer address
to := NewTestOverlay(addr.OverlayAddr()) // overlay topology drive // to := NewTestOverlay(addr.Over()) // overlay topology drive
pp := NewHive(params, to) // hive pp := NewHive(params, nil) // hive
// pp := NewHive(params, to) // hive
ct := BzzCodeMap(DiscoveryMsgs...) // bzz protocol code map ct := BzzCodeMap(DiscoveryMsgs...) // bzz protocol code map
services := func(p Peer) error { services := func(p *bzzPeer) error {
pp.Add(p) pp.Add(p)
p.DisconnectHook(func(err error) { p.DisconnectHook(func(err error) {
pp.Remove(p) pp.Remove(p)
@ -53,14 +54,14 @@ func TestOverlayRegistration(t *testing.T) {
defer s.Stop() defer s.Stop()
id := s.Ids[0] id := s.Ids[0]
raddr := NewPeerAddrFromNodeId(id) raddr := NewAddrFromNodeId(id)
s.runHandshakes() s.runHandshakes()
// hive should have called the overlay // hive should have called the overlay
if pp.Overlay.(*testOverlay).posMap[string(raddr.OverlayAddr())] == nil { // if pp.Overlay.(*testOverlay).posMap[string(raddr.Over())] == nil {
t.Fatalf("Overlay#On not called on new peer") // t.Fatalf("Overlay#On not called on new peer")
} // }
} }
@ -70,7 +71,7 @@ func TestRegisterAndConnect(t *testing.T) {
defer s.Stop() defer s.Stop()
id := s.Ids[0] id := s.Ids[0]
raddr := NewPeerAddrFromNodeId(id) raddr := NewAddrFromNodeId(id)
pp.Register(raddr) pp.Register(raddr)
@ -82,18 +83,18 @@ func TestRegisterAndConnect(t *testing.T) {
}, },
ticker: make(chan time.Time), ticker: make(chan time.Time),
} }
pp.Start(s, tc.ping) pp.Start(s, tc.ping, nil)
defer pp.Stop() defer pp.Stop()
tc.ticker <- time.Now() tc.ticker <- time.Now()
s.runHandshakes() s.runHandshakes()
if pp.Overlay.(*testOverlay).posMap[string(raddr.OverlayAddr())] == nil { // if pp.Overlay.(*testOverlay).posMap[string(raddr.Over())] == nil {
t.Fatalf("Overlay#On not called on new peer") // t.Fatalf("Overlay#On not called on new peer")
} // }
// retrieve and broadcast // retrieve and broadcast
ord := order(raddr.OverlayAddr()) ord := order(raddr.Over())
o := 0 o := 0
if ord == 0 { if ord == 0 {
o = 1 o = 1

View file

@ -46,24 +46,20 @@ a guaranteed constant maximum limit on the number of hops needed to reach one
node from the other. node from the other.
*/ */
type KadDiscovery interface { // KadParams holds the config params for Kademlia
NotifyPeer(Peer, uint8) error
NotifyProx(uint8) error
}
type KadParams struct { type KadParams struct {
// adjustable parameters // adjustable parameters
MaxProxDisplay int MaxProxDisplay int // number of rows the table shows
MinProxBinSize int MinProxBinSize int // nearest neighbour core minimum cardinality
MinBinSize int MinBinSize int // minimum number of peers in a row
MaxBinSize int MaxBinSize int // maximum number of peers in a row before pruning
RetryInterval int RetryInterval int // initial interval before a peer is first redialed
RetryExponent int RetryExponent int // exponent to multiply retry intervals with
MaxRetries int MaxRetries int // maximum number of redial attempts
PruneInterval int PruneInterval int // interval between peer pruning cycles
} }
// NewKadParams() returns a params struct with default values // NewKadParams returns a params struct with default values
func NewKadParams() *KadParams { func NewKadParams() *KadParams {
return &KadParams{ return &KadParams{
MaxProxDisplay: 8, MaxProxDisplay: 8,
@ -79,141 +75,94 @@ func NewKadParams() *KadParams {
// Kademlia is a table of live peers and a db of known peers // Kademlia is a table of live peers and a db of known peers
type Kademlia struct { type Kademlia struct {
addr PeerAddr // immutable baseaddress of the table *KadParams // Kademlia configuration parameters
// addr *pot.HashAddress // immutable baseaddress of the table base []byte // immutable baseaddress of the table
*KadParams // Kademlia configuration parameters addrs *pot.Pot // pots container for known peer addresses
addrs, peers *pot.Pot // pots container for peers conns *pot.Pot // pots container for live peer connections
lastProxLimit uint8 // stores the last calculated proxlimit depth uint8 // stores the last calculated depth
} }
// NewKademlia(addr, params) creates a Kademlia table for base address addr // NewKademlia creates a Kademlia table for base address addr
// with parameters as in params // with parameters as in params
// if params is nil, it uses default values // if params is nil, it uses default values
func NewKademlia(addr []byte, params *KadParams) *Kademlia { func NewKademlia(addr []byte, params *KadParams) *Kademlia {
if params == nil { if params == nil {
params = NewKadParams() params = NewKadParams()
} }
self := &Kademlia{ return &Kademlia{
addr: &peerAddr{OAddr: addr}, base: addr,
KadParams: params, KadParams: params,
addrs: pot.NewPot(nil, 0), addrs: pot.NewPot(nil, 0),
peers: pot.NewPot(nil, 0), conns: pot.NewPot(nil, 0),
} }
return self
} }
// Prune implements a forever loop reacting to a ticker time channel given type Notifier interface {
// as the first argument NotifyPeer(OverlayConn, uint8) error
// the loop quits if the channel is closed NotifyDepth(uint8) error
// it checks each kademlia bin and if the peer count is higher than
// the MaxBinSize parameter it drops the oldest n peers such that
// the bin is reduced to MinBinSize peers thus leaving slots to newly
// connecting peers
func (self *Kademlia) Prune(c <-chan time.Time) {
go func() {
for _ = range c {
log.Debug("pruning...")
total := 0
self.peers.EachBin(self.addr, 0, func(po, size int, f func(func(pot.PotVal, int) bool) bool) bool {
extra := size - self.MinBinSize
if size > self.MaxBinSize {
n := 0
f(func(v pot.PotVal, po int) bool {
p := v.(*KadPeer).Peer
if p != nil {
p.Drop(fmt.Errorf("bucket full"))
}
n++
return n < extra
})
total += extra
}
return true
})
log.Debug(fmt.Sprintf("pruned %v peers", total))
}
}()
} }
// KadPeer represents a Kademlia Peer and extends // OverlayPeer interface captures the common aspect of view of a peer from the Overlay
// * PeerAddr interface (overlay and underlay addresses) // topology driver
// * Peer interface (id, last seen, drop) type OverlayPeer interface {
type KadPeer struct { Address() []byte
PeerAddr }
Peer Peer
// OverlayConn represents a connected peer
type OverlayConn interface {
OverlayPeer
Drop(error) // call to indicate a peer should be expunged
Off() OverlayAddr // call to return a persitent OverlayAddr
}
type OverlayAddr interface {
OverlayPeer
On(OverlayConn) OverlayConn // call to return the connected peer
Update(OverlayAddr) OverlayAddr // returns the updated version of the original
}
// entry represents a Kademlia table entry (an extension of OverlayPeer)
// implements the pot.PotVal interface via BytesAddress, so entry can be
// used directly as a pot element
type entry struct {
pot.PotVal
OverlayPeer
seenAt time.Time seenAt time.Time
retries int retries int
} }
func (self *KadPeer) String() string { // newEntry creates a kademlia peer from an OverlayPeer interface
if self == nil { func newEntry(p OverlayPeer) *entry {
return "<nil>" return &entry{
} PotVal: pot.NewBytesVal(p, nil),
return fmt.Sprintf("%x", self.OverlayAddr()) OverlayPeer: p,
} seenAt: time.Now(),
func (self *Kademlia) callable(val pot.PotVal) *KadPeer {
kp := val.(*KadPeer)
// not callable if peer is live or exceeded maxRetries
if kp.Peer != nil || kp.retries > self.MaxRetries {
log.Trace(fmt.Sprintf("peer %v (%T) not callable", kp, kp.Peer))
return nil
}
// calculate the allowed number of retries based on time lapsed since last seen
timeAgo := time.Since(kp.seenAt)
var retries int
for delta := int(timeAgo) / self.RetryInterval; delta > 0; delta /= self.RetryExponent {
log.Trace(fmt.Sprintf("delta: %v", delta))
retries++
}
// this is never called concurrently, so safe to increment
// peer can be retried again
if retries < kp.retries {
log.Trace(fmt.Sprintf("log time needed before retry %v, wait only warrants %v", kp.retries, retries))
return nil
}
kp.retries++
log.Trace(fmt.Sprintf("peer %v is callable", kp))
return kp
}
// NewKadPeer creates a kademlia peer from a PeerAddr interface
func NewKadPeer(na PeerAddr) *KadPeer {
return &KadPeer{
PeerAddr: na,
seenAt: time.Now(),
} }
} }
// retrieve the base address func (self *entry) String() string {
// which is the overlayaddress used by peers to reach us return fmt.Sprintf("%x", self.Address())
func (self *Kademlia) GetAddr() PeerAddr {
return self.addr
} }
// Register(nas) enters each PeerAddr as kademlia peers into the // Register enters each OverlayAddr as kademlia peer record into the
// database of known peers // database of known peer addresses
func (self *Kademlia) Register(nas ...PeerAddr) error { func (self *Kademlia) Register(peers chan OverlayAddr) error {
label := fmt.Sprintf("%x", RandomAddr().OverlayAddr()) if len(peers) == 0 {
return fmt.Errorf("empty peers list")
}
np := pot.NewPot(nil, 0) np := pot.NewPot(nil, 0)
for _, na := range nas { defer func() { self.addrs.Merge(np) }()
if bytes.Equal(na.OverlayAddr(), self.addr.OverlayAddr()) { for p := range peers {
log.Warn(fmt.Sprintf("[%06s] add peers: %x is self.. skipped ", label, self.addr.OverlayAddr())) // error if self received, peer should know better
continue if bytes.Equal(p.Address(), self.base) {
return fmt.Errorf("add peers: %x is self", self.base)
} }
p := NewKadPeer(na) np, _, _ = pot.Add(np, pot.PotVal(newEntry(p)))
np, _, _ = pot.Add(np, pot.PotVal(p))
} }
oldpeers := pot.NewPot(nil, 0) // TODO: remove this check
oldpeers.Merge(self.addrs)
self.addrs.Merge(np)
m := make(map[string]bool) m := make(map[string]bool)
self.addrs.Each(func(val pot.PotVal, i int) bool { self.addrs.Each(func(val pot.PotVal, i int) bool {
_, found := m[val.String()] _, found := m[val.String()]
// TODO: remove this check
// log.Debug(fmt.Sprintf("-> %v %v", val, i))
if found { if found {
panic("duplicate found") panic("duplicate found")
} }
@ -223,148 +172,32 @@ func (self *Kademlia) Register(nas ...PeerAddr) error {
return nil return nil
} }
// On(p) inserts the peer as a kademlia peer into the live peers
func (self *Kademlia) On(p Peer) {
kp := NewKadPeer(p)
kp.Peer = p
self.peers.Swap(kp, func(v pot.PotVal) pot.PotVal {
// if not found live
if v == nil {
// switch the offline peer
self.addrs.Swap(kp, func(v pot.PotVal) pot.PotVal {
return pot.PotVal(kp)
})
// insert new peer
return pot.PotVal(kp)
}
// found among live peers, do nothing
return v
})
prox := self.proxLimit()
vp, ok := kp.Peer.(KadDiscovery)
if !ok {
// log.Trace(fmt.Sprintf("not discovery peer %T", kp))
return
}
go vp.NotifyProx(uint8(prox))
f := func(val pot.PotVal, po int) {
dp := val.(*KadPeer).Peer.(KadDiscovery)
log.Debug(fmt.Sprintf("peer %v notified of %v (%v)", dp, kp, po))
dp.NotifyPeer(kp.Peer, uint8(po))
if uint8(prox) != self.lastProxLimit {
self.lastProxLimit = uint8(prox)
dp.NotifyProx(uint8(prox))
}
log.Debug("peer notified")
}
self.peers.EachNeighbourAsync(kp, 1024, 255, f, false)
}
// Off removes a peer from among live peers
func (self *Kademlia) Off(p Peer) {
kp := NewKadPeer(p)
self.addrs.Swap(kp, func(v pot.PotVal) pot.PotVal {
if v != nil {
self.peers.Swap(kp, func(v pot.PotVal) pot.PotVal {
return nil
})
}
return nil
})
}
type ByteAddr struct {
key []byte
}
// EachLivePeer(base, po, f) is an iterator applying f to each live peer
// that has proximity order po or less as measured from the base
// if base is nil, kademlia base address is used
func (self *Kademlia) EachLivePeer(base []byte, o int, f func(Peer, int, bool) bool) {
var p pot.PotVal
if base == nil {
p = pot.PotVal(self.addr)
} else {
p = pot.PotVal(&peerAddr{OAddr: base})
}
self.peers.EachNeighbour(p, func(val pot.PotVal, po int) bool {
if po > o {
return true
}
isproxbin := false
if l, _ := p.PO(val, 0); l >= self.proxLimit() {
isproxbin = true
}
return f(val.(*KadPeer).Peer, po, isproxbin)
})
}
// EachPeer(base, po, f) is an iterator applying f to each known peer
// that has proximity order po or less as measured from the base
// if base is nil, kademlia base address is used
func (self *Kademlia) EachPeer(base []byte, o int, f func(PeerAddr, int) bool) {
var p pot.PotVal
if base == nil {
p = pot.PotVal(self.addr)
} else {
p = pot.NewHashAddressFromBytes(base)
}
self.addrs.EachNeighbour(p, func(val pot.PotVal, po int) bool {
if po > o {
return true
}
return f(val.(*KadPeer).Peer, po)
})
}
// proxLimit() returns the proximity order that defines the distance of
// the nearest neighbour set with cardinality >= MinProxBinSize
// if there is altogether less than MinProxBinSize peers it returns 0
func (self *Kademlia) proxLimit() int {
if self.peers.Size() < self.MinProxBinSize {
return 0
}
var proxLimit int
var size int
f := func(v pot.PotVal, i int) bool {
size++
proxLimit = i
return size < self.MinProxBinSize
}
self.peers.EachNeighbour(pot.PotVal(self.addr), f)
return proxLimit
}
// SuggestPeer returns a known peer for the lowest proximity bin for the // SuggestPeer returns a known peer for the lowest proximity bin for the
// lowest bincount below proxLimit // lowest bincount below depth
// naturally if there is an empty row it returns a peer for that // naturally if there is an empty row it returns a peer for that
// //
func (self *Kademlia) SuggestPeer() (p PeerAddr, o int, want bool) { func (self *Kademlia) SuggestPeer() (a OverlayAddr, o int, want bool) {
minsize := self.MinBinSize minsize := self.MinBinSize
proxLimit := self.proxLimit() depth := self.Depth()
// if there is a callable neighbour within the current proxBin, connect // if there is a callable neighbour within the current proxBin, connect
// this makes sure nearest neighbour set is fully connected // this makes sure nearest neighbour set is fully connected
log.Trace(fmt.Sprintf("candidate prox peer checking above PO %v", proxLimit)) log.Trace(fmt.Sprintf("candidate prox peer checking above PO %v", depth))
var ppo int var ppo int
self.addrs.EachNeighbour(self.addr, func(val pot.PotVal, po int) bool { ba := pot.NewBytesVal(self.base, nil)
r := self.callable(val) self.addrs.EachNeighbour(ba, func(val pot.PotVal, po int) bool {
if r == nil { a = self.callable(val)
return po >= proxLimit
}
p = r
ppo = po ppo = po
return false return a != nil && po >= depth
}) })
if p != nil { if a != nil {
log.Trace(fmt.Sprintf("candidate prox peer found: %v (%v), %v", p, ppo, p)) log.Trace(fmt.Sprintf("candidate prox peer found: %v (%v)", a, ppo))
return p, 0, false return a, 0, false
} }
log.Trace(fmt.Sprintf("no candidate prox peers to connect to (ProxLimit: %v, minProxSize: %v)", proxLimit, self.MinProxBinSize)) log.Trace(fmt.Sprintf("no candidate prox peers to connect to (Depth: %v, minProxSize: %v)", depth, self.MinProxBinSize))
var bpo []int var bpo []int
prev := -1 prev := -1
self.peers.EachBin(self.addr, 0, func(po, size int, f func(func(val pot.PotVal, i int) bool) bool) bool { self.conns.EachBin(pot.NewBytesVal(self.base, nil), 0, func(po, size int, f func(func(val pot.PotVal, i int) bool) bool) bool {
log.Trace(fmt.Sprintf("check PO%02d: ", po)) log.Trace(fmt.Sprintf("check PO%02d: ", po))
prev++ prev++
if po > prev { if po > prev {
@ -375,7 +208,7 @@ func (self *Kademlia) SuggestPeer() (p PeerAddr, o int, want bool) {
minsize = size minsize = size
bpo = append(bpo, po) bpo = append(bpo, po)
} }
return size > 0 && po < proxLimit return size > 0 && po < depth
}) })
// all buckets are full // all buckets are full
// minsize == self.MinBinSize // minsize == self.MinBinSize
@ -387,28 +220,165 @@ func (self *Kademlia) SuggestPeer() (p PeerAddr, o int, want bool) {
// try to select a candidate peer // try to select a candidate peer
for i := len(bpo) - 1; i >= 0; i-- { for i := len(bpo) - 1; i >= 0; i-- {
// find the first callable peer // find the first callable peer
self.addrs.EachBin(self.addr, bpo[i], func(po, size int, f func(func(val pot.PotVal, i int) bool) bool) bool { self.addrs.EachBin(ba, bpo[i], func(po, size int, f func(func(pot.PotVal, int) bool) bool) bool {
// for each bin we find callable candidate peers // for each bin we find callable candidate peers
f(func(val pot.PotVal, i int) bool { log.Trace(fmt.Sprintf("check PO%02d: ", po))
r := self.callable(val) f(func(val pot.PotVal, j int) bool {
log.Trace(fmt.Sprintf("check PO%02d: ", po)) a = self.callable(val)
if r == nil { return a != nil && po < depth
return i < proxLimit
}
p = r
return false
}) })
return false return false
}) })
// found a candidate // found a candidate
if p != nil { if a != nil {
break break
} }
// cannot find a candidate, ask for more for this proximity bin specifically // cannot find a candidate, ask for more for this proximity bin specifically
o = bpo[i] o = bpo[i]
want = true want = true
} }
return p, o, want return a, o, want
}
// On inserts the peer as a kademlia peer into the live peers
func (self *Kademlia) On(p OverlayPeer) {
e := newEntry(p)
self.conns.Swap(p, func(v pot.PotVal) pot.PotVal {
// if not found live
if v == nil {
// insert new online peer into addrs
self.addrs.Swap(p, func(v pot.PotVal) pot.PotVal {
return e
})
// insert new online peer into conns
return e
}
// found among live peers, do nothing
return v
})
np, ok := p.(Notifier)
if !ok {
return
}
depth := uint8(self.Depth())
if depth != self.depth {
self.depth = depth
} else {
depth = 0
}
go np.NotifyDepth(depth)
f := func(val pot.PotVal, po int) {
dp := val.(Notifier)
dp.NotifyPeer(p.(OverlayConn), uint8(po))
log.Trace(fmt.Sprintf("peer %v notified of %v (%v)", dp, p, po))
if depth > 0 {
dp.NotifyDepth(depth)
log.Trace("peer %v notified of new depth limit %v", dp, depth)
}
}
self.conns.EachNeighbourAsync(e, 1024, 255, f, false)
}
// Off removes a peer from among live peers
func (self *Kademlia) Off(p OverlayConn) {
self.addrs.Swap(p, func(v pot.PotVal) pot.PotVal {
// v cannot be nil, must check otherwise we overwrite entry
if v == nil {
panic(fmt.Sprintf("connected peer not found %v", p))
}
self.conns.Swap(p, func(v pot.PotVal) pot.PotVal {
// v cannot nil, but no need to check
return nil
})
return newEntry(p)
})
}
// EachConn is an iterator with args (base, po, f) applies f to each live peer
// that has proximity order po or less as measured from the base
// if base is nil, kademlia base address is used
func (self *Kademlia) EachConn(base []byte, o int, f func(OverlayConn, int, bool) bool) {
if len(base) == 0 {
base = self.base
}
p := pot.NewBytesVal(base, nil)
self.conns.EachNeighbour(p, func(val pot.PotVal, po int) bool {
if po > o {
return true
}
isproxbin := false
if l, _ := p.PO(val, 0); l >= self.Depth() {
isproxbin = true
}
return f(val.(OverlayConn), po, isproxbin)
})
}
// EachAddr(base, po, f) is an iterator applying f to each known peer
// that has proximity order po or less as measured from the base
// if base is nil, kademlia base address is used
func (self *Kademlia) EachAddr(base []byte, o int, f func(OverlayAddr, int) bool) {
if len(base) == 0 {
base = self.base
}
p := pot.NewBytesVal(base, nil)
self.addrs.EachNeighbour(p, func(val pot.PotVal, po int) bool {
if po > o {
return true
}
return f(val.(OverlayAddr), po)
})
}
// Depth returns the proximity order that defines the distance of
// the nearest neighbour set with cardinality >= MinProxBinSize
// if there is altogether less than MinProxBinSize peers it returns 0
func (self *Kademlia) Depth() (depth int) {
if self.conns.Size() < self.MinProxBinSize {
return 0
}
var size int
f := func(v pot.PotVal, i int) bool {
size++
depth = i
return size < self.MinProxBinSize
}
self.conns.EachNeighbour(pot.NewBytesVal(self.base, nil), f)
return depth
}
func (self *Kademlia) callable(val pot.PotVal) OverlayAddr {
e := val.(*entry)
// not callable if peer is live or exceeded maxRetries
if _, live := val.(OverlayConn); live || e.retries > self.MaxRetries {
log.Trace(fmt.Sprintf("peer %v (%T) not callable", e, e.OverlayPeer))
return nil
}
// calculate the allowed number of retries based on time lapsed since last seen
timeAgo := time.Since(e.seenAt)
var retries int
for delta := int(timeAgo) / self.RetryInterval; delta > 0; delta /= self.RetryExponent {
log.Trace(fmt.Sprintf("delta: %v", delta))
retries++
}
// this is never called concurrently, so safe to increment
// peer can be retried again
if retries < e.retries {
log.Trace(fmt.Sprintf("log time needed before retry %v, wait only warrants %v", e.retries, retries))
return nil
}
e.retries++
log.Trace(fmt.Sprintf("peer %v is callable", e))
return val.(OverlayAddr)
}
func (self *Kademlia) BaseAddr() []byte {
return self.base
} }
// kademlia table + kaddb table displayed with ascii // kademlia table + kaddb table displayed with ascii
@ -417,16 +387,16 @@ func (self *Kademlia) String() string {
var rows []string var rows []string
rows = append(rows, "=========================================================================") rows = append(rows, "=========================================================================")
rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %v", time.Now().UTC().Format(time.UnixDate), fmt.Sprintf("%x", self.addr.OverlayAddr()[:3]))) rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %v", time.Now().UTC().Format(time.UnixDate), self))
rows = append(rows, fmt.Sprintf("population: %d (%d), MinProxBinSize: %d, MinBinSize: %d, MaxBinSize: %d", self.peers.Size(), self.addrs.Size(), self.MinProxBinSize, self.MinBinSize, self.MaxBinSize)) rows = append(rows, fmt.Sprintf("population: %d (%d), MinProxBinSize: %d, MinBinSize: %d, MaxBinSize: %d", self.conns.Size(), self.addrs.Size(), self.MinProxBinSize, self.MinBinSize, self.MaxBinSize))
liverows := make([]string, self.MaxProxDisplay) liverows := make([]string, self.MaxProxDisplay)
peersrows := make([]string, self.MaxProxDisplay) peersrows := make([]string, self.MaxProxDisplay)
var proxLimit int var depth int
prev := -1 prev := -1
var proxLimitSet bool var depthSet bool
rest := self.peers.Size() rest := self.conns.Size()
self.peers.EachBin(self.addr, 0, func(po, size int, f func(func(val pot.PotVal, i int) bool) bool) bool { self.conns.EachBin(pot.NewBytesVal(self.base, nil), 0, func(po, size int, f func(func(val pot.PotVal, i int) bool) bool) bool {
var rowlen int var rowlen int
if po >= self.MaxProxDisplay { if po >= self.MaxProxDisplay {
po = self.MaxProxDisplay - 1 po = self.MaxProxDisplay - 1
@ -434,13 +404,13 @@ func (self *Kademlia) String() string {
row := []string{fmt.Sprintf("%2d", size)} row := []string{fmt.Sprintf("%2d", size)}
rest -= size rest -= size
f(func(val pot.PotVal, vpo int) bool { f(func(val pot.PotVal, vpo int) bool {
row = append(row, val.(*KadPeer).String()[:6]) row = append(row, val.(*entry).String()[:6])
rowlen++ rowlen++
return rowlen < 4 return rowlen < 4
}) })
if !proxLimitSet && (po > prev+1 || rest < self.MinProxBinSize) { if !depthSet && (po > prev+1 || rest < self.MinProxBinSize) {
proxLimitSet = true depthSet = true
proxLimit = prev + 1 depth = prev + 1
} }
for ; rowlen <= 5; rowlen++ { for ; rowlen <= 5; rowlen++ {
row = append(row, " ") row = append(row, " ")
@ -450,7 +420,7 @@ func (self *Kademlia) String() string {
return true return true
}) })
self.addrs.EachBin(self.addr, 0, func(po, size int, f func(func(val pot.PotVal, i int) bool) bool) bool { self.addrs.EachBin(pot.NewBytesVal(self.base, nil), 0, func(po, size int, f func(func(val pot.PotVal, i int) bool) bool) bool {
var rowlen int var rowlen int
if po >= self.MaxProxDisplay { if po >= self.MaxProxDisplay {
po = self.MaxProxDisplay - 1 po = self.MaxProxDisplay - 1
@ -461,8 +431,7 @@ func (self *Kademlia) String() string {
row := []string{fmt.Sprintf("%2d", size)} row := []string{fmt.Sprintf("%2d", size)}
// we are displaying live peers too // we are displaying live peers too
f(func(val pot.PotVal, vpo int) bool { f(func(val pot.PotVal, vpo int) bool {
kp := val.(*KadPeer) row = append(row, val.(*entry).String()[:6])
row = append(row, kp.String()[:6])
rowlen++ rowlen++
return rowlen < 4 return rowlen < 4
}) })
@ -471,7 +440,7 @@ func (self *Kademlia) String() string {
}) })
for i := 0; i < self.MaxProxDisplay; i++ { for i := 0; i < self.MaxProxDisplay; i++ {
if i == proxLimit { if i == depth {
rows = append(rows, fmt.Sprintf("============ PROX LIMIT: %d ==========================================", i)) rows = append(rows, fmt.Sprintf("============ PROX LIMIT: %d ==========================================", i))
} }
left := liverows[i] left := liverows[i]
@ -487,3 +456,32 @@ func (self *Kademlia) String() string {
rows = append(rows, "=========================================================================") rows = append(rows, "=========================================================================")
return "\n" + strings.Join(rows, "\n") return "\n" + strings.Join(rows, "\n")
} }
// Prune implements a forever loop reacting to a ticker time channel given
// as the first argument
// the loop quits if the channel is closed
// it checks each kademlia bin and if the peer count is higher than
// the MaxBinSize parameter it drops the oldest n peers such that
// the bin is reduced to MinBinSize peers thus leaving slots to newly
// connecting peers
func (self *Kademlia) Prune(c <-chan time.Time) {
go func() {
for range c {
total := 0
self.conns.EachBin(nil, 0, func(po, size int, f func(func(pot.PotVal, int) bool) bool) bool {
extra := size - self.MinBinSize
if size > self.MaxBinSize {
n := 0
f(func(v pot.PotVal, po int) bool {
v.(OverlayConn).Drop(fmt.Errorf("bucket full"))
n++
return n < extra
})
total += extra
}
return true
})
log.Debug(fmt.Sprintf("pruned %v peers", total))
}
}()
}

View file

@ -21,13 +21,12 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/pot" "github.com/ethereum/go-ethereum/pot"
) )
func testKadPeerAddr(s string) *peerAddr { func testKadPeerAddr(s string) *bzzAddr {
a := pot.NewHashAddress(s).Bytes() a := pot.NewHashAddress(s).Bytes()
return &peerAddr{OAddr: a, UAddr: a} return &bzzAddr{OAddr: a, UAddr: a}
} }
type testDropPeer struct { type testDropPeer struct {
@ -70,7 +69,7 @@ func (self *testDiscPeer) NotifyProx(po uint8) error {
return nil return nil
} }
func (self *testDiscPeer) NotifyPeer(p Peer, po uint8) error { func (self *testDiscPeer) NotifyPeer(p OverlayPeer, po uint8) error {
key := overlayStr(self) key := overlayStr(self)
key += overlayStr(p) key += overlayStr(p)
self.lock.Lock() self.lock.Lock()
@ -102,15 +101,15 @@ func newTestKademlia(b string) *testKademlia {
} }
func (k *testKademlia) newTestKadPeer(s string) Peer { func (k *testKademlia) newTestKadPeer(s string) Peer {
dp := &testDropPeer{&bzzPeer{peerAddr: testKadPeerAddr(s)}, k.dropc} dp := &testDropPeer{&bzzPeer{bzzAddr: testKadPeerAddr(s)}, k.dropc}
if k.Discovery { if k.Discovery {
return Peer(&testDiscPeer{dp, k.lock, k.notifications}) return Peer(&testDiscPeer{dp, k.lock, k.notifications})
} }
return Peer(dp) return Peer(dp)
} }
func overlayStr(a PeerAddr) string { func overlayStr(a OverlayPeer) string {
log.Error(fmt.Sprintf("PeerAddr: %v (%T)", a, a)) // log.Error(fmt.Sprintf("PeerAddr: %v (%T)", a, a))
// if a == (*KadPeer)(nil) || a == (*testDiscPeer)(nil) || a == (*bzzPeer)(nil) || a == nil { // if a == (*KadPeer)(nil) || a == (*testDiscPeer)(nil) || a == (*bzzPeer)(nil) || a == nil {
// return "<nil>" // return "<nil>"
// } // }
@ -126,14 +125,15 @@ func overlayStr(a PeerAddr) string {
// return "<nil>" // return "<nil>"
// } // }
// return pot.NewHashAddressFromBytes(p.OverlayAddr()).Bin()[:6] // return pot.NewHashAddressFromBytes(p.OverlayAddr()).Bin()[:6]
if a == nil { // if a == nil {
return "<nil>" // return "<nil>"
} // }
k, ok := a.(*KadPeer) // k, ok := a.(*KadPeer)
if ok && k.Peer != nil { // if ok && k.Peer != nil {
return pot.ToBin(a.(*KadPeer).Peer.OverlayAddr())[:6] // return pot.ToBin(a.(*KadPeer).Peer.Over())[:6]
} // }
return pot.ToBin(a.OverlayAddr())[:6] // return pot.ToBin(a.Over())[:6]
return pot.ToBin(a.Address())
} }
func (k *testKademlia) On(ons ...string) *testKademlia { func (k *testKademlia) On(ons ...string) *testKademlia {
@ -146,16 +146,16 @@ func (k *testKademlia) On(ons ...string) *testKademlia {
func (k *testKademlia) Off(offs ...string) *testKademlia { func (k *testKademlia) Off(offs ...string) *testKademlia {
for _, s := range offs { for _, s := range offs {
k.Kademlia.Off(k.newTestKadPeer(s)) k.Kademlia.Off(k.newTestKadPeer(s).(OverlayConn))
} }
return k return k
} }
func (k *testKademlia) Register(regs ...string) *testKademlia { func (k *testKademlia) Register(regs ...string) *testKademlia {
var ps []PeerAddr var ps []Addr
for _, s := range regs { for _, s := range regs {
ps = append(ps, PeerAddr(testKadPeerAddr(s))) ps = append(ps, Addr(testKadPeerAddr(s)))
} }
k.Kademlia.Register(ps...) k.Kademlia.Register(ps...)
return k return k

View file

@ -26,7 +26,6 @@ import (
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/protocols" "github.com/ethereum/go-ethereum/p2p/protocols"
"github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
"github.com/ethereum/go-ethereum/pot"
) )
const ( const (
@ -36,51 +35,68 @@ const (
ProtocolMaxMsgSize = 10 * 1024 * 1024 ProtocolMaxMsgSize = 10 * 1024 * 1024
) )
// bzz is the bzz protocol view of a protocols.Peer (itself an extension of p2p.Peer) // the Addr interface that peerPool needs
type bzzPeer struct { type Addr interface {
*protocols.Peer OverlayPeer
localAddr *peerAddr Over() []byte
*peerAddr // remote address Under() []byte
lastActive time.Time String() string
} }
// Peer interface represents an live peer connection
type Peer interface {
Addr // the address of a peer
Conn // the live connection (protocols.Peer)
LastActive() time.Time // last time active
}
// Conn interface represents an live peer connection
type Conn interface {
ID() discover.NodeID // the key that uniquely identifies the Node for the peerPool
Handshake(interface{}, time.Duration) (interface{}, error) // can send messages
Send(interface{}) error // can send messages
Drop(error) // disconnect this peer
Register(interface{}, func(interface{}) error) uint64 // register message-handler callbacks
DisconnectHook(func(error)) // register message-handler callbacks
Run() error // the run function to run a protocol
}
// bzzPeer is the bzz protocol view of a protocols.Peer (itself an extension of p2p.Peer)
// implements the Peer interface and all interfaces Peer implements: Addr, OverlayPeer
type bzzPeer struct {
Conn // represents the connection for online peers
localAddr *bzzAddr // local Peers address
*bzzAddr // remote address -> implements Addr interface = protocols.Peer
lastActive time.Time // time is updated whenever mutexes are releasing
}
// Off returns the overlay peer record for offline persistance
func (self *bzzPeer) Off() OverlayAddr {
return self.bzzAddr
}
// LastActive returns the time the peer was last active
func (self *bzzPeer) LastActive() time.Time { func (self *bzzPeer) LastActive() time.Time {
return self.lastActive return self.lastActive
} }
// implemented by peerAddr // BzzCodeMap compiles the message codes and message types bzz wire protocol.
type PeerAddr interface { // note each call to Register can start a new series (initial code is arg1)
OverlayAddr() []byte // the initial offset for a series is arbitrary (to ensure u)
UnderlayAddr() []byte
PO(pot.PotVal, int) (int, bool)
String() string
}
// the Peer interface that peerPool needs
type Peer interface {
PeerAddr
// String() string // pretty printable the Node
ID() discover.NodeID // the key that uniquely identifies the Node for the peerPool
Send(interface{}) error // can send messages
Drop(error) // disconnect this peer
Register(interface{}, func(interface{}) error) uint64 // register message-handler callbacks
DisconnectHook(func(error))
}
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(0, &bzzHandshake{})
ct.Register(msgs...) ct.Register(1, msgs...)
return ct return ct
} }
// Bzz is the protocol constructor // NewBzz 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(oAddr, uAddr []byte, ct *protocols.CodeMap, services func(Peer) error, peerInfo func(id discover.NodeID) interface{}, nodeInfo func() interface{}) *p2p.Protocol { func NewBzz(over, under []byte, ct *protocols.CodeMap, services func(*bzzPeer) error, peerInfo func(id discover.NodeID) interface{}, nodeInfo func() interface{}) *p2p.Protocol {
run := func(p *protocols.Peer) error { run := func(p *protocols.Peer) error {
bee := &bzzPeer{ bee := &bzzPeer{
Peer: p, Conn: p,
localAddr: &peerAddr{oAddr, uAddr}, localAddr: &bzzAddr{over, under},
} }
// protocol handshake and its validation // protocol handshake and its validation
// sets remote peer address // sets remote peer address
@ -115,57 +131,43 @@ func Bzz(oAddr, uAddr []byte, ct *protocols.CodeMap, services func(Peer) error,
type bzzHandshake struct { type bzzHandshake struct {
Version uint64 Version uint64
NetworkId uint64 NetworkId uint64
Addr *peerAddr Addr *bzzAddr
} }
func (self *bzzHandshake) String() string { func (self *bzzHandshake) String() string {
return fmt.Sprintf("Handshake: Version: %v, NetworkId: %v, Addr: %v", self.Version, self.NetworkId, self.Addr) return fmt.Sprintf("Handshake: Version: %v, NetworkId: %v, Addr: %v", self.Version, self.NetworkId, self.Addr)
} }
// peerAddr implements the PeerAddress interface // bzzAddr implements the PeerAddr interface
type peerAddr struct { type bzzAddr struct {
OAddr []byte OAddr []byte
UAddr []byte UAddr []byte
} }
func (self *peerAddr) OverlayAddr() []byte { // implements OverlayPeer interface to be used in pot package
func (self *bzzAddr) Address() []byte {
return self.OAddr return self.OAddr
} }
func (self *peerAddr) UnderlayAddr() []byte { func (self *bzzAddr) Over() []byte {
return self.OAddr
}
func (self *bzzAddr) Under() []byte {
return self.UAddr return self.UAddr
} }
func (self *peerAddr) PO(val pot.PotVal, pos int) (int, bool) { func (self *bzzAddr) On(p OverlayConn) OverlayConn {
kp := val.(PeerAddr) bp := p.(*bzzPeer)
one := kp.OverlayAddr() bp.bzzAddr = self
other := self.OAddr return bp
for i := pos / 8; i < len(one); i++ {
if one[i] == other[i] {
continue
}
oxo := one[i] ^ other[i]
start := 0
if i == pos/8 {
start = pos % 8
}
for j := start; j < 8; j++ {
if (uint8(oxo)>>uint8(7-j))&0x01 != 0 {
return i*8 + j, false
}
}
}
return len(one) * 8, true
// var ha *pot.HashAddress
// var left, right string
// if ok {
// ha = kp.HashAddress
// } else {
// ha = val.(*pot.HashAddress)
// }
} }
func (self *peerAddr) String() string { func (self *bzzAddr) Update(a OverlayAddr) OverlayAddr {
return &bzzAddr{self.OAddr, a.(Addr).Under()}
}
func (self *bzzAddr) String() string {
return fmt.Sprintf("%x <%x>", self.OAddr, self.UAddr) return fmt.Sprintf("%x <%x>", self.OAddr, self.UAddr)
} }
@ -180,22 +182,20 @@ func (self *bzzPeer) bzzHandshake() error {
Addr: self.localAddr, Addr: self.localAddr,
} }
hs, err := self.Handshake(lhs) hs, err := self.Handshake(lhs, time.Second)
if err != nil { if err != nil {
log.Error(fmt.Sprintf("handshake failed: %v", err)) log.Error(fmt.Sprintf("handshake failed: %v", err))
return err return err
} }
rhs := hs.(*bzzHandshake) rhs := hs.(*bzzHandshake)
self.peerAddr = rhs.Addr self.bzzAddr = rhs.Addr
err = checkBzzHandshake(rhs) err = checkBzzHandshake(rhs)
if err != nil { if err != nil {
log.Error(fmt.Sprintf("handshake between %v and %v failed: %v", self.localAddr, self.peerAddr, err)) log.Error(fmt.Sprintf("handshake between %v and %v failed: %v", self.localAddr, self.bzzAddr, err))
return err return err
} }
return nil return nil
} }
// checkBzzHandshake checks for the validity and compatibility of the remote handshake // checkBzzHandshake checks for the validity and compatibility of the remote handshake
@ -213,7 +213,7 @@ func checkBzzHandshake(rhs *bzzHandshake) error {
} }
// RandomAddr is a utility method generating an address from a public key // RandomAddr is a utility method generating an address from a public key
func RandomAddr() *peerAddr { func RandomAddr() *bzzAddr {
key, err := crypto.GenerateKey() key, err := crypto.GenerateKey()
if err != nil { if err != nil {
panic("unable to generate key") panic("unable to generate key")
@ -221,23 +221,20 @@ func RandomAddr() *peerAddr {
pubkey := crypto.FromECDSAPub(&key.PublicKey) pubkey := crypto.FromECDSAPub(&key.PublicKey)
var id discover.NodeID var id discover.NodeID
copy(id[:], pubkey[1:]) copy(id[:], pubkey[1:])
return &peerAddr{ return &bzzAddr{
OAddr: crypto.Keccak256(pubkey[1:]), OAddr: crypto.Keccak256(pubkey[1:]),
UAddr: id[:], UAddr: id[:],
} }
} }
// NodeId transforms the underlay address to an adapters.NodeId // NewNodeIdFromAddr transforms the underlay address to an adapters.NodeId
func NodeId(addr PeerAddr) *adapters.NodeId { func NewNodeIdFromAddr(addr Addr) *adapters.NodeId {
return adapters.NewNodeId(addr.UnderlayAddr()) return adapters.NewNodeId(addr.Under())
} }
// NewPeerAddrFromNodeId constucts a peerAddr from an adapters.NodeId // NewAddrFromNodeId constucts a bzzAddr from an adapters.NodeId
// the overlay address is derived as the hash of the nodeId // the overlay address is derived as the hash of the nodeId
func NewPeerAddrFromNodeId(n *adapters.NodeId) *peerAddr { func NewAddrFromNodeId(n *adapters.NodeId) *bzzAddr {
id := n.NodeID id := n.NodeID
return &peerAddr{ return &bzzAddr{crypto.Keccak256(id[:]), id[:]}
OAddr: crypto.Keccak256(id[:]),
UAddr: id[:],
}
} }

View file

@ -34,28 +34,28 @@ func bzzHandshakeExchange(lhs, rhs *bzzHandshake, id *adapters.NodeId) []p2ptest
} }
} }
func newBzzBaseTester(t *testing.T, n int, addr *peerAddr, ct *protocols.CodeMap, services func(Peer) error) *bzzTester { func newBzzBaseTester(t *testing.T, n int, addr *bzzAddr, ct *protocols.CodeMap, services func(*bzzPeer) error) *bzzTester {
if ct == nil { if ct == nil {
ct = BzzCodeMap() ct = BzzCodeMap()
} }
cs := make(map[string]chan bool) cs := make(map[string]chan bool)
srv := func(p Peer) error { srv := func(p *bzzPeer) error {
defer close(cs[p.ID().String()]) defer close(cs[p.ID().String()])
return services(p) return services(p)
} }
protocall := Bzz(addr.OverlayAddr(), addr.UnderlayAddr(), ct, srv, nil, nil).Run protocall := NewBzz(addr.Over(), addr.Under(), ct, srv, nil, nil).Run
s := p2ptest.NewProtocolTester(t, NodeId(addr), n, protocall) s := p2ptest.NewProtocolTester(t, NewNodeIdFromAddr(addr), n, protocall)
for _, id := range s.Ids { for _, id := range s.Ids {
cs[id.NodeID.String()] = make(chan bool) cs[id.NodeID.String()] = make(chan bool)
} }
return &bzzTester{ return &bzzTester{
addr: addr, addr: addr.Address(),
ProtocolTester: s, ProtocolTester: s,
cs: cs, cs: cs,
} }
@ -63,13 +63,13 @@ func newBzzBaseTester(t *testing.T, n int, addr *peerAddr, ct *protocols.CodeMap
type bzzTester struct { type bzzTester struct {
*p2ptest.ProtocolTester *p2ptest.ProtocolTester
addr *peerAddr addr []byte
cs map[string]chan bool cs map[string]chan bool
} }
func newBzzTester(t *testing.T, n int, addr *peerAddr, pp *p2ptest.TestPeerPool, ct *protocols.CodeMap, services func(Peer) error) *bzzTester { func newBzzTester(t *testing.T, n int, addr *bzzAddr, pp *p2ptest.TestPeerPool, ct *protocols.CodeMap, services func(Peer) error) *bzzTester {
extraservices := func(p Peer) error { extraservices := func(p *bzzPeer) error {
pp.Add(p) pp.Add(p)
p.DisconnectHook(func(err error) { p.DisconnectHook(func(err error) {
pp.Remove(p) pp.Remove(p)
@ -88,7 +88,7 @@ func newBzzTester(t *testing.T, n int, addr *peerAddr, pp *p2ptest.TestPeerPool,
// should test handshakes in one exchange? parallelisation // should test handshakes in one exchange? parallelisation
func (s *bzzTester) testHandshake(lhs, rhs *bzzHandshake, disconnects ...*p2ptest.Disconnect) { func (s *bzzTester) testHandshake(lhs, rhs *bzzHandshake, disconnects ...*p2ptest.Disconnect) {
var peers []*adapters.NodeId var peers []*adapters.NodeId
id := NodeId(rhs.Addr) id := NewNodeIdFromAddr(rhs.Addr)
if len(disconnects) > 0 { if len(disconnects) > 0 {
for _, d := range disconnects { for _, d := range disconnects {
peers = append(peers, d.Peer) peers = append(peers, d.Peer)
@ -106,13 +106,13 @@ func (s *bzzTester) runHandshakes(ids ...*adapters.NodeId) {
ids = s.Ids ids = s.Ids
} }
for _, id := range ids { for _, id := range ids {
s.testHandshake(correctBzzHandshake(s.addr), correctBzzHandshake(NewPeerAddrFromNodeId(id))) s.testHandshake(correctBzzHandshake(s.addr), correctBzzHandshake(NewAddrFromNodeId(id)))
<-s.cs[id.NodeID.String()] <-s.cs[id.NodeID.String()]
} }
} }
func correctBzzHandshake(addr *peerAddr) *bzzHandshake { func correctBzzHandshake(addr *bzzAddr) *bzzHandshake {
return &bzzHandshake{0, 322, addr} return &bzzHandshake{0, 322, addr}
} }
@ -125,7 +125,7 @@ func TestBzzHandshakeNetworkIdMismatch(t *testing.T) {
id := s.Ids[0] id := s.Ids[0]
s.testHandshake( s.testHandshake(
correctBzzHandshake(addr), correctBzzHandshake(addr),
&bzzHandshake{0, 321, NewPeerAddrFromNodeId(id)}, &bzzHandshake{0, 321, NewAddrFromNodeId(id)},
&p2ptest.Disconnect{Peer: id, Error: fmt.Errorf("network id mismatch 321 (!= 322)")}, &p2ptest.Disconnect{Peer: id, Error: fmt.Errorf("network id mismatch 321 (!= 322)")},
) )
} }
@ -139,7 +139,7 @@ func TestBzzHandshakeVersionMismatch(t *testing.T) {
id := s.Ids[0] id := s.Ids[0]
s.testHandshake( s.testHandshake(
correctBzzHandshake(addr), correctBzzHandshake(addr),
&bzzHandshake{1, 322, NewPeerAddrFromNodeId(id)}, &bzzHandshake{1, 322, NewAddrFromNodeId(id)},
&p2ptest.Disconnect{Peer: id, Error: fmt.Errorf("version mismatch 1 (!= 0)")}, &p2ptest.Disconnect{Peer: id, Error: fmt.Errorf("version mismatch 1 (!= 0)")},
) )
} }
@ -153,7 +153,7 @@ func TestBzzHandshakeSuccess(t *testing.T) {
id := s.Ids[0] id := s.Ids[0]
s.testHandshake( s.testHandshake(
correctBzzHandshake(addr), correctBzzHandshake(addr),
&bzzHandshake{0, 322, NewPeerAddrFromNodeId(id)}, &bzzHandshake{0, 322, NewAddrFromNodeId(id)},
) )
} }
@ -215,7 +215,7 @@ func TestBzzPeerPoolNotAdd(t *testing.T) {
defer s.Stop() defer s.Stop()
id := s.Ids[0] id := s.Ids[0]
s.testHandshake(correctBzzHandshake(addr), &bzzHandshake{0, 321, NewPeerAddrFromNodeId(id)}, &p2ptest.Disconnect{Peer: id, Error: fmt.Errorf("network id mismatch 321 (!= 322)")}) s.testHandshake(correctBzzHandshake(addr), &bzzHandshake{0, 321, NewAddrFromNodeId(id)}, &p2ptest.Disconnect{Peer: id, Error: fmt.Errorf("network id mismatch 321 (!= 322)")})
if pp.Has(id) { if pp.Has(id) {
t.Fatalf("peer %v incorrectly added: %v", id, pp) t.Fatalf("peer %v incorrectly added: %v", id, pp)
} }

View file

@ -80,7 +80,7 @@ type pssEnvelope struct {
TTL uint16 TTL uint16
Payload []byte Payload []byte
SenderOAddr []byte SenderOAddr []byte
SenderUAddr []byte // SenderUAddr []byte
} }
// Pre-Whisper placeholder // Pre-Whisper placeholder
@ -128,6 +128,7 @@ type Pss struct {
fwdcache map[pssDigest]pssCacheEntry // checksum of unique fields from pssmsg mapped to expiry, cache to determine whether to drop msg fwdcache map[pssDigest]pssCacheEntry // checksum of unique fields from pssmsg mapped to expiry, cache to determine whether to drop msg
cachettl time.Duration // how long to keep messages in fwdcache cachettl time.Duration // how long to keep messages in fwdcache
hasher func(string) storage.Hasher // hasher to digest message to cache hasher func(string) storage.Hasher // hasher to digest message to cache
baseAddr []byte
lock sync.Mutex lock sync.Mutex
} }
@ -135,7 +136,7 @@ func (self *Pss) hashMsg(msg *PssMsg) pssDigest {
hasher := self.hasher("SHA3")() hasher := self.hasher("SHA3")()
hasher.Reset() hasher.Reset()
hasher.Write(msg.GetRecipient()) hasher.Write(msg.GetRecipient())
hasher.Write(msg.Payload.SenderUAddr) // hasher.Write(msg.Payload.SenderUAddr)
hasher.Write(msg.Payload.SenderOAddr) hasher.Write(msg.Payload.SenderOAddr)
hasher.Write(msg.Payload.Topic[:]) hasher.Write(msg.Payload.Topic[:])
hasher.Write(msg.Payload.Payload) hasher.Write(msg.Payload.Payload)
@ -147,6 +148,7 @@ func (self *Pss) hashMsg(msg *PssMsg) pssDigest {
// //
// TODO error check overlay integrity // TODO error check overlay integrity
func NewPss(k Overlay, params *PssParams) *Pss { func NewPss(k Overlay, params *PssParams) *Pss {
baseAddr := k.BaseAddr()
return &Pss{ return &Pss{
Overlay: k, Overlay: k,
//peerPool: make(map[pot.Address]map[PssTopic]*PssReadWriter, PssPeerCapacity), //peerPool: make(map[pot.Address]map[PssTopic]*PssReadWriter, PssPeerCapacity),
@ -156,6 +158,7 @@ func NewPss(k Overlay, params *PssParams) *Pss {
fwdcache: make(map[pssDigest]pssCacheEntry), fwdcache: make(map[pssDigest]pssCacheEntry),
cachettl: params.Cachettl, cachettl: params.Cachettl,
hasher: storage.MakeHashFunc, hasher: storage.MakeHashFunc,
baseAddr: baseAddr,
} }
} }
@ -301,11 +304,11 @@ func (self *Pss) alertSubscribers(topic *PssTopic, msg []byte) error {
func (self *Pss) Send(to []byte, topic PssTopic, msg []byte) error { func (self *Pss) Send(to []byte, topic PssTopic, msg []byte) error {
pssenv := pssEnvelope{ pssenv := pssEnvelope{
SenderOAddr: self.Overlay.GetAddr().OverlayAddr(), SenderOAddr: self.baseAddr,
SenderUAddr: self.Overlay.GetAddr().UnderlayAddr(), // SenderUAddr: self.baseAddr.Under(),
Topic: topic, Topic: topic,
TTL: DefaultTTL, TTL: DefaultTTL,
Payload: msg, Payload: msg,
} }
pssmsg := &PssMsg{ pssmsg := &PssMsg{
@ -328,7 +331,7 @@ func (self *Pss) Forward(msg *PssMsg) error {
digest := self.hashMsg(msg) digest := self.hashMsg(msg)
if self.checkFwdCache(nil, digest) { if self.checkFwdCache(nil, digest) {
log.Trace(fmt.Sprintf("pss relay block-cache match: FROM %x TO %x", common.ByteLabel(self.Overlay.GetAddr().OverlayAddr()), common.ByteLabel(msg.GetRecipient()))) log.Trace(fmt.Sprintf("pss relay block-cache match: FROM %x TO %x", common.ByteLabel(self.baseAddr), common.ByteLabel(msg.GetRecipient())))
//return errorBlockByCache //return errorBlockByCache
return nil return nil
} }
@ -339,22 +342,22 @@ func (self *Pss) Forward(msg *PssMsg) error {
// send with kademlia // send with kademlia
// find the closest peer to the recipient and attempt to send // find the closest peer to the recipient and attempt to send
self.Overlay.EachLivePeer(msg.GetRecipient(), 256, func(p Peer, po int, isproxbin bool) bool { self.Overlay.EachConn(msg.GetRecipient(), 256, func(p OverlayConn, po int, isproxbin bool) bool {
if self.checkFwdCache(p.OverlayAddr(), digest) { if self.checkFwdCache(p.Address(), digest) {
log.Warn(fmt.Sprintf("BOUNCE DEFER PSS-relay FROM %x TO %x THRU %x:", common.ByteLabel(self.Overlay.GetAddr().OverlayAddr()), common.ByteLabel(msg.GetRecipient()), common.ByteLabel(p.OverlayAddr()))) log.Warn(fmt.Sprintf("BOUNCE DEFER PSS-relay FROM %x TO %x THRU %x:", common.ByteLabel(self.baseAddr), common.ByteLabel(msg.GetRecipient()), common.ByteLabel(p.Address())))
return true return true
} }
log.Warn(fmt.Sprintf("Attempting PSS-relay FROM %x TO %x THRU %x", common.ByteLabel(self.Overlay.GetAddr().OverlayAddr()), common.ByteLabel(msg.GetRecipient()), common.ByteLabel(p.OverlayAddr()))) log.Warn(fmt.Sprintf("Attempting PSS-relay FROM %x TO %x THRU %x", common.ByteLabel(self.baseAddr), common.ByteLabel(msg.GetRecipient()), common.ByteLabel(p.Address())))
err := p.Send(msg) err := p.(Peer).Send(msg)
if err != nil { if err != nil {
log.Warn(fmt.Sprintf("FAILED PSS-relay FROM %x TO %x THRU %x: %v", common.ByteLabel(self.Overlay.GetAddr().OverlayAddr()), common.ByteLabel(msg.GetRecipient()), common.ByteLabel(p.OverlayAddr()), err)) log.Warn(fmt.Sprintf("FAILED PSS-relay FROM %x TO %x THRU %x: %v", common.ByteLabel(self.baseAddr), common.ByteLabel(msg.GetRecipient()), common.ByteLabel(p.Address()), err))
return true return true
} }
sent++ sent++
if bytes.Equal(msg.GetRecipient(), p.OverlayAddr()) || !isproxbin { if bytes.Equal(msg.GetRecipient(), p.Address()) || !isproxbin {
return false return false
} }
log.Trace(fmt.Sprintf("%x is in proxbin, so we continue sending", common.ByteLabel(p.OverlayAddr()))) log.Trace(fmt.Sprintf("%x is in proxbin, so we continue sending", common.ByteLabel(p.Address())))
return true return true
}) })
if sent == 0 { if sent == 0 {
@ -469,7 +472,7 @@ func (self *PssProtocol) handle(msg []byte, p *p2p.Peer, senderAddr []byte) erro
} }
func (self *Pss) IsSelfRecipient(msg *PssMsg) bool { func (self *Pss) IsSelfRecipient(msg *PssMsg) bool {
if bytes.Equal(msg.GetRecipient(), self.Overlay.GetAddr().OverlayAddr()) { if bytes.Equal(msg.GetRecipient(), self.baseAddr) {
return true return true
} }
return false return false

View file

@ -59,19 +59,15 @@ type pssTestNode struct {
apifunc func() []rpc.API apifunc func() []rpc.API
} }
func (n *pssTestNode) Add(peer Peer) error { func (n *pssTestNode) Add(peer *bzzPeer) error {
err := n.Hive.Add(peer) err := n.Hive.Add(peer)
time.Sleep(time.Millisecond * 250) time.Sleep(time.Millisecond * 250)
n.triggerCheck() n.triggerCheck()
return err return err
} }
func (n *pssTestNode) Remove(peer Peer) {
n.Hive.Remove(peer)
}
func (n *pssTestNode) hiveKeepAlive() <-chan time.Time { func (n *pssTestNode) hiveKeepAlive() <-chan time.Time {
return time.Tick(time.Second * 10) return time.Tick(time.Millisecond * 300)
} }
func (n *pssTestNode) triggerCheck() { func (n *pssTestNode) triggerCheck() {
@ -79,7 +75,7 @@ func (n *pssTestNode) triggerCheck() {
} }
func (n *pssTestNode) OverlayAddr() []byte { func (n *pssTestNode) OverlayAddr() []byte {
return n.Pss.Overlay.GetAddr().OverlayAddr() return n.Pss.Overlay.BaseAddr()
} }
func (n *pssTestNode) UnderlayAddr() []byte { func (n *pssTestNode) UnderlayAddr() []byte {
@ -112,7 +108,7 @@ func newPssTestService(t *testing.T, handlefunc func(interface{}) error, testnod
} }
func (self *pssTestService) Start(server p2p.Server) error { func (self *pssTestService) Start(server p2p.Server) error {
return self.node.Hive.Start(server, self.node.hiveKeepAlive) return self.node.Hive.Start(server, self.node.hiveKeepAlive, nil)
} }
func (self *pssTestService) Stop() error { func (self *pssTestService) Stop() error {
@ -122,12 +118,12 @@ func (self *pssTestService) Stop() error {
func (self *pssTestService) Protocols() []p2p.Protocol { func (self *pssTestService) Protocols() []p2p.Protocol {
ct := BzzCodeMap() ct := BzzCodeMap()
ct.Register(0, &PssMsg{})
for _, m := range DiscoveryMsgs { for _, m := range DiscoveryMsgs {
ct.Register(m) ct.Register(1, m)
} }
ct.Register(&PssMsg{})
srv := func(p Peer) error { srv := func(p *bzzPeer) error {
p.Register(&PssMsg{}, self.msgFunc) p.Register(&PssMsg{}, self.msgFunc)
self.node.Add(p) self.node.Add(p)
p.DisconnectHook(func(err error) { p.DisconnectHook(func(err error) {
@ -136,7 +132,7 @@ func (self *pssTestService) Protocols() []p2p.Protocol {
return nil return nil
} }
proto := Bzz(self.node.OverlayAddr(), self.node.UnderlayAddr(), ct, srv, nil, nil) proto := NewBzz(self.node.OverlayAddr(), self.node.UnderlayAddr(), ct, srv, nil, nil)
return []p2p.Protocol{*proto} return []p2p.Protocol{*proto}
} }
@ -167,9 +163,9 @@ func TestPssCache(t *testing.T) {
Payload: pssEnvelope{ Payload: pssEnvelope{
TTL: 0, TTL: 0,
SenderOAddr: oaddr, SenderOAddr: oaddr,
SenderUAddr: uaddr, // SenderUAddr: uaddr,
Topic: topic, Topic: topic,
Payload: data, Payload: data,
}, },
} }
msg.SetRecipient(to) msg.SetRecipient(to)
@ -177,10 +173,10 @@ func TestPssCache(t *testing.T) {
msgtwo := &PssMsg{ msgtwo := &PssMsg{
Payload: pssEnvelope{ Payload: pssEnvelope{
TTL: 0, TTL: 0,
SenderOAddr: uaddr, SenderOAddr: oaddr,
SenderUAddr: oaddr, // SenderUAddr: oaddr,
Topic: topic, Topic: topic,
Payload: data, Payload: data,
}, },
} }
msgtwo.SetRecipient(to) msgtwo.SetRecipient(to)
@ -197,16 +193,16 @@ func TestPssCache(t *testing.T) {
} }
// check the sender cache // check the sender cache
err = ps.addFwdCacheSender(fwdaddr.OverlayAddr(), digest) err = ps.addFwdCacheSender(fwdaddr.Over(), digest)
if err != nil { if err != nil {
t.Fatalf("write to pss sender cache failed: %v", err) t.Fatalf("write to pss sender cache failed: %v", err)
} }
if !ps.checkFwdCache(fwdaddr.OverlayAddr(), digest) { if !ps.checkFwdCache(fwdaddr.Over(), digest) {
t.Fatalf("message %v should have SENDER record in cache but checkCache returned false", msg) t.Fatalf("message %v should have SENDER record in cache but checkCache returned false", msg)
} }
if ps.checkFwdCache(fwdaddr.OverlayAddr(), digesttwo) { if ps.checkFwdCache(fwdaddr.Over(), digesttwo) {
t.Fatalf("message %v should NOT have SENDER record in cache but checkCache returned true", msgtwo) t.Fatalf("message %v should NOT have SENDER record in cache but checkCache returned true", msgtwo)
} }
@ -229,12 +225,12 @@ func TestPssCache(t *testing.T) {
t.Fatalf("message %v should have expired from cache but checkCache returned true", msg) t.Fatalf("message %v should have expired from cache but checkCache returned true", msg)
} }
err = ps.AddToCache(fwdaddr.OverlayAddr(), msgtwo) err = ps.AddToCache(fwdaddr.Over(), msgtwo)
if err != nil { if err != nil {
t.Fatalf("public accessor cache write failed: %v", err) t.Fatalf("public accessor cache write failed: %v", err)
} }
if !ps.checkFwdCache(fwdaddr.OverlayAddr(), digesttwo) { if !ps.checkFwdCache(fwdaddr.Over(), digesttwo) {
t.Fatalf("message %v should have SENDER record in cache but checkCache returned false", msgtwo) t.Fatalf("message %v should have SENDER record in cache but checkCache returned false", msgtwo)
} }
} }
@ -243,7 +239,7 @@ func TestPssRegisterHandler(t *testing.T) {
var topic PssTopic var topic PssTopic
var err error var err error
addr := RandomAddr() addr := RandomAddr()
ps := makePss(addr.UnderlayAddr()) ps := makePss(addr.Under())
topic, _ = MakeTopic(protocolName, protocolVersion) topic, _ = MakeTopic(protocolName, protocolVersion)
err = ps.Register(topic, func(msg []byte, p *p2p.Peer, sender []byte) error { return nil }) err = ps.Register(topic, func(msg []byte, p *p2p.Peer, sender []byte) error { return nil })
@ -305,7 +301,8 @@ func testPssFullRandom(t *testing.T, numsends int, numnodes int, numfullnodes in
expectnodesids := []*adapters.NodeId{} // the nodes to expect on (needed by checker) expectnodesids := []*adapters.NodeId{} // the nodes to expect on (needed by checker)
expectnodesresults := make(map[*adapters.NodeId][]int) // which messages expect actually got expectnodesresults := make(map[*adapters.NodeId][]int) // which messages expect actually got
vct := protocols.NewCodeMap(protocolName, protocolVersion, 65535, &pssTestPayload{}) vct := protocols.NewCodeMap(protocolName, protocolVersion, ProtocolMaxMsgSize)
vct.Register(0, &pssTestPayload{})
topic, _ := MakeTopic(protocolName, protocolVersion) topic, _ := MakeTopic(protocolName, protocolVersion)
trigger := make(chan *adapters.NodeId) trigger := make(chan *adapters.NodeId)
@ -471,8 +468,8 @@ func testPssFullRandom(t *testing.T, numsends int, numnodes int, numfullnodes in
for i := 0; i < len(sends); i += 2 { for i := 0; i < len(sends); i += 2 {
t.Logf("Pss #%d: oaddr %x -> %x (uaddr %x -> %x)", i/2+1, t.Logf("Pss #%d: oaddr %x -> %x (uaddr %x -> %x)", i/2+1,
common.ByteLabel(nodes[fullnodes[sends[i]]].Pss.GetAddr().OverlayAddr()), common.ByteLabel(nodes[fullnodes[sends[i]]].Pss.BaseAddr()),
common.ByteLabel(nodes[fullnodes[sends[i+1]]].Pss.GetAddr().OverlayAddr()), common.ByteLabel(nodes[fullnodes[sends[i+1]]].Pss.BaseAddr()),
common.ByteLabel(fullnodes[sends[i]].Bytes()), common.ByteLabel(fullnodes[sends[i]].Bytes()),
common.ByteLabel(fullnodes[sends[i+1]].Bytes())) common.ByteLabel(fullnodes[sends[i+1]].Bytes()))
} }
@ -484,15 +481,15 @@ func testPssFullRandom(t *testing.T, numsends int, numnodes int, numfullnodes in
fails++ fails++
} }
} }
t.Logf("Node oaddr %x (uaddr %x) was sent %d msgs, of which %d failed", common.ByteLabel(nodes[id].Pss.GetAddr().OverlayAddr()), common.ByteLabel(id.Bytes()), len(results), fails) t.Logf("Node oaddr %x (uaddr %x) was sent %d msgs, of which %d failed", common.ByteLabel(nodes[id].Pss.BaseAddr()), common.ByteLabel(id.Bytes()), len(results), fails)
totalfails += fails totalfails += fails
} }
t.Logf("Total sent: %d, total fail: %d (%.2f%%)", len(sends)/2, totalfails, (float32(totalfails)/float32(len(sends)/2+1))*100) t.Logf("Total sent: %d, total fail: %d (%.2f%%)", len(sends)/2, totalfails, (float32(totalfails)/float32(len(sends)/2+1))*100)
for _, node := range nodes { for _, node := range nodes {
logstring := fmt.Sprintf("Node oaddr %x kademlia: ", common.ByteLabel(node.Pss.Overlay.GetAddr().OverlayAddr())) logstring := fmt.Sprintf("Node oaddr %x kademlia: ", common.ByteLabel(node.Pss.Overlay.BaseAddr()))
node.Pss.Overlay.EachLivePeer(nil, 256, func(p Peer, po int, isprox bool) bool { node.Pss.Overlay.EachConn(nil, 256, func(p Peer, po int, isprox bool) bool {
logstring += fmt.Sprintf("%x ", common.ByteLabel(p.OverlayAddr())) logstring += fmt.Sprintf("%x ", common.ByteLabel(p.Over()))
return true return true
}) })
t.Log(logstring) t.Log(logstring)
@ -511,7 +508,8 @@ func TestPssFullLinearEcho(t *testing.T) {
var firstpssnode *adapters.NodeId var firstpssnode *adapters.NodeId
var secondpssnode *adapters.NodeId var secondpssnode *adapters.NodeId
vct := protocols.NewCodeMap(protocolName, protocolVersion, 65535, &pssTestPayload{}) vct := protocols.NewCodeMap(protocolName, protocolVersion, ProtocolMaxMsgSize)
vct.Register(0, &pssTestPayload{})
topic, _ := MakeTopic(protocolName, protocolVersion) topic, _ := MakeTopic(protocolName, protocolVersion)
fullnodes := []*adapters.NodeId{} fullnodes := []*adapters.NodeId{}
@ -559,9 +557,8 @@ func TestPssFullLinearEcho(t *testing.T) {
node, ok := nodes[id] node, ok := nodes[id]
if !ok { if !ok {
return false, fmt.Errorf("unknown node: %s (%v)", id, node) return false, fmt.Errorf("unknown node: %s (%v)", id, node)
} else {
log.Trace(fmt.Sprintf("sim check ok node %v", id))
} }
log.Trace(fmt.Sprintf("sim check ok node %v", id))
return true, nil return true, nil
} }
@ -589,7 +586,7 @@ func TestPssFullLinearEcho(t *testing.T) {
// first find a node that we're connected to // first find a node that we're connected to
for firstpssnode == nonode { for firstpssnode == nonode {
log.Debug(fmt.Sprintf("Waiting for pss relaypeer for %x close to %x ...", common.ByteLabel(nodes[fullnodes[0]].OverlayAddr()), common.ByteLabel(nodes[ids[1]].OverlayAddr()))) log.Debug(fmt.Sprintf("Waiting for pss relaypeer for %x close to %x ...", common.ByteLabel(nodes[fullnodes[0]].OverlayAddr()), common.ByteLabel(nodes[ids[1]].OverlayAddr())))
nodes[fullnodes[0]].Pss.Overlay.EachLivePeer(nodes[fullnodes[1]].OverlayAddr(), 256, func(p Peer, po int, isprox bool) bool { nodes[fullnodes[0]].Pss.Overlay.EachConn(nodes[fullnodes[1]].OverlayAddr(), 256, func(p Peer, po int, isprox bool) bool {
for _, id := range ids { for _, id := range ids {
if id.NodeID == p.ID() { if id.NodeID == p.ID() {
firstpssnode = id firstpssnode = id
@ -609,7 +606,7 @@ func TestPssFullLinearEcho(t *testing.T) {
// then find the node it's connected to // then find the node it's connected to
for secondpssnode == nonode { for secondpssnode == nonode {
log.Debug(fmt.Sprintf("PSS kademlia: Waiting for recipientpeer for %x close to %x ...", common.ByteLabel(nodes[firstpssnode].OverlayAddr()), common.ByteLabel(nodes[fullnodes[1]].OverlayAddr()))) log.Debug(fmt.Sprintf("PSS kademlia: Waiting for recipientpeer for %x close to %x ...", common.ByteLabel(nodes[firstpssnode].OverlayAddr()), common.ByteLabel(nodes[fullnodes[1]].OverlayAddr())))
nodes[firstpssnode].Pss.Overlay.EachLivePeer(nodes[fullnodes[1]].OverlayAddr(), 256, func(p Peer, po int, isprox bool) bool { nodes[firstpssnode].Pss.Overlay.Eachc(nodes[fullnodes[1]].OverlayAddr(), 256, func(p Peer, po int, isprox bool) bool {
for _, id := range ids { for _, id := range ids {
if id.NodeID == p.ID() && id.NodeID != fullnodes[0].NodeID { if id.NodeID == p.ID() && id.NodeID != fullnodes[0].NodeID {
secondpssnode = id secondpssnode = id
@ -692,7 +689,8 @@ func TestPssFullWS(t *testing.T) {
var firstpssnode, secondpssnode *adapters.NodeId var firstpssnode, secondpssnode *adapters.NodeId
fullnodes := []*adapters.NodeId{} fullnodes := []*adapters.NodeId{}
vct := protocols.NewCodeMap(protocolName, protocolVersion, 65535, &pssTestPayload{}) vct := protocols.NewCodeMap(protocolName, protocolVersion, ProtocolMaxMsgSize)
vct.Register(0, &pssTestPayload{})
topic, _ := MakeTopic(pingTopicName, pingTopicVersion) topic, _ := MakeTopic(pingTopicName, pingTopicVersion)
trigger := make(chan *adapters.NodeId) trigger := make(chan *adapters.NodeId)
@ -788,7 +786,7 @@ func TestPssFullWS(t *testing.T) {
// then find the node it's connected to // then find the node it's connected to
for secondpssnode == nonode { for secondpssnode == nonode {
log.Debug(fmt.Sprintf("PSS kademlia: Waiting for recipientpeer for %x close to %x ...", common.ByteLabel(nodes[firstpssnode].OverlayAddr()), common.ByteLabel(nodes[fullnodes[1]].OverlayAddr()))) log.Debug(fmt.Sprintf("PSS kademlia: Waiting for recipientpeer for %x close to %x ...", common.ByteLabel(nodes[firstpssnode].OverlayAddr()), common.ByteLabel(nodes[fullnodes[1]].OverlayAddr())))
nodes[firstpssnode].Pss.Overlay.EachLivePeer(nodes[fullnodes[1]].OverlayAddr(), 256, func(p Peer, po int, isprox bool) bool { nodes[firstpssnode].Pss.Overlay.EachConn(nodes[fullnodes[1]].OverlayAddr(), 256, func(p Peer, po int, isprox bool) bool {
for _, id := range ids { for _, id := range ids {
if id.NodeID == p.ID() && id.NodeID != fullnodes[0].NodeID { if id.NodeID == p.ID() && id.NodeID != fullnodes[0].NodeID {
secondpssnode = id secondpssnode = id
@ -855,7 +853,7 @@ func TestPssFullWS(t *testing.T) {
action = func(ctx context.Context) error { action = func(ctx context.Context) error {
go func() { go func() {
clientrecv.EthSubscribe(ctx, ch, "newMsg", topic) clientrecv.EthSubscribe(ctx, ch, "newMsg", topic)
clientsend.Call(nil, "eth_sendRaw", nodes[secondpssnode].Pss.Overlay.GetAddr().OverlayAddr(), topic, []byte("ping")) clientsend.Call(nil, "eth_sendRaw", nodes[secondpssnode].Pss.Overlay.BaseAddr(), topic, []byte("ping"))
trigger <- secondpssnode trigger <- secondpssnode
}() }()
return nil return nil
@ -935,7 +933,7 @@ func newPssSimulationTester(t *testing.T, numnodes int, numfullnodes int, trigge
if testpeers[id] != nil { if testpeers[id] != nil {
handlefunc = makePssHandleProtocol(psss[id]) handlefunc = makePssHandleProtocol(psss[id])
log.Trace(fmt.Sprintf("Making full protocol id %x addr %x (testpeers %p)", common.ByteLabel(id.Bytes()), common.ByteLabel(addr.OverlayAddr()), testpeers)) log.Trace(fmt.Sprintf("Making full protocol id %x addr %x (testpeers %p)", common.ByteLabel(id.Bytes()), common.ByteLabel(addr.Over()), testpeers))
} else { } else {
handlefunc = makePssHandleForward(psss[id]) handlefunc = makePssHandleForward(psss[id])
} }
@ -965,7 +963,7 @@ func newPssSimulationTester(t *testing.T, numnodes int, numfullnodes int, trigge
} }
for i, conf := range configs { for i, conf := range configs {
addr := NewPeerAddrFromNodeId(conf.Id) addr := NewPeerAddrFromNodeId(conf.Id)
psss[conf.Id] = makePss(addr.OverlayAddr()) psss[conf.Id] = makePss(addr.Over())
if i < numfullnodes { if i < numfullnodes {
tp := &pssTestPeer{ tp := &pssTestPeer{
Peer: &protocols.Peer{ Peer: &protocols.Peer{
@ -1018,7 +1016,7 @@ func makeCustomProtocol(name string, version int, ct *protocols.CodeMap, testpee
return protocols.NewProtocol(name, uint(version), run, ct, nil, nil) return protocols.NewProtocol(name, uint(version), run, ct, nil, nil)
} }
func makeFakeMsg(ps *Pss, ct *protocols.CodeMap, topic PssTopic, senderaddr PeerAddr, content string) PssMsg { func makeFakeMsg(ps *Pss, ct *protocols.CodeMap, topic PssTopic, senderaddr Addr, content string) PssMsg {
data := pssTestPayload{} data := pssTestPayload{}
code, found := ct.GetCode(&data) code, found := ct.GetCode(&data)
if !found { if !found {
@ -1033,8 +1031,8 @@ func makeFakeMsg(ps *Pss, ct *protocols.CodeMap, topic PssTopic, senderaddr Peer
} }
pssenv := pssEnvelope{ pssenv := pssEnvelope{
SenderOAddr: senderaddr.OverlayAddr(), SenderOAddr: senderaddr.Over(),
SenderUAddr: senderaddr.UnderlayAddr(), SenderUAddr: senderaddr.Under(),
Topic: topic, Topic: topic,
TTL: DefaultTTL, TTL: DefaultTTL,
Payload: rlpbundle, Payload: rlpbundle,
@ -1042,7 +1040,7 @@ func makeFakeMsg(ps *Pss, ct *protocols.CodeMap, topic PssTopic, senderaddr Peer
pssmsg := PssMsg{ pssmsg := PssMsg{
Payload: pssenv, Payload: pssenv,
} }
pssmsg.SetRecipient(ps.Overlay.GetAddr().OverlayAddr()) pssmsg.SetRecipient(ps.Overlay.BaseAddr())
return pssmsg return pssmsg
} }

View file

@ -24,10 +24,31 @@ import (
// SimNode is the adapter used by Swarm simulations. // SimNode is the adapter used by Swarm simulations.
type SimNode struct { type SimNode struct {
id *adapters.NodeId
rw network.ReadWriter
hive *network.Hive hive *network.Hive
protocol *p2p.Protocol protocol *p2p.Protocol
} }
type simReadWriter struct {
m map[string][]byte
}
func (self *simReadWriter) ReadAll(s string) ([]byte, error) {
return self.m[s], nil
}
func (self *simReadWriter) WriteAll(s string, data []byte) error {
self.m[s] = data
return nil
}
func NewSimReadWriter() *simReadWriter {
return &simReadWriter{
make(map[string][]byte),
}
}
func (s *SimNode) Protocols() []p2p.Protocol { func (s *SimNode) Protocols() []p2p.Protocol {
return []p2p.Protocol{*s.protocol} return []p2p.Protocol{*s.protocol}
} }
@ -44,19 +65,12 @@ func af() <-chan time.Time {
// Start() starts up the hive // Start() starts up the hive
// makes SimNode implement node.Service // makes SimNode implement node.Service
func (self *SimNode) Start(server p2p.Server) error { func (self *SimNode) Start(server p2p.Server) error {
return self.hive.Start(server, af) self.init()
return self.hive.Start(server, af, self.rw)
} }
// Stop() shuts down the hive func (self *SimNode) init() {
// makes SimNode implement node.Service addr := network.NewPeerAddrFromNodeId(self.id)
func (self *SimNode) Stop() error {
self.hive.Stop()
return nil
}
// NewSimNode creates adapters for nodes in the simulation.
func NewSimNode(id *adapters.NodeId, snapshot []byte) node.Service {
addr := network.NewPeerAddrFromNodeId(id)
kp := network.NewKadParams() kp := network.NewKadParams()
kp.MinProxBinSize = 2 kp.MinProxBinSize = 2
@ -83,11 +97,25 @@ func NewSimNode(id *adapters.NodeId, snapshot []byte) node.Service {
ct := network.BzzCodeMap(network.DiscoveryMsgs...) // bzz protocol code map ct := network.BzzCodeMap(network.DiscoveryMsgs...) // bzz protocol code map
nodeInfo := func() interface{} { return pp.String() } nodeInfo := func() interface{} { return pp.String() }
self.hive = pp
self.protocol = network.Bzz(addr.OverlayAddr(), addr.UnderlayAddr(), ct, services, nil, nodeInfo)
}
return &SimNode{ // Stop() shuts down the hive
hive: pp, // makes SimNode implement node.Service
protocol: network.Bzz(addr.OverlayAddr(), addr.UnderlayAddr(), ct, services, nil, nodeInfo), func (self *SimNode) Stop() error {
self.hive.Stop()
return nil
}
// NewSimNode creates adapters for nodes in the simulation.
func NewSimNode(id *adapters.NodeId, snapshot []byte) node.Service {
s := &SimNode{
id: id,
rw: NewSimReadWriter(),
} }
s.init()
return s
} }
func createMockers() map[string]*simulations.MockerConfig { func createMockers() map[string]*simulations.MockerConfig {

View file

@ -1,182 +1,193 @@
package network package network
import ( //
"fmt" // import (
"strings" // "fmt"
"sync" // "strings"
// "sync"
"github.com/ethereum/go-ethereum/log" //
) // "github.com/ethereum/go-ethereum/log"
// )
const orders = 8 //
// const orders = 8
type testOverlay struct { //
mu sync.Mutex // type testOverlay struct {
addr []byte // mu sync.Mutex
pos [][]*testPeerAddr // addr []byte
posMap map[string]*testPeerAddr // pos [][]OverlayAddr
} // posMap map[string]OverlayAddr
// }
type testPeerAddr struct { //
PeerAddr // type testPeerAddr struct {
Peer Peer // Addr
} // Peer
// }
func (self *testOverlay) Register(nas ...PeerAddr) error { //
self.mu.Lock() // func (self *testPeerAddr) Address() []byte {
defer self.mu.Unlock() // return nil
return self.register(nas...) // }
} //
// func (self *testPeerAddr) Update(a OverlayAddr) OverlayAddr {
func (self *testOverlay) GetAddr() PeerAddr { // return self
return &peerAddr{ // }
OAddr: self.addr, //
UAddr: []byte{}, // func (self *testPeerAddr) On(p OverlayConn) OverlayConn {
} // return self
} // }
//
func (self *testOverlay) register(nas ...PeerAddr) error { // func (self *testPeerAddr) Off() OverlayAddr {
for _, na := range nas { // return self
tna := &testPeerAddr{PeerAddr: na} // }
addr := na.OverlayAddr() //
if self.posMap[string(addr)] != nil { // func (self *testOverlay) Register(peers chan OverlayAddr) error {
continue // self.mu.Lock()
} // defer self.mu.Unlock()
self.posMap[string(addr)] = tna // var nas []OverlayAddr
o := order(addr) // for a := range peers {
log.Trace(fmt.Sprintf("PO: %v, orders: %v", o, orders)) // nas = append(nas, a)
self.pos[o] = append(self.pos[o], tna) // }
} // return self.register(nas...)
return nil // }
} //
// func (self *testOverlay) BaseAddr() []byte {
func order(addr []byte) int { // return nil
return int(addr[0]) / 32 // }
} //
// func (self *testOverlay) register(nas ...OverlayAddr) error {
func (self *testOverlay) On(n Peer) { // for _, na := range nas {
self.mu.Lock() // addr := na.Address()
defer self.mu.Unlock() // if self.posMap[string(addr)] != nil {
addr := n.OverlayAddr() // continue
na := self.posMap[string(addr)] // }
if na == nil { // self.posMap[string(addr)] = na
self.register(n) // o := order(addr)
na = self.posMap[string(addr)] // log.Trace(fmt.Sprintf("PO: %v, orders: %v", o, orders))
} else if na.Peer != nil { // self.pos[o] = append(self.pos[o], na)
return // }
} // return nil
log.Trace(fmt.Sprintf("Online: %x", addr[:4])) // }
na.Peer = n //
return // func order(addr []byte) int {
} // return int(addr[0]) / 32
// }
func (self *testOverlay) Off(n Peer) { //
self.mu.Lock() // func (self *testOverlay) On(n OverlayConn) {
defer self.mu.Unlock() // self.mu.Lock()
addr := n.OverlayAddr() // defer self.mu.Unlock()
na := self.posMap[string(addr)] // addr := n.Address()
if na == nil { // na := self.posMap[string(addr)]
return // if na == nil {
} // self.register(n)
delete(self.posMap, string(addr)) // na = self.posMap[string(addr)]
na.Peer = nil // } else if na.Peer != nil {
} // return
// }
// caller must hold the lock // log.Trace(fmt.Sprintf("Online: %x", addr[:4]))
func (self *testOverlay) on(po []*testPeerAddr) (nodes []Peer) { // na.Peer = n
for _, na := range po { // return
if na.Peer != nil { // }
nodes = append(nodes, na.Peer) //
} // func (self *testOverlay) Off(n OverlayConn) {
} // self.mu.Lock()
return nodes // defer self.mu.Unlock()
} // addr := n.Over()
// na := self.posMap[string(addr)]
// caller must hold the lock // if na == nil {
func (self *testOverlay) off(po []*testPeerAddr) (nas []PeerAddr) { // return
for _, na := range po { // }
if na.Peer == (*bzzPeer)(nil) { // delete(self.posMap, string(addr))
nas = append(nas, PeerAddr(na)) // na.Peer = nil
} // }
} //
return nas // // caller must hold the lock
} // func (self *testOverlay) on(po []*testPeerAddr) (nodes []OverlayConn) {
// for _, na := range po {
func (self *testOverlay) EachLivePeer(base []byte, o int, f func(Peer, int, bool) bool) { // if na.Peer != nil {
if base == nil { // nodes = append(nodes, na)
base = self.addr // }
} // }
for i := o; i < len(self.pos); i++ { // return nodes
for _, na := range self.pos[i] { // }
if na.Peer != nil { //
if !f(na.Peer, o, false) { // // caller must hold the lock
return // func (self *testOverlay) off(po []*testPeerAddr) (nas []OverlayAddr) {
} // for _, na := range po {
} // if na.Peer == (*bzzPeer)(nil) {
} // nas = append(nas, Addr(na))
} // }
} // }
// return nas
func (self *testOverlay) EachPeer(base []byte, o int, f func(PeerAddr, int) bool) { // }
if base == nil { //
base = self.addr // func (self *testOverlay) EachConn(base []byte, o int, f func(OverlayConn, int, bool) bool) {
} // for i := o; i < len(self.pos); i++ {
for i := o; i < len(self.pos); i++ { // for _, na := range self.pos[i] {
for _, na := range self.pos[i] { // if na.Peer != nil {
if !f(na, i) { // if !f(na, o, false) {
return // return
} // }
} // }
} // }
} // }
// }
func (self *testOverlay) SuggestPeer() (PeerAddr, int, bool) { //
self.mu.Lock() // func (self *testOverlay) EachAddr(base []byte, o int, f func(OverlayAddr, int) bool) {
defer self.mu.Unlock() // for i := o; i < len(self.pos); i++ {
for i, po := range self.pos { // for _, na := range self.pos[i] {
ons := self.on(po) // if !f(na, i) {
if len(ons) < 2 { // return
offs := self.off(po) // }
if len(offs) > 0 { // }
log.Trace(fmt.Sprintf("node %v is off", offs[0])) // }
return offs[0], i, true // }
} //
} // func (self *testOverlay) SuggestPeer() (OverlayAddr, int, bool) {
} // self.mu.Lock()
return nil, 0, true // defer self.mu.Unlock()
} // for i, po := range self.pos {
// ons := self.on(po)
func (self *testOverlay) String() string { // if len(ons) < 2 {
self.mu.Lock() // offs := self.off(po)
defer self.mu.Unlock() // if len(offs) > 0 {
var t []string // log.Trace(fmt.Sprintf("node %v is off", offs[0]))
var ons, offs int // return offs[0], i, true
var ns []Peer // }
var nas []PeerAddr // }
for o, po := range self.pos { // }
var row []string // return nil, 0, true
ns = self.on(po) // }
nas = self.off(po) //
ons = len(ns) // func (self *testOverlay) String() string {
for _, n := range ns { // self.mu.Lock()
addr := n.OverlayAddr() // defer self.mu.Unlock()
row = append(row, fmt.Sprintf("%x", addr[:4])) // var t []string
} // var ons, offs int
row = append(row, "|") // var ns []Peer
offs = len(nas) // var nas []Addr
for _, na := range nas { // for o, po := range self.pos {
addr := na.OverlayAddr() // var row []string
row = append(row, fmt.Sprintf("%x", addr[:4])) // ns = self.on(po)
} // nas = self.off(po)
t = append(t, fmt.Sprintf("%v: (%v/%v) %v", o, ons, offs, strings.Join(row, " "))) // ons = len(ns)
} // for _, n := range ns {
return strings.Join(t, "\n") // addr := n.Over()
} // row = append(row, fmt.Sprintf("%x", addr[:4]))
// }
func NewTestOverlay(addr []byte) *testOverlay { // row = append(row, "|")
return &testOverlay{ // offs = len(nas)
addr: addr, // for _, na := range nas {
posMap: make(map[string]*testPeerAddr), // addr := na.Over()
pos: make([][]*testPeerAddr, orders), // row = append(row, fmt.Sprintf("%x", addr[:4]))
} // }
} // t = append(t, fmt.Sprintf("%v: (%v/%v) %v", o, ons, offs, strings.Join(row, " ")))
// }
// return strings.Join(t, "\n")
// }
//
// func NewTestOverlay(addr []byte) *testOverlay {
// return &testOverlay{
// addr: addr,
// posMap: make(map[string]*testPeerAddr),
// pos: make([][]*testPeerAddr, orders),
// }
// }

View file

@ -32,7 +32,6 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/api"
httpapi "github.com/ethereum/go-ethereum/swarm/api/http" httpapi "github.com/ethereum/go-ethereum/swarm/api/http"
@ -182,9 +181,10 @@ func (self *Swarm) Start(net p2p.Server) error {
func() <-chan time.Time { func() <-chan time.Time {
return time.NewTicker(time.Second).C return time.NewTicker(time.Second).C
}, },
nil,
) )
log.Info(fmt.Sprintf("Swarm network started on bzz address: %v", self.hive.GetAddr())) log.Info(fmt.Sprintf("Swarm network started on bzz address: %v", self.hive.BaseAddr()))
if self.pssEnabled { if self.pssEnabled {
pssparams := network.NewPssParams() pssparams := network.NewPssParams()
@ -238,48 +238,46 @@ func (self *Swarm) Stop() error {
// implements the node.Service interface // implements the node.Service interface
func (self *Swarm) Protocols() []p2p.Protocol { func (self *Swarm) Protocols() []p2p.Protocol {
ct := network.BzzCodeMap() ct := network.BzzCodeMap()
for _, m := range network.DiscoveryMsgs {
ct.Register(m)
}
if self.pssEnabled { if self.pssEnabled {
ct.Register(&network.PssMsg{}) ct.Register(1, &network.PssMsg{})
} }
ct.Register(2, network.DiscoveryMsgs...)
srv := func(p network.Peer) error { // srv := func(p network.Peer) error {
if self.pssEnabled { // if self.pssEnabled {
p.Register(&network.PssMsg{}, func(msg interface{}) error { // p.Register(&network.PssMsg{}, func(msg interface{}) error {
pssmsg := msg.(*network.PssMsg) // pssmsg := msg.(*network.PssMsg)
//
if self.pss.IsSelfRecipient(pssmsg) { // if self.pss.IsSelfRecipient(pssmsg) {
log.Trace("pss for us, yay! ... let's process!") // log.Trace("pss for us, yay! ... let's process!")
env := pssmsg.Payload // env := pssmsg.Payload
umsg := env.Payload // umsg := env.Payload
f := self.pss.GetHandler(env.Topic) // f := self.pss.GetHandler(env.Topic)
if f == nil { // if f == nil {
return fmt.Errorf("No registered handler for topic '%s'", env.Topic) // return fmt.Errorf("No registered handler for topic '%s'", env.Topic)
} // }
nid := adapters.NewNodeId(env.SenderUAddr) // nid := adapters.NewNodeId(env.SenderUAddr)
p := p2p.NewPeer(nid.NodeID, fmt.Sprintf("%x", common.ByteLabel(nid.Bytes())), []p2p.Cap{}) // p := p2p.NewPeer(nid.NodeID, fmt.Sprintf("%x", common.ByteLabel(nid.Bytes())), []p2p.Cap{})
return f(umsg, p, env.SenderOAddr) // return f(umsg, p, env.SenderOAddr)
} else { // } else {
log.Trace("pss was for someone else :'( ... forwarding") // log.Trace("pss was for someone else :'( ... forwarding")
return self.pss.Forward(pssmsg) // return self.pss.Forward(pssmsg)
} // }
return nil // return nil
}) // })
} // }
self.hive.Add(p) // self.hive.Add(p)
p.DisconnectHook(func(err error) { // p.DisconnectHook(func(err error) {
self.hive.Remove(p) // self.hive.Remove(p)
}) // })
return nil // return nil
} // }
proto := network.Bzz( proto := network.Bzz(
self.hive.Overlay.GetAddr().OverlayAddr(), self.hive.Overlay.GetAddr().Over(),
self.hive.Overlay.GetAddr().UnderlayAddr(), self.hive.Overlay.GetAddr().Under(),
ct, ct,
srv, nil,
nil, nil,
nil, nil,
) )