swarm/network: Kademlia fixes

This commit is contained in:
zelig 2017-05-16 15:49:44 -07:00 committed by Lewis Marshall
parent a03781dfb0
commit 5307e1ea77
5 changed files with 76 additions and 93 deletions

View file

@ -120,9 +120,8 @@ func (self *discPeer) handleSubPeersMsg(msg *subPeersMsg) error {
if uint8(po) < self.depth { if uint8(po) < self.depth {
return false return false
} }
log.Warn(fmt.Sprintf("peer %#v depth %v", p, self.depth))
if !self.seen(p) { if !self.seen(p) {
peers = append(peers, ToAddr(p)) peers = append(peers, ToAddr(p.Off()))
} }
return true return true
}) })
@ -147,13 +146,15 @@ func (self *discPeer) handlePeersMsg(msg *peersMsg) error {
return nil return nil
} }
var c chan OverlayAddr c := make(chan OverlayAddr)
go func() { go func() {
defer close(c)
for _, a := range msg.Peers { for _, a := range msg.Peers {
self.seen(a) self.seen(a)
c <- a c <- a
} }
}() }()
log.Info("discovery overlay register")
return self.overlay.Register(c) return self.overlay.Register(c)
} }
@ -168,7 +169,7 @@ func (self *discPeer) handleGetPeersMsg(msg *getPeersMsg) error {
self.overlay.EachConn(self.Over(), int(msg.Order), func(p OverlayConn, po int, isproxbin bool) bool { self.overlay.EachConn(self.Over(), int(msg.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
a := ToAddr(p) a := ToAddr(p.Off())
if self.seen(a) { if self.seen(a) {
peers = append(peers, a) peers = append(peers, a)
} }

View file

@ -126,7 +126,8 @@ func (self *Hive) Start(server *p2p.Server) error {
// to attempt to write to more (remove Peer when shutting down) // to attempt to write to more (remove Peer when shutting down)
return return
} }
log.Trace("hive delegate to overlay driver: suggest addr to connect to") log.Debug("hive delegate to overlay driver: suggest addr to connect to")
// log.Trace("hive delegate to overlay driver: suggest addr to connect to")
addr, order, want := self.SuggestPeer() addr, order, want := self.SuggestPeer()
if addr != nil { if addr != nil {
@ -143,16 +144,17 @@ func (self *Hive) Start(server *p2p.Server) error {
want = want && self.Discovery want = want && self.Discovery
if want { if want {
log.Debug(fmt.Sprintf("========> request peers nearest %v", addr))
RequestOrder(self.Overlay, uint8(order), self.PeersBroadcastSetSize, self.MaxPeersPerRequest) RequestOrder(self.Overlay, uint8(order), self.PeersBroadcastSetSize, self.MaxPeersPerRequest)
} }
log.Info(fmt.Sprintf("%v", self))
select { select {
case self.toggle <- want: case self.toggle <- want:
log.Trace(fmt.Sprintf("keep hive alive: %v", want)) log.Trace(fmt.Sprintf("keep hive alive: %v", want))
case <-self.quit: case <-self.quit:
return return
} }
// log.Info(fmt.Sprintf("%v", self))
} }
}() }()
return nil return nil
@ -177,13 +179,6 @@ func (self *Hive) Run(p *bzzPeer) error {
return p.Run(dp.HandleMsg) return p.Run(dp.HandleMsg)
} }
// 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 // NodeInfo function is used by the p2p.server RPC interface to display
// protocol specific node information // protocol specific node information
func (self *Hive) NodeInfo() interface{} { func (self *Hive) NodeInfo() interface{} {
@ -229,6 +224,9 @@ func ToAddr(pa OverlayPeer) *bzzAddr {
if addr, ok := pa.(*bzzAddr); ok { if addr, ok := pa.(*bzzAddr); ok {
return addr return addr
} }
if p, ok := pa.(*discPeer); ok {
return p.bzzAddr
}
return pa.(*bzzPeer).bzzAddr return pa.(*bzzPeer).bzzAddr
} }
@ -262,7 +260,7 @@ func (self *Hive) keepAlive() {
for { for {
select { select {
case <-tick: case <-tick:
log.Trace("wake up: make hive alive") log.Debug("wake up: make hive alive")
self.wake() self.wake()
case need := <-self.toggle: case need := <-self.toggle:
if ticker == nil && need { if ticker == nil && need {
@ -295,9 +293,9 @@ func (self *Hive) loadPeers() error {
return err return err
} }
var c chan OverlayAddr c := make(chan OverlayAddr)
defer close(c)
go func() { go func() {
defer close(c)
for _, a := range as { for _, a := range as {
c <- a c <- a
} }

View file

@ -162,10 +162,11 @@ func (self *Kademlia) Register(peers chan OverlayAddr) error {
if bytes.Equal(p.Address(), self.base) { if bytes.Equal(p.Address(), self.base) {
return fmt.Errorf("add peers: %x is self", self.base) return fmt.Errorf("add peers: %x is self", self.base)
} }
np, _, _ = pot.Add(np, pot.PotVal(newEntry(p))) np, _, _ = pot.Add(np, newEntry(p))
} }
com := self.addrs.Merge(np) com := self.addrs.Merge(np)
log.Trace(fmt.Sprintf("merged %v peers, %v known", np.Size(), com)) log.Debug(fmt.Sprintf("merged %v peers, %v known, total: %v", np.Size(), com, self.addrs.Size()))
// log.Trace(fmt.Sprintf("merged %v peers, %v known", np.Size(), com))
// TODO: remove this check // TODO: remove this check
m := make(map[string]bool) m := make(map[string]bool)
@ -189,7 +190,8 @@ func (self *Kademlia) SuggestPeer() (a OverlayAddr, o int, want bool) {
depth := self.Depth() 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", depth)) log.Debug(fmt.Sprintf("candidate prox peer checking above PO %v", depth))
// log.Trace(fmt.Sprintf("candidate prox peer checking above PO %v", depth))
var ppo int var ppo int
ba := pot.NewBytesVal(self.base, nil) ba := pot.NewBytesVal(self.base, nil)
self.addrs.EachNeighbour(ba, func(val pot.PotVal, po int) bool { self.addrs.EachNeighbour(ba, func(val pot.PotVal, po int) bool {
@ -266,12 +268,10 @@ func (self *Kademlia) On(p OverlayConn) {
return v return v
}) })
log.Trace(fmt.Sprintf("Notifier:%#v", p))
np, ok := p.(Notifier) np, ok := p.(Notifier)
if !ok { if !ok {
return return
} }
log.Trace(fmt.Sprintf("notify:%v", p))
depth := uint8(self.Depth()) depth := uint8(self.Depth())
if depth != self.depth { if depth != self.depth {
@ -284,10 +284,12 @@ func (self *Kademlia) On(p OverlayConn) {
f := func(val pot.PotVal, po int) { f := func(val pot.PotVal, po int) {
dp := val.(*entry).OverlayPeer.(Notifier) dp := val.(*entry).OverlayPeer.(Notifier)
dp.NotifyPeer(p.Off(), uint8(po)) dp.NotifyPeer(p.Off(), uint8(po))
log.Trace(fmt.Sprintf("peer %v notified of %v (%v)", dp, p, po)) // log.Trace(fmt.Sprintf("peer %v notified of %v (%v)", dp, p, po))
log.Debug(fmt.Sprintf("peer %v notified of %v (%v)", dp, p, po))
if depth > 0 { if depth > 0 {
dp.NotifyDepth(depth) dp.NotifyDepth(depth)
log.Trace("peer %v notified of new depth %v", dp, depth) log.Debug(fmt.Sprintf("peer %v notified of new depth %v", dp, depth))
// log.Trace(fmt.Sprintf("peer %v notified of new depth %v", dp, depth))
} }
} }
self.conns.EachNeighbourAsync(e, 1024, 255, f, false) self.conns.EachNeighbourAsync(e, 1024, 255, f, false)

View file

@ -20,6 +20,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net"
"sync" "sync"
"time" "time"
@ -185,6 +186,7 @@ func (b *Bzz) Stop() error {
func (b *Bzz) runHandshake(p *p2p.Peer, rw p2p.MsgReadWriter) error { func (b *Bzz) runHandshake(p *p2p.Peer, rw p2p.MsgReadWriter) error {
handshake := b.getHandshake(p.ID()) handshake := b.getHandshake(p.ID())
defer b.removeHandshake(p.ID())
if err := handshake.Perform(p, rw); err != nil { if err := handshake.Perform(p, rw); err != nil {
log.Error("handshake failed", "peer", p.ID(), "err", err) log.Error("handshake failed", "peer", p.ID(), "err", err)
@ -218,6 +220,12 @@ func (b *Bzz) runProtocol(spec *protocols.Spec, run func(*bzzPeer) error) func(*
} }
} }
func (b *Bzz) removeHandshake(peerID discover.NodeID) {
b.mtx.Lock()
defer b.mtx.Unlock()
delete(b.handshakes, peerID)
}
func (b *Bzz) getHandshake(peerID discover.NodeID) *bzzHandshake { func (b *Bzz) getHandshake(peerID discover.NodeID) *bzzHandshake {
b.mtx.Lock() b.mtx.Lock()
defer b.mtx.Unlock() defer b.mtx.Unlock()
@ -370,5 +378,8 @@ func NewNodeIdFromAddr(addr Addr) *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 NewAddrFromNodeId(n *adapters.NodeId) *bzzAddr { func NewAddrFromNodeId(n *adapters.NodeId) *bzzAddr {
id := n.NodeID id := n.NodeID
return &bzzAddr{crypto.Keccak256(id[:]), id[:]} return &bzzAddr{
OAddr: crypto.Keccak256(id[:]),
UAddr: []byte(discover.NewNode(id, net.IP{127, 0, 0, 1}, 30303, 30303).String()),
}
} }

View file

@ -11,66 +11,57 @@ import (
"net/http" "net/http"
"os" "os"
"runtime" "runtime"
"sync"
"time" "time"
"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/discover"
"github.com/ethereum/go-ethereum/p2p/simulations" "github.com/ethereum/go-ethereum/p2p/simulations"
"github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/network"
) )
// SimNode is the adapter used by Swarm simulations. type simStore struct {
type SimNode struct {
id *adapters.NodeId
rw network.ReadWriter
hive *network.Hive
protocol *p2p.Protocol
}
type simReadWriter struct {
m map[string][]byte m map[string][]byte
} }
func (self *simReadWriter) ReadAll(s string) ([]byte, error) { func (self *simStore) Load(s string) ([]byte, error) {
return self.m[s], nil return self.m[s], nil
} }
func (self *simReadWriter) WriteAll(s string, data []byte) error { func (self *simStore) Save(s string, data []byte) error {
self.m[s] = data self.m[s] = data
return nil return nil
} }
func NewSimReadWriter() *simReadWriter { func NewSimStore() *simStore {
return &simReadWriter{ return &simStore{
make(map[string][]byte), make(map[string][]byte),
} }
} }
func (s *SimNode) Protocols() []p2p.Protocol { type Simulation struct {
return []p2p.Protocol{*s.protocol} mtx sync.Mutex
stores map[discover.NodeID]*simStore
} }
func (s *SimNode) APIs() []rpc.API { func NewSimulation() *Simulation {
return nil return &Simulation{
stores: make(map[discover.NodeID]*simStore),
}
} }
// the hive update ticker for hive func (s *Simulation) NewService(id *adapters.NodeId, snapshot []byte) node.Service {
func af() <-chan time.Time { s.mtx.Lock()
return time.NewTicker(1 * time.Second).C store, ok := s.stores[id.NodeID]
} if !ok {
store = NewSimStore()
s.stores[id.NodeID] = store
}
s.mtx.Unlock()
// Start() starts up the hive addr := network.NewAddrFromNodeId(id)
// makes SimNode implement node.Service
func (self *SimNode) Start(server *p2p.Server) error {
self.init()
return self.hive.Start(server, af, self.rw)
}
func (self *SimNode) init() {
addr := network.NewPeerAddrFromNodeId(self.id)
kp := network.NewKadParams() kp := network.NewKadParams()
kp.MinProxBinSize = 2 kp.MinProxBinSize = 2
@ -80,42 +71,16 @@ func (self *SimNode) init() {
kp.RetryExponent = 2 kp.RetryExponent = 2
kp.RetryInterval = 1000000 kp.RetryInterval = 1000000
to := network.NewKademlia(addr.OverlayAddr(), kp) // overlay topology driver
hp := network.NewHiveParams() hp := network.NewHiveParams()
hp.CallInterval = 5000 hp.KeepAliveInterval = 5 * time.Second
pp := network.NewHive(hp, to) // hive config := &network.BzzConfig{
OverlayAddr: addr.Over(),
services := func(p network.Peer) error { UnderlayAddr: addr.Under(),
dp := network.NewDiscovery(p, to) KadParams: kp,
pp.Add(dp) HiveParams: hp,
log.Trace(fmt.Sprintf("kademlia on %v", dp)) Store: store,
p.DisconnectHook(func(err error) {
pp.Remove(dp)
})
return nil
} }
return network.NewBzz(config)
ct := network.BzzCodeMap(network.DiscoveryMsgs...) // bzz protocol code map
nodeInfo := func() interface{} { return pp.String() }
self.hive = pp
self.protocol = network.Bzz(addr.OverlayAddr(), addr.UnderlayAddr(), ct, services, nil, nodeInfo)
}
// Stop() shuts down the hive
// makes SimNode implement node.Service
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 {
@ -171,7 +136,12 @@ func setupMocker(net *simulations.Network) []*adapters.NodeId {
} else { } else {
peerId = ids[i-1] peerId = ids[i-1]
} }
if err := net.Connect(id, peerId); err != nil { ch := make(chan network.OverlayAddr)
go func() {
defer close(ch)
ch <- network.NewAddrFromNodeId(peerId)
}()
if err := net.GetNode(id).Node.(*adapters.SimNode).Service().(*network.Bzz).Hive.Register(ch); err != nil {
panic(err.Error()) panic(err.Error())
} }
} }
@ -243,10 +213,11 @@ func startStopMocker(net *simulations.Network) {
func main() { func main() {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) log.Root().SetHandler(log.LvlFilterHandler(log.LvlDebug, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
s := NewSimulation()
services := adapters.Services{ services := adapters.Services{
"overlay": NewSimNode, "overlay": s.NewService,
} }
adapters.RegisterServices(services) adapters.RegisterServices(services)