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 }