Skip to content

Commit

Permalink
Introduce separate fund to reward successful reports (#792)
Browse files Browse the repository at this point in the history
  • Loading branch information
mbidenaio authored and sidenaio committed Sep 16, 2021
1 parent 7dc5bf4 commit 08175f7
Show file tree
Hide file tree
Showing 8 changed files with 336 additions and 27 deletions.
63 changes: 63 additions & 0 deletions blockchain/rewards.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func rewardValidIdentities(appState *appstate.AppState, config *config.Consensus
totalRewardD := decimal.NewFromBigInt(totalReward, 0)
addSuccessfulValidationReward(appState, config, validationResults, totalRewardD, statsCollector)
addFlipReward(appState, config, validationResults, totalRewardD, statsCollector)
addReportReward(appState, config, validationResults, totalRewardD, statsCollector)
addInvitationReward(appState, config, validationResults, totalRewardD, seed, epochDurations, statsCollector)
addFoundationPayouts(appState, config, totalRewardD, statsCollector)
addZeroWalletFund(appState, config, totalRewardD, statsCollector)
Expand Down Expand Up @@ -119,6 +120,9 @@ func addFlipReward(appState *appstate.AppState, config *config.ConsensusConf, va
totalWeight += getFlipRewardCoef(f.Grade)
}
}
if config.ReportsRewardPercent > 0 {
continue
}
for _, reporters := range validationResult.ReportersToRewardByFlip {
if len(reporters) == 0 {
continue
Expand Down Expand Up @@ -163,6 +167,9 @@ func addFlipReward(appState *appstate.AppState, config *config.ConsensusConf, va
collector.AfterAddStake(statsCollector, addr, stake, appState)
}
}
if config.ReportsRewardPercent > 0 {
return
}
for i := uint32(1); i <= appState.State.ShardsNum(); i++ {
shardId := common.ShardId(i)
validationResult, ok := validationResults[shardId]
Expand Down Expand Up @@ -193,6 +200,62 @@ func addFlipReward(appState *appstate.AppState, config *config.ConsensusConf, va
}
}

func addReportReward(appState *appstate.AppState, config *config.ConsensusConf, validationResults map[common.ShardId]*types.ValidationResults,
totalReward decimal.Decimal, statsCollector collector.StatsCollector) {
if config.ReportsRewardPercent == 0 {
return
}
rewardD := totalReward.Mul(decimal.NewFromFloat32(config.ReportsRewardPercent))

totalWeight := uint64(0)

for i := uint32(1); i <= appState.State.ShardsNum(); i++ {
validationResult, ok := validationResults[common.ShardId(i)]
if !ok {
continue
}
for _, reporters := range validationResult.ReportersToRewardByFlip {
totalWeight += uint64(len(reporters))
}
}

if totalWeight == 0 {
return
}

rewardShare := rewardD.Div(decimal.NewFromBigInt(new(big.Int).SetUint64(totalWeight), 0))

collector.SetTotalReportsReward(statsCollector, math.ToInt(rewardD), math.ToInt(rewardShare))

for i := uint32(1); i <= appState.State.ShardsNum(); i++ {
shardId := common.ShardId(i)
validationResult, ok := validationResults[shardId]
if !ok {
continue
}
for flipIdx, reporters := range validationResult.ReportersToRewardByFlip {
if len(reporters) == 0 {
continue
}
for _, reporter := range reporters {
reward, stake := splitReward(math.ToInt(rewardShare), reporter.NewIdentityState == uint8(state.Newbie), config)
rewardDest := reporter.Address
if delegatee := appState.State.Delegatee(reporter.Address); delegatee != nil {
rewardDest = *delegatee
}
collector.BeginEpochRewardBalanceUpdate(statsCollector, rewardDest, reporter.Address, appState)
appState.State.AddBalance(rewardDest, reward)
appState.State.AddStake(reporter.Address, stake)
collector.CompleteBalanceUpdate(statsCollector, appState)
collector.AddMintedCoins(statsCollector, reward)
collector.AddMintedCoins(statsCollector, stake)
collector.AddReportedFlipsReward(statsCollector, rewardDest, reporter.Address, shardId, flipIdx, reward, stake)
collector.AfterAddStake(statsCollector, reporter.Address, stake, appState)
}
}
}
}

func getInvitationRewardCoef(age uint16, epochHeight uint32, epochDurations []uint32, config *config.ConsensusConf) float32 {
var baseCoef float32
switch age {
Expand Down
24 changes: 16 additions & 8 deletions blockchain/rewards_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func Test_rewardValidIdentities(t *testing.T) {
conf.FinalCommitteeReward = big.NewInt(5)
config.ApplyConsensusVersion(config.ConsensusV4, conf)
config.ApplyConsensusVersion(config.ConsensusV5, conf)
config.ApplyConsensusVersion(config.ConsensusV6, conf)

memdb := db.NewMemDB()

Expand All @@ -51,6 +52,7 @@ func Test_rewardValidIdentities(t *testing.T) {
appState.State.SetState(auth3, state.Human)
appState.State.SetState(auth4, state.Suspended)
appState.State.SetState(badAuth, state.Newbie)
appState.State.SetShardsNum(2)
appState.Commit(nil)

validationResults := map[common.ShardId]*types.ValidationResults{
Expand Down Expand Up @@ -81,15 +83,19 @@ func Test_rewardValidIdentities(t *testing.T) {
NewIdentityState: uint8(state.Verified),
},
},
},
},
2: {
ReportersToRewardByFlip: map[int]map[common.Address]*types.Candidate{
150: {
reporter: &types.Candidate{
Address: reporter,
NewIdentityState: uint8(state.Newbie),
},
},
151: {},
},
},
151: {},
},
},
}
appState.State.SetState(auth1, state.Verified)
appState.State.SetBirthday(auth1, 2)
Expand All @@ -110,8 +116,8 @@ func Test_rewardValidIdentities(t *testing.T) {

appState.Commit(nil)

validationReward := float32(240) / 5.557298 // 4^(1/3)+1^(1/3)+2^(1/3)+5^(1/3)
flipReward := float32(400) / 25
validationReward := float32(200) / 5.557298 // 4^(1/3)+1^(1/3)+2^(1/3)+5^(1/3)
flipReward := float32(350) / 23
godPayout := float32(100)

// sum all coefficients
Expand All @@ -120,7 +126,9 @@ func Test_rewardValidIdentities(t *testing.T) {
// auth4: conf.ThirdInvitationRewardCoef (18)
// god: conf.FirstInvitationRewardCoef + conf.SecondInvitationRewardCoef + conf.ThirdInvitationRewardCoef (3 + 9 + 18)
// total: 57
invitationReward := float32(4.2105263) // 240/57
invitationReward := float32(3.1578947) // 180/57

reportReward := float32(50) // 150 / 3

reward, stake := splitAndSum(conf, false, validationReward*normalAge(3), flipReward*12.0, invitationReward*conf.SecondInvitationRewardCoef)

Expand All @@ -131,7 +139,7 @@ func Test_rewardValidIdentities(t *testing.T) {
require.True(t, reward.Cmp(appState.State.GetBalance(auth2)) == 0)
require.True(t, stake.Cmp(appState.State.GetStakeBalance(auth2)) == 0)

reward, stake = splitAndSum(conf, false, validationReward*normalAge(1), flipReward*11.0, flipReward*0.5)
reward, stake = splitAndSum(conf, false, validationReward*normalAge(1), flipReward*11.0, reportReward)
require.True(t, reward.Cmp(appState.State.GetBalance(auth3)) == 0)
require.True(t, stake.Cmp(appState.State.GetStakeBalance(auth3)) == 0)

Expand All @@ -144,7 +152,7 @@ func Test_rewardValidIdentities(t *testing.T) {
require.True(t, reward.Cmp(appState.State.GetBalance(god)) == 0)
require.True(t, stake.Cmp(appState.State.GetStakeBalance(god)) == 0)

reward, stake = splitAndSum(conf, true, flipReward, flipReward*0.5)
reward, stake = splitAndSum(conf, true, reportReward, reportReward)
require.True(t, reward.Cmp(appState.State.GetBalance(reporter)) == 0)
require.True(t, stake.Cmp(appState.State.GetStakeBalance(reporter)) == 0)

Expand Down
6 changes: 6 additions & 0 deletions config/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type ConsensusConf struct {
SuccessfulValidationRewardPercent float32
FlipRewardPercent float32
ValidInvitationRewardPercent float32
ReportsRewardPercent float32
FoundationPayoutsPercent float32
ZeroWalletPercent float32
FirstInvitationRewardCoef float32
Expand Down Expand Up @@ -109,6 +110,7 @@ func init() {
SuccessfulValidationRewardPercent: 0.24,
FlipRewardPercent: 0.32,
ValidInvitationRewardPercent: 0.32,
ReportsRewardPercent: 0,
FoundationPayoutsPercent: 0.1,
ZeroWalletPercent: 0.02,
FirstInvitationRewardCoef: 3.0,
Expand Down Expand Up @@ -165,6 +167,10 @@ func ApplyConsensusVersion(ver ConsensusVerson, cfg *ConsensusConf) {
cfg.StartActivationDate = time.Date(2021, 05, 11, 8, 0, 0, 0, time.UTC).Unix()
cfg.EndActivationDate = time.Date(2021, 05, 18, 0, 0, 0, 0, time.UTC).Unix()
case ConsensusV6:
cfg.SuccessfulValidationRewardPercent = 0.2
cfg.FlipRewardPercent = 0.35
cfg.ValidInvitationRewardPercent = 0.18
cfg.ReportsRewardPercent = 0.15
cfg.EnableValidationSharding = true
cfg.ChangeKillTxValidation = true
cfg.IncreaseGodInvitesLimit = true
Expand Down
22 changes: 13 additions & 9 deletions core/ceremony/ceremony.go
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ func (vc *ValidationCeremony) ApplyNewEpoch(height uint64, appState *appstate.Ap

shardValidationResults := new(types.ValidationResults)
shardValidationResults.GoodInviters = make(map[common.Address]*types.InviterValidationResult)
shardValidationResults.BadAuthors, shardValidationResults.GoodAuthors, shardValidationResults.AuthorResults, flipsByAuthor, reportersToReward = vc.analyzeAuthors(flipQualification, reportersToReward, shardId)
shardValidationResults.BadAuthors, shardValidationResults.GoodAuthors, shardValidationResults.AuthorResults, flipsByAuthor, reportersToReward = vc.analyzeAuthors(flipQualification, reportersToReward, shardId, vc.config.Consensus)

vc.logInfoWithInteraction("Approved candidates", "shardId", shardId, "cnt", len(approvedCandidates))

Expand Down Expand Up @@ -1020,7 +1020,7 @@ func (vc *ValidationCeremony) ApplyNewEpoch(height uint64, appState *appstate.Ap
incSuccessfulInvites(shardValidationResults, god, identity, identityBirthday, newIdentityState, vc.epoch)
setValidationResultToGoodAuthor(addr, newIdentityState, missed, shardValidationResults)
setValidationResultToGoodInviter(shardValidationResults, addr, newIdentityState, identity.Invites)
reportersToReward.setValidationResult(addr, newIdentityState, missed, flipsByAuthor)
reportersToReward.setValidationResult(addr, newIdentityState, missed, flipsByAuthor, vc.config.Consensus)

value := cacheValue{
state: newIdentityState,
Expand Down Expand Up @@ -1166,8 +1166,8 @@ func getOrPutGoodInviter(validationResults *types.ValidationResults, address com
return inviter, true
}

func (vc *ValidationCeremony) analyzeAuthors(qualifications []FlipQualification, reportersToReward *reportersToReward, shardId common.ShardId) (badAuthors map[common.Address]types.BadAuthorReason, goodAuthors map[common.Address]*types.ValidationResult, authorResults map[common.Address]*types.AuthorResults, madeFlips map[common.Address][]int, filteredReportersToReward *reportersToReward) {

func (vc *ValidationCeremony) analyzeAuthors(qualifications []FlipQualification, reportersToReward *reportersToReward, shardId common.ShardId, cfg *config.ConsensusConf) (badAuthors map[common.Address]types.BadAuthorReason, goodAuthors map[common.Address]*types.ValidationResult, authorResults map[common.Address]*types.AuthorResults, madeFlips map[common.Address][]int, filteredReportersToReward *reportersToReward) {
rewardAnyReport := cfg.ReportsRewardPercent > 0
badAuthors = make(map[common.Address]types.BadAuthorReason)
goodAuthors = make(map[common.Address]*types.ValidationResult)
authorResults = make(map[common.Address]*types.AuthorResults)
Expand All @@ -1189,8 +1189,10 @@ func (vc *ValidationCeremony) analyzeAuthors(qualifications []FlipQualification,
}
if item.grade == types.GradeReported {
badAuthors[author] = types.WrongWordsBadAuthor
if item.status != Qualified && item.status != WeaklyQualified {
reportersToReward.deleteFlip(flipIdx)
if !rewardAnyReport {
if item.status != Qualified && item.status != WeaklyQualified {
reportersToReward.deleteFlip(flipIdx)
}
}
} else if _, ok := badAuthors[author]; !ok {
badAuthors[author] = types.QualifiedByNoneBadAuthor
Expand Down Expand Up @@ -1227,9 +1229,11 @@ func (vc *ValidationCeremony) analyzeAuthors(qualifications []FlipQualification,
for author := range badAuthors {
delete(goodAuthors, author)
reportersToReward.deleteReporter(author)
if _, ok := badAuthorsWithoutReport[author]; ok {
for _, flipIdx := range madeFlips[author] {
reportersToReward.deleteFlip(flipIdx)
if !rewardAnyReport {
if _, ok := badAuthorsWithoutReport[author]; ok {
for _, flipIdx := range madeFlips[author] {
reportersToReward.deleteFlip(flipIdx)
}
}
}
}
Expand Down
Loading

0 comments on commit 08175f7

Please sign in to comment.