| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- package pss
- import (
- "fmt"
- "math/rand"
- "testing"
- "time"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/p2p/protocols"
- "github.com/ethereum/go-ethereum/swarm/network"
- "github.com/ethereum/go-ethereum/swarm/pot"
- whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
- )
- type testCase struct {
- name string
- recipient []byte
- peers []pot.Address
- expected []int
- exclusive bool
- nFails int
- success bool
- errors string
- }
- var testCases []testCase
- // the purpose of this test is to see that pss.forward() function correctly
- // selects the peers for message forwarding, depending on the message address
- // and kademlia constellation.
- func TestForwardBasic(t *testing.T) {
- baseAddrBytes := make([]byte, 32)
- for i := 0; i < len(baseAddrBytes); i++ {
- baseAddrBytes[i] = 0xFF
- }
- var c testCase
- base := pot.NewAddressFromBytes(baseAddrBytes)
- var peerAddresses []pot.Address
- const depth = 10
- for i := 0; i <= depth; i++ {
- // add two peers for each proximity order
- a := pot.RandomAddressAt(base, i)
- peerAddresses = append(peerAddresses, a)
- a = pot.RandomAddressAt(base, i)
- peerAddresses = append(peerAddresses, a)
- }
- // skip one level, add one peer at one level deeper.
- // as a result, we will have an edge case of three peers in nearest neighbours' bin.
- peerAddresses = append(peerAddresses, pot.RandomAddressAt(base, depth+2))
- kad := network.NewKademlia(base[:], network.NewKadParams())
- ps := createPss(t, kad)
- defer ps.Stop()
- addPeers(kad, peerAddresses)
- const firstNearest = depth * 2 // shallowest peer in the nearest neighbours' bin
- nearestNeighbours := []int{firstNearest, firstNearest + 1, firstNearest + 2}
- var all []int // indices of all the peers
- for i := 0; i < len(peerAddresses); i++ {
- all = append(all, i)
- }
- for i := 0; i < len(peerAddresses); i++ {
- // send msg directly to the known peers (recipient address == peer address)
- c = testCase{
- name: fmt.Sprintf("Send direct to known, id: [%d]", i),
- recipient: peerAddresses[i][:],
- peers: peerAddresses,
- expected: []int{i},
- exclusive: false,
- }
- testCases = append(testCases, c)
- }
- for i := 0; i < firstNearest; i++ {
- // send random messages with proximity orders, corresponding to PO of each bin,
- // with one peer being closer to the recipient address
- a := pot.RandomAddressAt(peerAddresses[i], 64)
- c = testCase{
- name: fmt.Sprintf("Send random to each PO, id: [%d]", i),
- recipient: a[:],
- peers: peerAddresses,
- expected: []int{i},
- exclusive: false,
- }
- testCases = append(testCases, c)
- }
- for i := 0; i < firstNearest; i++ {
- // send random messages with proximity orders, corresponding to PO of each bin,
- // with random proximity relative to the recipient address
- po := i / 2
- a := pot.RandomAddressAt(base, po)
- c = testCase{
- name: fmt.Sprintf("Send direct to known, id: [%d]", i),
- recipient: a[:],
- peers: peerAddresses,
- expected: []int{po * 2, po*2 + 1},
- exclusive: true,
- }
- testCases = append(testCases, c)
- }
- for i := firstNearest; i < len(peerAddresses); i++ {
- // recipient address falls into the nearest neighbours' bin
- a := pot.RandomAddressAt(base, i)
- c = testCase{
- name: fmt.Sprintf("recipient address falls into the nearest neighbours' bin, id: [%d]", i),
- recipient: a[:],
- peers: peerAddresses,
- expected: nearestNeighbours,
- exclusive: false,
- }
- testCases = append(testCases, c)
- }
- // send msg with proximity order much deeper than the deepest nearest neighbour
- a2 := pot.RandomAddressAt(base, 77)
- c = testCase{
- name: "proximity order much deeper than the deepest nearest neighbour",
- recipient: a2[:],
- peers: peerAddresses,
- expected: nearestNeighbours,
- exclusive: false,
- }
- testCases = append(testCases, c)
- // test with partial addresses
- const part = 12
- for i := 0; i < firstNearest; i++ {
- // send messages with partial address falling into different proximity orders
- po := i / 2
- if i%8 != 0 {
- c = testCase{
- name: fmt.Sprintf("partial address falling into different proximity orders, id: [%d]", i),
- recipient: peerAddresses[i][:i],
- peers: peerAddresses,
- expected: []int{po * 2, po*2 + 1},
- exclusive: true,
- }
- testCases = append(testCases, c)
- }
- c = testCase{
- name: fmt.Sprintf("extended partial address falling into different proximity orders, id: [%d]", i),
- recipient: peerAddresses[i][:part],
- peers: peerAddresses,
- expected: []int{po * 2, po*2 + 1},
- exclusive: true,
- }
- testCases = append(testCases, c)
- }
- for i := firstNearest; i < len(peerAddresses); i++ {
- // partial address falls into the nearest neighbours' bin
- c = testCase{
- name: fmt.Sprintf("partial address falls into the nearest neighbours' bin, id: [%d]", i),
- recipient: peerAddresses[i][:part],
- peers: peerAddresses,
- expected: nearestNeighbours,
- exclusive: false,
- }
- testCases = append(testCases, c)
- }
- // partial address with proximity order deeper than any of the nearest neighbour
- a3 := pot.RandomAddressAt(base, part)
- c = testCase{
- name: "partial address with proximity order deeper than any of the nearest neighbour",
- recipient: a3[:part],
- peers: peerAddresses,
- expected: nearestNeighbours,
- exclusive: false,
- }
- testCases = append(testCases, c)
- // special cases where partial address matches a large group of peers
- // zero bytes of address is given, msg should be delivered to all the peers
- c = testCase{
- name: "zero bytes of address is given",
- recipient: []byte{},
- peers: peerAddresses,
- expected: all,
- exclusive: false,
- }
- testCases = append(testCases, c)
- // luminous radius of 8 bits, proximity order 8
- indexAtPo8 := 16
- c = testCase{
- name: "luminous radius of 8 bits",
- recipient: []byte{0xFF},
- peers: peerAddresses,
- expected: all[indexAtPo8:],
- exclusive: false,
- }
- testCases = append(testCases, c)
- // luminous radius of 256 bits, proximity order 8
- a4 := pot.Address{}
- a4[0] = 0xFF
- c = testCase{
- name: "luminous radius of 256 bits",
- recipient: a4[:],
- peers: peerAddresses,
- expected: []int{indexAtPo8, indexAtPo8 + 1},
- exclusive: true,
- }
- testCases = append(testCases, c)
- // check correct behaviour in case send fails
- for i := 2; i < firstNearest-3; i += 2 {
- po := i / 2
- // send random messages with proximity orders, corresponding to PO of each bin,
- // with different numbers of failed attempts.
- // msg should be received by only one of the deeper peers.
- a := pot.RandomAddressAt(base, po)
- c = testCase{
- name: fmt.Sprintf("Send direct to known, id: [%d]", i),
- recipient: a[:],
- peers: peerAddresses,
- expected: all[i+1:],
- exclusive: true,
- nFails: rand.Int()%3 + 2,
- }
- testCases = append(testCases, c)
- }
- for _, c := range testCases {
- testForwardMsg(t, ps, &c)
- }
- }
- // this function tests the forwarding of a single message. the recipient address is passed as param,
- // along with addresses of all peers, and indices of those peers which are expected to receive the message.
- func testForwardMsg(t *testing.T, ps *Pss, c *testCase) {
- recipientAddr := c.recipient
- peers := c.peers
- expected := c.expected
- exclusive := c.exclusive
- nFails := c.nFails
- tries := 0 // number of previous failed tries
- resultMap := make(map[pot.Address]int)
- defer func() { sendFunc = sendMsg }()
- sendFunc = func(_ *Pss, sp *network.Peer, _ *PssMsg) bool {
- if tries < nFails {
- tries++
- return false
- }
- a := pot.NewAddressFromBytes(sp.Address())
- resultMap[a]++
- return true
- }
- msg := newTestMsg(recipientAddr)
- ps.forward(msg)
- // check test results
- var fail bool
- precision := len(recipientAddr)
- if precision > 4 {
- precision = 4
- }
- s := fmt.Sprintf("test [%s]\nmsg address: %x..., radius: %d", c.name, recipientAddr[:precision], 8*len(recipientAddr))
- // false negatives (expected message didn't reach peer)
- if exclusive {
- var cnt int
- for _, i := range expected {
- a := peers[i]
- cnt += resultMap[a]
- resultMap[a] = 0
- }
- if cnt != 1 {
- s += fmt.Sprintf("\n%d messages received by %d peers with indices: [%v]", cnt, len(expected), expected)
- fail = true
- }
- } else {
- for _, i := range expected {
- a := peers[i]
- received := resultMap[a]
- if received != 1 {
- s += fmt.Sprintf("\npeer number %d [%x...] received %d messages", i, a[:4], received)
- fail = true
- }
- resultMap[a] = 0
- }
- }
- // false positives (unexpected message reached peer)
- for k, v := range resultMap {
- if v != 0 {
- // find the index of the false positive peer
- var j int
- for j = 0; j < len(peers); j++ {
- if peers[j] == k {
- break
- }
- }
- s += fmt.Sprintf("\npeer number %d [%x...] received %d messages", j, k[:4], v)
- fail = true
- }
- }
- if fail {
- t.Fatal(s)
- }
- }
- func addPeers(kad *network.Kademlia, addresses []pot.Address) {
- for _, a := range addresses {
- p := newTestDiscoveryPeer(a, kad)
- kad.On(p)
- }
- }
- func createPss(t *testing.T, kad *network.Kademlia) *Pss {
- privKey, err := crypto.GenerateKey()
- pssp := NewPssParams().WithPrivateKey(privKey)
- ps, err := NewPss(kad, pssp)
- if err != nil {
- t.Fatal(err.Error())
- }
- return ps
- }
- func newTestDiscoveryPeer(addr pot.Address, kad *network.Kademlia) *network.Peer {
- rw := &p2p.MsgPipeRW{}
- 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[:])),
- },
- }
- return network.NewPeer(bp, kad)
- }
- func newTestMsg(addr []byte) *PssMsg {
- msg := newPssMsg(&msgParams{})
- msg.To = addr[:]
- msg.Expire = uint32(time.Now().Add(time.Second * 60).Unix())
- msg.Payload = &whisper.Envelope{
- Topic: [4]byte{},
- Data: []byte("i have nothing to hide"),
- }
- return msg
- }
|