Skip to content

Commit 638804b

Browse files
Yutong PeiCoderZhi
andauthored
add vote reviser (iotexproject#2370)
* add vote reviser * fix unit test * address comment * fix a bug * remove reviseHeights from staking config * revert correction for staking receipt log Co-authored-by: zhi <[email protected]>
1 parent 4daa619 commit 638804b

File tree

6 files changed

+141
-7
lines changed

6 files changed

+141
-7
lines changed

action/protocol/staking/handlers_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func TestProtocol_HandleCreateStake(t *testing.T) {
7070
require.NoError(err)
7171

7272
// create protocol
73-
p, err := NewProtocol(depositGas, genesis.Default.Staking, nil)
73+
p, err := NewProtocol(depositGas, genesis.Default.Staking, nil, genesis.Default.GreenlandBlockHeight)
7474
require.NoError(err)
7575

7676
// set up candidate
@@ -2582,7 +2582,7 @@ func initAll(t *testing.T, ctrl *gomock.Controller) (protocol.StateManager, *Pro
25822582
require.NoError(err)
25832583

25842584
// create protocol
2585-
p, err := NewProtocol(depositGas, genesis.Default.Staking, nil)
2585+
p, err := NewProtocol(depositGas, genesis.Default.Staking, nil, genesis.Default.GreenlandBlockHeight)
25862586
require.NoError(err)
25872587

25882588
// set up candidate

action/protocol/staking/protocol.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ type (
7171
config Configuration
7272
hu config.HeightUpgrade
7373
candBucketsIndexer *CandidatesBucketsIndexer
74+
voteReviser *VoteReviser
7475
}
7576

7677
// Configuration is the staking protocol configuration.
@@ -87,7 +88,7 @@ type (
8788
)
8889

8990
// NewProtocol instantiates the protocol of staking
90-
func NewProtocol(depositGas DepositGas, cfg genesis.Staking, candBucketsIndexer *CandidatesBucketsIndexer) (*Protocol, error) {
91+
func NewProtocol(depositGas DepositGas, cfg genesis.Staking, candBucketsIndexer *CandidatesBucketsIndexer, reviseHeights ...uint64) (*Protocol, error) {
9192
h := hash.Hash160b([]byte(protocolID))
9293
addr, err := address.FromBytes(h[:])
9394
if err != nil {
@@ -109,6 +110,9 @@ func NewProtocol(depositGas DepositGas, cfg genesis.Staking, candBucketsIndexer
109110
return nil, ErrInvalidAmount
110111
}
111112

113+
// new vote reviser, revise ate greenland
114+
voteReviser := NewVoteReviser(cfg.VoteWeightCalConsts, reviseHeights...)
115+
112116
return &Protocol{
113117
addr: addr,
114118
config: Configuration{
@@ -123,6 +127,7 @@ func NewProtocol(depositGas DepositGas, cfg genesis.Staking, candBucketsIndexer
123127
},
124128
depositGas: depositGas,
125129
candBucketsIndexer: candBucketsIndexer,
130+
voteReviser: voteReviser,
126131
}, nil
127132
}
128133

@@ -219,6 +224,15 @@ func (p *Protocol) CreatePreStates(ctx context.Context, sm protocol.StateManager
219224
}
220225
}
221226

227+
if p.voteReviser.NeedRevise(blkCtx.BlockHeight) {
228+
csm, err := NewCandidateStateManager(sm, p.hu.IsPost(config.Greenland, blkCtx.BlockHeight))
229+
if err != nil {
230+
return err
231+
}
232+
if err := p.voteReviser.Revise(csm, blkCtx.BlockHeight); err != nil {
233+
return err
234+
}
235+
}
222236
if p.candBucketsIndexer == nil {
223237
return nil
224238
}

action/protocol/staking/protocol_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func TestProtocol(t *testing.T) {
8383
}
8484

8585
// test loading with no candidate in stateDB
86-
stk, err := NewProtocol(nil, genesis.Default.Staking, nil)
86+
stk, err := NewProtocol(nil, genesis.Default.Staking, nil, genesis.Default.GreenlandBlockHeight)
8787
r.NotNil(stk)
8888
r.NoError(err)
8989
buckets, _, err := getAllBuckets(sm)
@@ -188,7 +188,7 @@ func TestCreatePreStates(t *testing.T) {
188188
ctrl := gomock.NewController(t)
189189
defer ctrl.Finish()
190190
sm := testdb.NewMockStateManager(ctrl)
191-
p, err := NewProtocol(nil, genesis.Default.Staking, nil)
191+
p, err := NewProtocol(nil, genesis.Default.Staking, nil, genesis.Default.GreenlandBlockHeight)
192192
require.NoError(err)
193193
ctx := protocol.WithBlockCtx(
194194
protocol.WithBlockchainCtx(

action/protocol/staking/validations_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func TestIsValidCandidateName(t *testing.T) {
6464

6565
func initTestProtocol(t *testing.T) (*Protocol, []*Candidate) {
6666
require := require.New(t)
67-
p, err := NewProtocol(nil, genesis.Default.Staking, nil)
67+
p, err := NewProtocol(nil, genesis.Default.Staking, nil, genesis.Default.GreenlandBlockHeight)
6868
require.NoError(err)
6969

7070
var cans []*Candidate
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package staking
2+
3+
import (
4+
"math/big"
5+
"sort"
6+
7+
"github.com/pkg/errors"
8+
"go.uber.org/zap"
9+
10+
"github.com/iotexproject/iotex-core/action/protocol"
11+
"github.com/iotexproject/iotex-core/blockchain/genesis"
12+
"github.com/iotexproject/iotex-core/pkg/log"
13+
"github.com/iotexproject/iotex-core/state"
14+
)
15+
16+
// VoteReviser is used to recalculate candidate votes.
17+
type VoteReviser struct {
18+
reviseHeights []uint64
19+
cache map[uint64]CandidateList
20+
c genesis.VoteWeightCalConsts
21+
}
22+
23+
// NewVoteReviser creates a VoteReviser.
24+
func NewVoteReviser(c genesis.VoteWeightCalConsts, reviseHeights ...uint64) *VoteReviser {
25+
return &VoteReviser{
26+
reviseHeights: reviseHeights,
27+
cache: make(map[uint64]CandidateList),
28+
c: c,
29+
}
30+
}
31+
32+
// Revise recalculate candidate votes on preset revising height.
33+
func (vr *VoteReviser) Revise(csm CandidateStateManager, height uint64) error {
34+
if !vr.isCacheExist(height) {
35+
cands, err := vr.calculateVoteWeight(csm)
36+
if err != nil {
37+
return err
38+
}
39+
vr.storeToCache(height, cands)
40+
}
41+
return vr.flush(height, csm)
42+
}
43+
44+
func (vr *VoteReviser) storeToCache(height uint64, cands CandidateList) {
45+
vr.cache[height] = cands
46+
}
47+
48+
func (vr *VoteReviser) isCacheExist(height uint64) bool {
49+
_, ok := vr.cache[height]
50+
return ok
51+
}
52+
53+
// NeedRevise returns true if height needs revise
54+
func (vr *VoteReviser) NeedRevise(height uint64) bool {
55+
for _, h := range vr.reviseHeights {
56+
if height == h {
57+
return true
58+
}
59+
}
60+
return false
61+
}
62+
63+
func (vr *VoteReviser) calculateVoteWeight(sm protocol.StateManager) (CandidateList, error) {
64+
cands, _, err := getAllCandidates(sm)
65+
switch {
66+
case errors.Cause(err) == state.ErrStateNotExist:
67+
case err != nil:
68+
return nil, err
69+
}
70+
candm := make(map[string]*Candidate)
71+
for _, cand := range cands {
72+
candm[cand.Owner.String()] = cand.Clone()
73+
candm[cand.Owner.String()].Votes = new(big.Int)
74+
candm[cand.Owner.String()].SelfStake = new(big.Int)
75+
}
76+
buckets, _, err := getAllBuckets(sm)
77+
switch {
78+
case errors.Cause(err) == state.ErrStateNotExist:
79+
case err != nil:
80+
return nil, err
81+
}
82+
83+
for _, bucket := range buckets {
84+
if bucket.isUnstaked() {
85+
continue
86+
}
87+
cand, ok := candm[bucket.Candidate.String()]
88+
if !ok {
89+
log.L().Error("invalid bucket candidate", zap.Uint64("bucket index", bucket.Index), zap.String("candidate", bucket.Candidate.String()))
90+
continue
91+
}
92+
93+
if cand.SelfStakeBucketIdx == bucket.Index {
94+
cand.AddVote(calculateVoteWeight(vr.c, bucket, true))
95+
cand.SelfStake = bucket.StakedAmount
96+
} else {
97+
cand.AddVote(calculateVoteWeight(vr.c, bucket, false))
98+
}
99+
}
100+
101+
cands = make(CandidateList, 0, len(candm))
102+
for _, cand := range candm {
103+
cands = append(cands, cand)
104+
}
105+
return cands, nil
106+
}
107+
108+
func (vr *VoteReviser) flush(height uint64, csm CandidateStateManager) error {
109+
cands, ok := vr.cache[height]
110+
if !ok {
111+
return nil
112+
}
113+
sort.Sort(cands)
114+
for _, cand := range cands {
115+
if err := csm.Upsert(cand); err != nil {
116+
return err
117+
}
118+
}
119+
return nil
120+
}

chainservice/chainservice.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ func New(
240240
)
241241
// staking protocol need to be put in registry before poll protocol when enabling
242242
if cfg.Chain.EnableStakingProtocol {
243-
stakingProtocol, err = staking.NewProtocol(rewarding.DepositGas, cfg.Genesis.Staking, candBucketsIndexer)
243+
stakingProtocol, err = staking.NewProtocol(rewarding.DepositGas, cfg.Genesis.Staking, candBucketsIndexer, cfg.Genesis.GreenlandBlockHeight)
244244
if err != nil {
245245
return nil, err
246246
}

0 commit comments

Comments
 (0)