Skip to content

Commit

Permalink
[api] ReadStateBucketByIndices return existing buckets (#3878)
Browse files Browse the repository at this point in the history
  • Loading branch information
envestcc committed Jun 9, 2023
1 parent 0eddba5 commit 6d5d929
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 5 deletions.
19 changes: 18 additions & 1 deletion action/protocol/staking/candidate_statereader.go
Expand Up @@ -256,6 +256,23 @@ func (c *candSR) getBucketsWithIndices(indices BucketIndices) ([]*VoteBucket, er
return buckets, nil
}

// getExistingBucketsWithIndices returns buckets with given indices, if some of bucket
// does not exist, they will be ignored and return the rest of buckets
func (c *candSR) getExistingBucketsWithIndices(indices BucketIndices) ([]*VoteBucket, error) {
buckets := make([]*VoteBucket, 0, len(indices))
for _, i := range indices {
b, err := c.getBucket(i)
if err != nil {
if errors.Is(err, state.ErrStateNotExist) {
continue
}
return buckets, err
}
buckets = append(buckets, b)
}
return buckets, nil
}

func (c *candSR) getBucketIndices(addr address.Address, prefix byte) (*BucketIndices, uint64, error) {
var (
bis BucketIndices
Expand Down Expand Up @@ -408,7 +425,7 @@ func (c *candSR) readStateBucketByIndices(ctx context.Context, req *iotexapi.Rea
if err != nil {
return &iotextypes.VoteBucketList{}, height, err
}
buckets, err := c.getBucketsWithIndices(BucketIndices(req.GetIndex()))
buckets, err := c.getExistingBucketsWithIndices(BucketIndices(req.GetIndex()))
if err != nil {
return nil, height, err
}
Expand Down
5 changes: 2 additions & 3 deletions blockindex/contractstaking/cache.go
Expand Up @@ -142,10 +142,9 @@ func (s *contractStakingCache) BucketsByIndices(indices []uint64) ([]*Bucket, er
vbs := make([]*Bucket, 0, len(indices))
for _, id := range indices {
vb, ok := s.getBucket(id)
if !ok {
return nil, errors.Wrapf(ErrBucketNotExist, "id %d", id)
if ok {
vbs = append(vbs, vb)
}
vbs = append(vbs, vb)
}
return vbs, nil
}
Expand Down
99 changes: 98 additions & 1 deletion blockindex/contractstaking/indexer_test.go
Expand Up @@ -65,6 +65,7 @@ func TestContractStakingIndexerLoadCache(t *testing.T) {

// create a stake
height := uint64(1)
startHeight := uint64(1)
handler := newContractStakingEventHandler(indexer.cache, height)
activateBucketType(r, handler, 10, 100, height)
owner := identityset.Address(0)
Expand All @@ -77,7 +78,7 @@ func TestContractStakingIndexerLoadCache(t *testing.T) {
r.NoError(indexer.Stop(context.Background()))

// load cache from db
newIndexer, err := NewContractStakingIndexer(db.NewBoltDB(cfg), _testStakingContractAddress, 0)
newIndexer, err := NewContractStakingIndexer(db.NewBoltDB(cfg), _testStakingContractAddress, startHeight)
r.NoError(err)
r.NoError(newIndexer.Start(context.Background()))

Expand All @@ -91,6 +92,7 @@ func TestContractStakingIndexerLoadCache(t *testing.T) {
newHeight, err := newIndexer.Height()
r.NoError(err)
r.Equal(height, newHeight)
r.Equal(startHeight, newIndexer.StartHeight())
r.EqualValues(1, newIndexer.TotalBucketCount())
r.NoError(newIndexer.Stop(context.Background()))
}
Expand Down Expand Up @@ -429,6 +431,101 @@ func TestContractStakingIndexerChangeBucketType(t *testing.T) {
})
}

func TestContractStakingIndexerReadBuckets(t *testing.T) {
r := require.New(t)
testDBPath, err := testutil.PathOfTempFile("staking.db")
r.NoError(err)
defer testutil.CleanupPath(testDBPath)
cfg := db.DefaultConfig
cfg.DbPath = testDBPath
kvStore := db.NewBoltDB(cfg)
indexer, err := NewContractStakingIndexer(kvStore, _testStakingContractAddress, 0)
r.NoError(err)
r.NoError(indexer.Start(context.Background()))

// init bucket type
bucketTypeData := [][2]int64{
{10, 10},
{20, 10},
{10, 100},
{20, 100},
}
height := uint64(1)
handler := newContractStakingEventHandler(indexer.cache, height)
for _, data := range bucketTypeData {
activateBucketType(r, handler, data[0], data[1], height)
}
err = indexer.commit(handler)
r.NoError(err)

// stake
stakeData := []struct {
owner, delegate int
amount, duration uint64
}{
{1, 2, 10, 10},
{1, 2, 20, 10},
{1, 2, 10, 100},
{1, 2, 20, 100},
{1, 3, 10, 100},
{1, 3, 20, 100},
}
height++
handler = newContractStakingEventHandler(indexer.cache, height)
for i, data := range stakeData {
stake(r, handler, identityset.Address(data.owner), identityset.Address(data.delegate), int64(i), int64(data.amount), int64(data.duration), height)
}
r.NoError(err)
r.NoError(indexer.commit(handler))

t.Run("Buckets", func(t *testing.T) {
buckets, err := indexer.Buckets()
r.NoError(err)
r.Len(buckets, len(stakeData))
})

t.Run("BucketsByCandidate", func(t *testing.T) {
candidateMap := make(map[int]int)
for i := range stakeData {
candidateMap[stakeData[i].delegate]++
}
for cand := range candidateMap {
buckets, err := indexer.BucketsByCandidate(identityset.Address(cand))
r.NoError(err)
r.Len(buckets, candidateMap[cand])
}
})

t.Run("BucketsByIndices", func(t *testing.T) {
indices := []uint64{0, 1, 2, 3, 4, 5, 6}
buckets, err := indexer.BucketsByIndices(indices)
r.NoError(err)
expectedLen := 0
for _, idx := range indices {
if int(idx) < len(stakeData) {
expectedLen++
}
}
r.Len(buckets, expectedLen)
})

t.Run("TotalBucketCount", func(t *testing.T) {
r.EqualValues(len(stakeData), indexer.TotalBucketCount())
})

t.Run("CandidateVotes", func(t *testing.T) {
candidateMap := make(map[int]int64)
for i := range stakeData {
candidateMap[stakeData[i].delegate] += int64(stakeData[i].amount)
}
candidates := []int{1, 2, 3}
for _, cand := range candidates {
votes := candidateMap[cand]
r.EqualValues(votes, indexer.CandidateVotes(identityset.Address(cand)).Uint64())
}
})
}

func BenchmarkIndexer_PutBlockBeforeContractHeight(b *testing.B) {
// Create a new Indexer with a contract height of 100
indexer := &Indexer{contractDeployHeight: 100}
Expand Down

0 comments on commit 6d5d929

Please sign in to comment.