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  }