Skip to content

Commit

Permalink
Merge d1fc3ab into 66edd61
Browse files Browse the repository at this point in the history
  • Loading branch information
envestcc authored Aug 27, 2023
2 parents 66edd61 + d1fc3ab commit 9165501
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 44 deletions.
28 changes: 28 additions & 0 deletions blockindex/contractstaking/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,36 +81,57 @@ func (s *Indexer) StartHeight() uint64 {

// CandidateVotes returns the candidate votes
func (s *Indexer) CandidateVotes(candidate address.Address, height uint64) (*big.Int, error) {
if s.isIgnored(height) {
return big.NewInt(0), nil
}
return s.cache.CandidateVotes(candidate, height)
}

// Buckets returns the buckets
func (s *Indexer) Buckets(height uint64) ([]*Bucket, error) {
if s.isIgnored(height) {
return []*Bucket{}, nil
}
return s.cache.Buckets(height)
}

// Bucket returns the bucket
func (s *Indexer) Bucket(id uint64, height uint64) (*Bucket, bool, error) {
if s.isIgnored(height) {
return nil, false, nil
}
return s.cache.Bucket(id, height)
}

// BucketsByIndices returns the buckets by indices
func (s *Indexer) BucketsByIndices(indices []uint64, height uint64) ([]*Bucket, error) {
if s.isIgnored(height) {
return []*Bucket{}, nil
}
return s.cache.BucketsByIndices(indices, height)
}

// BucketsByCandidate returns the buckets by candidate
func (s *Indexer) BucketsByCandidate(candidate address.Address, height uint64) ([]*Bucket, error) {
if s.isIgnored(height) {
return []*Bucket{}, nil
}
return s.cache.BucketsByCandidate(candidate, height)
}

// TotalBucketCount returns the total bucket count including active and burnt buckets
func (s *Indexer) TotalBucketCount(height uint64) (uint64, error) {
if s.isIgnored(height) {
return 0, nil
}
return s.cache.TotalBucketCount(height)
}

// BucketTypes returns the active bucket types
func (s *Indexer) BucketTypes(height uint64) ([]*BucketType, error) {
if s.isIgnored(height) {
return []*BucketType{}, nil
}
btMap, err := s.cache.ActiveBucketTypes(height)
if err != nil {
return nil, err
Expand Down Expand Up @@ -185,3 +206,10 @@ func (s *Indexer) reloadCache() error {
func (s *Indexer) loadFromDB() error {
return s.cache.LoadFromDB(s.kvstore)
}

// isIgnored returns true if before cotractDeployHeight.
// it aims to be compatible with blocks between feature hard-fork and contract deployed
// read interface should return empty result instead of invalid height error if it returns true
func (s *Indexer) isIgnored(height uint64) bool {
return height < s.contractDeployHeight
}
76 changes: 57 additions & 19 deletions blockindex/contractstaking/indexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package contractstaking
import (
"context"
"math/big"
"strconv"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -916,29 +917,66 @@ func TestContractStakingIndexerVotes(t *testing.T) {
r.NoError(err)
r.Len(bts, 6)
})
}

t.Run("heightRestriction", func(t *testing.T) {
cases := []struct {
height uint64
valid bool
}{
{0, true},
{height - 1, true},
{height, true},
{height + 1, false},
}
for i := range cases {
h := cases[i].height
if cases[i].valid {
func TestIndexer_ReadHeightRestriction(t *testing.T) {
r := require.New(t)

cases := []struct {
startHeight uint64
height uint64
readHeight uint64
valid bool
}{
{0, 0, 0, true},
{0, 0, 1, false},
{0, 2, 0, true},
{0, 2, 1, true},
{0, 2, 2, true},
{0, 2, 3, false},
{10, 0, 0, true},
{10, 0, 1, true},
{10, 0, 9, true},
{10, 0, 10, false},
{10, 0, 11, false},
{10, 10, 0, true},
{10, 10, 1, true},
{10, 10, 9, true},
{10, 10, 10, true},
{10, 10, 11, false},
}

for idx, c := range cases {
name := strconv.FormatInt(int64(idx), 10)
t.Run(name, func(t *testing.T) {
// Create a new Indexer
height := c.height
startHeight := c.startHeight
cfg := config.Default.DB
dbPath, err := testutil.PathOfTempFile("db")
r.NoError(err)
cfg.DbPath = dbPath
indexer, err := NewContractStakingIndexer(db.NewBoltDB(cfg), identityset.Address(1).String(), startHeight)
r.NoError(err)
r.NoError(indexer.Start(context.Background()))
defer func() {
r.NoError(indexer.Stop(context.Background()))
testutil.CleanupPath(dbPath)
}()
indexer.cache.putHeight(height)
// check read api
h := c.readHeight
delegate := identityset.Address(1)
if c.valid {
_, err = indexer.Buckets(h)
r.NoError(err)
_, err = indexer.BucketTypes(h)
r.NoError(err)
_, err = indexer.BucketsByCandidate(delegate1, h)
_, err = indexer.BucketsByCandidate(delegate, h)
r.NoError(err)
_, err = indexer.BucketsByIndices([]uint64{1, 2, 3, 4, 5, 8}, h)
r.NoError(err)
_, err = indexer.CandidateVotes(delegate1, h)
_, err = indexer.CandidateVotes(delegate, h)
r.NoError(err)
_, _, err = indexer.Bucket(1, h)
r.NoError(err)
Expand All @@ -949,19 +987,19 @@ func TestContractStakingIndexerVotes(t *testing.T) {
r.ErrorIs(err, ErrInvalidHeight)
_, err = indexer.BucketTypes(h)
r.ErrorIs(err, ErrInvalidHeight)
_, err = indexer.BucketsByCandidate(delegate1, h)
_, err = indexer.BucketsByCandidate(delegate, h)
r.ErrorIs(err, ErrInvalidHeight)
_, err = indexer.BucketsByIndices([]uint64{1, 2, 3, 4, 5, 8}, h)
r.ErrorIs(err, ErrInvalidHeight)
_, err = indexer.CandidateVotes(delegate1, h)
_, err = indexer.CandidateVotes(delegate, h)
r.ErrorIs(err, ErrInvalidHeight)
_, _, err = indexer.Bucket(1, h)
r.ErrorIs(err, ErrInvalidHeight)
_, err = indexer.TotalBucketCount(h)
r.ErrorIs(err, ErrInvalidHeight)
}
}
})
})
}
}

func TestIndexer_PutBlock(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions blockindex/sgd_indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,10 @@ func (sgd *sgdRegistry) validateQueryHeight(height uint64) error {
if height == 0 {
return nil
}
// Compatible with blocks between feature hard-fork and contract deployed
if height < sgd.startHeight {
return nil
}
tipHeight, err := sgd.height()
if err != nil {
return err
Expand Down
111 changes: 86 additions & 25 deletions blockindex/sgd_indexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/hex"
"math/big"
"strconv"
"sync/atomic"
"testing"

Expand All @@ -15,6 +16,8 @@ import (
"github.com/iotexproject/iotex-core/blockchain/block"
"github.com/iotexproject/iotex-core/blockchain/genesis"
"github.com/iotexproject/iotex-core/db"
"github.com/iotexproject/iotex-core/db/batch"
"github.com/iotexproject/iotex-core/pkg/util/byteutil"
"github.com/iotexproject/iotex-core/state"
"github.com/iotexproject/iotex-core/test/identityset"
"github.com/iotexproject/iotex-core/testutil"
Expand Down Expand Up @@ -109,31 +112,6 @@ func TestNewSGDRegistry(t *testing.T) {
r.Equal(receiverAddress, receiver)
r.True(isApproved)
r.Equal(_sgdPercentage, percentage)

t.Run("heightRestriction", func(t *testing.T) {
cases := []struct {
height uint64
isErr bool
}{
{0, false},
{1, true},
{2, false},
{3, true},
}
for i := range cases {
if cases[i].isErr {
_, err = sgdRegistry.FetchContracts(ctx, cases[i].height)
r.ErrorContains(err, "invalid height")
_, _, _, err = sgdRegistry.CheckContract(ctx, registerAddress.String(), cases[i].height)
r.ErrorContains(err, "invalid height")
} else {
_, err = sgdRegistry.FetchContracts(ctx, cases[i].height)
r.Nil(err)
_, _, _, err = sgdRegistry.CheckContract(ctx, registerAddress.String(), cases[i].height)
r.Nil(err)
}
}
})
})
t.Run("disapproveContract", func(t *testing.T) {
builder := block.NewTestingBuilder()
Expand Down Expand Up @@ -182,6 +160,89 @@ func TestNewSGDRegistry(t *testing.T) {
r.ErrorIs(err, state.ErrStateNotExist)
})
})
t.Run("heightRestriction", func(t *testing.T) {
cases := []struct {
startHeight uint64
height uint64
readHeight uint64
valid bool
}{
{0, 0, 0, true},
{0, 0, 1, false},
{0, 2, 0, true},
{0, 2, 1, false},
{0, 2, 2, true},
{0, 2, 3, false},
{10, 0, 0, true},
{10, 0, 1, true},
{10, 0, 9, true},
{10, 0, 10, false},
{10, 0, 11, false},
{10, 10, 0, true},
{10, 10, 1, true},
{10, 10, 9, true},
{10, 10, 10, true},
{10, 10, 11, false},
}
for i := range cases {
name := strconv.FormatInt(int64(i), 10)
t.Run(name, func(t *testing.T) {
testDBPath, err := testutil.PathOfTempFile("sgd")
r.NoError(err)
ctx := context.Background()
cfg := db.DefaultConfig
cfg.DbPath = testDBPath
kvStore := db.NewBoltDB(cfg)
sgdRegistry := &sgdRegistry{
contract: _testSGDContractAddress,
startHeight: cases[i].startHeight,
kvStore: kvStore,
}
r.NoError(sgdRegistry.Start(ctx))
defer func() {
r.NoError(sgdRegistry.Stop(ctx))
testutil.CleanupPath(testDBPath)
}()
// register
nonce := uint64(0)
registerAddress, err := address.FromHex("5b38da6a701c568545dcfcb03fcb875f56beddc4")
r.NoError(err)
builder := block.NewTestingBuilder()
event := _sgdABI.Events["ContractRegistered"]
data, _ := hex.DecodeString("0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc400000000000000000000000078731d3ca6b7e34ac0f824c42a7cc18a495cabab")
exec, err := action.SignedExecution(_testSGDContractAddress, identityset.PrivateKey(27), atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data)
r.NoError(err)
h, _ := exec.Hash()
logs := &action.Log{
Address: _testSGDContractAddress,
Topics: []hash.Hash256{hash.Hash256(event.ID)},
Data: data,
}
expectHeight, err := sgdRegistry.expectHeight()
r.NoError(err)
blk := createTestingBlock(builder, expectHeight, h, exec, logs)
r.NoError(sgdRegistry.PutBlock(ctx, blk))
_, _, _, err = sgdRegistry.CheckContract(ctx, registerAddress.String(), 1)
r.NoError(err)
// update height
b := batch.NewBatch()
b.Put(_sgdToHeightNS, _sgdCurrentHeight, byteutil.Uint64ToBytesBigEndian(cases[i].height), "failed to put current height")
sgdRegistry.kvStore.WriteBatch(b)
// check
if !cases[i].valid {
_, err = sgdRegistry.FetchContracts(ctx, cases[i].readHeight)
r.ErrorContains(err, "invalid height")
_, _, _, err = sgdRegistry.CheckContract(ctx, registerAddress.String(), cases[i].readHeight)
r.ErrorContains(err, "invalid height")
} else {
_, err = sgdRegistry.FetchContracts(ctx, cases[i].readHeight)
r.Nil(err)
_, _, _, err = sgdRegistry.CheckContract(ctx, registerAddress.String(), cases[i].readHeight)
r.Nil(err)
}
})
}
})
}

func createTestingBlock(builder *block.TestingBuilder, height uint64, h hash.Hash256, act action.SealedEnvelope, logs *action.Log) *block.Block {
Expand Down

0 comments on commit 9165501

Please sign in to comment.