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