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

Update RestakeRewards boolean to a RewardMethod enum #612

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 30 additions & 17 deletions lib/block_view_stake.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,17 @@ import (
// TYPES: StakeEntry
//

type StakingRewardMethod = uint8

const (
StakingRewardMethodPayToBalance StakingRewardMethod = iota
StakingRewardMethodRestake StakingRewardMethod = 1
)

type StakeEntry struct {
StakerPKID *PKID
ValidatorPKID *PKID
RestakeRewards bool
RewardMethod StakingRewardMethod
StakeAmountNanos *uint256.Int
ExtraData map[string][]byte
isDeleted bool
Expand All @@ -50,7 +57,7 @@ func (stakeEntry *StakeEntry) Copy() *StakeEntry {
return &StakeEntry{
StakerPKID: stakeEntry.StakerPKID.NewPKID(),
ValidatorPKID: stakeEntry.ValidatorPKID.NewPKID(),
RestakeRewards: stakeEntry.RestakeRewards,
RewardMethod: stakeEntry.RewardMethod,
StakeAmountNanos: stakeEntry.StakeAmountNanos.Clone(),
ExtraData: copyExtraData(stakeEntry.ExtraData),
isDeleted: stakeEntry.isDeleted,
Expand All @@ -72,7 +79,7 @@ func (stakeEntry *StakeEntry) RawEncodeWithoutMetadata(blockHeight uint64, skipM
var data []byte
data = append(data, EncodeToBytes(blockHeight, stakeEntry.StakerPKID, skipMetadata...)...)
data = append(data, EncodeToBytes(blockHeight, stakeEntry.ValidatorPKID, skipMetadata...)...)
data = append(data, BoolToByte(stakeEntry.RestakeRewards))
data = append(data, stakeEntry.RewardMethod)
data = append(data, VariableEncodeUint256(stakeEntry.StakeAmountNanos)...)
data = append(data, EncodeExtraData(stakeEntry.ExtraData)...)
return data
Expand All @@ -93,10 +100,10 @@ func (stakeEntry *StakeEntry) RawDecodeWithoutMetadata(blockHeight uint64, rr *b
return errors.Wrapf(err, "StakeEntry.Decode: Problem reading ValidatorPKID: ")
}

// RestakeRewards
stakeEntry.RestakeRewards, err = ReadBoolByte(rr)
// RewardMethod
stakeEntry.RewardMethod, err = rr.ReadByte()
if err != nil {
return errors.Wrapf(err, "StakeEntry.Decode: Problem reading RestakeRewards")
return errors.Wrapf(err, "StakeEntry.Decode: Problem reading RewardMethod")
}

// StakeAmountNanos
Expand Down Expand Up @@ -224,7 +231,7 @@ func (lockedStakeEntry *LockedStakeEntry) GetEncoderType() EncoderType {

type StakeMetadata struct {
ValidatorPublicKey *PublicKey
RestakeRewards bool
RewardMethod StakingRewardMethod
StakeAmountNanos *uint256.Int
}

Expand All @@ -235,7 +242,7 @@ func (txnData *StakeMetadata) GetTxnType() TxnType {
func (txnData *StakeMetadata) ToBytes(preSignature bool) ([]byte, error) {
var data []byte
data = append(data, EncodeByteArray(txnData.ValidatorPublicKey.ToBytes())...)
data = append(data, BoolToByte(txnData.RestakeRewards))
data = append(data, txnData.RewardMethod)
data = append(data, VariableEncodeUint256(txnData.StakeAmountNanos)...)
return data, nil
}
Expand All @@ -250,10 +257,10 @@ func (txnData *StakeMetadata) FromBytes(data []byte) error {
}
txnData.ValidatorPublicKey = NewPublicKey(validatorPublicKeyBytes)

// RestakeRewards
txnData.RestakeRewards, err = ReadBoolByte(rr)
// RewardMethod
txnData.RewardMethod, err = rr.ReadByte()
if err != nil {
return errors.Wrapf(err, "StakeMetadata.FromBytes: Problem reading RestakeRewards: ")
return errors.Wrapf(err, "StakeMetadata.FromBytes: Problem reading RewardMethod: ")
}

// StakeAmountNanos
Expand Down Expand Up @@ -370,15 +377,15 @@ func (txnData *UnlockStakeMetadata) New() DeSoTxnMetadata {
type StakeTxindexMetadata struct {
StakerPublicKeyBase58Check string
ValidatorPublicKeyBase58Check string
RestakeRewards bool
RewardMethod StakingRewardMethod
StakeAmountNanos *uint256.Int
}

func (txindexMetadata *StakeTxindexMetadata) RawEncodeWithoutMetadata(blockHeight uint64, skipMetadata ...bool) []byte {
var data []byte
data = append(data, EncodeByteArray([]byte(txindexMetadata.StakerPublicKeyBase58Check))...)
data = append(data, EncodeByteArray([]byte(txindexMetadata.ValidatorPublicKeyBase58Check))...)
data = append(data, BoolToByte(txindexMetadata.RestakeRewards))
data = append(data, txindexMetadata.RewardMethod)
data = append(data, VariableEncodeUint256(txindexMetadata.StakeAmountNanos)...)
return data
}
Expand All @@ -400,10 +407,10 @@ func (txindexMetadata *StakeTxindexMetadata) RawDecodeWithoutMetadata(blockHeigh
}
txindexMetadata.ValidatorPublicKeyBase58Check = string(validatorPublicKeyBase58CheckBytes)

// RestakeRewards
txindexMetadata.RestakeRewards, err = ReadBoolByte(rr)
// RewardMethod
txindexMetadata.RewardMethod, err = rr.ReadByte()
if err != nil {
return errors.Wrapf(err, "StakeTxindexMetadata.Decode: Problem reading RestakeRewards: ")
return errors.Wrapf(err, "StakeTxindexMetadata.Decode: Problem reading RewardMethod: ")
}

// StakeAmountNanos
Expand Down Expand Up @@ -1354,7 +1361,7 @@ func (bav *UtxoView) _connectStake(
currentStakeEntry := &StakeEntry{
StakerPKID: transactorPKIDEntry.PKID,
ValidatorPKID: prevValidatorEntry.ValidatorPKID,
RestakeRewards: txMeta.RestakeRewards,
RewardMethod: txMeta.RewardMethod,
StakeAmountNanos: stakeAmountNanos,
ExtraData: mergeExtraData(prevExtraData, txn.ExtraData),
}
Expand Down Expand Up @@ -1979,6 +1986,11 @@ func (bav *UtxoView) IsValidStakeMetadata(transactorPkBytes []byte, metadata *St
return errors.Wrapf(RuleErrorInvalidStakeValidatorDisabledDelegatedStake, "UtxoView.IsValidStakeMetadata: ")
}

// Validate RewardMethod.
if metadata.RewardMethod != StakingRewardMethodPayToBalance && metadata.RewardMethod != StakingRewardMethodRestake {
return errors.Wrapf(RuleErrorInvalidStakingRewardMethod, "UtxoView.IsValidStakeMetadata: ")
}

// Validate 0 <= StakeAmountNanos <= transactor's DESO Balance. We ignore
// the txn fees in this check. The StakeAmountNanos will be validated to
// be less than the transactor's DESO balance net of txn fees in the call
Expand Down Expand Up @@ -3092,6 +3104,7 @@ func (bav *UtxoView) IsValidStakeLimitKey(transactorPublicKeyBytes []byte, stake
//

const RuleErrorInvalidStakerPKID RuleError = "RuleErrorInvalidStakerPKID"
const RuleErrorInvalidStakingRewardMethod RuleError = "RuleErrorInvalidStakingRewardMethod"
const RuleErrorInvalidStakeAmountNanos RuleError = "RuleErrorInvalidStakeAmountNanos"
const RuleErrorInvalidStakeInsufficientBalance RuleError = "RuleErrorInvalidStakeInsufficientBalance"
const RuleErrorInvalidStakeValidatorDisabledDelegatedStake RuleError = "RuleErrorInvalidStakeValidatorDisabledDelegatedStake"
Expand Down
41 changes: 28 additions & 13 deletions lib/block_view_stake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func _testStaking(t *testing.T, flushToDB bool) {

stakeMetadata := &StakeMetadata{
ValidatorPublicKey: NewPublicKey(m0PkBytes),
RestakeRewards: false,
RewardMethod: StakingRewardMethodPayToBalance,
StakeAmountNanos: uint256.NewInt().SetUint64(100),
}
_, err = _submitStakeTxn(
Expand All @@ -142,7 +142,7 @@ func _testStaking(t *testing.T, flushToDB bool) {
// RuleErrorInvalidValidatorPKID
stakeMetadata := &StakeMetadata{
ValidatorPublicKey: NewPublicKey(m2PkBytes),
RestakeRewards: false,
RewardMethod: StakingRewardMethodPayToBalance,
StakeAmountNanos: uint256.NewInt(),
}
_, err = _submitStakeTxn(
Expand All @@ -151,11 +151,24 @@ func _testStaking(t *testing.T, flushToDB bool) {
require.Error(t, err)
require.Contains(t, err.Error(), RuleErrorInvalidValidatorPKID)
}
{
// RuleErrorInvalidStakingRewardMethod
stakeMetadata := &StakeMetadata{
ValidatorPublicKey: NewPublicKey(m0PkBytes),
RewardMethod: 99,
StakeAmountNanos: uint256.NewInt().SetUint64(1),
}
_, err = _submitStakeTxn(
testMeta, m1Pub, m1Priv, stakeMetadata, nil, flushToDB,
)
require.Error(t, err)
require.Contains(t, err.Error(), RuleErrorInvalidStakingRewardMethod)
}
{
// RuleErrorInvalidStakeAmountNanos
stakeMetadata := &StakeMetadata{
ValidatorPublicKey: NewPublicKey(m0PkBytes),
RestakeRewards: false,
RewardMethod: StakingRewardMethodPayToBalance,
StakeAmountNanos: nil,
}
_, err = _submitStakeTxn(
Expand All @@ -168,6 +181,7 @@ func _testStaking(t *testing.T, flushToDB bool) {
// RuleErrorInvalidStakeAmountNanos
stakeMetadata := &StakeMetadata{
ValidatorPublicKey: NewPublicKey(m0PkBytes),
RewardMethod: StakingRewardMethodPayToBalance,
StakeAmountNanos: uint256.NewInt(),
}
_, err = _submitStakeTxn(
Expand All @@ -180,6 +194,7 @@ func _testStaking(t *testing.T, flushToDB bool) {
// RuleErrorInvalidStakeAmountNanos
stakeMetadata := &StakeMetadata{
ValidatorPublicKey: NewPublicKey(m0PkBytes),
RewardMethod: StakingRewardMethodPayToBalance,
StakeAmountNanos: MaxUint256,
}
_, err = _submitStakeTxn(
Expand All @@ -192,7 +207,7 @@ func _testStaking(t *testing.T, flushToDB bool) {
// RuleErrorInvalidStakeInsufficientBalance
stakeMetadata := &StakeMetadata{
ValidatorPublicKey: NewPublicKey(m0PkBytes),
RestakeRewards: false,
RewardMethod: StakingRewardMethodPayToBalance,
StakeAmountNanos: uint256.NewInt().SetUint64(math.MaxUint64),
}
_, err = _submitStakeTxn(
Expand All @@ -206,7 +221,7 @@ func _testStaking(t *testing.T, flushToDB bool) {
m1OldDESOBalanceNanos := getDESOBalanceNanos(m1PkBytes)
stakeMetadata := &StakeMetadata{
ValidatorPublicKey: NewPublicKey(m0PkBytes),
RestakeRewards: false,
RewardMethod: StakingRewardMethodPayToBalance,
StakeAmountNanos: uint256.NewInt().SetUint64(100),
}
extraData := map[string][]byte{"TestKey": []byte("TestValue")}
Expand All @@ -219,7 +234,7 @@ func _testStaking(t *testing.T, flushToDB bool) {
stakeEntry, err := utxoView().GetStakeEntry(m0PKID, m1PKID)
require.NoError(t, err)
require.NotNil(t, stakeEntry)
require.False(t, stakeEntry.RestakeRewards)
require.Equal(t, stakeEntry.RewardMethod, StakingRewardMethodPayToBalance)
require.Equal(t, stakeEntry.StakeAmountNanos, uint256.NewInt().SetUint64(100))
require.Equal(t, stakeEntry.ExtraData["TestKey"], []byte("TestValue"))

Expand All @@ -238,7 +253,7 @@ func _testStaking(t *testing.T, flushToDB bool) {
m1OldDESOBalanceNanos := getDESOBalanceNanos(m1PkBytes)
stakeMetadata := &StakeMetadata{
ValidatorPublicKey: NewPublicKey(m0PkBytes),
RestakeRewards: false,
RewardMethod: StakingRewardMethodPayToBalance,
StakeAmountNanos: uint256.NewInt().SetUint64(50),
}
extraData := map[string][]byte{"TestKey": []byte("TestValue2")}
Expand All @@ -251,7 +266,7 @@ func _testStaking(t *testing.T, flushToDB bool) {
stakeEntry, err := utxoView().GetStakeEntry(m0PKID, m1PKID)
require.NoError(t, err)
require.NotNil(t, stakeEntry)
require.False(t, stakeEntry.RestakeRewards)
require.Equal(t, stakeEntry.RewardMethod, StakingRewardMethodPayToBalance)
require.Equal(t, stakeEntry.StakeAmountNanos, uint256.NewInt().SetUint64(150))
require.Equal(t, stakeEntry.ExtraData["TestKey"], []byte("TestValue2"))

Expand All @@ -266,11 +281,11 @@ func _testStaking(t *testing.T, flushToDB bool) {
require.Equal(t, m1OldDESOBalanceNanos-feeNanos-stakeMetadata.StakeAmountNanos.Uint64(), m1NewDESOBalanceNanos)
}
{
// m1 changes the RestakeRewards flag on their stake with m0.
// m1 changes the RewardMethod value on their stake with m0.
m1OldDESOBalanceNanos := getDESOBalanceNanos(m1PkBytes)
stakeMetadata := &StakeMetadata{
ValidatorPublicKey: NewPublicKey(m0PkBytes),
RestakeRewards: true,
RewardMethod: StakingRewardMethodRestake,
StakeAmountNanos: uint256.NewInt(),
}
extraData := map[string][]byte{"TestKey": []byte("TestValue2")}
Expand All @@ -286,8 +301,8 @@ func _testStaking(t *testing.T, flushToDB bool) {
require.Equal(t, stakeEntry.StakeAmountNanos, uint256.NewInt().SetUint64(150))
require.Equal(t, stakeEntry.ExtraData["TestKey"], []byte("TestValue2"))

// Verify the StakeEntry.RestakeRewards flag is updated to true.
require.True(t, stakeEntry.RestakeRewards)
// Verify the StakeEntry.RewardMethod has changed to StakingRewardMethodRestake.
require.Equal(t, stakeEntry.RewardMethod, StakingRewardMethodRestake)

// Verify the ValidatorEntry.TotalStakeAmountNanos does not change.
validatorEntry, err := utxoView().GetValidatorByPKID(m0PKID)
Expand Down Expand Up @@ -1725,7 +1740,7 @@ func _testGetTopStakesByStakeAmount(t *testing.T, flushToDB bool) {
constructAndSubmitStakeTxn := func(stakerPk string, stakerPriv string, validatorPkBytes []byte, amountNanos uint64) {
stakeMetadata := &StakeMetadata{
ValidatorPublicKey: NewPublicKey(validatorPkBytes),
RestakeRewards: false,
RewardMethod: StakingRewardMethodPayToBalance,
StakeAmountNanos: uint256.NewInt().SetUint64(amountNanos),
}
_, err := _submitStakeTxn(testMeta, stakerPk, stakerPriv, stakeMetadata, nil, flushToDB)
Expand Down
13 changes: 9 additions & 4 deletions lib/pos_epoch_complete_hook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,14 @@ func TestRunEpochCompleteHook(t *testing.T) {
_, err = _submitRegisterAsValidatorTxn(testMeta, publicKey, privateKey, registerMetadata, nil, true)
require.NoError(t, err)

rewardMethod := StakingRewardMethodPayToBalance
if restakeRewards {
rewardMethod = StakingRewardMethodRestake
}

stakeMetadata := &StakeMetadata{
ValidatorPublicKey: NewPublicKey(pkBytes),
RestakeRewards: restakeRewards,
RewardMethod: rewardMethod,
StakeAmountNanos: uint256.NewInt().SetUint64(stakeAmountNanos),
}
_, err = _submitStakeTxn(testMeta, publicKey, privateKey, stakeMetadata, nil, true)
Expand Down Expand Up @@ -462,7 +467,7 @@ func TestRunEpochCompleteHook(t *testing.T) {
require.Len(t, snapshotStakeEntries, 6)
}
{
// Test staking rewards distribution with RestakeRewards enabled.
// Test staking rewards distribution with restaking enabled.

// m6 now has a 14333333578 nano balance from staking rewards so far.
balance, err := utxoView().GetDeSoBalanceNanosForPublicKey(m6PkBytes)
Expand All @@ -478,14 +483,14 @@ func TestRunEpochCompleteHook(t *testing.T) {
require.Equal(t, balance, uint64(16747126681))
}
{
// Test staking rewards distribution with RestakeRewards enabled.
// Test staking rewards distribution with restaking enabled.

// m6 has 700 nanos staked.
stakeEntry, err := utxoView().GetStakeEntry(m6PKID, m6PKID)
require.NoError(t, err)
require.Equal(t, stakeEntry.StakeAmountNanos, uint256.NewInt().SetUint64(700))

// m6 sets their RestakeRewards flag to true.
// m6 enables restaking.
_registerAndStake(m6Pub, m6Priv, 0, true)

// m6's wallet balance is 16747126627 after they submit their stake transaction.
Expand Down
2 changes: 1 addition & 1 deletion lib/pos_snapshot_entries.go
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ type SnapshotStakeMapKey struct {
// This is a bare bones in-memory only construct used to capture the ValidatorPKID,
// StakerPKID, and StakeAmountNanos from a StakeEntry that has been snapshotted. We
// define a new type here rather than re-using the StakeEntry type to reduce the risk
// of bugs. The StakeEntry type has additional fields (ex: RestakeRewards, ExtraData)
// of bugs. The StakeEntry type has additional fields (ex: RewardMethod, ExtraData)
// that are not snapshotted.
type SnapshotStakeEntry struct {
SnapshotAtEpochNumber uint64
Expand Down
2 changes: 1 addition & 1 deletion lib/pos_staking_rewards.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (bav *UtxoView) DistributeStakingRewardsToSnapshotStakes(blockHeight uint64
// StakeEntry. Their stake is currently in lockup.

// For case 1, we distribute the rewards by adding them to the staker's staked amount.
if stakeEntry != nil && stakeEntry.RestakeRewards {
if stakeEntry != nil && stakeEntry.RewardMethod == StakingRewardMethodRestake {
stakeEntry.StakeAmountNanos.Add(stakeEntry.StakeAmountNanos, rewardAmount)
bav._setStakeEntryMappings(stakeEntry)

Expand Down