diff --git a/cmd/swarm-snapshot/create.go b/cmd/swarm-snapshot/create.go index 7d4cdcc0f8..db932b0cf8 100644 --- a/cmd/swarm-snapshot/create.go +++ b/cmd/swarm-snapshot/create.go @@ -60,7 +60,7 @@ func createSnapshot(filename string, nodes int, services []string) (err error) { sim := simulation.NewInProc(map[string]simulation.ServiceFunc{ "bzz": func(ctx *adapters.ServiceContext, bucket *sync.Map) (node.Service, func(), error) { - addr := network.NewAddr(ctx.Config.Node()) + addr := network.NewBzzAddrFromEnode(ctx.Config.Node()) kad := network.NewKademlia(addr.Over(), network.NewKadParams()) hp := network.NewHiveParams() hp.KeepAliveInterval = time.Duration(200) * time.Millisecond diff --git a/cmd/swarm/run_test.go b/cmd/swarm/run_test.go index d9b9ca1eb5..2cdf76fa98 100644 --- a/cmd/swarm/run_test.go +++ b/cmd/swarm/run_test.go @@ -131,7 +131,10 @@ func newTestCluster(t *testing.T, size int) *testCluster { } // connect the nodes together - for _, node := range cluster.Nodes { + for i, node := range cluster.Nodes { + if i == 0 { + continue + } if err := node.Client.Call(nil, "admin_addPeer", cluster.Nodes[0].Enode); err != nil { t.Fatal(err) } diff --git a/network/capability/capability.go b/network/capability/capability.go index bd0e8d926f..10f458f493 100644 --- a/network/capability/capability.go +++ b/network/capability/capability.go @@ -185,3 +185,33 @@ func (c *Capabilities) DecodeRLP(s *rlp.Stream) error { return nil } + +// Match returns true if all bits set in the argument is also set in the receiver +func (c *Capability) Match(capCompare *Capability) bool { + if capCompare == nil || len(c.Cap) != len(capCompare.Cap) { + return false + } + // on the first occurrence of false where query has true we can fail + for i, flag := range capCompare.Cap { + if flag && !c.Cap[i] { + return false + } + } + return true +} + +// Match returns true if all bits set in all capability arguments are also set in the receiver's capabilities +func (c *Capabilities) Match(capsCompare *Capabilities) bool { + for _, capCompare := range capsCompare.Caps { + + // if queryied id doesn't exist in object we can nay right away + cap := c.Get(capCompare.Id) + if cap == nil { + return false + } + if !cap.Match(capCompare) { + return false + } + } + return true +} diff --git a/network/capability/capability_test.go b/network/capability/capability_test.go index a4d734e98e..b6095e19e9 100644 --- a/network/capability/capability_test.go +++ b/network/capability/capability_test.go @@ -172,3 +172,59 @@ func TestCapabilitiesRLP(t *testing.T) { t.Fatalf("cap 1 caps not correct, expected %v, got %v", cap2.Cap, cap2Restored.Cap) } } + +// TestCapabilitiesQuery tests methods for quering capability states +func TestCapabilitiesQuery(t *testing.T) { + + // Initialize capability + caps := NewCapabilities() + + // Register module. Should succeed + c1 := NewCapability(1, 3) + c1.Set(1) + err := caps.Add(c1) + if err != nil { + t.Fatalf("RegisterCapabilityModule fail: %v", err) + } + + c2 := NewCapability(42, 9) + c2.Set(2) + c2.Set(8) + err = caps.Add(c2) + if err != nil { + t.Fatalf("RegisterCapabilityModule fail: %v", err) + } + + capsCompare := NewCapabilities() + capCompare := NewCapability(42, 10) + capCompare.Set(2) + capCompare.Set(8) + capsCompare.Add(capCompare) + if caps.Match(capsCompare) { + t.Fatalf("Expected cCompare with mismatch length to fail; %s != %s", capsCompare, caps) + } + capsCompare = NewCapabilities() + capCompare = NewCapability(42, 9) + capCompare.Set(2) + capsCompare.Add(capCompare) + if !caps.Match(capsCompare) { + t.Fatalf("Expected %s to match %s", capsCompare, caps) + } + + capCompare = NewCapability(1, 3) + capsCompare.Add(capCompare) + if !caps.Match(capsCompare) { + t.Fatalf("Expected %s to match %s", capsCompare, caps) + } + + capCompare.Set(1) + if !caps.Match(capsCompare) { + t.Fatalf("Expected %s to match %s", capsCompare, caps) + } + + capCompare.Set(2) + if caps.Match(capsCompare) { + t.Fatalf("Expected %s not to match %s", capsCompare, caps) + } + +} diff --git a/network/discovery.go b/network/discovery.go index 5d97f0f1b6..87a55e3eb6 100644 --- a/network/discovery.go +++ b/network/discovery.go @@ -21,6 +21,8 @@ import ( "fmt" "sync" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethersphere/swarm/log" "github.com/ethersphere/swarm/pot" ) @@ -95,6 +97,7 @@ func (d *Peer) NotifyPeer(a *BzzAddr, po uint8) { resp := &peersMsg{ Peers: []*BzzAddr{a}, } + log.Warn("notifypeer", "notify", resp) go d.Send(context.TODO(), resp) } @@ -127,6 +130,27 @@ type peersMsg struct { Peers []*BzzAddr } +// DecodeRLP implements rlp.Decoder interface +func (p *peersMsg) DecodeRLP(s *rlp.Stream) error { + _, err := s.List() + if err != nil { + return err + } + _, err = s.List() + if err != nil { + return err + } + for { + var addr BzzAddr + err = s.Decode(&addr) + if err != nil { + break + } + p.Peers = append(p.Peers, &addr) + } + return nil +} + // String pretty prints a peersMsg func (msg peersMsg) String() string { return fmt.Sprintf("%T: %v", msg, msg.Peers) @@ -140,7 +164,6 @@ func (d *Peer) handlePeersMsg(msg *peersMsg) error { if len(msg.Peers) == 0 { return nil } - for _, a := range msg.Peers { d.seen(a) NotifyPeer(a, d.kad) diff --git a/network/discovery_test.go b/network/discovery_test.go index f7b61af627..6e191aa56b 100644 --- a/network/discovery_test.go +++ b/network/discovery_test.go @@ -17,8 +17,8 @@ package network import ( + "bytes" "crypto/ecdsa" - crand "crypto/rand" "encoding/binary" "fmt" "math/rand" @@ -48,7 +48,7 @@ func TestSubPeersMsg(t *testing.T) { } node := s.Nodes[0] - raddr := NewAddr(node) + raddr := NewBzzAddrFromEnode(node) pp.Register(raddr) // start the hive and wait for the connection @@ -114,18 +114,15 @@ func testInitialPeersMsg(t *testing.T, peerPO, peerDepth int) { connect := func(a pot.Address, po int) (addrs []*BzzAddr) { n := rand.Intn(maxPeersPerPO) for i := 0; i < n; i++ { - peer, err := newDiscPeer(pot.RandomAddressAt(a, po)) - if err != nil { - t.Fatal(err) - } + peer := newDiscPeer(pot.RandomAddressAt(a, po)) hive.On(peer) addrs = append(addrs, peer.BzzAddr) } return addrs } register := func(a pot.Address, po int) { - addr := pot.RandomAddressAt(a, po) - hive.Register(&BzzAddr{OAddr: addr[:]}) + discPeer := newDiscPeer(a) + hive.Register(discPeer.BzzAddr) } // generate connected and just registered peers @@ -238,20 +235,21 @@ func testSortPeers(peers []*BzzAddr) []*BzzAddr { // as we are not creating a real node via the protocol, // we need to create the discovery peer objects for the additional kademlia // nodes manually -func newDiscPeer(addr pot.Address) (*Peer, error) { - pKey, err := ecdsa.GenerateKey(crypto.S256(), crand.Reader) - if err != nil { - return nil, err - } +func newDiscPeer(addr pot.Address) *Peer { + + // deterministically create enode id + // Input to the non-random input buffer is 2xaddress since it munches 256 bits + addrSeed := append(addr.Bytes(), addr.Bytes()...) + pKey, _ := ecdsa.GenerateKey(crypto.S256(), bytes.NewBuffer(addrSeed)) pubKey := pKey.PublicKey nod := enode.NewV4(&pubKey, net.IPv4(127, 0, 0, 1), 0, 0) - bzzAddr := &BzzAddr{OAddr: addr[:], UAddr: []byte(nod.String())} + bzzAddr := NewBzzAddr(addr[:], []byte(nod.String())) id := nod.ID() p2pPeer := p2p.NewPeer(id, id.String(), nil) return NewPeer(&BzzPeer{ Peer: protocols.NewPeer(p2pPeer, &dummyMsgRW{}, DiscoverySpec), BzzAddr: bzzAddr, - }, nil), nil + }, nil) } type dummyMsgRW struct{} diff --git a/network/enr.go b/network/enr.go index dc1264c385..432c2b1ca9 100644 --- a/network/enr.go +++ b/network/enr.go @@ -48,12 +48,6 @@ func (b *ENRAddrEntry) DecodeRLP(s *rlp.Stream) error { return nil } -type ENRLightNodeEntry bool - -func (b ENRLightNodeEntry) ENRKey() string { - return "bzzlightnode" -} - type ENRBootNodeEntry bool func (b ENRBootNodeEntry) ENRKey() string { @@ -61,22 +55,19 @@ func (b ENRBootNodeEntry) ENRKey() string { } func getENRBzzPeer(p *p2p.Peer, rw p2p.MsgReadWriter, spec *protocols.Spec) *BzzPeer { - var lightnode ENRLightNodeEntry var bootnode ENRBootNodeEntry // retrieve the ENR Record data record := p.Node().Record() - record.Load(&lightnode) record.Load(&bootnode) - // get the address; separate function as long as we need swarm/network:NewAddr() to call it + // get the address; separate function as long as we need swarm/network:NewBzzAddrFromEnode() to call it addr := getENRBzzAddr(p.Node()) // build the peer using the retrieved data return &BzzPeer{ - Peer: protocols.NewPeer(p, rw, spec), - LightNode: bool(lightnode), - BzzAddr: addr, + Peer: protocols.NewPeer(p, rw, spec), + BzzAddr: addr, } } @@ -86,8 +77,5 @@ func getENRBzzAddr(nod *enode.Node) *BzzAddr { record := nod.Record() record.Load(&addr) - return &BzzAddr{ - OAddr: addr.data, - UAddr: []byte(nod.String()), - } + return NewBzzAddr(addr.data, []byte(nod.String())) } diff --git a/network/hive.go b/network/hive.go index 3134553be6..73fc00aefa 100644 --- a/network/hive.go +++ b/network/hive.go @@ -209,7 +209,8 @@ func (h *Hive) PeerInfo(id enode.ID) interface{} { if p == nil { return nil } - addr := NewAddr(p.Node()) + // TODO this is bogus, the overlay address will not be correct + addr := NewBzzAddrFromEnode(p.Node()) return struct { OAddr hexutil.Bytes UAddr hexutil.Bytes diff --git a/network/hive_test.go b/network/hive_test.go index ff08a85690..670d1727f0 100644 --- a/network/hive_test.go +++ b/network/hive_test.go @@ -55,7 +55,7 @@ func TestRegisterAndConnect(t *testing.T) { } node := s.Nodes[0] - raddr := NewAddr(node) + raddr := NewBzzAddrFromEnode(node) pp.Register(raddr) // start the hive @@ -100,7 +100,7 @@ func TestRegisterAndConnect(t *testing.T) { } } -// TestHiveStatePersistance creates a protocol simulation with n peers for a node +// TestHiveStatePersistence creates a protocol simulation with n peers for a node // After protocols complete, the node is shut down and the state is stored. // Another simulation is created, where 0 nodes are created, but where the stored state is passed // The test succeeds if all the peers from the stored state are known after the protocols of the @@ -108,7 +108,7 @@ func TestRegisterAndConnect(t *testing.T) { // // Actual connectivity is not in scope for this test, as the peers loaded from state are not known to // the simulation; the test only verifies that the peers are known to the node -func TestHiveStatePersistance(t *testing.T) { +func TestHiveStatePersistence(t *testing.T) { dir, err := ioutil.TempDir("", "hive_test_store") if err != nil { t.Fatal(err) @@ -152,7 +152,7 @@ func TestHiveStatePersistance(t *testing.T) { h1, cleanup1 := startHive(t, dir) peers := make(map[string]bool) for i := 0; i < peersCount; i++ { - raddr := RandomAddr() + raddr := RandomBzzAddr() h1.Register(raddr) peers[raddr.String()] = true } diff --git a/network/kademlia.go b/network/kademlia.go index f767137ba5..d16eac967a 100644 --- a/network/kademlia.go +++ b/network/kademlia.go @@ -19,6 +19,7 @@ package network import ( "bytes" "encoding/hex" + "errors" "fmt" "math/rand" "sort" @@ -29,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/metrics" "github.com/ethersphere/swarm/log" + "github.com/ethersphere/swarm/network/capability" "github.com/ethersphere/swarm/pot" sv "github.com/ethersphere/swarm/version" ) @@ -84,15 +86,16 @@ func NewKadParams() *KadParams { // Kademlia is a table of live peers and a db of known peers (node records) type Kademlia struct { - lock sync.RWMutex - *KadParams // Kademlia configuration parameters - base []byte // immutable baseaddress of the table - addrs *pot.Pot // pots container for known peer addresses - conns *pot.Pot // pots container for live peer connections - depth uint8 // stores the last current depth of saturation - nDepth int // stores the last neighbourhood depth - nDepthMu sync.RWMutex // protects neighbourhood depth nDepth - nDepthSig []chan struct{} // signals when neighbourhood depth nDepth is changed + lock sync.RWMutex + capabilityIndex map[string]*capabilityIndex + *KadParams // Kademlia configuration parameters + base []byte // immutable baseaddress of the table + addrs *pot.Pot // pots container for known peer addresses + conns *pot.Pot // pots container for live peer connections + depth uint8 // stores the last current depth of saturation + nDepth int // stores the last neighbourhood depth + nDepthMu sync.RWMutex // protects neighbourhood depth nDepth + nDepthSig []chan struct{} // signals when neighbourhood depth nDepth is changed } type KademliaInfo struct { @@ -111,11 +114,92 @@ func NewKademlia(addr []byte, params *KadParams) *Kademlia { if params == nil { params = NewKadParams() } - return &Kademlia{ - base: addr, - KadParams: params, - addrs: pot.NewPot(nil, 0), - conns: pot.NewPot(nil, 0), + k := &Kademlia{ + base: addr, + KadParams: params, + capabilityIndex: make(map[string]*capabilityIndex), + addrs: pot.NewPot(nil, 0), + conns: pot.NewPot(nil, 0), + } + k.RegisterCapabilityIndex("full", *fullCapability) + k.RegisterCapabilityIndex("light", *lightCapability) + return k +} + +// RegisterCapabilityIndex adds an entry to the capability index of the kademlia +// The capability index is associated with the supplied string s +// Any peers matching any bits set in the capability in the index, will be added to the index (or removed on removal) +func (k *Kademlia) RegisterCapabilityIndex(s string, c capability.Capability) error { + if s == "" { + return errors.New("Cannot add index with empty string key") + } else if _, ok := k.capabilityIndex[s]; ok { + return fmt.Errorf("Capability index '%s' already exists", s) + } + log.Debug("Registered cap index", "s", s, "c", c) + k.capabilityIndex[s] = NewCapabilityIndex(c) + return nil +} + +// adds a peer to any capability indices it matches +func (k *Kademlia) addToCapabilityIndex(p interface{}) { + var ok bool + var eAddr *BzzAddr + var ePeer *Peer + ePeer, ok = p.(*Peer) + if ok { + eAddr = ePeer.BzzAddr + } else { + eAddr = p.(*entry).BzzAddr + } + for s, idxItem := range k.capabilityIndex { + for _, vCap := range eAddr.Capabilities.Caps { + if idxItem.Id != vCap.Id { + continue + } + if vCap.Match(idxItem.Capability) { + log.Trace("Added peer to capability index", "conn", ok, "s", s, "v", vCap, "p", p) + if ok { + k.capabilityIndex[s].conns, _, _ = pot.Add(idxItem.conns, ePeer, Pof) + } else { + k.capabilityIndex[s].addrs, _, _ = pot.Add(idxItem.addrs, newEntry(eAddr), Pof) + } + } + } + } +} + +// removes a peer from any capability indices it matches +func (k *Kademlia) removeFromCapabilityIndex(p interface{}, disconnectOnly bool) { + var ok bool + var eAddr *BzzAddr + var ePeer *Peer + ePeer, ok = p.(*Peer) + if ok { + eAddr = ePeer.BzzAddr + } else if disconnectOnly { + return + } else { + eAddr = p.(*entry).BzzAddr + } + for s, idxItem := range k.capabilityIndex { + if ok { + conns, _, found, _ := pot.Swap(idxItem.conns, ePeer, Pof, func(_ pot.Val) pot.Val { + return nil + }) + if found { + log.Trace("Removed peer from capability conns index", "s", s, "p", ePeer) + idxItem.conns = conns + } + } + if !disconnectOnly { + addrs, _, found, _ := pot.Swap(idxItem.addrs, eAddr, Pof, func(_ pot.Val) pot.Val { + return nil + }) + if found { + log.Trace("Removed peer from capability addrs index", "s", s, "p", eAddr) + idxItem.addrs = addrs + } + } } } @@ -135,6 +219,22 @@ func newEntry(p *BzzAddr) *entry { } } +// index providing quick access to all peers having a certain capability set +type capabilityIndex struct { + *capability.Capability + conns *pot.Pot + addrs *pot.Pot +} + +// NewCapabilityIndex creates a new capability index with a copy the provided capabilities array +func NewCapabilityIndex(c capability.Capability) *capabilityIndex { + return &capabilityIndex{ + Capability: &c, + conns: pot.NewPot(nil, 0), + addrs: pot.NewPot(nil, 0), + } +} + // Label is a short tag for the entry for debug func Label(e *entry) string { return fmt.Sprintf("%s (%d)", e.Hex()[:4], e.retries) @@ -153,7 +253,7 @@ func (k *Kademlia) Register(peers ...*BzzAddr) error { metrics.GetOrRegisterCounter("kad.register", nil).Inc(1) - var known, size int + var size int for _, p := range peers { log.Trace("kademlia trying to register", "addr", p) // error if self received, peer should know better @@ -161,8 +261,7 @@ func (k *Kademlia) Register(peers ...*BzzAddr) error { if bytes.Equal(p.Address(), k.base) { return fmt.Errorf("add peers: %x is self", k.base) } - var found bool - k.addrs, _, found, _ = 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 { // if not found if v == nil { log.Trace("registering new peer", "addr", p) @@ -181,9 +280,7 @@ func (k *Kademlia) Register(peers ...*BzzAddr) error { return v }) - if found { - known++ - } + k.addToCapabilityIndex(newEntry(p)) size++ } @@ -323,7 +420,8 @@ func (k *Kademlia) On(p *Peer) (uint8, bool) { // found among live peers, do nothing return v }) - if ins && !p.BzzPeer.LightNode { + k.addToCapabilityIndex(p) + if ins { a := newEntry(p.BzzAddr) a.conn = p // insert new online peer into addrs @@ -410,27 +508,33 @@ func (k *Kademlia) SubscribeToNeighbourhoodDepthChange() (c <-chan struct{}, uns func (k *Kademlia) Off(p *Peer) { k.lock.Lock() defer k.lock.Unlock() - var del bool - if !p.BzzPeer.LightNode { - k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { - // v cannot be nil, must check otherwise we overwrite entry - if v == nil { - panic(fmt.Sprintf("connected peer not found %v", p)) - } - del = true - return newEntry(p.BzzAddr) - }) - } else { - del = true - } + k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { + // v cannot be nil, must check otherwise we overwrite entry + if v == nil { + panic(fmt.Sprintf("connected peer not found %v", p)) + } + return newEntry(p.BzzAddr) + }) + // note the following only ran if the peer was a lightnode + k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(_ pot.Val) pot.Val { + // v cannot be nil, but no need to check + return nil + }) + k.removeFromCapabilityIndex(p, true) + k.setNeighbourhoodDepth() +} - if del { - k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(_ pot.Val) pot.Val { - // v cannot be nil, but no need to check - return nil - }) - k.setNeighbourhoodDepth() +// EachConnFiltered performs the same action as EachConn +// with the difference that it will only return peers that matches the specified capability index filter +func (k *Kademlia) EachConnFiltered(base []byte, capKey string, o int, f func(*Peer, int) bool) error { + k.lock.RLock() + defer k.lock.RUnlock() + c, ok := k.capabilityIndex[capKey] + if !ok { + return fmt.Errorf("Unregistered capability index '%s'", capKey) } + k.eachConn(base, c.conns, o, f) + return nil } // EachConn is an iterator with args (base, po, f) applies f to each live peer @@ -439,14 +543,17 @@ func (k *Kademlia) Off(p *Peer) { func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int) bool) { k.lock.RLock() defer k.lock.RUnlock() - k.eachConn(base, o, f) + k.eachConn(base, k.conns, o, f) } -func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int) bool) { +func (k *Kademlia) eachConn(base []byte, db *pot.Pot, o int, f func(*Peer, int) bool) { if len(base) == 0 { base = k.base } - k.conns.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { + if db == nil { + db = k.conns + } + db.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { if po > o { return true } @@ -454,20 +561,37 @@ func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int) bool) { }) } +// EachAddrFiltered performs the same action as EachAddr +// with the difference that it will only return peers that matches the specified capability index filter +func (k *Kademlia) EachAddrFiltered(base []byte, capKey string, o int, f func(*BzzAddr, int) bool) error { + k.lock.RLock() + defer k.lock.RUnlock() + c, ok := k.capabilityIndex[capKey] + if !ok { + return fmt.Errorf("Unregistered capability index '%s'", capKey) + } + log.Debug("filter with capname", "key", capKey, "cap", c) + k.eachAddr(base, c.addrs, o, f) + return nil +} + // EachAddr called with (base, po, f) is an iterator applying f to each known peer // that has proximity order o or less as measured from the base // if base is nil, kademlia base address is used func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int) bool) { k.lock.RLock() defer k.lock.RUnlock() - k.eachAddr(base, o, f) + k.eachAddr(base, k.addrs, o, f) } -func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int) bool) { +func (k *Kademlia) eachAddr(base []byte, db *pot.Pot, o int, f func(*BzzAddr, int) bool) { if len(base) == 0 { base = k.base } - k.addrs.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { + if db == nil { + db = k.addrs + } + db.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { if po > o { return true } @@ -836,7 +960,7 @@ func (k *Kademlia) knowNeighbours(addrs [][]byte) (got bool, n int, missing [][] pm := make(map[string]bool) depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) // create a map with all peers at depth and deeper known in the kademlia - k.eachAddr(nil, 255, func(p *BzzAddr, po int) bool { + k.eachAddr(nil, k.addrs, 255, func(p *BzzAddr, po int) bool { // in order deepest to shallowest compared to the kademlia base address // all bins (except self) are included (0 <= bin <= 255) if po < depth { @@ -875,7 +999,7 @@ func (k *Kademlia) connectedNeighbours(peers [][]byte) (got bool, n int, missing // in order deepest to shallowest compared to the kademlia base address // all bins (except self) are included (0 <= bin <= 255) depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) - k.eachConn(nil, 255, func(p *Peer, po int) bool { + k.eachConn(nil, nil, 255, func(p *Peer, po int) bool { if po < depth { return false } diff --git a/network/kademlia_test.go b/network/kademlia_test.go index be20ece17c..b751b61552 100644 --- a/network/kademlia_test.go +++ b/network/kademlia_test.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethersphere/swarm/network/capability" "github.com/ethersphere/swarm/p2p/protocols" "github.com/ethersphere/swarm/pot" ) @@ -37,7 +38,7 @@ func init() { func testKadPeerAddr(s string) *BzzAddr { a := pot.NewAddressFromString(s) - return &BzzAddr{OAddr: a, UAddr: a} + return NewBzzAddr(a, a) } func newTestKademliaParams() *KadParams { @@ -60,19 +61,19 @@ func newTestKademlia(t *testing.T, b string) *testKademlia { } } -func (tk *testKademlia) newTestKadPeer(s string, lightNode bool) *Peer { - return NewPeer(&BzzPeer{BzzAddr: testKadPeerAddr(s), LightNode: lightNode}, tk.Kademlia) +func (tk *testKademlia) newTestKadPeer(s string) *Peer { + return NewPeer(&BzzPeer{BzzAddr: testKadPeerAddr(s)}, tk.Kademlia) } func (tk *testKademlia) On(ons ...string) { for _, s := range ons { - tk.Kademlia.On(tk.newTestKadPeer(s, false)) + tk.Kademlia.On(tk.newTestKadPeer(s)) } } func (tk *testKademlia) Off(offs ...string) { for _, s := range offs { - tk.Kademlia.Off(tk.newTestKadPeer(s, false)) + tk.Kademlia.Off(tk.newTestKadPeer(s)) } } @@ -95,7 +96,7 @@ func (tk *testKademlia) Register(regs ...string) { // // TODO: Make test adapt to change in NeighbourhoodSize func TestNeighbourhoodDepth(t *testing.T) { - baseAddressBytes := RandomAddr().OAddr + baseAddressBytes := RandomBzzAddr().OAddr kad := NewKademlia(baseAddressBytes, NewKadParams()) baseAddress := pot.NewAddressFromBytes(baseAddressBytes) @@ -472,31 +473,6 @@ func TestOffEffectingAddressBookNormalNode(t *testing.T) { } } -// a light node should not be in the address book -func TestOffEffectingAddressBookLightNode(t *testing.T) { - tk := newTestKademlia(t, "00000000") - // light node peer added to kademlia - tk.Kademlia.On(tk.newTestKadPeer("01000000", true)) - // peer should not be in the address book - if tk.addrs.Size() != 0 { - t.Fatal("known peer addresses should contain 0 entry") - } - // peer should be among live connections - if tk.conns.Size() != 1 { - t.Fatal("live peers should contain 1 entry") - } - // remove peer from kademlia - tk.Kademlia.Off(tk.newTestKadPeer("01000000", true)) - // peer should not be in the address book - if tk.addrs.Size() != 0 { - t.Fatal("known peer addresses should contain 0 entry") - } - // peer should not be among live connections - if tk.conns.Size() != 0 { - t.Fatal("live peers should contain 0 entry") - } -} - func TestSuggestPeerRetries(t *testing.T) { tk := newTestKademlia(t, "00000000") tk.RetryInterval = int64(300 * time.Millisecond) // cycle @@ -552,11 +528,8 @@ func newTestDiscoveryPeer(addr pot.Address, kad *Kademlia) *Peer { p := p2p.NewPeer(enode.ID{}, "foo", []p2p.Cap{}) pp := protocols.NewPeer(p, rw, &protocols.Spec{}) bp := &BzzPeer{ - Peer: pp, - BzzAddr: &BzzAddr{ - OAddr: addr.Bytes(), - UAddr: []byte(fmt.Sprintf("%x", addr[:])), - }, + Peer: pp, + BzzAddr: NewBzzAddr(addr.Bytes(), []byte(fmt.Sprintf("%x", addr[:]))), } return NewPeer(bp, kad) } @@ -670,3 +643,303 @@ func TestKademlia_SubscribeToNeighbourhoodDepthChange(t *testing.T) { } }) } + +// TestCapabilitiesIndex checks that capability indices contains only the peers that have the filters' capability bits set +// It tests the state of the indices after registering, connecting, disconnecting and removing peers +// +// It sets up peers with capability arrays 42:101, 42:001 and 666:101, and registers these capabilities as filters in the kademlia +// It also sets up a peer with both capability arrays 42:101 and 666:101 +// Lastly it registers a filter for the capability 42:010 in the kademlia which will match no peers +// +// The tests are split up to make them easier to read +func TestCapabilityIndex(t *testing.T) { + t.Run("register", testCapabilityIndexRegister) + t.Run("connect", testCapabilityIndexConnect) + t.Run("disconnect", testCapabilityIndexDisconnect) + t.Run("remove", testCapabilityIndexRemove) +} + +// set up capabilities and peers for each individual test +func testCapabilityIndexHelper() (*Kademlia, map[string]*Peer, map[string]*capability.Capability) { + + bzzAddrs := make(map[string]*BzzAddr) + discPeers := make(map[string]*Peer) + caps := make(map[string]*capability.Capability) + + kp := NewKadParams() + addr := RandomBzzAddr() + base := addr.OAddr + k := NewKademlia(base, kp) + + caps["42:101"] = capability.NewCapability(42, 3) + caps["42:101"].Set(0) + caps["42:101"].Set(2) + k.RegisterCapabilityIndex("42:101", *caps["42:101"]) + + caps["42:001"] = capability.NewCapability(42, 3) + caps["42:001"].Set(2) + k.RegisterCapabilityIndex("42:001", *caps["42:001"]) + + caps["42:010"] = capability.NewCapability(42, 3) + caps["42:010"].Set(1) + k.RegisterCapabilityIndex("42:010", *caps["42:010"]) + + caps["666:101"] = capability.NewCapability(666, 3) + caps["666:101"].Set(0) + caps["666:101"].Set(2) + k.RegisterCapabilityIndex("666:101", *caps["666:101"]) + + bzzAddrs["42:101"] = RandomBzzAddr() + bzzAddrs["42:101"].Capabilities.Add(caps["42:101"]) + discPeers["42:101"] = NewPeer(&BzzPeer{BzzAddr: bzzAddrs["42:101"]}, k) + + bzzAddrs["42:001"] = RandomBzzAddr() + bzzAddrs["42:001"].Capabilities.Add(caps["42:001"]) + discPeers["42:001"] = NewPeer(&BzzPeer{BzzAddr: bzzAddrs["42:001"]}, k) + + bzzAddrs["666:101"] = RandomBzzAddr() + bzzAddrs["666:101"].Capabilities.Add(caps["666:101"]) + discPeers["666:101"] = NewPeer(&BzzPeer{BzzAddr: bzzAddrs["666:101"]}, k) + + bzzAddrs["42:101,666:101"] = RandomBzzAddr() + bzzAddrs["42:101,666:101"].Capabilities.Add(caps["666:101"]) + bzzAddrs["42:101,666:101"].Capabilities.Add(caps["42:101"]) + discPeers["42:101,666:101"] = NewPeer(&BzzPeer{BzzAddr: bzzAddrs["42:101,666:101"]}, k) + + k.Register(bzzAddrs["42:101"], bzzAddrs["42:001"], bzzAddrs["666:101"], bzzAddrs["42:101,666:101"]) + + return k, discPeers, caps +} + +// test indices after registering peers +func testCapabilityIndexRegister(t *testing.T) { + + k, _, caps := testCapabilityIndexHelper() + + // Call without filter should still return all peers + c := 0 + k.EachAddr(k.BaseAddr(), 255, func(_ *BzzAddr, _ int) bool { + c++ + return true + }) + if c != 4 { + t.Fatalf("EachAddr expected 3 peers, got %d", c) + } + + // match capability 42:101 + c = 0 + k.EachAddrFiltered(k.BaseAddr(), "42:101", 255, func(a *BzzAddr, _ int) bool { + c++ + cp := a.Capabilities.Get(42) + if !cp.Match(caps["42:101"]) { + t.Fatalf("EachAddrFiltered '42:101' capability mismatch, expected %v, got %v", caps["42:101"], cp) + } + return true + }) + if c != 2 { + t.Fatalf("EachAddrFiltered 'full' expected 2 peer, got %d", c) + } + + // Match capability 42:101 and 42:001 + c = 0 + k.EachAddrFiltered(k.BaseAddr(), "42:001", 255, func(a *BzzAddr, _ int) bool { + c++ + return true + }) + if c != 3 { + t.Fatalf("EachAddrFiltered '42:001' expected 2 peers, got %d", c) + } + + // Match no capability + c = 0 + k.EachAddrFiltered(k.BaseAddr(), "42:010", 255, func(a *BzzAddr, _ int) bool { + c++ + return true + }) + if c != 0 { + t.Fatalf("EachAddrFiltered '42:010' expected 0 peers, got %d", c) + } + + // Match 666:101 + // Also checks that one node has both 42:101 and 666:101 + c = 0 + k.EachAddrFiltered(k.BaseAddr(), "666:101", 255, func(a *BzzAddr, _ int) bool { + c++ + cp := a.Capabilities.Get(666) + if !cp.Match(caps["666:101"]) { + t.Fatalf("EachAddrFiltered 'other' capability mismatch, expected %v, got %v", caps["666:101"], cp) + } + cp = a.Capabilities.Get(42) + if cp != nil { + c++ + } + return true + }) + if c != 3 { + t.Fatalf("EachAddrFiltered 'other' expected 3 capability matches, got %d", c) + } +} + +// test indices after connecting peers +func testCapabilityIndexConnect(t *testing.T) { + + k, discPeers, caps := testCapabilityIndexHelper() + + // Set 42:101 and 42:101,666:101 as connected + k.On(discPeers["42:001"]) + k.On(discPeers["42:101,666:101"]) + + // Call without filter should return the single connected peer + c := 0 + k.EachConn(k.BaseAddr(), 255, func(_ *Peer, _ int) bool { + c++ + return true + }) + if c != 2 { + t.Fatalf("EachConn expected 2 peers, got %d", c) + } + + // Check that the "42:101,666:101" peer exists in the indices for both capability arrays + // first the "666:101" index ... + c = 0 + k.EachConnFiltered(k.BaseAddr(), "666:101", 255, func(p *Peer, _ int) bool { + c++ + cp := p.Capabilities.Get(666) + if !cp.Match(caps["666:101"]) { + t.Fatalf("EachConnFiltered '666:101' missing capability %v", caps["666:101"]) + } + cp = p.Capabilities.Get(42) + if !cp.Match(caps["42:101"]) { + t.Fatalf("EachConnFiltered '666:101' missing capability %v", caps["42:101"]) + } + return true + }) + if c != 1 { + t.Fatalf("EachConnFiltered 'other' expected 1 peer, got %d", c) + } + + // ... and in 42:101 + c = 0 + k.EachConnFiltered(k.BaseAddr(), "42:101", 255, func(p *Peer, _ int) bool { + c++ + cp := p.Capabilities.Get(666) + if !cp.Match(caps["666:101"]) { + t.Fatalf("EachConnFiltered '42:101' missing capability %v", caps["666:101"]) + } + cp = p.Capabilities.Get(42) + if !cp.Match(caps["42:101"]) { + t.Fatalf("EachConnFiltered '42:101' missing capability %v", caps["42:101"]) + } + return true + }) + if c != 1 { + t.Fatalf("EachConnFiltered 'more' expected 1 peer, got %d", c) + } +} + +// test indices after disconnecting peers +func testCapabilityIndexDisconnect(t *testing.T) { + + k, discPeers, caps := testCapabilityIndexHelper() + + // Set "42:101" and "42:101,666:101" as connected + // And then disconnect the "42:101,666:101" peer + k.On(discPeers["42:001"]) + k.On(discPeers["42:101,666:101"]) + k.Off(discPeers["42:101,666:101"]) + + // Check that the "42:101,666:101" is now removed from connections + c := 0 + k.EachConnFiltered(k.BaseAddr(), "666:101", 255, func(_ *Peer, _ int) bool { + c++ + return true + }) + if c != 0 { + t.Fatalf("EachConnFiltered '666:101' expected 0 peers, got %d", c) + } + + // Check that there is still a "666:101" peer among known peers + // (the two matched peers will be "42:101,666:101" and "666:101") + c = 0 + k.EachAddrFiltered(k.BaseAddr(), "666:101", 255, func(_ *BzzAddr, _ int) bool { + c++ + return true + }) + if c != 2 { + t.Fatalf("EachAddrFiltered '666:101' expected 2 peers, got %d", c) + } + + // Check that the "42:001" peer is still registered as connected + c = 0 + k.EachConnFiltered(k.BaseAddr(), "42:001", 255, func(p *Peer, _ int) bool { + c++ + cp := p.Capabilities.Get(42) + if !cp.Match(caps["42:001"]) { + t.Fatalf("EachConnFiltered '42:001' missing capability %v", caps["42:001"]) + } + return true + }) + if c != 1 { + t.Fatalf("EachConnFiltered '42:001' expected 1 peer, got %d", c) + } +} + +// test indices after (disconnecting and) removing peers +func testCapabilityIndexRemove(t *testing.T) { + + k, discPeers, caps := testCapabilityIndexHelper() + + // Set "42:101" and "42:101,666:101" as connected + // And then disconnect the "42:101,666:101" peer + k.On(discPeers["42:001"]) + k.On(discPeers["42:101,666:101"]) + k.Off(discPeers["42:101,666:101"]) + + // Remove "less" from both connection and known peers (pruning) list + // TODO replace with the "prune" method when one is implemented + k.removeFromCapabilityIndex(discPeers["42:001"], false) + + // Check that the "42:001" peer is no longer registered as connected + c := 0 + k.EachConnFiltered(k.BaseAddr(), "42:001", 255, func(p *Peer, _ int) bool { + c++ + return true + }) + if c != 0 { + t.Fatalf("EachConnFiltered '42:001' expected 0 peers, got %d", c) + } + + // check that the "42:001" peer is not known anymore + // (the two matched peers will be "42:101,666:101" and "42:101") + c = 0 + k.EachAddrFiltered(k.BaseAddr(), "42:001", 255, func(p *BzzAddr, _ int) bool { + c++ + cp := p.Capabilities.Get(42) + if !cp.Match(caps["42:101"]) { + t.Fatalf("EachConnFiltered '42:001' should now return only capability '42:101': %v", caps["42:101"]) + } + return true + }) + if c != 2 { + t.Fatalf("EachAddrFiltered '42:001' expected 2 peer, got %d", c) + } + + // Remove "42:101,666:101" from known peers list (pruning only) + // TODO replace with the "prune" method when one is implemented + k.removeFromCapabilityIndex(discPeers["42:101,666:101"], false) + + // check that the "42:101,666:101" peer is not known anymore + // (the only matched peer should now be "42:101") + c = 0 + k.EachAddrFiltered(k.BaseAddr(), "42:101", 255, func(p *BzzAddr, _ int) bool { + c++ + cp := p.Capabilities.Get(666) + if cp != nil { + t.Fatalf("EachAddrFiltered '42:101' should not contain a peer with capability %v", caps["666:101"]) + } + return true + }) + if c != 1 { + t.Fatalf("EachAddrFiltered '42:101' expected 1 peer, got %d", c) + } +} diff --git a/network/network.go b/network/network.go index 747f9003ab..a0aae05141 100644 --- a/network/network.go +++ b/network/network.go @@ -3,17 +3,76 @@ package network import ( "crypto/ecdsa" "fmt" + "io" "net" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethersphere/swarm/network/capability" ) // BzzAddr implements the PeerAddr interface type BzzAddr struct { - OAddr []byte - UAddr []byte + OAddr []byte + UAddr []byte + Capabilities *capability.Capabilities +} + +// EncodeRLP implements rlp.Encoder +func (b *BzzAddr) EncodeRLP(w io.Writer) error { + err := rlp.Encode(w, b.OAddr) + if err != nil { + return err + } + err = rlp.Encode(w, b.UAddr) + if err != nil { + return err + } + y, err := rlp.EncodeToBytes(b.Capabilities) + if err != nil { + return err + } + err = rlp.Encode(w, y) + if err != nil { + return err + } + return nil +} + +// DecodeRLP implements rlp.Decoder +func (b *BzzAddr) DecodeRLP(s *rlp.Stream) error { + var err error + + b.OAddr, err = s.Bytes() + if err != nil { + return fmt.Errorf("oaddr --- %v", err) + } + b.UAddr, err = s.Bytes() + if err != nil { + return fmt.Errorf("uaddr --- %v", err) + } + + y, err := s.Bytes() + if err != nil { + return fmt.Errorf("capsbytes --- %v", err) + } + err = rlp.DecodeBytes(y, &b.Capabilities) + if err != nil { + return fmt.Errorf("caps --- %v", err) + } + return nil +} + +// NewBzzAddr creates a new BzzAddr with the specified byte values for over- and underlayaddresses +// It will contain an empty capabilities object +func NewBzzAddr(oaddr []byte, uaddr []byte) *BzzAddr { + return &BzzAddr{ + OAddr: oaddr, + UAddr: uaddr, + Capabilities: capability.NewCapabilities(), + } } // Address implements OverlayPeer interface to be used in Overlay. @@ -42,34 +101,45 @@ func (a *BzzAddr) ID() enode.ID { // Update updates the underlay address of a peer record func (a *BzzAddr) Update(na *BzzAddr) *BzzAddr { - return &BzzAddr{a.OAddr, na.UAddr} + return &BzzAddr{a.OAddr, na.UAddr, a.Capabilities} } // String pretty prints the address func (a *BzzAddr) String() string { - return fmt.Sprintf("%x <%s>", a.OAddr, a.UAddr) + return fmt.Sprintf("%x <%s> cap:%s", a.OAddr, a.UAddr, a.Capabilities) } -// RandomAddr is a utility method generating an address from a public key -func RandomAddr() *BzzAddr { +// RandomBzzAddr is a utility method generating a private key and corresponding enode id +// It in turn calls NewBzzAddrFromEnode to generate a corresponding overlay address from enode +func RandomBzzAddr() *BzzAddr { key, err := crypto.GenerateKey() if err != nil { panic("unable to generate key") } node := enode.NewV4(&key.PublicKey, net.IP{127, 0, 0, 1}, 30303, 30303) - return NewAddr(node) + return NewBzzAddrFromEnode(node) +} + +// NewBzzAddrFromEnode creates a BzzAddr where the overlay address is the byte representation of the enode i +// It is only used for test purposes +// TODO: This method should be replaced by (optionally deterministic) generation of addresses using NewEnode and PrivateKeyToBzzKey +func NewBzzAddrFromEnode(enod *enode.Node) *BzzAddr { + return &BzzAddr{OAddr: enod.ID().Bytes(), UAddr: []byte(enod.URLv4()), Capabilities: capability.NewCapabilities()} } -// NewAddr constructs a BzzAddr from a node record. -func NewAddr(node *enode.Node) *BzzAddr { - return &BzzAddr{OAddr: node.ID().Bytes(), UAddr: []byte(node.URLv4())} +// WithCapabilities is a chained constructor method to set the capabilities array for a BzzAddr +func (b *BzzAddr) WithCapabilities(c *capability.Capabilities) *BzzAddr { + b.Capabilities = c + return b } +// PrivateKeyToBzzKey create a swarm overlay address from the given private key func PrivateKeyToBzzKey(prvKey *ecdsa.PrivateKey) []byte { pubkeyBytes := crypto.FromECDSAPub(&prvKey.PublicKey) return crypto.Keccak256Hash(pubkeyBytes).Bytes() } +// EnodeParams contains the parameters used to create new Enode Records type EnodeParams struct { PrivateKey *ecdsa.PrivateKey EnodeKey *ecdsa.PrivateKey @@ -77,6 +147,7 @@ type EnodeParams struct { Bootnode bool } +// NewEnodeRecord creates a new valid swarm node ENR record from the given parameters func NewEnodeRecord(params *EnodeParams) (*enr.Record, error) { if params.PrivateKey == nil { @@ -87,11 +158,11 @@ func NewEnodeRecord(params *EnodeParams) (*enr.Record, error) { var record enr.Record record.Set(NewENRAddrEntry(bzzkeybytes)) - record.Set(ENRLightNodeEntry(params.Lightnode)) record.Set(ENRBootNodeEntry(params.Bootnode)) return &record, nil } +// NewEnode creates a new enode object for the given parameters func NewEnode(params *EnodeParams) (*enode.Node, error) { record, err := NewEnodeRecord(params) if err != nil { diff --git a/network/network_test.go b/network/network_test.go new file mode 100644 index 0000000000..15df554c58 --- /dev/null +++ b/network/network_test.go @@ -0,0 +1,42 @@ +package network + +import ( + "bytes" + "testing" + + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethersphere/swarm/network/capability" +) + +// TestBzzAddrRLPSerialzation verifies reverisibility of RLP serialization of BzzAddr +func TestBzzAddrRLPSerialization(t *testing.T) { + caps := capability.NewCapabilities() + caps.Add(lightCapability) + addr := RandomBzzAddr().WithCapabilities(caps) + b, err := rlp.EncodeToBytes(addr) + if err != nil { + t.Fatal(err) + } + var addrRecovered BzzAddr + err = rlp.DecodeBytes(b, &addrRecovered) + if err != nil { + t.Fatal(err) + } + if !addr.Match(&addrRecovered) { + t.Fatalf("bzzaddr mismatch, expected %v, got %v", addr, addrRecovered) + } +} + +// Match returns true if the passed BzzAddr is identical to the receiver +func (b *BzzAddr) Match(bcmp *BzzAddr) bool { + if !bytes.Equal(b.OAddr, bcmp.OAddr) { + return false + } + if !bytes.Equal(b.UAddr, bcmp.UAddr) { + return false + } + if !b.Capabilities.Match(bcmp.Capabilities) { + return false + } + return true +} diff --git a/network/networkid_test.go b/network/networkid_test.go index cd60e89849..95ace13f5d 100644 --- a/network/networkid_test.go +++ b/network/networkid_test.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/simulations" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/rpc" + "github.com/ethersphere/swarm/network/capability" "github.com/ethersphere/swarm/testutil" ) @@ -198,7 +199,7 @@ func newServices() adapters.Services { } return adapters.Services{ "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { - addr := NewAddr(ctx.Config.Node()) + addr := NewBzzAddrFromEnode(ctx.Config.Node()).WithCapabilities(capability.NewCapabilities()) hp := NewHiveParams() hp.Discovery = false cnt++ diff --git a/network/protocol.go b/network/protocol.go index be8cc0d024..6721c6249f 100644 --- a/network/protocol.go +++ b/network/protocol.go @@ -56,7 +56,7 @@ var DefaultTestNetworkID = rand.Uint64() // BzzSpec is the spec of the generic swarm handshake var BzzSpec = &protocols.Spec{ Name: "bzz", - Version: 12, + Version: 13, MaxMsgSize: 10 * 1024 * 1024, Messages: []interface{}{ HandshakeMsg{}, @@ -66,7 +66,7 @@ var BzzSpec = &protocols.Spec{ // DiscoverySpec is the spec for the bzz discovery subprotocols var DiscoverySpec = &protocols.Spec{ Name: "hive", - Version: 10, + Version: 11, MaxMsgSize: 10 * 1024 * 1024, Messages: []interface{}{ peersMsg{}, @@ -125,7 +125,6 @@ type Bzz struct { handshakes map[enode.ID]*HandshakeMsg streamerSpec *protocols.Spec streamerRun func(*BzzPeer) error - capabilities *capability.Capabilities // capabilities control and state retrievalSpec *protocols.Spec retrievalRun func(*BzzPeer) error } @@ -139,13 +138,12 @@ func NewBzz(config *BzzConfig, kad *Kademlia, store state.Store, streamerSpec, r bzz := &Bzz{ Hive: NewHive(config.HiveParams, kad, store), NetworkID: config.NetworkID, - localAddr: &BzzAddr{config.OverlayAddr, config.UnderlayAddr}, + localAddr: NewBzzAddr(config.OverlayAddr, config.UnderlayAddr), handshakes: make(map[enode.ID]*HandshakeMsg), streamerRun: streamerRun, streamerSpec: streamerSpec, retrievalRun: retrievalRun, retrievalSpec: retrievalSpec, - capabilities: capability.NewCapabilities(), } if config.BootnodeMode { @@ -157,9 +155,9 @@ func NewBzz(config *BzzConfig, kad *Kademlia, store state.Store, streamerSpec, r // temporary soon-to-be-legacy light/full, as above if config.LightNode { - bzz.capabilities.Add(newLightCapability()) + bzz.localAddr.Capabilities.Add(newLightCapability()) } else { - bzz.capabilities.Add(newFullCapability()) + bzz.localAddr.Capabilities.Add(newFullCapability()) } return bzz @@ -173,8 +171,9 @@ func (b *Bzz) Stop() error { // UpdateLocalAddr updates underlayaddress of the running node func (b *Bzz) UpdateLocalAddr(byteaddr []byte) *BzzAddr { b.localAddr = b.localAddr.Update(&BzzAddr{ - UAddr: byteaddr, - OAddr: b.localAddr.OAddr, + UAddr: byteaddr, + OAddr: b.localAddr.OAddr, + Capabilities: b.localAddr.Capabilities, }) return b.localAddr @@ -265,7 +264,6 @@ func (b *Bzz) RunProtocol(spec *protocols.Spec, run func(*BzzPeer) error) func(* Peer: protocols.NewPeer(p, rw, spec), BzzAddr: handshake.peerAddr, lastActive: time.Now(), - LightNode: isLightCapability(handshake.Capabilities.Get(0)), // this is a temporary member kept until kademlia code accommodates Capabilities instead } log.Debug("peer created", "addr", handshake.peerAddr.String()) @@ -288,7 +286,6 @@ func (b *Bzz) performHandshake(p *protocols.Peer, handshake *HandshakeMsg) error return err } handshake.peerAddr = rsh.(*HandshakeMsg).Addr - handshake.Capabilities = rsh.(*HandshakeMsg).Capabilities return nil } @@ -323,11 +320,10 @@ type BzzPeer struct { *protocols.Peer // represents the connection for online peers *BzzAddr // remote address -> implements Addr interface = protocols.Peer lastActive time.Time // time is updated whenever mutexes are releasing - LightNode bool } func NewBzzPeer(p *protocols.Peer) *BzzPeer { - return &BzzPeer{Peer: p, BzzAddr: NewAddr(p.Node())} + return &BzzPeer{Peer: p, BzzAddr: NewBzzAddrFromEnode(p.Node())} } // ID returns the peer's underlay node identifier. @@ -347,10 +343,9 @@ func (p *BzzPeer) ID() enode.ID { * Capabilities: the capabilities bitvector */ type HandshakeMsg struct { - Version uint64 - NetworkID uint64 - Addr *BzzAddr - Capabilities *capability.Capabilities + Version uint64 + NetworkID uint64 + Addr *BzzAddr // peerAddr is the address received in the peer handshake peerAddr *BzzAddr @@ -362,7 +357,7 @@ type HandshakeMsg struct { // String pretty prints the handshake func (bh *HandshakeMsg) String() string { - return fmt.Sprintf("Handshake: Version: %v, NetworkID: %v, Addr: %v, peerAddr: %v, caps: %s", bh.Version, bh.NetworkID, bh.Addr, bh.peerAddr, bh.Capabilities) + return fmt.Sprintf("Handshake: Version: %v, NetworkID: %v, Addr: %v, peerAddr: %v", bh.Version, bh.NetworkID, bh.Addr, bh.peerAddr) } // Perform initiates the handshake and validates the remote handshake message @@ -375,8 +370,8 @@ func (b *Bzz) checkHandshake(hs interface{}) error { return fmt.Errorf("version mismatch %d (!= %d)", rhs.Version, BzzSpec.Version) } // temporary check for valid capability settings, legacy full/light - if !isFullCapability(rhs.Capabilities.Get(0)) && !isLightCapability(rhs.Capabilities.Get(0)) { - return fmt.Errorf("invalid capabilities setting: %s", rhs.Capabilities) + if !isFullCapability(rhs.Addr.Capabilities.Get(0)) && !isLightCapability(rhs.Addr.Capabilities.Get(0)) { + return fmt.Errorf("invalid capabilities setting: %s", rhs.Addr.Capabilities) } return nil } @@ -396,12 +391,11 @@ func (b *Bzz) GetOrCreateHandshake(peerID enode.ID) (*HandshakeMsg, bool) { handshake, found := b.handshakes[peerID] if !found { handshake = &HandshakeMsg{ - Version: uint64(BzzSpec.Version), - NetworkID: b.NetworkID, - Addr: b.localAddr, - Capabilities: b.capabilities, - init: make(chan bool, 1), - done: make(chan struct{}), + Version: uint64(BzzSpec.Version), + NetworkID: b.NetworkID, + Addr: b.localAddr, + init: make(chan bool, 1), + done: make(chan struct{}), } // when handhsake is first created for a remote peer // it is initialised with the init diff --git a/network/protocol_test.go b/network/protocol_test.go index 6e36515b52..f91e1725ca 100644 --- a/network/protocol_test.go +++ b/network/protocol_test.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethersphere/swarm/network/capability" "github.com/ethersphere/swarm/p2p/protocols" p2ptest "github.com/ethersphere/swarm/p2p/testing" @@ -36,7 +37,7 @@ import ( ) const ( - TestProtocolVersion = 12 + TestProtocolVersion = 13 ) var TestProtocolNetworkID = DefaultTestNetworkID @@ -77,11 +78,11 @@ func newBzzHandshakeMsg(version uint64, networkId uint64, addr *BzzAddr, lightNo cap = newFullCapability() } capabilities.Add(cap) + addr.Capabilities = capabilities msg := &HandshakeMsg{ - Version: version, - NetworkID: networkId, - Addr: addr, - Capabilities: capabilities, + Version: version, + NetworkID: networkId, + Addr: addr, } return msg @@ -118,7 +119,7 @@ func newBzzBaseTesterWithAddrs(prvkey *ecdsa.PrivateKey, addrs [][]byte, spec *p mu.Lock() nodeToAddr[p.ID()] = addrs[0] mu.Unlock() - bzzAddr := &BzzAddr{addrs[0], []byte(p.Node().String())} + bzzAddr := NewBzzAddr(addrs[0], []byte(p.Node().String())) addrs = addrs[1:] return srv(&BzzPeer{Peer: protocols.NewPeer(p, rw, spec), BzzAddr: bzzAddr}) } @@ -184,7 +185,6 @@ func newBzzHandshakeTester(n int, prvkey *ecdsa.PrivateKey, lightNode bool) (*bz var record enr.Record bzzkey := PrivateKeyToBzzKey(prvkey) record.Set(NewENRAddrEntry(bzzkey)) - record.Set(ENRLightNodeEntry(lightNode)) err := enode.SignV4(&record, prvkey) if err != nil { return nil, err @@ -234,6 +234,36 @@ func correctBzzHandshake(addr *BzzAddr, lightNode bool) *HandshakeMsg { return newBzzHandshakeMsg(TestProtocolVersion, TestProtocolNetworkID, addr, lightNode) } +// TestBzzHandshakeRLPSerialization verifies the reversibility of RLP serialization of HandshakeMsg +func TestBzzHandshakeRLPSerialization(t *testing.T) { + caps := capability.NewCapabilities() + caps.Add(fullCapability) + addr := RandomBzzAddr().WithCapabilities(caps) + msg := &HandshakeMsg{ + Version: 42, + NetworkID: 666, + Addr: addr, + } + b, err := rlp.EncodeToBytes(msg) + if err != nil { + t.Fatal(err) + } + var msgRecovered HandshakeMsg + err = rlp.DecodeBytes(b, &msgRecovered) + if err != nil { + t.Fatal(err) + } + if msg.Version != msgRecovered.Version { + t.Fatalf("version mismatch, expected %v, got %v", msg.Version, msgRecovered.Version) + } + if msg.NetworkID != msgRecovered.NetworkID { + t.Fatalf("networkid mismatch, expected %v, got %v", msg.NetworkID, msgRecovered.NetworkID) + } + if !msg.Addr.Match(msgRecovered.Addr) { + t.Fatalf("bzzaddr mismatch, expected %v, got %v", msg.Addr, msgRecovered.Addr) + } +} + func TestBzzHandshakeNetworkIDMismatch(t *testing.T) { lightNode := false prvkey, err := crypto.GenerateKey() @@ -249,7 +279,7 @@ func TestBzzHandshakeNetworkIDMismatch(t *testing.T) { err = s.testHandshake( correctBzzHandshake(s.addr, lightNode), - newBzzHandshakeMsg(TestProtocolVersion, 321, NewAddr(node), false), + newBzzHandshakeMsg(TestProtocolVersion, 321, NewBzzAddrFromEnode(node), false), &p2ptest.Disconnect{Peer: node.ID(), Error: fmt.Errorf("Handshake error: Message handler error: (msg code 0): network id mismatch 321 (!= %v)", TestProtocolNetworkID)}, ) @@ -273,7 +303,7 @@ func TestBzzHandshakeVersionMismatch(t *testing.T) { err = s.testHandshake( correctBzzHandshake(s.addr, lightNode), - newBzzHandshakeMsg(0, TestProtocolNetworkID, NewAddr(node), false), + newBzzHandshakeMsg(0, TestProtocolNetworkID, NewBzzAddrFromEnode(node), false), &p2ptest.Disconnect{Peer: node.ID(), Error: fmt.Errorf("Handshake error: Message handler error: (msg code 0): version mismatch 0 (!= %d)", TestProtocolVersion)}, ) @@ -296,13 +326,13 @@ func TestBzzHandshakeInvalidCapabilities(t *testing.T) { defer s.Stop() node := s.Nodes[0] - msg := newBzzHandshakeMsg(TestProtocolVersion, TestProtocolNetworkID, NewAddr(node), false) - cap := msg.Capabilities.Get(0) + msg := newBzzHandshakeMsg(TestProtocolVersion, TestProtocolNetworkID, NewBzzAddrFromEnode(node), false) + cap := msg.Addr.Capabilities.Get(0) cap.Set(14) err = s.testHandshake( correctBzzHandshake(s.addr, lightNode), msg, - &p2ptest.Disconnect{Peer: node.ID(), Error: fmt.Errorf("Handshake error: Message handler error: (msg code 0): invalid capabilities setting: %s", msg.Capabilities)}, + &p2ptest.Disconnect{Peer: node.ID(), Error: fmt.Errorf("Handshake error: Message handler error: (msg code 0): invalid capabilities setting: %s", msg.Addr.Capabilities)}, ) if err != nil { @@ -324,7 +354,7 @@ func TestBzzHandshakeSuccess(t *testing.T) { err = s.testHandshake( correctBzzHandshake(s.addr, lightNode), - newBzzHandshakeMsg(TestProtocolVersion, TestProtocolNetworkID, NewAddr(node), false), + newBzzHandshakeMsg(TestProtocolVersion, TestProtocolNetworkID, NewBzzAddrFromEnode(node), false), ) if err != nil { @@ -354,7 +384,7 @@ func TestBzzHandshakeLightNode(t *testing.T) { defer pt.Stop() node := pt.Nodes[0] - addr := NewAddr(node) + addr := NewBzzAddrFromEnode(node) err = pt.testHandshake( correctBzzHandshake(pt.addr, false), @@ -374,7 +404,7 @@ func TestBzzHandshakeLightNode(t *testing.T) { select { case <-pt.bzz.handshakes[node.ID()].done: - for _, cp := range pt.bzz.handshakes[node.ID()].Capabilities.Caps { + for _, cp := range pt.bzz.handshakes[node.ID()].peerAddr.Capabilities.Caps { if cp.String() != nodeCapability.String() { t.Fatalf("peer LightNode flag is %v, should be %v", cp.String(), nodeCapability.String()) } diff --git a/network/retrieval/retrieve.go b/network/retrieval/retrieve.go index d2d35dd7dd..9ab21ca41f 100644 --- a/network/retrieval/retrieve.go +++ b/network/retrieval/retrieve.go @@ -237,11 +237,6 @@ func (r *Retrieval) findPeer(ctx context.Context, req *storage.Request) (retPeer return true } - // skip light nodes, even though they support `bzz-retrieve` protocol - if p.LightNode { - return true - } - // do not send request back to peer who asked us. maybe merge with SkipPeer at some point if bytes.Equal(req.Origin.Bytes(), id.Bytes()) { return true diff --git a/network/retrieval/retrieve_test.go b/network/retrieval/retrieve_test.go index 75379bedbf..acde870f82 100644 --- a/network/retrieval/retrieve_test.go +++ b/network/retrieval/retrieve_test.go @@ -231,13 +231,12 @@ func setupTestDeliveryForwardingSimulation(t *testing.T) (sim *simulation.Simula func TestRequestFromPeers(t *testing.T) { dummyPeerID := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") - addr := network.RandomAddr() + addr := network.RandomBzzAddr() to := network.NewKademlia(addr.OAddr, network.NewKadParams()) protocolsPeer := protocols.NewPeer(p2p.NewPeer(dummyPeerID, "dummy", []p2p.Cap{{Name: "bzz-retrieve", Version: 1}}), nil, nil) peer := network.NewPeer(&network.BzzPeer{ - BzzAddr: network.RandomAddr(), - LightNode: false, - Peer: protocolsPeer, + BzzAddr: network.RandomBzzAddr(), + Peer: protocolsPeer, }, to) to.On(peer) @@ -255,38 +254,9 @@ func TestRequestFromPeers(t *testing.T) { } } -// 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()) - - protocolsPeer := protocols.NewPeer(p2p.NewPeer(dummyPeerID, "dummy", []p2p.Cap{{Name: "bzz-retrieve", Version: 1}}), nil, nil) - - // setting up a lightnode - peer := network.NewPeer(&network.BzzPeer{ - BzzAddr: network.RandomAddr(), - LightNode: true, - Peer: protocolsPeer, - }, to) - - to.On(peer) - - r := New(to, nil, to.BaseAddr(), nil) - req := storage.NewRequest(storage.Address(hash0[:])) - - // making a request which should return with "no peer found" - _, err := r.findPeer(context.Background(), req) - - if err != ErrNoPeerFound { - t.Fatalf("expected '%v', got %v", ErrNoPeerFound, err) - } -} - //TestHasPriceImplementation is to check that Retrieval implements protocols.Prices func TestHasPriceImplementation(t *testing.T) { - addr := network.RandomAddr() + addr := network.RandomBzzAddr() to := network.NewKademlia(addr.OAddr, network.NewKadParams()) r := New(to, nil, to.BaseAddr(), nil) @@ -311,7 +281,7 @@ func TestHasPriceImplementation(t *testing.T) { func newBzzRetrieveWithLocalstore(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { n := ctx.Config.Node() - addr := network.NewAddr(n) + addr := network.NewBzzAddrFromEnode(n) localStore, localStoreCleanup, err := newTestLocalStore(n.ID(), addr, nil) if err != nil { @@ -437,7 +407,7 @@ func nodeConfigAtPo(t *testing.T, baseaddr []byte, po int) *adapters.NodeConfig t.Fatalf("unable to create enode: %v", err) } - n := network.NewAddr(nod) + n := network.NewBzzAddrFromEnode(nod) foundPo = chunk.Proximity(baseaddr, n.Over()) } diff --git a/network/simulation/example_test.go b/network/simulation/example_test.go index f8d126552f..e97a20c505 100644 --- a/network/simulation/example_test.go +++ b/network/simulation/example_test.go @@ -36,7 +36,7 @@ func ExampleSimulation_WaitTillHealthy() { sim := simulation.NewInProc(map[string]simulation.ServiceFunc{ "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { - addr := network.NewAddr(ctx.Config.Node()) + addr := network.NewBzzAddrFromEnode(ctx.Config.Node()) hp := network.NewHiveParams() hp.Discovery = false config := &network.BzzConfig{ diff --git a/network/simulation/kademlia_test.go b/network/simulation/kademlia_test.go index 73f8e71a8d..703a92174b 100644 --- a/network/simulation/kademlia_test.go +++ b/network/simulation/kademlia_test.go @@ -128,7 +128,7 @@ func TestWaitTillHealthy(t *testing.T) { func createSimServiceMap(discovery bool) map[string]ServiceFunc { return map[string]ServiceFunc{ "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { - addr := network.NewAddr(ctx.Config.Node()) + addr := network.NewBzzAddrFromEnode(ctx.Config.Node()) hp := network.NewHiveParams() hp.Discovery = discovery config := &network.BzzConfig{ diff --git a/network/simulation/node_test.go b/network/simulation/node_test.go index 84699f1e62..b2edb2237c 100644 --- a/network/simulation/node_test.go +++ b/network/simulation/node_test.go @@ -280,7 +280,7 @@ func TestUploadSnapshot(t *testing.T) { log.Debug("Creating simulation") s := NewInProc(map[string]ServiceFunc{ "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { - addr := network.NewAddr(ctx.Config.Node()) + addr := network.NewBzzAddrFromEnode(ctx.Config.Node()) hp := network.NewHiveParams() hp.Discovery = false config := &network.BzzConfig{ diff --git a/network/simulation/simulation.go b/network/simulation/simulation.go index 09ae64a231..5cc2df6f75 100644 --- a/network/simulation/simulation.go +++ b/network/simulation/simulation.go @@ -102,8 +102,7 @@ func NewInProc(services map[string]ServiceFunc) (s *Simulation) { // NewBzzInProc is the same as NewInProc but injects bzz as a default protocol func NewBzzInProc(services map[string]ServiceFunc) (s *Simulation) { services["bzz"] = func(ctx *adapters.ServiceContext, bucket *sync.Map) (node.Service, func(), error) { - addr := network.NewAddr(ctx.Config.Node()) - + addr := network.NewBzzAddrFromEnode(ctx.Config.Node()) hp := network.NewHiveParams() hp.KeepAliveInterval = time.Duration(200) * time.Millisecond hp.Discovery = false diff --git a/network/simulations/discovery/discovery_test.go b/network/simulations/discovery/discovery_test.go index 1a8f90b163..5ce46ad286 100644 --- a/network/simulations/discovery/discovery_test.go +++ b/network/simulations/discovery/discovery_test.go @@ -491,7 +491,7 @@ func triggerChecks(trigger chan enode.ID, net *simulations.Network, id enode.ID) } func newService(ctx *adapters.ServiceContext) (node.Service, error) { - addr := network.NewAddr(ctx.Config.Node()) + addr := network.NewBzzAddrFromEnode(ctx.Config.Node()) kp := network.NewKadParams() kp.NeighbourhoodSize = testNeighbourhoodSize diff --git a/network/simulations/overlay.go b/network/simulations/overlay.go index cae543d6ad..c353a79968 100644 --- a/network/simulations/overlay.go +++ b/network/simulations/overlay.go @@ -65,7 +65,7 @@ func (s *Simulation) NewService(ctx *adapters.ServiceContext) (node.Service, err } s.mtx.Unlock() - addr := network.NewAddr(node) + addr := network.NewBzzAddrFromEnode(node) kp := network.NewKadParams() kp.NeighbourhoodSize = 2 diff --git a/network/stream/v2/common_test.go b/network/stream/v2/common_test.go index 1f57a17dec..5f844846db 100644 --- a/network/stream/v2/common_test.go +++ b/network/stream/v2/common_test.go @@ -110,7 +110,7 @@ func newSyncSimServiceFunc(o *SyncSimServiceOptions) func(ctx *adapters.ServiceC } return func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { n := ctx.Config.Node() - addr := network.NewAddr(n) + addr := network.NewBzzAddrFromEnode(n) localStore, localStoreCleanup, err := newTestLocalStore(n.ID(), addr, nil) if err != nil { diff --git a/network/stream/v2/cursors_test.go b/network/stream/v2/cursors_test.go index 6b4315d53d..23bef7ef4a 100644 --- a/network/stream/v2/cursors_test.go +++ b/network/stream/v2/cursors_test.go @@ -550,11 +550,8 @@ func TestCorrectCursorsExchangeRace(t *testing.T) { protoPeer := protocols.NewPeer(ptpPeer, rw, &protocols.Spec{}) peerAddr := pot.RandomAddressAt(pivotAddr, i) bzzPeer := &network.BzzPeer{ - Peer: protoPeer, - BzzAddr: &network.BzzAddr{ - OAddr: peerAddr.Bytes(), - UAddr: []byte(fmt.Sprintf("%x", peerAddr[:])), - }, + Peer: protoPeer, + BzzAddr: network.NewBzzAddr(peerAddr.Bytes(), []byte(fmt.Sprintf("%x", peerAddr[:]))), } peer := network.NewPeer(bzzPeer, pivotKad) pivotKad.On(peer) diff --git a/network/stream/v2/syncing_test.go b/network/stream/v2/syncing_test.go index 2cac8310b9..e18b422821 100644 --- a/network/stream/v2/syncing_test.go +++ b/network/stream/v2/syncing_test.go @@ -699,11 +699,8 @@ func TestStarNetworkSyncWithBogusNodes(t *testing.T) { protoPeer := protocols.NewPeer(ptpPeer, rw, &protocols.Spec{}) peerAddr := pot.RandomAddressAt(pivotAddr, i) bzzPeer := &network.BzzPeer{ - Peer: protoPeer, - BzzAddr: &network.BzzAddr{ - OAddr: peerAddr.Bytes(), - UAddr: []byte(fmt.Sprintf("%x", peerAddr[:])), - }, + Peer: protoPeer, + BzzAddr: network.NewBzzAddr(peerAddr.Bytes(), []byte(fmt.Sprintf("%x", peerAddr[:]))), } peer := network.NewPeer(bzzPeer, pivotKad) pivotKad.On(peer) diff --git a/pot/pot.go b/pot/pot.go index 9579f43056..b2964e09e4 100644 --- a/pot/pot.go +++ b/pot/pot.go @@ -209,6 +209,7 @@ func remove(t *Pot, val Val, pof Pof) (r *Pot, po int, found bool) { // if f(v) returns v' <> v then v' is inserted into the Pot // if (v) == v the Pot is not changed // it panics if Pof(f(v), k) show that v' and v are not key-equal +// BUG if "default" empty pot is supplied (created with NewPot(nil, 0), quieried address NOT found, then returned pot will be a nil value func Swap(t *Pot, k Val, pof Pof, f func(v Val) Val) (r *Pot, po int, found bool, change bool) { var val Val if t.pin == nil { diff --git a/pss/client/client_test.go b/pss/client/client_test.go index 62cf51b604..c9e5428a52 100644 --- a/pss/client/client_test.go +++ b/pss/client/client_test.go @@ -248,7 +248,7 @@ func newServices() adapters.Services { return ps, nil }, "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { - addr := network.NewAddr(ctx.Config.Node()) + addr := network.NewBzzAddrFromEnode(ctx.Config.Node()) hp := network.NewHiveParams() hp.Discovery = false config := &network.BzzConfig{ diff --git a/pss/client/doc.go b/pss/client/doc.go index 8dd7ca7551..62ee6d275d 100644 --- a/pss/client/doc.go +++ b/pss/client/doc.go @@ -84,7 +84,7 @@ // os.Exit(1) // } // -// addr := pot.RandomAddress() // should be a real address, of course +// addr := pot.RandomBzzAddress() // should be a real address, of course // psc.AddPssPeer(addr, spec) // // // use the protocol for something diff --git a/pss/forwarding_test.go b/pss/forwarding_test.go index d936f02259..ea56c489c4 100644 --- a/pss/forwarding_test.go +++ b/pss/forwarding_test.go @@ -338,11 +338,8 @@ func newTestDiscoveryPeer(addr pot.Address, kad *network.Kademlia) *network.Peer p := p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}) pp := protocols.NewPeer(p, rw, &protocols.Spec{}) bp := &network.BzzPeer{ - Peer: pp, - BzzAddr: &network.BzzAddr{ - OAddr: addr.Bytes(), - UAddr: []byte(fmt.Sprintf("%x", addr[:])), - }, + Peer: pp, + BzzAddr: network.NewBzzAddr(addr.Bytes(), []byte(fmt.Sprintf("%x", addr[:]))), } return network.NewPeer(bp, kad) } diff --git a/pss/notify/notify_test.go b/pss/notify/notify_test.go index 25b7f4113a..e0b6f992db 100644 --- a/pss/notify/notify_test.go +++ b/pss/notify/notify_test.go @@ -237,7 +237,7 @@ func newServices(allowRaw bool) adapters.Services { return ps, nil }, "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { - addr := network.NewAddr(ctx.Config.Node()) + addr := network.NewBzzAddrFromEnode(ctx.Config.Node()) hp := network.NewHiveParams() hp.Discovery = false config := &network.BzzConfig{ diff --git a/pss/prox_test.go b/pss/prox_test.go index 1d49f2df1e..f427559a8e 100644 --- a/pss/prox_test.go +++ b/pss/prox_test.go @@ -405,7 +405,7 @@ func newProxServices(td *testData, allowRaw bool, handlerContextFuncs map[messag // however, we need to keep track of it in the test driver as well. // if the translation in the network package changes, that can cause these tests to unpredictably fail // therefore we keep a local copy of the translation here - addr := network.NewAddr(ctx.Config.Node()) + addr := network.NewBzzAddrFromEnode(ctx.Config.Node()) bzzPrivateKey, err = simulation.BzzPrivateKeyFromConfig(ctx.Config) if err != nil { return nil, nil, err diff --git a/pss/pss_test.go b/pss/pss_test.go index 624b1f33fa..e6624a3f16 100644 --- a/pss/pss_test.go +++ b/pss/pss_test.go @@ -108,7 +108,7 @@ func TestAPITopic(t *testing.T) { // matching of address hints; whether a message could be or is for the node func TestAddressMatch(t *testing.T) { - localaddr := network.RandomAddr().Over() + localaddr := network.RandomBzzAddr().Over() copy(localaddr[:8], []byte("deadbeef")) remoteaddr := []byte("feedbeef") kadparams := network.NewKadParams() @@ -160,7 +160,7 @@ func TestAddressMatch(t *testing.T) { func TestAddressMatchProx(t *testing.T) { // recipient node address - localAddr := network.RandomAddr().Over() + localAddr := network.RandomBzzAddr().Over() localPotAddr := pot.NewAddressFromBytes(localAddr) // set up kademlia @@ -191,11 +191,8 @@ func TestAddressMatchProx(t *testing.T) { protoPeer := protocols.NewPeer(ptpPeer, rw, &protocols.Spec{}) peerAddr := pot.RandomAddressAt(localPotAddr, i) bzzPeer := &network.BzzPeer{ - Peer: protoPeer, - BzzAddr: &network.BzzAddr{ - OAddr: peerAddr.Bytes(), - UAddr: []byte(fmt.Sprintf("%x", peerAddr[:])), - }, + Peer: protoPeer, + BzzAddr: network.NewBzzAddr(peerAddr.Bytes(), []byte(fmt.Sprintf("%x", peerAddr[:]))), } peer := network.NewPeer(bzzPeer, kad) kad.On(peer) @@ -481,8 +478,8 @@ func TestKeys(t *testing.T) { // set up peer with mock address, mapped to mocked publicaddress and with mocked symkey addr := make(PssAddress, 32) - copy(addr, network.RandomAddr().Over()) - outkey := network.RandomAddr().Over() + copy(addr, network.RandomBzzAddr().Over()) + outkey := network.RandomBzzAddr().Over() topicobj := message.NewTopic([]byte("foo:42")) ps.SetPeerPublicKey(&theirprivkey.PublicKey, topicobj, addr) outkeyid, err := ps.SetSymmetricKey(outkey, topicobj, addr, false) @@ -529,7 +526,7 @@ func TestGetPublickeyEntries(t *testing.T) { ps := newTestPss(privkey, nil, nil) defer ps.Stop() - peeraddr := network.RandomAddr().Over() + peeraddr := network.RandomBzzAddr().Over() topicaddr := make(map[message.Topic]PssAddress) topicaddr[message.Topic{0x13}] = peeraddr topicaddr[message.Topic{0x2a}] = peeraddr[:16] @@ -589,12 +586,12 @@ func TestPeerCapabilityMismatch(t *testing.T) { } // initialize kad - baseaddr := network.RandomAddr() + baseaddr := network.RandomBzzAddr() kad := network.NewKademlia((baseaddr).Over(), network.NewKadParams()) rw := &p2p.MsgPipeRW{} // one peer has a mismatching version of pss - wrongpssaddr := network.RandomAddr() + wrongpssaddr := network.RandomBzzAddr() wrongpsscap := p2p.Cap{ Name: protocolName, Version: 0, @@ -602,11 +599,11 @@ func TestPeerCapabilityMismatch(t *testing.T) { nid := enode.ID{0x01} wrongpsspeer := network.NewPeer(&network.BzzPeer{ Peer: protocols.NewPeer(p2p.NewPeer(nid, common.ToHex(wrongpssaddr.Over()), []p2p.Cap{wrongpsscap}), rw, nil), - BzzAddr: &network.BzzAddr{OAddr: wrongpssaddr.Over(), UAddr: nil}, + BzzAddr: network.NewBzzAddr(wrongpssaddr.Over(), nil), }, kad) // one peer doesn't even have pss (boo!) - nopssaddr := network.RandomAddr() + nopssaddr := network.RandomBzzAddr() nopsscap := p2p.Cap{ Name: "nopss", Version: 1, @@ -614,7 +611,7 @@ func TestPeerCapabilityMismatch(t *testing.T) { nid = enode.ID{0x02} nopsspeer := network.NewPeer(&network.BzzPeer{ Peer: protocols.NewPeer(p2p.NewPeer(nid, common.ToHex(nopssaddr.Over()), []p2p.Cap{nopsscap}), rw, nil), - BzzAddr: &network.BzzAddr{OAddr: nopssaddr.Over(), UAddr: nil}, + BzzAddr: network.NewBzzAddr(nopssaddr.Over(), nil), }, kad) // add peers to kademlia and activate them @@ -647,7 +644,7 @@ func TestRawAllow(t *testing.T) { if err != nil { t.Fatal(err) } - baseAddr := network.RandomAddr() + baseAddr := network.RandomBzzAddr() kad := network.NewKademlia((baseAddr).Over(), network.NewKadParams()) ps := newTestPss(privKey, kad, nil) defer ps.Stop() @@ -892,8 +889,8 @@ func testSendSym(t *testing.T) { log.Trace("rsub", "id", rsub) defer rsub.Unsubscribe() - lrecvkey := network.RandomAddr().Over() - rrecvkey := network.RandomAddr().Over() + lrecvkey := network.RandomBzzAddr().Over() + rrecvkey := network.RandomBzzAddr().Over() var lkeyids [2]string var rkeyids [2]string @@ -1373,7 +1370,7 @@ func benchmarkSymKeySend(b *testing.B) { rand.Read(msg) topic := message.NewTopic([]byte("foo")) to := make(PssAddress, 32) - copy(to[:], network.RandomAddr().Over()) + copy(to[:], network.RandomBzzAddr().Over()) symkeyid, err := ps.GenerateSymmetricKey(topic, to, true) if err != nil { b.Fatalf("could not generate symkey: %v", err) @@ -1415,7 +1412,7 @@ func benchmarkAsymKeySend(b *testing.B) { rand.Read(msg) topic := message.NewTopic([]byte("foo")) to := make(PssAddress, 32) - copy(to[:], network.RandomAddr().Over()) + copy(to[:], network.RandomBzzAddr().Over()) ps.SetPeerPublicKey(&privkey.PublicKey, topic, to) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -1463,7 +1460,7 @@ func benchmarkSymkeyBruteforceChangeaddr(b *testing.B) { topic := message.NewTopic([]byte("foo")) for i := 0; i < int(keycount); i++ { to := make(PssAddress, 32) - copy(to[:], network.RandomAddr().Over()) + copy(to[:], network.RandomBzzAddr().Over()) keyid, err = ps.GenerateSymmetricKey(topic, to, true) if err != nil { b.Fatalf("cant generate symkey #%d: %v", i, err) @@ -1535,7 +1532,7 @@ func benchmarkSymkeyBruteforceSameaddr(b *testing.B) { defer ps.Stop() topic := message.NewTopic([]byte("foo")) for i := 0; i < int(keycount); i++ { - copy(addr[i], network.RandomAddr().Over()) + copy(addr[i], network.RandomBzzAddr().Over()) keyid, err = ps.GenerateSymmetricKey(topic, addr[i], true) if err != nil { b.Fatalf("cant generate symkey #%d: %v", i, err) @@ -1628,7 +1625,7 @@ func newServices(allowRaw bool) map[string]simulation.ServiceFunc { } return map[string]simulation.ServiceFunc{ "bzz": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - addr := network.NewAddr(ctx.Config.Node()) + addr := network.NewBzzAddrFromEnode(ctx.Config.Node()) bzzPrivateKey, err := simulation.BzzPrivateKeyFromConfig(ctx.Config) if err != nil { return nil, nil, err