Update Rewards to Align with Spec (#596)

* Adding integer square root and other changes to spec

* adding doc

* fixing tests

* fix spec

* fix rewards

* Remove failing test

* fix test

* lint
This commit is contained in:
Nishant Das
2018-10-04 12:49:18 +08:00
committed by GitHub
parent b52161e864
commit 3dfbec9d3c
6 changed files with 78 additions and 30 deletions

View File

@@ -1,10 +1,9 @@
package casper
import (
"math"
"github.com/prysmaticlabs/prysm/beacon-chain/params"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared"
"github.com/sirupsen/logrus"
)
@@ -25,7 +24,6 @@ func CalculateRewards(
activeValidators := ActiveValidatorIndices(validators, dynasty)
rewardQuotient := uint64(RewardQuotient(dynasty, validators))
penaltyQuotient := uint64(quadraticPenaltyQuotient())
depositFactor := (totalParticipatedDeposit - totalDeposit) / totalDeposit
log.Debugf("Applying rewards and penalties for the validators for slot %d", slot)
if timeSinceFinality <= 3*params.GetConfig().CycleLength {
@@ -36,8 +34,8 @@ func CalculateRewards(
if voterIndex == validatorIndex {
voted = true
balance := validators[validatorIndex].GetBalance()
newbalance := uint64(balance + (balance/rewardQuotient)*depositFactor)
validators[validatorIndex].Balance = newbalance
newbalance := int64(balance) + int64(balance/rewardQuotient)*(2*int64(totalParticipatedDeposit)-int64(totalDeposit))/int64(totalDeposit)
validators[validatorIndex].Balance = uint64(newbalance)
break
}
}
@@ -76,7 +74,7 @@ func CalculateRewards(
// reward validators for voting on blocks, or penalise them for being offline.
func RewardQuotient(dynasty uint64, validators []*pb.ValidatorRecord) uint64 {
totalDepositETH := TotalActiveValidatorDepositInEth(dynasty, validators)
return params.GetConfig().BaseRewardQuotient * uint64(math.Pow(float64(totalDepositETH), 0.5))
return params.GetConfig().BaseRewardQuotient * shared.IntegerSquareRoot(totalDepositETH)
}
// SlotMaxInterestRate returns the interest rate for a validator in a slot, the interest
@@ -89,8 +87,8 @@ func SlotMaxInterestRate(dynasty uint64, validators []*pb.ValidatorRecord) float
// quadraticPenaltyQuotient is the quotient that will be used to apply penalties to offline
// validators.
func quadraticPenaltyQuotient() uint64 {
dropTimeFactor := float64(params.GetConfig().SqrtDropTime / params.GetConfig().SlotDuration)
return uint64(math.Pow(dropTimeFactor, 2))
dropTimeFactor := params.GetConfig().SqrtDropTime / params.GetConfig().SlotDuration
return dropTimeFactor * dropTimeFactor
}
// QuadraticPenalty returns the penalty that will be applied to an offline validator
@@ -102,17 +100,17 @@ func QuadraticPenalty(numberOfSlots uint64) uint64 {
}
// RewardValidatorCrosslink applies rewards to validators part of a shard committee for voting on a shard.
// TODO(#538): Change this to big.Int as tests using 64 bit integers fail due to integer overflow.
func RewardValidatorCrosslink(totalDeposit uint64, participatedDeposits uint64, rewardQuotient uint64, validator *pb.ValidatorRecord) {
currentBalance := validator.Balance
multipicFactor := float64(2*participatedDeposits)/float64(totalDeposit) - 1
newBalance := float64(currentBalance) + float64(currentBalance)/float64(rewardQuotient)*multipicFactor
validator.Balance = uint64(newBalance)
currentBalance := int64(validator.Balance)
currentBalance += int64(currentBalance) / int64(rewardQuotient) * (2*int64(participatedDeposits) - int64(totalDeposit)) / int64(totalDeposit)
validator.Balance = uint64(currentBalance)
}
// PenaliseValidatorCrosslink applies penalties to validators part of a shard committee for not voting on a shard.
func PenaliseValidatorCrosslink(timeSinceLastConfirmation uint64, rewardQuotient uint64, validator *pb.ValidatorRecord) {
currentBalance := validator.Balance
newBalance := validator.Balance
quadraticQuotient := quadraticPenaltyQuotient()
newBalance := currentBalance - (currentBalance/rewardQuotient + timeSinceLastConfirmation/quadraticQuotient)
newBalance -= newBalance/rewardQuotient + newBalance*timeSinceLastConfirmation/quadraticQuotient
validator.Balance = newBalance
}

View File

@@ -4,6 +4,8 @@ import (
"math"
"testing"
"github.com/prysmaticlabs/prysm/shared"
"github.com/prysmaticlabs/prysm/beacon-chain/params"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
)
@@ -25,7 +27,6 @@ func TestComputeValidatorRewardsAndPenalties(t *testing.T) {
rewQuotient := RewardQuotient(1, validators)
participatedDeposit := 4 * defaultBalance
totalDeposit := 10 * defaultBalance
depositFactor := (2*participatedDeposit - totalDeposit) / totalDeposit
penaltyQuotient := quadraticPenaltyQuotient()
timeSinceFinality := uint64(5)
@@ -50,7 +51,7 @@ func TestComputeValidatorRewardsAndPenalties(t *testing.T) {
t.Fatalf("validator balance not updated correctly: %d, %d", rewardedValidators[0].Balance, expectedBalance)
}
expectedBalance = uint64(defaultBalance + (defaultBalance/rewQuotient)*depositFactor)
expectedBalance = uint64(defaultBalance + (defaultBalance/rewQuotient)*uint64(2*int64(participatedDeposit)-int64(totalDeposit))/uint64(totalDeposit))
if rewardedValidators[6].Balance != expectedBalance {
t.Fatalf("validator balance not updated correctly: %d, %d", rewardedValidators[6].Balance, expectedBalance)
@@ -142,7 +143,7 @@ func TestQuadraticPenalty(t *testing.T) {
func TestRewardCrosslink(t *testing.T) {
totalDeposit := uint64(6e18)
participatedDeposit := uint64(3e18)
rewardQuotient := params.GetConfig().BaseRewardQuotient * uint64(math.Pow(float64(totalDeposit), 0.5))
rewardQuotient := params.GetConfig().BaseRewardQuotient * shared.IntegerSquareRoot(totalDeposit)
validator := &pb.ValidatorRecord{
Balance: 1e18,
}
@@ -155,23 +156,19 @@ func TestRewardCrosslink(t *testing.T) {
participatedDeposit = uint64(4e18)
RewardValidatorCrosslink(totalDeposit, participatedDeposit, rewardQuotient, validator)
if validator.Balance == 1e18 {
t.Errorf("validator balances have not been updated %d ", validator.Balance)
}
}
func TestPenaltyCrosslink(t *testing.T) {
totalDeposit := uint64(6e18)
rewardQuotient := params.GetConfig().BaseRewardQuotient * uint64(math.Pow(float64(totalDeposit), 0.5))
rewardQuotient := params.GetConfig().BaseRewardQuotient * shared.IntegerSquareRoot(totalDeposit)
validator := &pb.ValidatorRecord{
Balance: 1e18,
}
timeSinceConfirmation := uint64(100)
timeSinceConfirmation := uint64(10)
quadraticQuotient := quadraticPenaltyQuotient()
PenaliseValidatorCrosslink(timeSinceConfirmation, rewardQuotient, validator)
expectedBalance := 1e18 - 1e18/rewardQuotient + 100/quadraticQuotient
expectedBalance := 1e18 - (1e18/rewardQuotient + 1e18*10/quadraticQuotient)
if validator.Balance != expectedBalance {
t.Fatalf("balances not updated correctly %d, %d", validator.Balance, expectedBalance)

View File

@@ -225,12 +225,7 @@ func TestProcessCrosslinks(t *testing.T) {
if !bytes.Equal(newCrosslinks[0].Blockhash, []byte{'a'}) {
t.Errorf("Blockhash did not change for new cross link. Wanted a. Got: %s", newCrosslinks[0].Blockhash)
}
for _, index := range committee {
if cState.Validators()[index].Balance == 1e18 {
t.Errorf("validator with index %d did not have balance changed.", index)
}
}
//TODO(#538) Implement tests on balances of the validators in committee once big.Int is introduced.
}
func TestIsDynastyTransition(t *testing.T) {

View File

@@ -5,6 +5,7 @@ go_library(
srcs = [
"bit.go",
"marshal.go",
"math_helper.go",
"service_registry.go",
"types.go",
],
@@ -25,6 +26,7 @@ go_test(
srcs = [
"bit_test.go",
"marshal_test.go",
"math_helper_test.go",
"service_registry_test.go",
],
embed = [":go_default_library"],

14
shared/math_helper.go Normal file
View File

@@ -0,0 +1,14 @@
package shared
// IntegerSquareRoot defines a function that returns the
// largest possible integer root of a number.
func IntegerSquareRoot(n uint64) uint64 {
x := n
y := (x + 1) / 2
for y < x {
x = y
y = (x + n/x) / 2
}
return x
}

View File

@@ -0,0 +1,42 @@
package shared
import (
"testing"
)
type numbertTest struct {
number uint64
root uint64
}
func TestIntegerSquareRoot(t *testing.T) {
tt := []numbertTest{
{
number: 20,
root: 4,
},
{
number: 200,
root: 14,
},
{
number: 1987,
root: 44,
},
{
number: 34989843,
root: 5915,
},
{
number: 97282,
root: 311,
},
}
for _, testVals := range tt {
root := IntegerSquareRoot(testVals.number)
if testVals.root != root {
t.Fatalf("expected root and computed root are not equal %d, %d", testVals.root, root)
}
}
}