swarm/network: light nodes are not dialed, saved and requested from (#17975)

* RequestFromPeers does not use peers marked as lightnode

* fix warning about variable name

* write tests for RequestFromPeers

* lightnodes should be omitted from the addressbook

* resolve pr comments regarding logging, formatting and comments

* resolve pr comments regarding comments and added a missing newline

* add assertions to check peers in live connections
This commit is contained in:
Mark Vujevits 2018-11-07 20:33:36 +01:00 committed by Viktor Trón
parent 0bcff8f525
commit 81533deae5
4 changed files with 153 additions and 13 deletions

View File

@ -261,7 +261,7 @@ func (k *Kademlia) On(p *Peer) (uint8, bool) {
// found among live peers, do nothing // found among live peers, do nothing
return v return v
}) })
if ins { if ins && !p.BzzPeer.LightNode {
a := newEntry(p.BzzAddr) a := newEntry(p.BzzAddr)
a.conn = p a.conn = p
// insert new online peer into addrs // insert new online peer into addrs
@ -329,6 +329,7 @@ func (k *Kademlia) Off(p *Peer) {
k.lock.Lock() k.lock.Lock()
defer k.lock.Unlock() defer k.lock.Unlock()
var del bool var del bool
if !p.BzzPeer.LightNode {
k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val {
// v cannot be nil, must check otherwise we overwrite entry // v cannot be nil, must check otherwise we overwrite entry
if v == nil { if v == nil {
@ -337,6 +338,9 @@ func (k *Kademlia) Off(p *Peer) {
del = true del = true
return newEntry(p.BzzAddr) return newEntry(p.BzzAddr)
}) })
} else {
del = true
}
if del { if del {
k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(_ pot.Val) pot.Val { k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(_ pot.Val) pot.Val {

View File

@ -46,19 +46,19 @@ func newTestKademlia(b string) *Kademlia {
return NewKademlia(base, params) return NewKademlia(base, params)
} }
func newTestKadPeer(k *Kademlia, s string) *Peer { func newTestKadPeer(k *Kademlia, s string, lightNode bool) *Peer {
return NewPeer(&BzzPeer{BzzAddr: testKadPeerAddr(s)}, k) return NewPeer(&BzzPeer{BzzAddr: testKadPeerAddr(s), LightNode: lightNode}, k)
} }
func On(k *Kademlia, ons ...string) { func On(k *Kademlia, ons ...string) {
for _, s := range ons { for _, s := range ons {
k.On(newTestKadPeer(k, s)) k.On(newTestKadPeer(k, s, false))
} }
} }
func Off(k *Kademlia, offs ...string) { func Off(k *Kademlia, offs ...string) {
for _, s := range offs { for _, s := range offs {
k.Off(newTestKadPeer(k, s)) k.Off(newTestKadPeer(k, s, false))
} }
} }
@ -254,6 +254,56 @@ func TestSuggestPeerFindPeers(t *testing.T) {
} }
// a node should stay in the address book if it's removed from the kademlia
func TestOffEffectingAddressBookNormalNode(t *testing.T) {
k := newTestKademlia("00000000")
// peer added to kademlia
k.On(newTestKadPeer(k, "01000000", false))
// peer should be in the address book
if k.addrs.Size() != 1 {
t.Fatal("known peer addresses should contain 1 entry")
}
// peer should be among live connections
if k.conns.Size() != 1 {
t.Fatal("live peers should contain 1 entry")
}
// remove peer from kademlia
k.Off(newTestKadPeer(k, "01000000", false))
// peer should be in the address book
if k.addrs.Size() != 1 {
t.Fatal("known peer addresses should contain 1 entry")
}
// peer should not be among live connections
if k.conns.Size() != 0 {
t.Fatal("live peers should contain 0 entry")
}
}
// a light node should not be in the address book
func TestOffEffectingAddressBookLightNode(t *testing.T) {
k := newTestKademlia("00000000")
// light node peer added to kademlia
k.On(newTestKadPeer(k, "01000000", true))
// peer should not be in the address book
if k.addrs.Size() != 0 {
t.Fatal("known peer addresses should contain 0 entry")
}
// peer should be among live connections
if k.conns.Size() != 1 {
t.Fatal("live peers should contain 1 entry")
}
// remove peer from kademlia
k.Off(newTestKadPeer(k, "01000000", true))
// peer should not be in the address book
if k.addrs.Size() != 0 {
t.Fatal("known peer addresses should contain 0 entry")
}
// peer should not be among live connections
if k.conns.Size() != 0 {
t.Fatal("live peers should contain 0 entry")
}
}
func TestSuggestPeerRetries(t *testing.T) { func TestSuggestPeerRetries(t *testing.T) {
k := newTestKademlia("00000000") k := newTestKademlia("00000000")
k.RetryInterval = int64(300 * time.Millisecond) // cycle k.RetryInterval = int64(300 * time.Millisecond) // cycle

View File

@ -245,7 +245,10 @@ func (d *Delivery) RequestFromPeers(ctx context.Context, req *network.Request) (
} else { } else {
d.kad.EachConn(req.Addr[:], 255, func(p *network.Peer, po int, nn bool) bool { d.kad.EachConn(req.Addr[:], 255, func(p *network.Peer, po int, nn bool) bool {
id := p.ID() id := p.ID()
// TODO: skip light nodes that do not accept retrieve requests if p.LightNode {
// skip light nodes
return true
}
if req.SkipPeer(id.String()) { if req.SkipPeer(id.String()) {
log.Trace("Delivery.RequestFromPeers: skip peer", "peer id", id) log.Trace("Delivery.RequestFromPeers: skip peer", "peer id", id)
return true return true

View File

@ -29,10 +29,13 @@ import (
"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/enode"
"github.com/ethereum/go-ethereum/p2p/protocols"
"github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
p2ptest "github.com/ethereum/go-ethereum/p2p/testing" p2ptest "github.com/ethereum/go-ethereum/p2p/testing"
"github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/log"
"github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/network"
pq "github.com/ethereum/go-ethereum/swarm/network/priorityqueue"
"github.com/ethereum/go-ethereum/swarm/network/simulation" "github.com/ethereum/go-ethereum/swarm/network/simulation"
"github.com/ethereum/go-ethereum/swarm/state" "github.com/ethereum/go-ethereum/swarm/state"
"github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage"
@ -274,6 +277,86 @@ func TestStreamerUpstreamRetrieveRequestMsgExchange(t *testing.T) {
} }
} }
// if there is one peer in the Kademlia, RequestFromPeers should return it
func TestRequestFromPeers(t *testing.T) {
dummyPeerID := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8")
addr := network.RandomAddr()
to := network.NewKademlia(addr.OAddr, network.NewKadParams())
delivery := NewDelivery(to, nil)
protocolsPeer := protocols.NewPeer(p2p.NewPeer(dummyPeerID, "dummy", nil), nil, nil)
peer := network.NewPeer(&network.BzzPeer{
BzzAddr: network.RandomAddr(),
LightNode: false,
Peer: protocolsPeer,
}, to)
to.On(peer)
r := NewRegistry(addr.ID(), delivery, nil, nil, nil)
// an empty priorityQueue has to be created to prevent a goroutine being called after the test has finished
sp := &Peer{
Peer: protocolsPeer,
pq: pq.New(int(PriorityQueue), PriorityQueueCap),
streamer: r,
}
r.setPeer(sp)
req := network.NewRequest(
storage.Address(hash0[:]),
true,
&sync.Map{},
)
ctx := context.Background()
id, _, err := delivery.RequestFromPeers(ctx, req)
if err != nil {
t.Fatal(err)
}
if *id != dummyPeerID {
t.Fatalf("Expected an id, got %v", id)
}
}
// RequestFromPeers should not return light nodes
func TestRequestFromPeersWithLightNode(t *testing.T) {
dummyPeerID := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8")
addr := network.RandomAddr()
to := network.NewKademlia(addr.OAddr, network.NewKadParams())
delivery := NewDelivery(to, nil)
protocolsPeer := protocols.NewPeer(p2p.NewPeer(dummyPeerID, "dummy", nil), nil, nil)
// setting up a lightnode
peer := network.NewPeer(&network.BzzPeer{
BzzAddr: network.RandomAddr(),
LightNode: true,
Peer: protocolsPeer,
}, to)
to.On(peer)
r := NewRegistry(addr.ID(), delivery, nil, nil, nil)
// an empty priorityQueue has to be created to prevent a goroutine being called after the test has finished
sp := &Peer{
Peer: protocolsPeer,
pq: pq.New(int(PriorityQueue), PriorityQueueCap),
streamer: r,
}
r.setPeer(sp)
req := network.NewRequest(
storage.Address(hash0[:]),
true,
&sync.Map{},
)
ctx := context.Background()
// making a request which should return with "no peer found"
_, _, err := delivery.RequestFromPeers(ctx, req)
expectedError := "no peer found"
if err.Error() != expectedError {
t.Fatalf("expected '%v', got %v", expectedError, err)
}
}
func TestStreamerDownstreamChunkDeliveryMsgExchange(t *testing.T) { func TestStreamerDownstreamChunkDeliveryMsgExchange(t *testing.T) {
tester, streamer, localStore, teardown, err := newStreamerTester(t, &RegistryOptions{ tester, streamer, localStore, teardown, err := newStreamerTester(t, &RegistryOptions{
Retrieval: RetrievalDisabled, Retrieval: RetrievalDisabled,