github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/staking/candidate_buckets_indexer_test.go (about) 1 package staking 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/iotexproject/iotex-proto/golang/iotextypes" 8 "github.com/stretchr/testify/require" 9 "google.golang.org/protobuf/proto" 10 11 "github.com/iotexproject/iotex-core/db" 12 "github.com/iotexproject/iotex-core/testutil" 13 ) 14 15 func TestCandidatesBucketsIndexer_PutGetCandidates(t *testing.T) { 16 require := require.New(t) 17 18 testPath, err := testutil.PathOfTempFile("test-candidate") 19 require.NoError(err) 20 defer func() { 21 testutil.CleanupPath(testPath) 22 }() 23 24 cfg := db.DefaultConfig 25 cfg.DbPath = testPath 26 store := db.NewBoltDB(cfg) 27 cbi, err := NewStakingCandidatesBucketsIndexer(store) 28 require.NoError(err) 29 ctx := context.Background() 30 require.NoError(cbi.Start(ctx)) 31 defer func() { 32 require.NoError(cbi.Stop(ctx)) 33 }() 34 35 // nothing in db, return empty list 36 r, height, err := cbi.GetCandidates(1, 0, 1) 37 require.NoError(err) 38 require.EqualValues(0, height) 39 require.Zero(len(r.Candidates)) 40 41 cand := []*iotextypes.CandidateV2{ 42 { 43 OwnerAddress: "owner1", 44 Name: "abc", 45 SelfStakeBucketIdx: 123, 46 }, 47 } 48 cand2 := &iotextypes.CandidateListV2{ 49 Candidates: cand, 50 } 51 cand3 := &iotextypes.CandidateListV2{ 52 Candidates: append(cand, &iotextypes.CandidateV2{ 53 OwnerAddress: "owner2", 54 Name: "xyz", 55 SelfStakeBucketIdx: 456, 56 }), 57 } 58 59 tests := []struct { 60 height uint64 61 candidates *iotextypes.CandidateListV2 62 }{ 63 {0, nil}, 64 {1, &iotextypes.CandidateListV2{}}, 65 {2, cand2}, 66 {3, cand3}, 67 {4, cand3}, // same as block 3 68 {5, cand3}, // same as block 3 69 {6, cand2}, // same as block 2 70 } 71 tests2 := []struct { 72 offset, limit uint32 73 }{ 74 {0, 1}, 75 {0, 2}, 76 {1, 5}, 77 {1234, 5}, 78 } 79 80 for _, v := range tests { 81 require.NoError(cbi.PutCandidates(v.height, v.candidates)) 82 83 for _, v2 := range tests2 { 84 r, b, err := cbi.GetCandidates(v.height, v2.offset, v2.limit) 85 require.NoError(err) 86 require.Equal(b, v.height) 87 if tests[v.height].candidates == nil { 88 continue 89 } 90 expectLen := uint32(len(tests[v.height].candidates.Candidates)) 91 if expectLen == 0 || v2.offset >= expectLen { 92 require.Zero(len(r.Candidates)) 93 continue 94 } 95 end := v2.offset + v2.limit 96 if end > expectLen { 97 end = expectLen 98 } 99 // check the returned list 100 expect := tests[v.height].candidates.Candidates[v2.offset:end] 101 for i, v := range expect { 102 actual := r.Candidates[i] 103 require.Equal(v.OwnerAddress, actual.OwnerAddress) 104 require.Equal(v.Name, actual.Name) 105 require.Equal(v.SelfStakeBucketIdx, actual.SelfStakeBucketIdx) 106 } 107 } 108 } 109 110 // test height > latest height 111 require.EqualValues(6, cbi.latestCandidatesHeight) 112 r, height, err = cbi.GetCandidates(7, 0, 1) 113 require.NoError(err) 114 require.EqualValues(6, height) 115 require.Equal(1, len(r.Candidates)) 116 expect := tests[6].candidates.Candidates[0] 117 actual := r.Candidates[0] 118 require.Equal(expect.OwnerAddress, actual.OwnerAddress) 119 require.Equal(expect.Name, actual.Name) 120 require.Equal(expect.SelfStakeBucketIdx, actual.SelfStakeBucketIdx) 121 122 // test with a key larger than any existing key 123 height = 8810200527999860736 124 candMax := &iotextypes.CandidateListV2{ 125 Candidates: append(cand, &iotextypes.CandidateV2{ 126 OwnerAddress: "ownermax", 127 Name: "alphabeta", 128 SelfStakeBucketIdx: 789, 129 }), 130 } 131 require.NoError(cbi.PutCandidates(height, candMax)) 132 lcHash := cbi.latestCandidatesHash 133 r, _, err = cbi.GetCandidates(height, 0, 4) 134 require.NoError(err) 135 c, err := getFromIndexer(store, StakingCandidatesNamespace, height+1) 136 require.NoError(err) 137 a, err := proto.Marshal(r) 138 require.NoError(err) 139 require.Equal(a, c) 140 require.NoError(cbi.Stop(ctx)) 141 142 // reopen db to read latest height and hash 143 require.NoError(cbi.Start(ctx)) 144 require.Equal(height, cbi.latestCandidatesHeight) 145 require.Equal(lcHash, cbi.latestCandidatesHash) 146 } 147 148 func TestCandidatesBucketsIndexer_PutGetBuckets(t *testing.T) { 149 require := require.New(t) 150 151 testPath, err := testutil.PathOfTempFile("test-bucket") 152 require.NoError(err) 153 defer testutil.CleanupPath(testPath) 154 155 cfg := db.DefaultConfig 156 cfg.DbPath = testPath 157 store := db.NewBoltDB(cfg) 158 cbi, err := NewStakingCandidatesBucketsIndexer(store) 159 require.NoError(err) 160 ctx := context.Background() 161 require.NoError(cbi.Start(ctx)) 162 defer func() { 163 require.NoError(cbi.Stop(ctx)) 164 }() 165 166 // nothing in db, return empty list 167 r, height, err := cbi.GetBuckets(1, 0, 1) 168 require.NoError(err) 169 require.EqualValues(0, height) 170 require.Zero(len(r.Buckets)) 171 172 bucket := []*iotextypes.VoteBucket{ 173 { 174 Index: uint64(1234), 175 AutoStake: true, 176 Owner: "abc", 177 }, 178 } 179 vote2 := &iotextypes.VoteBucketList{ 180 Buckets: bucket, 181 } 182 vote4 := &iotextypes.VoteBucketList{ 183 Buckets: append(bucket, &iotextypes.VoteBucket{ 184 Index: uint64(5678), 185 AutoStake: false, 186 Owner: "xyz", 187 }), 188 } 189 190 tests := []struct { 191 height uint64 192 buckets *iotextypes.VoteBucketList 193 }{ 194 {0, nil}, 195 {1, &iotextypes.VoteBucketList{}}, 196 {2, vote2}, 197 {3, vote2}, // same as block 2 198 {4, vote4}, 199 {5, vote4}, // same as block 4 200 {6, vote2}, // same as block 2 201 } 202 tests2 := []struct { 203 offset, limit uint32 204 }{ 205 {0, 1}, 206 {0, 2}, 207 {1, 5}, 208 {1234, 5}, 209 } 210 211 for _, v := range tests { 212 require.NoError(cbi.PutBuckets(v.height, v.buckets)) 213 214 for _, v2 := range tests2 { 215 r, b, err := cbi.GetBuckets(v.height, v2.offset, v2.limit) 216 require.NoError(err) 217 require.Equal(b, v.height) 218 if tests[v.height].buckets == nil { 219 continue 220 } 221 expectLen := uint32(len(tests[v.height].buckets.Buckets)) 222 if expectLen == 0 || v2.offset >= expectLen { 223 require.Zero(len(r.Buckets)) 224 continue 225 } 226 end := v2.offset + v2.limit 227 if end > expectLen { 228 end = expectLen 229 } 230 // check the returned list 231 expect := tests[v.height].buckets.Buckets[v2.offset:end] 232 for i, v := range expect { 233 actual := r.Buckets[i] 234 require.Equal(v.Index, actual.Index) 235 require.Equal(v.AutoStake, actual.AutoStake) 236 require.Equal(v.Owner, actual.Owner) 237 } 238 } 239 } 240 241 // test height > latest height 242 require.EqualValues(6, cbi.latestBucketsHeight) 243 r, b, err := cbi.GetBuckets(7, 0, 1) 244 require.NoError(err) 245 require.EqualValues(6, b) 246 require.Equal(1, len(r.Buckets)) 247 expect := tests[6].buckets.Buckets[0] 248 actual := r.Buckets[0] 249 require.Equal(expect.Index, actual.Index) 250 require.Equal(expect.AutoStake, actual.AutoStake) 251 require.Equal(expect.Owner, actual.Owner) 252 253 // test with a key larger than any existing key 254 height = 8810200527999860736 255 voteMax := &iotextypes.VoteBucketList{ 256 Buckets: append(bucket, &iotextypes.VoteBucket{ 257 Index: uint64(1357), 258 AutoStake: false, 259 Owner: "ownermax", 260 }), 261 } 262 require.NoError(cbi.PutBuckets(height, voteMax)) 263 lbHash := cbi.latestBucketsHash 264 r, _, err = cbi.GetBuckets(height, 0, 4) 265 require.NoError(err) 266 c, err := getFromIndexer(store, StakingBucketsNamespace, height+1) 267 require.NoError(err) 268 a, err := proto.Marshal(r) 269 require.NoError(err) 270 require.Equal(a, c) 271 require.NoError(cbi.Stop(ctx)) 272 273 // reopen db to read latest height and hash 274 require.NoError(cbi.Start(ctx)) 275 require.Equal(height, cbi.latestBucketsHeight) 276 require.Equal(lbHash, cbi.latestBucketsHash) 277 }