Commit cefe893b authored by Petar Radovic's avatar Petar Radovic Committed by GitHub

Hive alternative (#22)

 hive - initial implementation
parent 8931a3ef
...@@ -45,3 +45,21 @@ func (i *inmem) Put(overlay swarm.Address, addr ma.Multiaddr) (exists bool) { ...@@ -45,3 +45,21 @@ func (i *inmem) Put(overlay swarm.Address, addr ma.Multiaddr) (exists bool) {
i.entries[overlay.String()] = peerEntry{overlay: overlay, multiaddr: addr} i.entries[overlay.String()] = peerEntry{overlay: overlay, multiaddr: addr}
return e return e
} }
func (i *inmem) Overlays() []swarm.Address {
keys := make([]swarm.Address, 0, len(i.entries))
for k := range i.entries {
keys = append(keys, swarm.MustParseHexAddress(k))
}
return keys
}
func (i *inmem) Multiaddresses() []ma.Multiaddr {
values := make([]ma.Multiaddr, 0, len(i.entries))
for _, v := range i.entries {
values = append(values, v.multiaddr)
}
return values
}
...@@ -5,11 +5,17 @@ ...@@ -5,11 +5,17 @@
package discovery package discovery
import ( import (
"github.com/ethersphere/bee/pkg/swarm" "context"
"github.com/ethersphere/bee/pkg/swarm"
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
) )
type BroadcastRecord struct {
Overlay swarm.Address
Addr ma.Multiaddr
}
type Driver interface { type Driver interface {
BroadcastPeer(addressee swarm.Address, overlay swarm.Address, addr ma.Multiaddr) error BroadcastPeers(ctx context.Context, addressee swarm.Address, peers ...BroadcastRecord) error
} }
...@@ -5,34 +5,35 @@ ...@@ -5,34 +5,35 @@
package mock package mock
import ( import (
"context"
"sync" "sync"
"github.com/ethersphere/bee/pkg/discovery"
"github.com/ethersphere/bee/pkg/swarm" "github.com/ethersphere/bee/pkg/swarm"
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
) )
type Discovery struct { type Discovery struct {
mtx sync.Mutex mtx sync.Mutex
ctr int //how many ops ctr int //how many ops
records map[string]broadcastRecord records map[string]discovery.BroadcastRecord
}
type broadcastRecord struct {
overlay swarm.Address
multiaddr ma.Multiaddr
} }
func NewDiscovery() *Discovery { func NewDiscovery() *Discovery {
return &Discovery{ return &Discovery{
records: make(map[string]broadcastRecord), records: make(map[string]discovery.BroadcastRecord),
} }
} }
func (d *Discovery) BroadcastPeer(addressee swarm.Address, overlay swarm.Address, addr ma.Multiaddr) error { func (d *Discovery) BroadcastPeers(ctx context.Context, addressee swarm.Address, peers ...discovery.BroadcastRecord) error {
for _, peer := range peers {
d.mtx.Lock() d.mtx.Lock()
defer d.mtx.Unlock()
d.ctr++ d.ctr++
d.records[addressee.String()] = broadcastRecord{overlay: overlay, multiaddr: addr} d.records[addressee.String()] = discovery.BroadcastRecord{Overlay: peer.Overlay, Addr: peer.Addr}
d.mtx.Unlock()
}
return nil return nil
} }
...@@ -49,5 +50,5 @@ func (d *Discovery) AddresseeRecord(addressee swarm.Address) (overlay swarm.Addr ...@@ -49,5 +50,5 @@ func (d *Discovery) AddresseeRecord(addressee swarm.Address) (overlay swarm.Addr
if !exists { if !exists {
return swarm.Address{}, nil return swarm.Address{}, nil
} }
return rec.overlay, rec.multiaddr return rec.Overlay, rec.Addr
} }
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package hive
var MaxBatchSize = maxBatchSize
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package hive
import (
"context"
"fmt"
"time"
"github.com/ethersphere/bee/pkg/addressbook"
"github.com/ethersphere/bee/pkg/discovery"
"github.com/ethersphere/bee/pkg/hive/pb"
"github.com/ethersphere/bee/pkg/logging"
"github.com/ethersphere/bee/pkg/p2p"
"github.com/ethersphere/bee/pkg/p2p/protobuf"
"github.com/ethersphere/bee/pkg/swarm"
ma "github.com/multiformats/go-multiaddr"
)
const (
protocolName = "hive"
protocolVersion = "1.0.0"
peersStreamName = "peers"
messageTimeout = 5 * time.Second // maximum allowed time for a message to be read or written.
maxBatchSize = 50
)
type Service struct {
streamer p2p.Streamer
addressBook addressbook.GetterPutter
logger logging.Logger
}
type Options struct {
Streamer p2p.Streamer
AddressBook addressbook.GetterPutter
Logger logging.Logger
}
func New(o Options) *Service {
return &Service{
streamer: o.Streamer,
logger: o.Logger,
addressBook: o.AddressBook,
}
}
func (s *Service) Protocol() p2p.ProtocolSpec {
return p2p.ProtocolSpec{
Name: protocolName,
Version: protocolVersion,
StreamSpecs: []p2p.StreamSpec{
{
Name: peersStreamName,
Handler: s.peersHandler,
},
},
}
}
func (s *Service) BroadcastPeers(ctx context.Context, addressee swarm.Address, peers ...discovery.BroadcastRecord) error {
max := maxBatchSize
for len(peers) > 0 {
if max > len(peers) {
max = len(peers)
}
if err := s.sendPeers(ctx, addressee, peers[:max]); err != nil {
return err
}
peers = peers[max:]
}
return nil
}
func (s *Service) sendPeers(ctx context.Context, peer swarm.Address, peers []discovery.BroadcastRecord) error {
stream, err := s.streamer.NewStream(ctx, peer, protocolName, protocolVersion, peersStreamName)
if err != nil {
return fmt.Errorf("new stream: %w", err)
}
defer stream.Close()
w, _ := protobuf.NewWriterAndReader(stream)
var peersRequest pb.Peers
for _, p := range peers {
peersRequest.Peers = append(peersRequest.Peers, &pb.BzzAddress{
Overlay: p.Overlay.Bytes(),
Underlay: p.Addr.String(),
})
}
if err := w.WriteMsg(&peersRequest); err != nil {
return fmt.Errorf("write Peers message: %w", err)
}
return stream.FullClose()
}
func (s *Service) peersHandler(peer p2p.Peer, stream p2p.Stream) error {
defer stream.Close()
_, r := protobuf.NewWriterAndReader(stream)
var peersReq pb.Peers
if err := r.ReadMsgWithTimeout(messageTimeout, &peersReq); err != nil {
return fmt.Errorf("read requestPeers message: %w", err)
}
for _, newPeer := range peersReq.Peers {
addr, err := ma.NewMultiaddr(newPeer.Underlay)
if err != nil {
s.logger.Infof("Skipping peer in response %s: %w", newPeer, err)
continue
}
// todo: this might be changed depending on where do we decide to connect peers
s.addressBook.Put(swarm.NewAddress(newPeer.Overlay), addr)
}
return nil
}
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package hive_test
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"math/rand"
"reflect"
"sort"
"strconv"
"testing"
"time"
ma "github.com/multiformats/go-multiaddr"
"github.com/ethersphere/bee/pkg/addressbook/inmem"
"github.com/ethersphere/bee/pkg/discovery"
"github.com/ethersphere/bee/pkg/hive"
"github.com/ethersphere/bee/pkg/hive/pb"
"github.com/ethersphere/bee/pkg/logging"
"github.com/ethersphere/bee/pkg/p2p/protobuf"
"github.com/ethersphere/bee/pkg/p2p/streamtest"
"github.com/ethersphere/bee/pkg/swarm"
)
type AddressExporter interface {
Overlays() []swarm.Address
Multiaddresses() []ma.Multiaddr
}
func TestBroadcastPeers(t *testing.T) {
rand.Seed(time.Now().UnixNano())
logger := logging.New(ioutil.Discard, 0)
// populate all expected and needed random resources for 2 full batches
// tests cases that uses fewer resources can use sub-slices of this data
var multiaddrs []ma.Multiaddr
var addrs []swarm.Address
var records []discovery.BroadcastRecord
var wantMsgs []pb.Peers
for i := 0; i < 2; i++ {
wantMsgs = append(wantMsgs, pb.Peers{Peers: []*pb.BzzAddress{}})
}
for i := 0; i < 2*hive.MaxBatchSize; i++ {
ma, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/" + strconv.Itoa(i))
if err != nil {
t.Fatal(err)
}
multiaddrs = append(multiaddrs, ma)
addrs = append(addrs, swarm.NewAddress(createRandomBytes()))
wantMsgs[i/hive.MaxBatchSize].Peers = append(wantMsgs[i/hive.MaxBatchSize].Peers, &pb.BzzAddress{Overlay: addrs[i].Bytes(), Underlay: multiaddrs[i].String()})
records = append(records, discovery.BroadcastRecord{Overlay: addrs[i], Addr: multiaddrs[i]})
}
testCases := map[string]struct {
addresee swarm.Address
peers []discovery.BroadcastRecord
wantMsgs []pb.Peers
wantKeys []swarm.Address
wantValues []ma.Multiaddr
}{
"OK - single record": {
addresee: swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"),
peers: []discovery.BroadcastRecord{{Overlay: addrs[0], Addr: multiaddrs[0]}},
wantMsgs: []pb.Peers{{Peers: wantMsgs[0].Peers[:1]}},
wantKeys: []swarm.Address{addrs[0]},
wantValues: []ma.Multiaddr{multiaddrs[0]},
},
"OK - single batch - multiple records": {
addresee: swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"),
peers: records[:15],
wantMsgs: []pb.Peers{{Peers: wantMsgs[0].Peers[:15]}},
wantKeys: addrs[:15],
wantValues: multiaddrs[:15],
},
"OK - single batch - max number of records": {
addresee: swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"),
peers: records[:hive.MaxBatchSize],
wantMsgs: []pb.Peers{{Peers: wantMsgs[0].Peers[:hive.MaxBatchSize]}},
wantKeys: addrs[:hive.MaxBatchSize],
wantValues: multiaddrs[:hive.MaxBatchSize],
},
"OK - multiple batches": {
addresee: swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"),
peers: records[:hive.MaxBatchSize+10],
wantMsgs: []pb.Peers{{Peers: wantMsgs[0].Peers}, {Peers: wantMsgs[1].Peers[:10]}},
wantKeys: addrs[:hive.MaxBatchSize+10],
wantValues: multiaddrs[:hive.MaxBatchSize+10],
},
"OK - multiple batches - max number of records": {
addresee: swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"),
peers: records[:2*hive.MaxBatchSize],
wantMsgs: []pb.Peers{{Peers: wantMsgs[0].Peers}, {Peers: wantMsgs[1].Peers}},
wantKeys: addrs[:2*hive.MaxBatchSize],
wantValues: multiaddrs[:2*hive.MaxBatchSize],
},
}
for _, tc := range testCases {
addressbook := inmem.New()
exporter, ok := addressbook.(AddressExporter)
if !ok {
t.Fatal("could not type assert AddressExporter")
}
// create a hive server that handles the incoming stream
server := hive.New(hive.Options{
Logger: logger,
AddressBook: addressbook,
})
// setup the stream recorder to record stream data
recorder := streamtest.New(
streamtest.WithProtocols(server.Protocol()),
)
// create a hive client that will do broadcast
client := hive.New(hive.Options{
Streamer: recorder,
Logger: logger,
})
if err := client.BroadcastPeers(context.Background(), tc.addresee, tc.peers...); err != nil {
t.Fatal(err)
}
// get a record for this stream
records, err := recorder.Records(tc.addresee, "hive", "1.0.0", "peers")
if err != nil {
t.Fatal(err)
}
if l := len(records); l != len(tc.wantMsgs) {
t.Fatalf("got %v records, want %v", l, len(tc.wantMsgs))
}
// there is a one record per batch (wantMsg)
for i, record := range records {
messages, err := readAndAssertPeersMsgs(record.In(), 1)
if err != nil {
t.Fatal(err)
}
if fmt.Sprint(messages[0]) != fmt.Sprint(tc.wantMsgs[i]) {
t.Errorf("Messages got %v, want %v", messages, tc.wantMsgs)
}
}
if !compareOverlays(exporter.Overlays(), tc.wantKeys) {
t.Errorf("Overlays got %v, want %v", exporter.Overlays(), tc.wantKeys)
}
if !compareMultiaddrses(exporter.Multiaddresses(), tc.wantValues) {
t.Errorf("Multiaddresses got %v, want %v", exporter.Multiaddresses(), tc.wantValues)
}
}
}
func compareOverlays(keys []swarm.Address, wantKeys []swarm.Address) bool {
var stringKeys []string
for _, k := range keys {
stringKeys = append(stringKeys, k.String())
}
var stringWantKeys []string
for _, k := range wantKeys {
stringWantKeys = append(stringWantKeys, k.String())
}
sort.Strings(stringKeys)
sort.Strings(stringWantKeys)
return reflect.DeepEqual(stringKeys, stringWantKeys)
}
func compareMultiaddrses(values []ma.Multiaddr, wantValues []ma.Multiaddr) bool {
var stringVal []string
for _, v := range values {
stringVal = append(stringVal, v.String())
}
var stringWantVal []string
for _, v := range wantValues {
stringWantVal = append(stringWantVal, v.String())
}
sort.Strings(stringVal)
sort.Strings(stringWantVal)
return reflect.DeepEqual(stringVal, stringWantVal)
}
func readAndAssertPeersMsgs(in []byte, expectedLen int) ([]pb.Peers, error) {
messages, err := protobuf.ReadMessages(
bytes.NewReader(in),
func() protobuf.Message {
return new(pb.Peers)
},
)
if err != nil {
return nil, err
}
if len(messages) != expectedLen {
return nil, fmt.Errorf("got %v messages, want %v", len(messages), expectedLen)
}
var peers []pb.Peers
for _, m := range messages {
peers = append(peers, *m.(*pb.Peers))
}
return peers, nil
}
func createRandomBytes() []byte {
randBytes := make([]byte, 32)
rand.Read(randBytes)
return randBytes
}
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate sh -c "protoc -I . -I \"$(go list -f '{{ .Dir }}' -m github.com/gogo/protobuf)/protobuf\" --gogofaster_out=. hive.proto"
// Package pb holds only Protocol Buffer definitions and generated code.
package pb
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: hive.proto
package pb
import (
fmt "fmt"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type Peers struct {
Peers []*BzzAddress `protobuf:"bytes,1,rep,name=peers,proto3" json:"peers,omitempty"`
}
func (m *Peers) Reset() { *m = Peers{} }
func (m *Peers) String() string { return proto.CompactTextString(m) }
func (*Peers) ProtoMessage() {}
func (*Peers) Descriptor() ([]byte, []int) {
return fileDescriptor_d635d1ead41ba02c, []int{0}
}
func (m *Peers) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *Peers) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_Peers.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *Peers) XXX_Merge(src proto.Message) {
xxx_messageInfo_Peers.Merge(m, src)
}
func (m *Peers) XXX_Size() int {
return m.Size()
}
func (m *Peers) XXX_DiscardUnknown() {
xxx_messageInfo_Peers.DiscardUnknown(m)
}
var xxx_messageInfo_Peers proto.InternalMessageInfo
func (m *Peers) GetPeers() []*BzzAddress {
if m != nil {
return m.Peers
}
return nil
}
type BzzAddress struct {
Overlay []byte `protobuf:"bytes,1,opt,name=Overlay,proto3" json:"Overlay,omitempty"`
Underlay string `protobuf:"bytes,2,opt,name=Underlay,proto3" json:"Underlay,omitempty"`
}
func (m *BzzAddress) Reset() { *m = BzzAddress{} }
func (m *BzzAddress) String() string { return proto.CompactTextString(m) }
func (*BzzAddress) ProtoMessage() {}
func (*BzzAddress) Descriptor() ([]byte, []int) {
return fileDescriptor_d635d1ead41ba02c, []int{1}
}
func (m *BzzAddress) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *BzzAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_BzzAddress.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *BzzAddress) XXX_Merge(src proto.Message) {
xxx_messageInfo_BzzAddress.Merge(m, src)
}
func (m *BzzAddress) XXX_Size() int {
return m.Size()
}
func (m *BzzAddress) XXX_DiscardUnknown() {
xxx_messageInfo_BzzAddress.DiscardUnknown(m)
}
var xxx_messageInfo_BzzAddress proto.InternalMessageInfo
func (m *BzzAddress) GetOverlay() []byte {
if m != nil {
return m.Overlay
}
return nil
}
func (m *BzzAddress) GetUnderlay() string {
if m != nil {
return m.Underlay
}
return ""
}
func init() {
proto.RegisterType((*Peers)(nil), "pb.Peers")
proto.RegisterType((*BzzAddress)(nil), "pb.BzzAddress")
}
func init() { proto.RegisterFile("hive.proto", fileDescriptor_d635d1ead41ba02c) }
var fileDescriptor_d635d1ead41ba02c = []byte{
// 156 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xca, 0xc8, 0x2c, 0x4b,
0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2a, 0x48, 0x52, 0xd2, 0xe5, 0x62, 0x0d, 0x48,
0x4d, 0x2d, 0x2a, 0x16, 0x52, 0xe1, 0x62, 0x2d, 0x00, 0x31, 0x24, 0x18, 0x15, 0x98, 0x35, 0xb8,
0x8d, 0xf8, 0xf4, 0x0a, 0x92, 0xf4, 0x9c, 0xaa, 0xaa, 0x1c, 0x53, 0x52, 0x8a, 0x52, 0x8b, 0x8b,
0x83, 0x20, 0x92, 0x4a, 0x4e, 0x5c, 0x5c, 0x08, 0x41, 0x21, 0x09, 0x2e, 0x76, 0xff, 0xb2, 0xd4,
0xa2, 0x9c, 0xc4, 0x4a, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x9e, 0x20, 0x18, 0x57, 0x48, 0x8a, 0x8b,
0x23, 0x34, 0x2f, 0x05, 0x22, 0xc5, 0xa4, 0xc0, 0xa8, 0xc1, 0x19, 0x04, 0xe7, 0x3b, 0x49, 0x9c,
0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31,
0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x12, 0x1b, 0xd8, 0x5d, 0xc6, 0x80, 0x00,
0x00, 0x00, 0xff, 0xff, 0x55, 0x1e, 0x74, 0x45, 0xa5, 0x00, 0x00, 0x00,
}
func (m *Peers) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Peers) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *Peers) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Peers) > 0 {
for iNdEx := len(m.Peers) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.Peers[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintHive(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
func (m *BzzAddress) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *BzzAddress) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *BzzAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Underlay) > 0 {
i -= len(m.Underlay)
copy(dAtA[i:], m.Underlay)
i = encodeVarintHive(dAtA, i, uint64(len(m.Underlay)))
i--
dAtA[i] = 0x12
}
if len(m.Overlay) > 0 {
i -= len(m.Overlay)
copy(dAtA[i:], m.Overlay)
i = encodeVarintHive(dAtA, i, uint64(len(m.Overlay)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintHive(dAtA []byte, offset int, v uint64) int {
offset -= sovHive(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *Peers) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if len(m.Peers) > 0 {
for _, e := range m.Peers {
l = e.Size()
n += 1 + l + sovHive(uint64(l))
}
}
return n
}
func (m *BzzAddress) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Overlay)
if l > 0 {
n += 1 + l + sovHive(uint64(l))
}
l = len(m.Underlay)
if l > 0 {
n += 1 + l + sovHive(uint64(l))
}
return n
}
func sovHive(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozHive(x uint64) (n int) {
return sovHive(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Peers) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowHive
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Peers: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Peers: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Peers", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowHive
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthHive
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthHive
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Peers = append(m.Peers, &BzzAddress{})
if err := m.Peers[len(m.Peers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipHive(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthHive
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthHive
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *BzzAddress) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowHive
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: BzzAddress: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: BzzAddress: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Overlay", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowHive
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthHive
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthHive
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Overlay = append(m.Overlay[:0], dAtA[iNdEx:postIndex]...)
if m.Overlay == nil {
m.Overlay = []byte{}
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Underlay", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowHive
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthHive
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthHive
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Underlay = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipHive(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthHive
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthHive
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipHive(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowHive
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowHive
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowHive
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthHive
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupHive
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthHive
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthHive = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowHive = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupHive = fmt.Errorf("proto: unexpected end of group")
)
syntax = "proto3";
package pb;
message Peers {
repeated BzzAddress peers = 1;
}
message BzzAddress {
bytes Overlay = 1;
string Underlay = 2;
}
...@@ -388,7 +388,7 @@ func TestConnectWithMockDiscovery(t *testing.T) { ...@@ -388,7 +388,7 @@ func TestConnectWithMockDiscovery(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if v := disc2.Broadcasts(); v != 1 { if v := disc2.Broadcasts(); v != 2 {
t.Fatalf("expected 1 peer broadcasts, got %d", v) t.Fatalf("expected 2 peer broadcasts, got %d", v)
} }
} }
...@@ -20,6 +20,7 @@ const ( ...@@ -20,6 +20,7 @@ const (
ProtocolName = "handshake" ProtocolName = "handshake"
ProtocolVersion = "1.0.0" ProtocolVersion = "1.0.0"
StreamName = "handshake" StreamName = "handshake"
messageTimeout = 5 * time.Second // maximum allowed time for a message to be read or written.
) )
// ErrNetworkIDIncompatible should be returned by handshake handlers if // ErrNetworkIDIncompatible should be returned by handshake handlers if
...@@ -30,9 +31,6 @@ var ErrNetworkIDIncompatible = errors.New("incompatible network ID") ...@@ -30,9 +31,6 @@ var ErrNetworkIDIncompatible = errors.New("incompatible network ID")
// the handshake response has been received by an already processed peer. // the handshake response has been received by an already processed peer.
var ErrHandshakeDuplicate = errors.New("duplicate handshake") var ErrHandshakeDuplicate = errors.New("duplicate handshake")
// messageTimeout is the maximal allowed time for a message to be read or written.
var messageTimeout = 5 * time.Second
// PeerFinder has the information if the peer already exists in swarm. // PeerFinder has the information if the peer already exists in swarm.
type PeerFinder interface { type PeerFinder interface {
Exists(overlay swarm.Address) (found bool) Exists(overlay swarm.Address) (found bool)
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package full package full
import ( import (
"context"
"math/rand" "math/rand"
"sync" "sync"
"time" "time"
...@@ -24,7 +25,7 @@ var _ topology.Driver = (*driver)(nil) ...@@ -24,7 +25,7 @@ var _ topology.Driver = (*driver)(nil)
// driver drives the connectivity between nodes. It is a basic implementation of a connectivity driver. // driver drives the connectivity between nodes. It is a basic implementation of a connectivity driver.
// that enabled full connectivity in the sense that: // that enabled full connectivity in the sense that:
// - Every peer which is added to the driver gets broadcasted to every other peer regardless of its address. // - Every peer which is added to the driver gets broadcasted to every other peer regardless of its address.
// - A random peer is picked when asking for a peer to retrieve an arbitrary chunk (PeerSuggester interface). // - A random peer is picked when asking for a peer to retrieve an arbitrary chunk (Peerer interface).
type driver struct { type driver struct {
mtx sync.Mutex mtx sync.Mutex
connected map[string]swarm.Address connected map[string]swarm.Address
...@@ -41,7 +42,8 @@ func New(disc discovery.Driver, addressBook addressbook.Getter) topology.Driver ...@@ -41,7 +42,8 @@ func New(disc discovery.Driver, addressBook addressbook.Getter) topology.Driver
} }
// AddPeer adds a new peer to the topology driver. // AddPeer adds a new peer to the topology driver.
// the peer would be subsequently broadcasted to all connected peers. // The peer would be subsequently broadcasted to all connected peers.
// All conneceted peers are also broadcasted to the new peer.
func (d *driver) AddPeer(overlay swarm.Address) error { func (d *driver) AddPeer(overlay swarm.Address) error {
d.mtx.Lock() d.mtx.Lock()
defer d.mtx.Unlock() defer d.mtx.Unlock()
...@@ -51,14 +53,27 @@ func (d *driver) AddPeer(overlay swarm.Address) error { ...@@ -51,14 +53,27 @@ func (d *driver) AddPeer(overlay swarm.Address) error {
return topology.ErrNotFound return topology.ErrNotFound
} }
var connectedNodes []discovery.BroadcastRecord
for _, addressee := range d.connected { for _, addressee := range d.connected {
err := d.discovery.BroadcastPeer(addressee, overlay, ma) cma, exists := d.addressBook.Get(addressee)
if !exists {
return topology.ErrNotFound
}
err := d.discovery.BroadcastPeers(context.Background(), addressee, discovery.BroadcastRecord{Overlay: overlay, Addr: ma})
if err != nil { if err != nil {
return err return err
} }
connectedNodes = append(connectedNodes, discovery.BroadcastRecord{Overlay: addressee, Addr: cma})
}
err := d.discovery.BroadcastPeers(context.Background(), overlay, connectedNodes...)
if err != nil {
return err
} }
// add peer in the end to avoid broadcast to itself // add new node to connected nodes to avoid double broadcasts
d.connected[overlay.String()] = overlay d.connected[overlay.String()] = overlay
return nil return nil
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment