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 }