Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[contractstaking]fix vote bug when change delegate #3888

Merged
merged 17 commits into from
Jun 19, 2023
Merged
38 changes: 3 additions & 35 deletions blockindex/contractstaking/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ type (
candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket
bucketTypeMap map[uint64]*BucketType // map[bucketTypeId]BucketType
propertyBucketTypeMap map[int64]map[uint64]uint64 // map[amount][duration]index
height uint64
totalBucketCount uint64 // total number of buckets including burned buckets
contractAddress string // contract address for the bucket
mutex sync.RWMutex // a RW mutex for the cache to protect concurrent access
totalBucketCount uint64 // total number of buckets including burned buckets
contractAddress string // contract address for the bucket
mutex sync.RWMutex // a RW mutex for the cache to protect concurrent access
}
)

Expand All @@ -44,12 +43,6 @@ func newContractStakingCache(contractAddr string) *contractStakingCache {
}
}

func (s *contractStakingCache) Height() uint64 {
s.mutex.RLock()
defer s.mutex.RUnlock()
return s.height
}

func (s *contractStakingCache) CandidateVotes(candidate address.Address) *big.Int {
s.mutex.RLock()
defer s.mutex.RUnlock()
Expand Down Expand Up @@ -190,13 +183,6 @@ func (s *contractStakingCache) DeleteBucketInfo(id uint64) {
s.deleteBucketInfo(id)
}

func (s *contractStakingCache) PutHeight(h uint64) {
s.mutex.Lock()
defer s.mutex.Unlock()

s.putHeight(h)
}

func (s *contractStakingCache) Merge(delta *contractStakingDelta) error {
s.mutex.Lock()
defer s.mutex.Unlock()
Expand Down Expand Up @@ -233,20 +219,6 @@ func (s *contractStakingCache) LoadFromDB(kvstore db.KVStore) error {
s.mutex.Lock()
defer s.mutex.Unlock()

// load height
var height uint64
h, err := kvstore.Get(_StakingNS, _stakingHeightKey)
if err != nil {
if !errors.Is(err, db.ErrNotExist) {
return err
}
height = 0
} else {
height = byteutil.BytesToUint64BigEndian(h)

}
s.putHeight(height)

// load total bucket count
var totalBucketCount uint64
tbc, err := kvstore.Get(_StakingNS, _stakingTotalBucketCountKey)
Expand Down Expand Up @@ -388,10 +360,6 @@ func (s *contractStakingCache) deleteBucketInfo(id uint64) {
delete(s.candidateBucketMap[bi.Delegate.String()], id)
}

func (s *contractStakingCache) putHeight(h uint64) {
s.height = h
}

func (s *contractStakingCache) putTotalBucketCount(count uint64) {
s.totalBucketCount = count
}
Expand Down
14 changes: 0 additions & 14 deletions blockindex/contractstaking/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,6 @@ import (
"github.com/iotexproject/iotex-core/testutil"
)

func TestContractStakingCache_Height(t *testing.T) {
require := require.New(t)
cache := newContractStakingCache("")

cache.PutHeight(12345)
require.Equal(uint64(12345), cache.Height())

cache.PutHeight(54321)
require.Equal(uint64(54321), cache.Height())
}

func TestContractStakingCache_CandidateVotes(t *testing.T) {
require := require.New(t)
cache := newContractStakingCache("")
Expand Down Expand Up @@ -437,7 +426,6 @@ func TestContractStakingCache_LoadFromDB(t *testing.T) {

err = cache.LoadFromDB(kvstore)
require.NoError(err)
require.Equal(uint64(0), cache.Height())
require.Equal(uint64(0), cache.TotalBucketCount())
require.Equal(0, len(cache.Buckets()))
require.EqualValues(0, cache.BucketTypeCount())
Expand All @@ -447,7 +435,6 @@ func TestContractStakingCache_LoadFromDB(t *testing.T) {
kvstore.Put(_StakingNS, _stakingTotalBucketCountKey, byteutil.Uint64ToBytesBigEndian(10))
err = cache.LoadFromDB(kvstore)
require.NoError(err)
require.Equal(uint64(12345), cache.Height())
require.Equal(uint64(10), cache.TotalBucketCount())
require.Equal(0, len(cache.Buckets()))
require.EqualValues(0, cache.BucketTypeCount())
Expand All @@ -459,7 +446,6 @@ func TestContractStakingCache_LoadFromDB(t *testing.T) {
kvstore.Put(_StakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(1), bucketType.Serialize())
err = cache.LoadFromDB(kvstore)
require.NoError(err)
require.Equal(uint64(12345), cache.Height())
require.Equal(uint64(10), cache.TotalBucketCount())
bi, ok := cache.BucketInfo(1)
require.True(ok)
Expand Down
4 changes: 0 additions & 4 deletions blockindex/contractstaking/dirty_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ func newContractStakingDirty(clean *contractStakingCache) *contractStakingDirty
}
}

func (dirty *contractStakingDirty) putHeight(h uint64) {
dirty.batch.Put(_StakingNS, _stakingHeightKey, byteutil.Uint64ToBytesBigEndian(h), "failed to put height")
}

func (dirty *contractStakingDirty) addBucketInfo(id uint64, bi *bucketInfo) error {
dirty.batch.Put(_StakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.Serialize(), "failed to put bucket info")
return dirty.delta.AddBucketInfo(id, bi)
Expand Down
4 changes: 0 additions & 4 deletions blockindex/contractstaking/dirty_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,4 @@ func TestContractStakingDirty_noSideEffectOnClean(t *testing.T) {
require.EqualValues(identityset.Address(1).String(), bi.Delegate.String())
require.EqualValues(identityset.Address(2).String(), bi.Owner.String())

// put height in dirty cache
dirty.putHeight(1)
// check that clean cache is not affected
require.EqualValues(0, clean.Height())
}
9 changes: 3 additions & 6 deletions blockindex/contractstaking/event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,6 @@ const (
type contractStakingEventHandler struct {
dirty *contractStakingDirty
tokenOwner map[uint64]address.Address
height uint64
}

var (
Expand All @@ -367,13 +366,11 @@ func init() {
}
}

func newContractStakingEventHandler(cache *contractStakingCache, height uint64) *contractStakingEventHandler {
func newContractStakingEventHandler(cache *contractStakingCache) *contractStakingEventHandler {
dirty := newContractStakingDirty(cache)
dirty.putHeight(height)
return &contractStakingEventHandler{
envestcc marked this conversation as resolved.
Show resolved Hide resolved
dirty: dirty,
tokenOwner: make(map[uint64]address.Address),
height: height,
}
}

Expand Down Expand Up @@ -422,9 +419,9 @@ func (eh *contractStakingEventHandler) HandleEvent(ctx context.Context, blk *blo
}
}

func (eh *contractStakingEventHandler) Result() (batch.KVStoreBatch, *contractStakingDelta, uint64) {
func (eh *contractStakingEventHandler) Result() (batch.KVStoreBatch, *contractStakingDelta) {
batch, delta := eh.dirty.finalize()
return batch, delta, eh.height
return batch, delta
envestcc marked this conversation as resolved.
Show resolved Hide resolved
}

func (eh *contractStakingEventHandler) handleTransferEvent(event eventParam) error {
Expand Down
41 changes: 33 additions & 8 deletions blockindex/contractstaking/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package contractstaking
import (
"context"
"math/big"
"sync/atomic"

"github.com/ethereum/go-ethereum/common/math"
"github.com/iotexproject/iotex-address/address"
Expand All @@ -17,6 +18,7 @@ import (
"github.com/iotexproject/iotex-core/blockchain/block"
"github.com/iotexproject/iotex-core/blockchain/blockdao"
"github.com/iotexproject/iotex-core/db"
"github.com/iotexproject/iotex-core/pkg/util/byteutil"
)

const (
Expand Down Expand Up @@ -52,6 +54,7 @@ type (
cache *contractStakingCache // in-memory index for clean data, used to query index data
contractAddress string // stake contract address
contractDeployHeight uint64 // height of the contract deployment
height atomic.Value // uint64, current block height
dustinxie marked this conversation as resolved.
Show resolved Hide resolved
}
)

Expand All @@ -76,7 +79,7 @@ func (s *Indexer) Start(ctx context.Context) error {
if err := s.kvstore.Start(ctx); err != nil {
return err
}
return s.cache.LoadFromDB(s.kvstore)
return s.loadFromDB(s.kvstore)
}

// Stop stops the indexer
Expand All @@ -90,7 +93,7 @@ func (s *Indexer) Stop(ctx context.Context) error {

// Height returns the tip block height
func (s *Indexer) Height() (uint64, error) {
return s.cache.Height(), nil
return s.height.Load().(uint64), nil
}

// StartHeight returns the start height of the indexer
Expand Down Expand Up @@ -144,7 +147,7 @@ func (s *Indexer) PutBlock(ctx context.Context, blk *block.Block) error {
return nil
}
// new event handler for this block
handler := newContractStakingEventHandler(s.cache, blk.Height())
handler := newContractStakingEventHandler(s.cache)
dustinxie marked this conversation as resolved.
Show resolved Hide resolved

// handle events of block
for _, receipt := range blk.Receipts {
Expand All @@ -162,22 +165,26 @@ func (s *Indexer) PutBlock(ctx context.Context, blk *block.Block) error {
}

// commit the result
return s.commit(handler)
return s.commit(handler, blk.Height())
}

// DeleteTipBlock deletes the tip block from indexer
func (s *Indexer) DeleteTipBlock(context.Context, *block.Block) error {
return errors.New("not implemented")
}

func (s *Indexer) commit(handler *contractStakingEventHandler) error {
batch, delta, height := handler.Result()
func (s *Indexer) commit(handler *contractStakingEventHandler, height uint64) error {
batch, delta := handler.Result()
// update cache
if err := s.cache.Merge(delta); err != nil {
s.reloadCache()
return err
}
s.cache.PutHeight(height)
s.cache.PutTotalBucketCount(s.cache.TotalBucketCount() + delta.AddedBucketCnt())
// update indexer height cache
s.height.Store(height)
envestcc marked this conversation as resolved.
Show resolved Hide resolved
// update db
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new state at old height without lock?

batch.Put(_StakingNS, _stakingHeightKey, byteutil.Uint64ToBytesBigEndian(height), "failed to put height")
if err := s.kvstore.WriteBatch(batch); err != nil {
s.reloadCache()
return err
Expand All @@ -187,5 +194,23 @@ func (s *Indexer) commit(handler *contractStakingEventHandler) error {

func (s *Indexer) reloadCache() error {
s.cache = newContractStakingCache(s.contractAddress)
return s.cache.LoadFromDB(s.kvstore)
return s.loadFromDB(s.kvstore)
}

func (s *Indexer) loadFromDB(kvstore db.KVStore) error {
// load height
var height uint64
h, err := kvstore.Get(_StakingNS, _stakingHeightKey)
if err != nil {
if !errors.Is(err, db.ErrNotExist) {
return err
}
height = 0
} else {
height = byteutil.BytesToUint64BigEndian(h)

}
s.height.Store(height)
// load cache
return s.cache.LoadFromDB(kvstore)
}
Loading