mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
WIP network rewrite
This commit is contained in:
parent
b77b855f2c
commit
c870e2be26
18 changed files with 1024 additions and 835 deletions
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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{
|
||||||
|
|
|
||||||
|
|
@ -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[:]
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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[:],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue