forwarding_test.go 9.8 KB

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