github.com/ethersphere/bee/v2@v2.2.0/pkg/hive/hive_test.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package hive_test
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"errors"
    11  	"fmt"
    12  	"strconv"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/ethereum/go-ethereum/common"
    17  	ma "github.com/multiformats/go-multiaddr"
    18  
    19  	ab "github.com/ethersphere/bee/v2/pkg/addressbook"
    20  	"github.com/ethersphere/bee/v2/pkg/bzz"
    21  	"github.com/ethersphere/bee/v2/pkg/crypto"
    22  	"github.com/ethersphere/bee/v2/pkg/hive"
    23  	"github.com/ethersphere/bee/v2/pkg/hive/pb"
    24  	"github.com/ethersphere/bee/v2/pkg/log"
    25  	"github.com/ethersphere/bee/v2/pkg/p2p/protobuf"
    26  	"github.com/ethersphere/bee/v2/pkg/p2p/streamtest"
    27  	"github.com/ethersphere/bee/v2/pkg/spinlock"
    28  	"github.com/ethersphere/bee/v2/pkg/statestore/mock"
    29  	"github.com/ethersphere/bee/v2/pkg/swarm"
    30  	"github.com/ethersphere/bee/v2/pkg/util/testutil"
    31  )
    32  
    33  var (
    34  	nonce = common.HexToHash("0x2").Bytes()
    35  	block = common.HexToHash("0x1").Bytes()
    36  )
    37  
    38  const spinTimeout = time.Second * 5
    39  
    40  func TestHandlerRateLimit(t *testing.T) {
    41  	t.Parallel()
    42  
    43  	logger := log.Noop
    44  	statestore := mock.NewStateStore()
    45  	addressbook := ab.New(statestore)
    46  	networkID := uint64(1)
    47  
    48  	addressbookclean := ab.New(mock.NewStateStore())
    49  
    50  	// new recorder for handling Ping
    51  	streamer := streamtest.New()
    52  	// create a hive server that handles the incoming stream
    53  	server := hive.New(streamer, addressbookclean, networkID, false, true, logger)
    54  	testutil.CleanupCloser(t, server)
    55  
    56  	serverAddress := swarm.RandAddress(t)
    57  
    58  	// setup the stream recorder to record stream data
    59  	serverRecorder := streamtest.New(
    60  		streamtest.WithProtocols(server.Protocol()),
    61  		streamtest.WithBaseAddr(serverAddress),
    62  	)
    63  
    64  	peers := make([]swarm.Address, hive.LimitBurst+1)
    65  	for i := range peers {
    66  
    67  		underlay, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/" + strconv.Itoa(i))
    68  		if err != nil {
    69  			t.Fatal(err)
    70  		}
    71  		pk, err := crypto.GenerateSecp256k1Key()
    72  		if err != nil {
    73  			t.Fatal(err)
    74  		}
    75  		signer := crypto.NewDefaultSigner(pk)
    76  		overlay, err := crypto.NewOverlayAddress(pk.PublicKey, networkID, block)
    77  		if err != nil {
    78  			t.Fatal(err)
    79  		}
    80  		bzzAddr, err := bzz.NewAddress(signer, underlay, overlay, networkID, nonce)
    81  		if err != nil {
    82  			t.Fatal(err)
    83  		}
    84  
    85  		err = addressbook.Put(bzzAddr.Overlay, *bzzAddr)
    86  		if err != nil {
    87  			t.Fatal(err)
    88  		}
    89  		peers[i] = bzzAddr.Overlay
    90  	}
    91  
    92  	// create a hive client that will do broadcast
    93  	client := hive.New(serverRecorder, addressbook, networkID, false, true, logger)
    94  	err := client.BroadcastPeers(context.Background(), serverAddress, peers...)
    95  	if err != nil {
    96  		t.Fatal(err)
    97  	}
    98  	testutil.CleanupCloser(t, client)
    99  
   100  	rec, err := serverRecorder.Records(serverAddress, "hive", "1.1.0", "peers")
   101  	if err != nil {
   102  		t.Fatal(err)
   103  	}
   104  
   105  	lastRec := rec[len(rec)-1]
   106  
   107  	if lastRec.Err() != nil {
   108  		t.Fatal("want nil error")
   109  	}
   110  }
   111  
   112  func TestBroadcastPeers(t *testing.T) {
   113  	t.Parallel()
   114  
   115  	logger := log.Noop
   116  	statestore := mock.NewStateStore()
   117  	addressbook := ab.New(statestore)
   118  	networkID := uint64(1)
   119  
   120  	// populate all expected and needed random resources for 2 full batches
   121  	// tests cases that uses fewer resources can use sub-slices of this data
   122  	var bzzAddresses []bzz.Address
   123  	var overlays []swarm.Address
   124  	var wantMsgs []pb.Peers
   125  
   126  	for i := 0; i < 2; i++ {
   127  		wantMsgs = append(wantMsgs, pb.Peers{Peers: []*pb.BzzAddress{}})
   128  	}
   129  
   130  	for i := 0; i < 2*hive.MaxBatchSize; i++ {
   131  		base := "/ip4/127.0.0.1/udp/"
   132  		if i == 2*hive.MaxBatchSize-1 {
   133  			base = "/ip4/1.1.1.1/udp/" // The last underlay has public address.
   134  		}
   135  		underlay, err := ma.NewMultiaddr(base + strconv.Itoa(i))
   136  		if err != nil {
   137  			t.Fatal(err)
   138  		}
   139  		pk, err := crypto.GenerateSecp256k1Key()
   140  		if err != nil {
   141  			t.Fatal(err)
   142  		}
   143  		signer := crypto.NewDefaultSigner(pk)
   144  		overlay, err := crypto.NewOverlayAddress(pk.PublicKey, networkID, block)
   145  		if err != nil {
   146  			t.Fatal(err)
   147  		}
   148  		bzzAddr, err := bzz.NewAddress(signer, underlay, overlay, networkID, nonce)
   149  		if err != nil {
   150  			t.Fatal(err)
   151  		}
   152  
   153  		bzzAddresses = append(bzzAddresses, *bzzAddr)
   154  		overlays = append(overlays, bzzAddr.Overlay)
   155  		err = addressbook.Put(bzzAddr.Overlay, *bzzAddr)
   156  		if err != nil {
   157  			t.Fatal(err)
   158  		}
   159  
   160  		wantMsgs[i/hive.MaxBatchSize].Peers = append(wantMsgs[i/hive.MaxBatchSize].Peers, &pb.BzzAddress{
   161  			Overlay:   bzzAddresses[i].Overlay.Bytes(),
   162  			Underlay:  bzzAddresses[i].Underlay.Bytes(),
   163  			Signature: bzzAddresses[i].Signature,
   164  			Nonce:     nonce,
   165  		})
   166  	}
   167  
   168  	testCases := map[string]struct {
   169  		addresee          swarm.Address
   170  		peers             []swarm.Address
   171  		wantMsgs          []pb.Peers
   172  		wantOverlays      []swarm.Address
   173  		wantBzzAddresses  []bzz.Address
   174  		allowPrivateCIDRs bool
   175  		pingErr           func(addr ma.Multiaddr) (time.Duration, error)
   176  	}{
   177  		"OK - single record": {
   178  			addresee:          swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"),
   179  			peers:             []swarm.Address{overlays[0]},
   180  			wantMsgs:          []pb.Peers{{Peers: wantMsgs[0].Peers[:1]}},
   181  			wantOverlays:      []swarm.Address{overlays[0]},
   182  			wantBzzAddresses:  []bzz.Address{bzzAddresses[0]},
   183  			allowPrivateCIDRs: true,
   184  		},
   185  		"OK - single batch - multiple records": {
   186  			addresee:          swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"),
   187  			peers:             overlays[:15],
   188  			wantMsgs:          []pb.Peers{{Peers: wantMsgs[0].Peers[:15]}},
   189  			wantOverlays:      overlays[:15],
   190  			wantBzzAddresses:  bzzAddresses[:15],
   191  			allowPrivateCIDRs: true,
   192  		},
   193  		"OK - single batch - max number of records": {
   194  			addresee:          swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"),
   195  			peers:             overlays[:hive.MaxBatchSize],
   196  			wantMsgs:          []pb.Peers{{Peers: wantMsgs[0].Peers[:hive.MaxBatchSize]}},
   197  			wantOverlays:      overlays[:hive.MaxBatchSize],
   198  			wantBzzAddresses:  bzzAddresses[:hive.MaxBatchSize],
   199  			allowPrivateCIDRs: true,
   200  		},
   201  		"OK - multiple batches": {
   202  			addresee:          swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"),
   203  			peers:             overlays[:hive.MaxBatchSize+10],
   204  			wantMsgs:          []pb.Peers{{Peers: wantMsgs[0].Peers}, {Peers: wantMsgs[1].Peers[:10]}},
   205  			wantOverlays:      overlays[:hive.MaxBatchSize+10],
   206  			wantBzzAddresses:  bzzAddresses[:hive.MaxBatchSize+10],
   207  			allowPrivateCIDRs: true,
   208  		},
   209  		"OK - multiple batches - max number of records": {
   210  			addresee:          swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"),
   211  			peers:             overlays[:2*hive.MaxBatchSize],
   212  			wantMsgs:          []pb.Peers{{Peers: wantMsgs[0].Peers}, {Peers: wantMsgs[1].Peers}},
   213  			wantOverlays:      overlays[:2*hive.MaxBatchSize],
   214  			wantBzzAddresses:  bzzAddresses[:2*hive.MaxBatchSize],
   215  			allowPrivateCIDRs: true,
   216  		},
   217  		"OK - single batch - skip ping failures": {
   218  			addresee:          swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"),
   219  			peers:             overlays[:15],
   220  			wantMsgs:          []pb.Peers{{Peers: wantMsgs[0].Peers[:15]}},
   221  			wantOverlays:      overlays[:10],
   222  			wantBzzAddresses:  bzzAddresses[:10],
   223  			allowPrivateCIDRs: true,
   224  			pingErr: func(addr ma.Multiaddr) (rtt time.Duration, err error) {
   225  				for _, v := range bzzAddresses[10:15] {
   226  					if v.Underlay.Equal(addr) {
   227  						return rtt, errors.New("ping failure")
   228  					}
   229  				}
   230  				return rtt, nil
   231  			},
   232  		},
   233  		"Ok - don't advertise private CIDRs": {
   234  			addresee:          overlays[len(overlays)-1],
   235  			peers:             overlays[:15],
   236  			wantMsgs:          []pb.Peers{{}},
   237  			wantOverlays:      nil,
   238  			wantBzzAddresses:  nil,
   239  			allowPrivateCIDRs: false,
   240  		},
   241  	}
   242  
   243  	for name, tc := range testCases {
   244  		tc := tc
   245  		t.Run(name, func(t *testing.T) {
   246  			t.Parallel()
   247  
   248  			addressbookclean := ab.New(mock.NewStateStore())
   249  
   250  			// new recorder for handling Ping
   251  			var streamer *streamtest.Recorder
   252  			if tc.pingErr != nil {
   253  				streamer = streamtest.New(streamtest.WithPingErr(tc.pingErr))
   254  			} else {
   255  				streamer = streamtest.New()
   256  			}
   257  			// create a hive server that handles the incoming stream
   258  			server := hive.New(streamer, addressbookclean, networkID, false, true, logger)
   259  			testutil.CleanupCloser(t, server)
   260  
   261  			// setup the stream recorder to record stream data
   262  			recorder := streamtest.New(
   263  				streamtest.WithProtocols(server.Protocol()),
   264  			)
   265  
   266  			// create a hive client that will do broadcast
   267  			client := hive.New(recorder, addressbook, networkID, false, tc.allowPrivateCIDRs, logger)
   268  			if err := client.BroadcastPeers(context.Background(), tc.addresee, tc.peers...); err != nil {
   269  				t.Fatal(err)
   270  			}
   271  			testutil.CleanupCloser(t, client)
   272  
   273  			// get a record for this stream
   274  			records, err := recorder.Records(tc.addresee, "hive", "1.1.0", "peers")
   275  			if err != nil {
   276  				t.Fatal(err)
   277  			}
   278  			if l := len(records); l != len(tc.wantMsgs) {
   279  				t.Fatalf("got %v records, want %v", l, len(tc.wantMsgs))
   280  			}
   281  
   282  			// there is a one record per batch (wantMsg)
   283  			for i, record := range records {
   284  				messages, err := readAndAssertPeersMsgs(record.In(), 1)
   285  				if err != nil {
   286  					t.Fatal(err)
   287  				}
   288  
   289  				if fmt.Sprint(messages[0]) != fmt.Sprint(tc.wantMsgs[i]) {
   290  					t.Errorf("Messages got %v, want %v", messages, tc.wantMsgs)
   291  				}
   292  			}
   293  
   294  			expectOverlaysEventually(t, addressbookclean, tc.wantOverlays)
   295  			expectBzzAddresessEventually(t, addressbookclean, tc.wantBzzAddresses)
   296  		})
   297  	}
   298  }
   299  
   300  func expectOverlaysEventually(t *testing.T, exporter ab.Interface, wantOverlays []swarm.Address) {
   301  	t.Helper()
   302  
   303  	var (
   304  		overlays []swarm.Address
   305  		err      error
   306  	)
   307  
   308  	err = spinlock.Wait(spinTimeout, func() bool {
   309  		overlays, err = exporter.Overlays()
   310  		if err != nil {
   311  			t.Fatal(err)
   312  		}
   313  
   314  		return len(overlays) == len(wantOverlays)
   315  	})
   316  	if err != nil {
   317  		t.Fatal("timed out waiting for overlays")
   318  	}
   319  
   320  	for _, v := range wantOverlays {
   321  		if !swarm.ContainsAddress(overlays, v) {
   322  			t.Errorf("overlay %s expected but not found", v.String())
   323  		}
   324  	}
   325  
   326  	if t.Failed() {
   327  		t.Errorf("overlays got %v, want %v", overlays, wantOverlays)
   328  	}
   329  }
   330  
   331  func expectBzzAddresessEventually(t *testing.T, exporter ab.Interface, wantBzzAddresses []bzz.Address) {
   332  	t.Helper()
   333  
   334  	var (
   335  		addresses []bzz.Address
   336  		err       error
   337  	)
   338  
   339  	err = spinlock.Wait(spinTimeout, func() bool {
   340  		addresses, err = exporter.Addresses()
   341  		if err != nil {
   342  			t.Fatal(err)
   343  		}
   344  
   345  		return len(addresses) == len(wantBzzAddresses)
   346  	})
   347  	if err != nil {
   348  		t.Fatal("timed out waiting for bzz addresses")
   349  	}
   350  
   351  	for _, v := range wantBzzAddresses {
   352  		if !bzz.ContainsAddress(addresses, &v) {
   353  			t.Errorf("address %s expected but not found", v.Overlay.String())
   354  		}
   355  	}
   356  
   357  	if t.Failed() {
   358  		t.Errorf("bzz addresses got %v, want %v", addresses, wantBzzAddresses)
   359  	}
   360  }
   361  
   362  func readAndAssertPeersMsgs(in []byte, expectedLen int) ([]pb.Peers, error) {
   363  	messages, err := protobuf.ReadMessages(
   364  		bytes.NewReader(in),
   365  		func() protobuf.Message {
   366  			return new(pb.Peers)
   367  		},
   368  	)
   369  
   370  	if err != nil {
   371  		return nil, err
   372  	}
   373  
   374  	if len(messages) != expectedLen {
   375  		return nil, fmt.Errorf("got %v messages, want %v", len(messages), expectedLen)
   376  	}
   377  
   378  	peers := make([]pb.Peers, len(messages))
   379  	for i := range messages {
   380  		peers[i] = *messages[i].(*pb.Peers)
   381  	}
   382  
   383  	return peers, nil
   384  }