You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

301 lines
7.8 KiB

  1. package statesync
  2. import (
  3. "testing"
  4. "github.com/stretchr/testify/require"
  5. "github.com/tendermint/tendermint/types"
  6. )
  7. func TestSnapshot_Key(t *testing.T) {
  8. testcases := map[string]struct {
  9. modify func(*snapshot)
  10. }{
  11. "new height": {func(s *snapshot) { s.Height = 9 }},
  12. "new format": {func(s *snapshot) { s.Format = 9 }},
  13. "new chunk count": {func(s *snapshot) { s.Chunks = 9 }},
  14. "new hash": {func(s *snapshot) { s.Hash = []byte{9} }},
  15. "no metadata": {func(s *snapshot) { s.Metadata = nil }},
  16. }
  17. for name, tc := range testcases {
  18. tc := tc
  19. t.Run(name, func(t *testing.T) {
  20. s := snapshot{
  21. Height: 3,
  22. Format: 1,
  23. Chunks: 7,
  24. Hash: []byte{1, 2, 3},
  25. Metadata: []byte{255},
  26. }
  27. before := s.Key()
  28. tc.modify(&s)
  29. after := s.Key()
  30. require.NotEqual(t, before, after)
  31. })
  32. }
  33. }
  34. func TestSnapshotPool_Add(t *testing.T) {
  35. peerID := types.NodeID("aa")
  36. // Adding to the pool should work
  37. pool := newSnapshotPool()
  38. added, err := pool.Add(peerID, &snapshot{
  39. Height: 1,
  40. Format: 1,
  41. Chunks: 1,
  42. Hash: []byte{1},
  43. })
  44. require.NoError(t, err)
  45. require.True(t, added)
  46. // Adding again from a different peer should return false
  47. otherNodeID := types.NodeID("bb")
  48. added, err = pool.Add(otherNodeID, &snapshot{
  49. Height: 1,
  50. Format: 1,
  51. Chunks: 1,
  52. Hash: []byte{1},
  53. })
  54. require.NoError(t, err)
  55. require.False(t, added)
  56. snapshot := pool.Best()
  57. require.NotNil(t, snapshot)
  58. }
  59. func TestSnapshotPool_GetPeer(t *testing.T) {
  60. pool := newSnapshotPool()
  61. s := &snapshot{Height: 1, Format: 1, Chunks: 1, Hash: []byte{1}}
  62. peerAID := types.NodeID("aa")
  63. peerBID := types.NodeID("bb")
  64. _, err := pool.Add(peerAID, s)
  65. require.NoError(t, err)
  66. _, err = pool.Add(peerBID, s)
  67. require.NoError(t, err)
  68. _, err = pool.Add(peerAID, &snapshot{Height: 2, Format: 1, Chunks: 1, Hash: []byte{1}})
  69. require.NoError(t, err)
  70. // GetPeer currently picks a random peer, so lets run it until we've seen both.
  71. seenA := false
  72. seenB := false
  73. for !seenA || !seenB {
  74. peer := pool.GetPeer(s)
  75. if peer == peerAID {
  76. seenA = true
  77. }
  78. if peer == peerBID {
  79. seenB = true
  80. }
  81. }
  82. // GetPeer should return empty for an unknown snapshot
  83. peer := pool.GetPeer(&snapshot{Height: 9, Format: 9})
  84. require.EqualValues(t, "", peer)
  85. }
  86. func TestSnapshotPool_GetPeers(t *testing.T) {
  87. pool := newSnapshotPool()
  88. s := &snapshot{Height: 1, Format: 1, Chunks: 1, Hash: []byte{1}}
  89. peerAID := types.NodeID("aa")
  90. peerBID := types.NodeID("bb")
  91. _, err := pool.Add(peerAID, s)
  92. require.NoError(t, err)
  93. _, err = pool.Add(peerBID, s)
  94. require.NoError(t, err)
  95. _, err = pool.Add(peerAID, &snapshot{Height: 2, Format: 1, Chunks: 1, Hash: []byte{2}})
  96. require.NoError(t, err)
  97. peers := pool.GetPeers(s)
  98. require.Len(t, peers, 2)
  99. require.Equal(t, peerAID, peers[0])
  100. require.EqualValues(t, peerBID, peers[1])
  101. }
  102. func TestSnapshotPool_Ranked_Best(t *testing.T) {
  103. pool := newSnapshotPool()
  104. // snapshots in expected order (best to worst). Highest height wins, then highest format.
  105. // Snapshots with different chunk hashes are considered different, and the most peers is
  106. // tie-breaker.
  107. expectSnapshots := []struct {
  108. snapshot *snapshot
  109. peers []types.NodeID
  110. }{
  111. {&snapshot{Height: 2, Format: 2, Chunks: 4, Hash: []byte{1, 3}}, []types.NodeID{"AA", "BB", "CC", "DD"}},
  112. {&snapshot{Height: 1, Format: 1, Chunks: 4, Hash: []byte{1, 2}}, []types.NodeID{"AA", "BB", "CC", "DD"}},
  113. {&snapshot{Height: 2, Format: 2, Chunks: 5, Hash: []byte{1, 2}}, []types.NodeID{"AA", "BB", "CC"}},
  114. {&snapshot{Height: 2, Format: 1, Chunks: 3, Hash: []byte{1, 2}}, []types.NodeID{"AA", "BB", "CC"}},
  115. {&snapshot{Height: 1, Format: 2, Chunks: 5, Hash: []byte{1, 2}}, []types.NodeID{"AA", "BB", "CC"}},
  116. }
  117. // Add snapshots in reverse order, to make sure the pool enforces some order.
  118. for i := len(expectSnapshots) - 1; i >= 0; i-- {
  119. for _, peerID := range expectSnapshots[i].peers {
  120. _, err := pool.Add(peerID, expectSnapshots[i].snapshot)
  121. require.NoError(t, err)
  122. }
  123. }
  124. // Ranked should return the snapshots in the same order
  125. ranked := pool.Ranked()
  126. require.Len(t, ranked, len(expectSnapshots))
  127. for i := range ranked {
  128. require.Equal(t, expectSnapshots[i].snapshot, ranked[i])
  129. }
  130. // Check that best snapshots are returned in expected order
  131. for i := range expectSnapshots {
  132. snapshot := expectSnapshots[i].snapshot
  133. require.Equal(t, snapshot, pool.Best())
  134. pool.Reject(snapshot)
  135. }
  136. require.Nil(t, pool.Best())
  137. }
  138. func TestSnapshotPool_Reject(t *testing.T) {
  139. pool := newSnapshotPool()
  140. peerID := types.NodeID("aa")
  141. snapshots := []*snapshot{
  142. {Height: 2, Format: 2, Chunks: 1, Hash: []byte{1, 2}},
  143. {Height: 2, Format: 1, Chunks: 1, Hash: []byte{1, 2}},
  144. {Height: 1, Format: 2, Chunks: 1, Hash: []byte{1, 2}},
  145. {Height: 1, Format: 1, Chunks: 1, Hash: []byte{1, 2}},
  146. }
  147. for _, s := range snapshots {
  148. _, err := pool.Add(peerID, s)
  149. require.NoError(t, err)
  150. }
  151. pool.Reject(snapshots[0])
  152. require.Equal(t, snapshots[1:], pool.Ranked())
  153. added, err := pool.Add(peerID, snapshots[0])
  154. require.NoError(t, err)
  155. require.False(t, added)
  156. added, err = pool.Add(peerID, &snapshot{Height: 3, Format: 3, Chunks: 1, Hash: []byte{1}})
  157. require.NoError(t, err)
  158. require.True(t, added)
  159. }
  160. func TestSnapshotPool_RejectFormat(t *testing.T) {
  161. pool := newSnapshotPool()
  162. peerID := types.NodeID("aa")
  163. snapshots := []*snapshot{
  164. {Height: 2, Format: 2, Chunks: 1, Hash: []byte{1, 2}},
  165. {Height: 2, Format: 1, Chunks: 1, Hash: []byte{1, 2}},
  166. {Height: 1, Format: 2, Chunks: 1, Hash: []byte{1, 2}},
  167. {Height: 1, Format: 1, Chunks: 1, Hash: []byte{1, 2}},
  168. }
  169. for _, s := range snapshots {
  170. _, err := pool.Add(peerID, s)
  171. require.NoError(t, err)
  172. }
  173. pool.RejectFormat(1)
  174. require.Equal(t, []*snapshot{snapshots[0], snapshots[2]}, pool.Ranked())
  175. added, err := pool.Add(peerID, &snapshot{Height: 3, Format: 1, Chunks: 1, Hash: []byte{1}})
  176. require.NoError(t, err)
  177. require.False(t, added)
  178. require.Equal(t, []*snapshot{snapshots[0], snapshots[2]}, pool.Ranked())
  179. added, err = pool.Add(peerID, &snapshot{Height: 3, Format: 3, Chunks: 1, Hash: []byte{1}})
  180. require.NoError(t, err)
  181. require.True(t, added)
  182. }
  183. func TestSnapshotPool_RejectPeer(t *testing.T) {
  184. pool := newSnapshotPool()
  185. peerAID := types.NodeID("aa")
  186. peerBID := types.NodeID("bb")
  187. s1 := &snapshot{Height: 1, Format: 1, Chunks: 1, Hash: []byte{1}}
  188. s2 := &snapshot{Height: 2, Format: 1, Chunks: 1, Hash: []byte{2}}
  189. s3 := &snapshot{Height: 3, Format: 1, Chunks: 1, Hash: []byte{2}}
  190. _, err := pool.Add(peerAID, s1)
  191. require.NoError(t, err)
  192. _, err = pool.Add(peerAID, s2)
  193. require.NoError(t, err)
  194. _, err = pool.Add(peerBID, s2)
  195. require.NoError(t, err)
  196. _, err = pool.Add(peerBID, s3)
  197. require.NoError(t, err)
  198. pool.RejectPeer(peerAID)
  199. require.Empty(t, pool.GetPeers(s1))
  200. peers2 := pool.GetPeers(s2)
  201. require.Len(t, peers2, 1)
  202. require.Equal(t, peerBID, peers2[0])
  203. peers3 := pool.GetPeers(s2)
  204. require.Len(t, peers3, 1)
  205. require.Equal(t, peerBID, peers3[0])
  206. // it should no longer be possible to add the peer back
  207. _, err = pool.Add(peerAID, s1)
  208. require.NoError(t, err)
  209. require.Empty(t, pool.GetPeers(s1))
  210. }
  211. func TestSnapshotPool_RemovePeer(t *testing.T) {
  212. pool := newSnapshotPool()
  213. peerAID := types.NodeID("aa")
  214. peerBID := types.NodeID("bb")
  215. s1 := &snapshot{Height: 1, Format: 1, Chunks: 1, Hash: []byte{1}}
  216. s2 := &snapshot{Height: 2, Format: 1, Chunks: 1, Hash: []byte{2}}
  217. _, err := pool.Add(peerAID, s1)
  218. require.NoError(t, err)
  219. _, err = pool.Add(peerAID, s2)
  220. require.NoError(t, err)
  221. _, err = pool.Add(peerBID, s1)
  222. require.NoError(t, err)
  223. pool.RemovePeer(peerAID)
  224. peers1 := pool.GetPeers(s1)
  225. require.Len(t, peers1, 1)
  226. require.Equal(t, peerBID, peers1[0])
  227. peers2 := pool.GetPeers(s2)
  228. require.Empty(t, peers2)
  229. // it should still be possible to add the peer back
  230. _, err = pool.Add(peerAID, s1)
  231. require.NoError(t, err)
  232. peers1 = pool.GetPeers(s1)
  233. require.Len(t, peers1, 2)
  234. require.Equal(t, peerAID, peers1[0])
  235. require.Equal(t, peerBID, peers1[1])
  236. }