github.com/codingfuture/orig-energi3@v0.8.4/swarm/pss/forwarding_test.go (about)

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