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

[staking] fix weighted votes of contract staking bucket #3936

Merged
merged 11 commits into from
Oct 13, 2023
Merged
1 change: 1 addition & 0 deletions action/protocol/staking/staking_statereader.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ func (c *compositeStakingStateReader) isContractStakingEnabled() bool {
return c.contractIndexer != nil
}

// TODO: move into compositeStakingStateReader
func addContractStakingVotes(ctx context.Context, candidate *iotextypes.CandidateV2, contractStakingSR ContractStakingIndexer, height uint64) error {
votes, ok := big.NewInt(0).SetString(candidate.TotalWeightedVotes, 10)
if !ok {
Expand Down
2 changes: 1 addition & 1 deletion action/protocol/staking/vote_bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ func CalculateVoteWeight(c genesis.VoteWeightCalConsts, v *VoteBucket, selfStake
if remainingTime > 0 {
weight += math.Log(math.Ceil(remainingTime/86400)*(1+m)) / math.Log(c.DurationLg) / 100
}
if v.isNative() && selfStake && v.AutoStake && v.StakedDuration >= time.Duration(91)*24*time.Hour {
if selfStake && v.AutoStake && v.StakedDuration >= time.Duration(91)*24*time.Hour {
// self-stake extra bonus requires enable auto-stake for at least 3 months
weight *= c.SelfStake
}
Expand Down
78 changes: 65 additions & 13 deletions action/protocol/staking/vote_bucket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func TestCalculateVoteWeight(t *testing.T) {
expected: big.NewInt(125),
},
{
name: "NFT, auto-stake enabled, self-stake enabled",
name: "NFT, auto-stake enabled",
consts: consts,
voteBucket: &VoteBucket{
StakedDuration: 30 * 17280 * blockInterval,
Expand All @@ -170,47 +170,99 @@ func TestCalculateVoteWeight(t *testing.T) {
StakedAmount: big.NewInt(10000),
ContractAddress: identityset.Address(1).String(),
},
selfStake: true,
selfStake: false,
expected: big.NewInt(12245),
},
{
name: "NFT, auto-stake enabled, self-stake disabled",
name: "NFT, auto-stake disabled",
consts: consts,
voteBucket: &VoteBucket{
StakedDuration: 30 * 17280 * blockInterval,
StakedDurationBlockNumber: 30 * 17280,
AutoStake: false,
StakedAmount: big.NewInt(10000),
ContractAddress: identityset.Address(1).String(),
},
selfStake: false,
expected: big.NewInt(11865),
},
{
name: "NFT-I, auto-stake enabled",
consts: consts,
voteBucket: &VoteBucket{
StakedDuration: 91 * 17280 * blockInterval,
StakedDurationBlockNumber: 91 * 17280,
AutoStake: true,
StakedAmount: big.NewInt(10000),
ContractAddress: identityset.Address(1).String(),
},
selfStake: false,
expected: big.NewInt(12245),
expected: big.NewInt(12854),
},
{
name: "NFT, auto-stake disabled, self-stake enabled",
name: "NFT-I, auto-stake disabled",
consts: consts,
voteBucket: &VoteBucket{
StakedDuration: 30 * 17280 * blockInterval,
StakedDurationBlockNumber: 30 * 17280,
StakedDuration: 91 * 17280 * blockInterval,
StakedDurationBlockNumber: 91 * 17280,
AutoStake: false,
StakedAmount: big.NewInt(10000),
ContractAddress: identityset.Address(1).String(),
},
selfStake: true,
expected: big.NewInt(11865),
expected: big.NewInt(12474),
},
{
name: "NFT, auto-stake disabled, self-stake disabled",
name: "NFT-II, auto-stake enabled",
consts: consts,
voteBucket: &VoteBucket{
StakedDuration: 30 * 17280 * blockInterval,
StakedDurationBlockNumber: 30 * 17280,
StakedDuration: 91 * 17280 * blockInterval,
StakedDurationBlockNumber: 91 * 17280,
AutoStake: true,
StakedAmount: big.NewInt(100000),
ContractAddress: identityset.Address(1).String(),
},
selfStake: false,
expected: big.NewInt(128543),
},
{
name: "NFT-II, auto-stake disabled",
consts: consts,
voteBucket: &VoteBucket{
StakedDuration: 91 * 17280 * blockInterval,
StakedDurationBlockNumber: 91 * 17280,
AutoStake: false,
StakedAmount: big.NewInt(10000),
StakedAmount: big.NewInt(100000),
ContractAddress: identityset.Address(1).String(),
},
selfStake: true,
expected: big.NewInt(124741),
},
{
name: "NFT-III, auto-stake enabled",
consts: consts,
voteBucket: &VoteBucket{
StakedDuration: 2 * 17280 * blockInterval,
StakedDurationBlockNumber: 2 * 17280,
AutoStake: true,
StakedAmount: big.NewInt(1000),
ContractAddress: identityset.Address(1).String(),
},
selfStake: false,
expected: big.NewInt(11865),
expected: big.NewInt(1076),
},
{
name: "NFT-III, auto-stake disabled",
consts: consts,
voteBucket: &VoteBucket{
StakedDuration: 2 * 17280 * blockInterval,
StakedDurationBlockNumber: 2 * 17280,
AutoStake: false,
StakedAmount: big.NewInt(1000),
ContractAddress: identityset.Address(1).String(),
},
selfStake: true,
expected: big.NewInt(1038),
},
}

Expand Down
3 changes: 3 additions & 0 deletions blockindex/contractstaking/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ func (s *contractStakingCache) CandidateVotes(ctx context.Context, candidate add
}
bt := s.mustGetBucketType(bi.TypeIndex)
if featureCtx.FixContractStakingWeightedVotes {
if s.config.CalculateVoteWeight == nil {
return nil, errors.New("calculate vote weight function is not set")
}
Copy link
Member

Choose a reason for hiding this comment

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

if we add this check, it should be added at creation time, when the func is passed to Newxxx

Copy link
Member Author

Choose a reason for hiding this comment

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

ok

votes.Add(votes, s.config.CalculateVoteWeight(assembleBucket(id, bi, bt, s.config.ContractAddress, s.config.BlockInterval)))
Copy link
Member

Choose a reason for hiding this comment

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

throw error if CalculateVoteWeight is nullptr when Config is empty

Copy link
Member Author

Choose a reason for hiding this comment

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

ok

} else {
votes.Add(votes, bt.Amount)
Expand Down
9 changes: 5 additions & 4 deletions blockindex/contractstaking/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ type (

// Config is the config for contract staking indexer
Config struct {
ContractAddress string // stake contract ContractAddress
ContractDeployHeight uint64 // height of the contract deployment
CalculateVoteWeight calculateVoteWeightFunc // calculate vote weight function
BlockInterval time.Duration // block produce interval
ContractAddress string // stake contract ContractAddress
ContractDeployHeight uint64 // height of the contract deployment
// TODO: move calculateVoteWeightFunc out of config
CalculateVoteWeight calculateVoteWeightFunc // calculate vote weight function
BlockInterval time.Duration // block produce interval
}

calculateVoteWeightFunc func(v *Bucket) *big.Int
Expand Down