github.com/jincm/wesharechain@v0.0.0-20210122032815-1537409ce26a/chain/swarm/pss/forwarding_test.go (about)

     1  package pss
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/ethereum/go-ethereum/crypto"
    10  	"github.com/ethereum/go-ethereum/p2p"
    11  	"github.com/ethereum/go-ethereum/p2p/enode"
    12  	"github.com/ethereum/go-ethereum/p2p/protocols"
    13  	"github.com/ethereum/go-ethereum/swarm/network"
    14  	"github.com/ethereum/go-ethereum/swarm/pot"
    15  	whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
    16  )
    17  
    18  type testCase struct {
    19  	name      string
    20  	recipient []byte
    21  	peers     []pot.Address
    22  	expected  []int
    23  	exclusive bool
    24  	nFails    int
    25  	success   bool
    26  	errors    string
    27  }
    28  
    29  var testCases []testCase
    30  
    31  // the purpose of this test is to see that pss.forward() function correctly
    32  // selects the peers for message forwarding, depending on the message address
    33  // and kademlia constellation.
    34  func TestForwardBasic(t *testing.T) {
    35  	baseAddrBytes := make([]byte, 32)
    36  	for i := 0; i < len(baseAddrBytes); i++ {
    37  		baseAddrBytes[i] = 0xFF
    38  	}
    39  	var c testCase
    40  	base := pot.NewAddressFromBytes(baseAddrBytes)
    41  	var peerAddresses []pot.Address
    42  	const depth = 10
    43  	for i := 0; i <= depth; i++ {
    44  		// add two peers for each proximity order
    45  		a := pot.RandomAddressAt(base, i)
    46  		peerAddresses = append(peerAddresses, a)
    47  		a = pot.RandomAddressAt(base, i)
    48  		peerAddresses = append(peerAddresses, a)
    49  	}
    50  
    51  	// skip one level, add one peer at one level deeper.
    52  	// as a result, we will have an edge case of three peers in nearest neighbours' bin.
    53  	peerAddresses = append(peerAddresses, pot.RandomAddressAt(base, depth+2))
    54  
    55  	kad := network.NewKademlia(base[:], network.NewKadParams())
    56  	ps := createPss(t, kad)
    57  	defer ps.Stop()
    58  	addPeers(kad, peerAddresses)
    59  
    60  	const firstNearest = depth * 2 // shallowest peer in the nearest neighbours' bin
    61  	nearestNeighbours := []int{firstNearest, firstNearest + 1, firstNearest + 2}
    62  	var all []int // indices of all the peers
    63  	for i := 0; i < len(peerAddresses); i++ {
    64  		all = append(all, i)
    65  	}
    66  
    67  	for i := 0; i < len(peerAddresses); i++ {
    68  		// send msg directly to the known peers (recipient address == peer address)
    69  		c = testCase{
    70  			name:      fmt.Sprintf("Send direct to known, id: [%d]", i),
    71  			recipient: peerAddresses[i][:],
    72  			peers:     peerAddresses,
    73  			expected:  []int{i},
    74  			exclusive: false,
    75  		}
    76  		testCases = append(testCases, c)
    77  	}
    78  
    79  	for i := 0; i < firstNearest; i++ {
    80  		// send random messages with proximity orders, corresponding to PO of each bin,
    81  		// with one peer being closer to the recipient address
    82  		a := pot.RandomAddressAt(peerAddresses[i], 64)
    83  		c = testCase{
    84  			name:      fmt.Sprintf("Send random to each PO, id: [%d]", i),
    85  			recipient: a[:],
    86  			peers:     peerAddresses,
    87  			expected:  []int{i},
    88  			exclusive: false,
    89  		}
    90  		testCases = append(testCases, c)
    91  	}
    92  
    93  	for i := 0; i < firstNearest; i++ {
    94  		// send random messages with proximity orders, corresponding to PO of each bin,
    95  		// with random proximity relative to the recipient address
    96  		po := i / 2
    97  		a := pot.RandomAddressAt(base, po)
    98  		c = testCase{
    99  			name:      fmt.Sprintf("Send direct to known, id: [%d]", i),
   100  			recipient: a[:],
   101  			peers:     peerAddresses,
   102  			expected:  []int{po * 2, po*2 + 1},
   103  			exclusive: true,
   104  		}
   105  		testCases = append(testCases, c)
   106  	}
   107  
   108  	for i := firstNearest; i < len(peerAddresses); i++ {
   109  		// recipient address falls into the nearest neighbours' bin
   110  		a := pot.RandomAddressAt(base, i)
   111  		c = testCase{
   112  			name:      fmt.Sprintf("recipient address falls into the nearest neighbours' bin, id: [%d]", i),
   113  			recipient: a[:],
   114  			peers:     peerAddresses,
   115  			expected:  nearestNeighbours,
   116  			exclusive: false,
   117  		}
   118  		testCases = append(testCases, c)
   119  	}
   120  
   121  	// send msg with proximity order much deeper than the deepest nearest neighbour
   122  	a2 := pot.RandomAddressAt(base, 77)
   123  	c = testCase{
   124  		name:      "proximity order much deeper than the deepest nearest neighbour",
   125  		recipient: a2[:],
   126  		peers:     peerAddresses,
   127  		expected:  nearestNeighbours,
   128  		exclusive: false,
   129  	}
   130  	testCases = append(testCases, c)
   131  
   132  	// test with partial addresses
   133  	const part = 12
   134  
   135  	for i := 0; i < firstNearest; i++ {
   136  		// send messages with partial address falling into different proximity orders
   137  		po := i / 2
   138  		if i%8 != 0 {
   139  			c = testCase{
   140  				name:      fmt.Sprintf("partial address falling into different proximity orders, id: [%d]", i),
   141  				recipient: peerAddresses[i][:i],
   142  				peers:     peerAddresses,
   143  				expected:  []int{po * 2, po*2 + 1},
   144  				exclusive: true,
   145  			}
   146  			testCases = append(testCases, c)
   147  		}
   148  		c = testCase{
   149  			name:      fmt.Sprintf("extended partial address falling into different proximity orders, id: [%d]", i),
   150  			recipient: peerAddresses[i][:part],
   151  			peers:     peerAddresses,
   152  			expected:  []int{po * 2, po*2 + 1},
   153  			exclusive: true,
   154  		}
   155  		testCases = append(testCases, c)
   156  	}
   157  
   158  	for i := firstNearest; i < len(peerAddresses); i++ {
   159  		// partial address falls into the nearest neighbours' bin
   160  		c = testCase{
   161  			name:      fmt.Sprintf("partial address falls into the nearest neighbours' bin, id: [%d]", i),
   162  			recipient: peerAddresses[i][:part],
   163  			peers:     peerAddresses,
   164  			expected:  nearestNeighbours,
   165  			exclusive: false,
   166  		}
   167  		testCases = append(testCases, c)
   168  	}
   169  
   170  	// partial address with proximity order deeper than any of the nearest neighbour
   171  	a3 := pot.RandomAddressAt(base, part)
   172  	c = testCase{
   173  		name:      "partial address with proximity order deeper than any of the nearest neighbour",
   174  		recipient: a3[:part],
   175  		peers:     peerAddresses,
   176  		expected:  nearestNeighbours,
   177  		exclusive: false,
   178  	}
   179  	testCases = append(testCases, c)
   180  
   181  	// special cases where partial address matches a large group of peers
   182  
   183  	// zero bytes of address is given, msg should be delivered to all the peers
   184  	c = testCase{
   185  		name:      "zero bytes of address is given",
   186  		recipient: []byte{},
   187  		peers:     peerAddresses,
   188  		expected:  all,
   189  		exclusive: false,
   190  	}
   191  	testCases = append(testCases, c)
   192  
   193  	// luminous radius of 8 bits, proximity order 8
   194  	indexAtPo8 := 16
   195  	c = testCase{
   196  		name:      "luminous radius of 8 bits",
   197  		recipient: []byte{0xFF},
   198  		peers:     peerAddresses,
   199  		expected:  all[indexAtPo8:],
   200  		exclusive: false,
   201  	}
   202  	testCases = append(testCases, c)
   203  
   204  	// luminous radius of 256 bits, proximity order 8
   205  	a4 := pot.Address{}
   206  	a4[0] = 0xFF
   207  	c = testCase{
   208  		name:      "luminous radius of 256 bits",
   209  		recipient: a4[:],
   210  		peers:     peerAddresses,
   211  		expected:  []int{indexAtPo8, indexAtPo8 + 1},
   212  		exclusive: true,
   213  	}
   214  	testCases = append(testCases, c)
   215  
   216  	// check correct behaviour in case send fails
   217  	for i := 2; i < firstNearest-3; i += 2 {
   218  		po := i / 2
   219  		// send random messages with proximity orders, corresponding to PO of each bin,
   220  		// with different numbers of failed attempts.
   221  		// msg should be received by only one of the deeper peers.
   222  		a := pot.RandomAddressAt(base, po)
   223  		c = testCase{
   224  			name:      fmt.Sprintf("Send direct to known, id: [%d]", i),
   225  			recipient: a[:],
   226  			peers:     peerAddresses,
   227  			expected:  all[i+1:],
   228  			exclusive: true,
   229  			nFails:    rand.Int()%3 + 2,
   230  		}
   231  		testCases = append(testCases, c)
   232  	}
   233  
   234  	for _, c := range testCases {
   235  		testForwardMsg(t, ps, &c)
   236  	}
   237  }
   238  
   239  // this function tests the forwarding of a single message. the recipient address is passed as param,
   240  // along with addresses of all peers, and indices of those peers which are expected to receive the message.
   241  func testForwardMsg(t *testing.T, ps *Pss, c *testCase) {
   242  	recipientAddr := c.recipient
   243  	peers := c.peers
   244  	expected := c.expected
   245  	exclusive := c.exclusive
   246  	nFails := c.nFails
   247  	tries := 0 // number of previous failed tries
   248  
   249  	resultMap := make(map[pot.Address]int)
   250  
   251  	defer func() { sendFunc = sendMsg }()
   252  	sendFunc = func(_ *Pss, sp *network.Peer, _ *PssMsg) bool {
   253  		if tries < nFails {
   254  			tries++
   255  			return false
   256  		}
   257  		a := pot.NewAddressFromBytes(sp.Address())
   258  		resultMap[a]++
   259  		return true
   260  	}
   261  
   262  	msg := newTestMsg(recipientAddr)
   263  	ps.forward(msg)
   264  
   265  	// check test results
   266  	var fail bool
   267  	precision := len(recipientAddr)
   268  	if precision > 4 {
   269  		precision = 4
   270  	}
   271  	s := fmt.Sprintf("test [%s]\nmsg address: %x..., radius: %d", c.name, recipientAddr[:precision], 8*len(recipientAddr))
   272  
   273  	// false negatives (expected message didn't reach peer)
   274  	if exclusive {
   275  		var cnt int
   276  		for _, i := range expected {
   277  			a := peers[i]
   278  			cnt += resultMap[a]
   279  			resultMap[a] = 0
   280  		}
   281  		if cnt != 1 {
   282  			s += fmt.Sprintf("\n%d messages received by %d peers with indices: [%v]", cnt, len(expected), expected)
   283  			fail = true
   284  		}
   285  	} else {
   286  		for _, i := range expected {
   287  			a := peers[i]
   288  			received := resultMap[a]
   289  			if received != 1 {
   290  				s += fmt.Sprintf("\npeer number %d [%x...] received %d messages", i, a[:4], received)
   291  				fail = true
   292  			}
   293  			resultMap[a] = 0
   294  		}
   295  	}
   296  
   297  	// false positives (unexpected message reached peer)
   298  	for k, v := range resultMap {
   299  		if v != 0 {
   300  			// find the index of the false positive peer
   301  			var j int
   302  			for j = 0; j < len(peers); j++ {
   303  				if peers[j] == k {
   304  					break
   305  				}
   306  			}
   307  			s += fmt.Sprintf("\npeer number %d [%x...] received %d messages", j, k[:4], v)
   308  			fail = true
   309  		}
   310  	}
   311  
   312  	if fail {
   313  		t.Fatal(s)
   314  	}
   315  }
   316  
   317  func addPeers(kad *network.Kademlia, addresses []pot.Address) {
   318  	for _, a := range addresses {
   319  		p := newTestDiscoveryPeer(a, kad)
   320  		kad.On(p)
   321  	}
   322  }
   323  
   324  func createPss(t *testing.T, kad *network.Kademlia) *Pss {
   325  	privKey, err := crypto.GenerateKey()
   326  	pssp := NewPssParams().WithPrivateKey(privKey)
   327  	ps, err := NewPss(kad, pssp)
   328  	if err != nil {
   329  		t.Fatal(err.Error())
   330  	}
   331  	return ps
   332  }
   333  
   334  func newTestDiscoveryPeer(addr pot.Address, kad *network.Kademlia) *network.Peer {
   335  	rw := &p2p.MsgPipeRW{}
   336  	p := p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{})
   337  	pp := protocols.NewPeer(p, rw, &protocols.Spec{})
   338  	bp := &network.BzzPeer{
   339  		Peer: pp,
   340  		BzzAddr: &network.BzzAddr{
   341  			OAddr: addr.Bytes(),
   342  			UAddr: []byte(fmt.Sprintf("%x", addr[:])),
   343  		},
   344  	}
   345  	return network.NewPeer(bp, kad)
   346  }
   347  
   348  func newTestMsg(addr []byte) *PssMsg {
   349  	msg := newPssMsg(&msgParams{})
   350  	msg.To = addr[:]
   351  	msg.Expire = uint32(time.Now().Add(time.Second * 60).Unix())
   352  	msg.Payload = &whisper.Envelope{
   353  		Topic: [4]byte{},
   354  		Data:  []byte("i have nothing to hide"),
   355  	}
   356  	return msg
   357  }