Skip to content

Commit

Permalink
Merge pull request #132 from decentrio/patch-2
Browse files Browse the repository at this point in the history
Patch 2: Fix UnbondingQueueKey
  • Loading branch information
jiujiteiro authored Apr 2, 2024
2 parents 688ea0b + 5299d5a commit 8675108
Show file tree
Hide file tree
Showing 2 changed files with 281 additions and 1 deletion.
152 changes: 152 additions & 0 deletions app/fork_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package app

import (
"fmt"
"testing"
"time"

"cosmossdk.io/math"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/stretchr/testify/require"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"

sdk "github.com/cosmos/cosmos-sdk/types"
)

var oneEnternityLater = time.Date(9999, 9, 9, 9, 9, 9, 9, time.UTC)

func TestFork(t *testing.T) {
realio := Setup(false, nil)

ctx := realio.BaseApp.NewContext(false, tmproto.Header{Height: int64(ForkHeight)})
stakingKeeper := realio.StakingKeeper

timeKey := time.Date(2024, 4, 1, 1, 1, 1, 1, time.UTC)

duplicativeUnbondingDelegation := stakingtypes.UnbondingDelegation{
DelegatorAddress: "test_del_1",
ValidatorAddress: "test_val_1",
Entries: []stakingtypes.UnbondingDelegationEntry{
stakingtypes.NewUnbondingDelegationEntry(int64(ForkHeight), timeKey, math.OneInt()),
},
}

stakingKeeper.InsertUBDQueue(ctx, duplicativeUnbondingDelegation, timeKey)
stakingKeeper.InsertUBDQueue(ctx, duplicativeUnbondingDelegation, timeKey)

duplicativeRedelegation := stakingtypes.Redelegation{
DelegatorAddress: "test_del_1",
ValidatorSrcAddress: "test_val_1",
ValidatorDstAddress: "test_val_2",
Entries: []stakingtypes.RedelegationEntry{
stakingtypes.NewRedelegationEntry(int64(ForkHeight), timeKey, math.OneInt(), sdk.OneDec()),
},
}
stakingKeeper.InsertRedelegationQueue(ctx, duplicativeRedelegation, timeKey)
stakingKeeper.InsertRedelegationQueue(ctx, duplicativeRedelegation, timeKey)
stakingKeeper.InsertRedelegationQueue(ctx, duplicativeRedelegation, timeKey)

duplicativeVal := stakingtypes.Validator{
OperatorAddress: "test_op",
UnbondingHeight: int64(ForkHeight),
UnbondingTime: timeKey,
}

stakingKeeper.InsertUnbondingValidatorQueue(ctx, duplicativeVal)
stakingKeeper.InsertUnbondingValidatorQueue(ctx, duplicativeVal)

require.True(t, checkDuplicateUBDQueue(ctx, *realio))
require.True(t, checkDuplicateRelegationQueue(ctx, *realio))
require.True(t, checkDuplicateValQueue(ctx, *realio))

realio.ScheduleForkUpgrade(ctx)

require.False(t, checkDuplicateUBDQueue(ctx, *realio))
require.False(t, checkDuplicateRelegationQueue(ctx, *realio))
require.False(t, checkDuplicateValQueue(ctx, *realio))

dvPairs := stakingKeeper.GetUBDQueueTimeSlice(ctx, timeKey)
require.Equal(t, dvPairs[0].DelegatorAddress, duplicativeUnbondingDelegation.DelegatorAddress)
require.Equal(t, dvPairs[0].ValidatorAddress, duplicativeUnbondingDelegation.ValidatorAddress)

triplets := stakingKeeper.GetRedelegationQueueTimeSlice(ctx, timeKey)
require.Equal(t, triplets[0].DelegatorAddress, duplicativeRedelegation.DelegatorAddress)
require.Equal(t, triplets[0].ValidatorDstAddress, duplicativeRedelegation.ValidatorDstAddress)
require.Equal(t, triplets[0].ValidatorSrcAddress, duplicativeRedelegation.ValidatorSrcAddress)

vals := stakingKeeper.GetUnbondingValidators(ctx, timeKey, int64(ForkHeight))
require.Equal(t, vals[0], duplicativeVal.OperatorAddress)

Check failure on line 79 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed (gofumpt)

Check failure on line 79 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed (gofumpt)
}

func checkDuplicateUBDQueue(ctx sdk.Context, realio RealioNetwork) bool {
ubdIter := realio.StakingKeeper.UBDQueueIterator(ctx, oneEnternityLater)
defer ubdIter.Close()

for ; ubdIter.Valid(); ubdIter.Next() {
timeslice := stakingtypes.DVPairs{}
value := ubdIter.Value()
realio.appCodec.MustUnmarshal(value, &timeslice)
if checkDuplicateUBD(timeslice.Pairs) {
return true
}
}
return false
}

func checkDuplicateUBD(eles []stakingtypes.DVPair) bool {

Check failure on line 97 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

`eles` is a misspelling of `eels` (misspell)

Check failure on line 97 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

`eles` is a misspelling of `eels` (misspell)
unique_eles := map[string]bool{}

Check failure on line 98 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

`eles` is a misspelling of `eels` (misspell)

Check failure on line 98 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

`eles` is a misspelling of `eels` (misspell)
for _, ele := range eles {

Check failure on line 99 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

`eles` is a misspelling of `eels` (misspell)

Check failure on line 99 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

`eles` is a misspelling of `eels` (misspell)
unique_eles[ele.String()] = true

Check failure on line 100 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

`eles` is a misspelling of `eels` (misspell)

Check failure on line 100 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

`eles` is a misspelling of `eels` (misspell)
}
fmt.Println(eles, "eles")

Check failure on line 102 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

`eles` is a misspelling of `eels` (misspell)

Check failure on line 102 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

`eles` is a misspelling of `eels` (misspell)

return len(unique_eles) != len(eles)

Check failure on line 104 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

`eles` is a misspelling of `eels` (misspell)

Check failure on line 104 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

`eles` is a misspelling of `eels` (misspell)
}

func checkDuplicateRelegationQueue(ctx sdk.Context, realio RealioNetwork) bool {
redeIter := realio.StakingKeeper.RedelegationQueueIterator(ctx, oneEnternityLater)
defer redeIter.Close()

for ; redeIter.Valid(); redeIter.Next() {
timeslice := stakingtypes.DVVTriplets{}
value := redeIter.Value()
realio.appCodec.MustUnmarshal(value, &timeslice)
if checkDuplicateRedelegation(timeslice.Triplets) {
return true
}
}
return false
}

func checkDuplicateRedelegation(eles []stakingtypes.DVVTriplet) bool {
unique_eles := map[string]bool{}
for _, ele := range eles {
unique_eles[ele.String()] = true
}

return len(unique_eles) != len(eles)
}

func checkDuplicateValQueue(ctx sdk.Context, realio RealioNetwork) bool {
valsIter := realio.StakingKeeper.ValidatorQueueIterator(ctx, oneEnternityLater, 9999)
defer valsIter.Close()

for ; valsIter.Valid(); valsIter.Next() {
timeslice := stakingtypes.ValAddresses{}
value := valsIter.Value()
realio.appCodec.MustUnmarshal(value, &timeslice)
if checkDuplicateValAddr(timeslice.Addresses) {
return true
}
}
return false
}

Check failure on line 144 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed (gofumpt)

Check failure on line 144 in app/fork_test.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed (gofumpt)
func checkDuplicateValAddr(eles []string) bool {
unique_eles := map[string]bool{}
for _, ele := range eles {
unique_eles[ele] = true
}

return len(unique_eles) != len(eles)
}
130 changes: 129 additions & 1 deletion app/forks.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package app

import (
"sort"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

var ForkHeight = 5989487

// ScheduleForkUpgrade executes any necessary fork logic for based upon the current
// block height and chain ID (mainnet or testnet). It sets an upgrade plan once
// the chain reaches the pre-defined upgrade height.
Expand All @@ -12,7 +18,14 @@ import (
//
// 1. Release a non-breaking patch version so that the chain can set the scheduled upgrade plan at upgrade-height.
// 2. Release the software defined in the upgrade-info
func (app *RealioNetwork) ScheduleForkUpgrade(_ sdk.Context) {
func (app *RealioNetwork) ScheduleForkUpgrade(ctx sdk.Context) {
if ctx.BlockHeight() == 5989487 {

// remove duplicate UnbondingQueueKey
removeDuplicateValueUnbondingQueueKey(app, ctx)
removeDuplicateValueRedelegationQueueKey(app, ctx)
removeDuplicateUnbondingValidator(app, ctx)
}
// NOTE: there are no testnet forks for the existing versions
// if !types.IsMainnet(ctx.ChainID()) {
// return
Expand Down Expand Up @@ -43,3 +56,118 @@ func (app *RealioNetwork) ScheduleForkUpgrade(_ sdk.Context) {
// )
//}
}

func removeDuplicateValueRedelegationQueueKey(app *RealioNetwork, ctx sdk.Context) {
// Get Staking keeper, codec and staking store
sk := app.StakingKeeper
cdc := app.AppCodec()
store := ctx.KVStore(app.keys[stakingtypes.ModuleName])

// remove duplicate UnbondingQueueKey
ubdTime := sk.UnbondingTime(ctx)
currTime := ctx.BlockTime()

redelegationTimesliceIterator := sk.RedelegationQueueIterator(ctx, currTime.Add(ubdTime)) // make sure to iterate all queue
defer redelegationTimesliceIterator.Close()

for ; redelegationTimesliceIterator.Valid(); redelegationTimesliceIterator.Next() {
timeslice := stakingtypes.DVVTriplets{}
value := redelegationTimesliceIterator.Value()
cdc.MustUnmarshal(value, &timeslice)

triplets := removeDuplicateDVVTriplets(timeslice.Triplets)
bz := cdc.MustMarshal(&stakingtypes.DVVTriplets{Triplets: triplets})

store.Set(redelegationTimesliceIterator.Key(), bz)
}

Check failure on line 83 in app/forks.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed (gofumpt)

Check failure on line 83 in app/forks.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed (gofumpt)
}

func removeDuplicateDVVTriplets(triplets []stakingtypes.DVVTriplet) []stakingtypes.DVVTriplet {
var list []stakingtypes.DVVTriplet
for _, item := range triplets {
if !containsDVVTriplets(list, item) {
list = append(list, item)
}
}
return list
}

func containsDVVTriplets(s []stakingtypes.DVVTriplet, e stakingtypes.DVVTriplet) bool {
for _, a := range s {
if a.DelegatorAddress == e.DelegatorAddress &&
a.ValidatorSrcAddress == e.ValidatorSrcAddress &&
a.ValidatorDstAddress == e.ValidatorDstAddress {
return true
}
}
return false
}

func removeDuplicateUnbondingValidator(app *RealioNetwork, ctx sdk.Context) {
valIter := app.StakingKeeper.ValidatorQueueIterator(ctx, time.Date(9999, 9, 9, 9, 9, 9, 9, time.UTC), 99999999999999)
defer valIter.Close()

for ; valIter.Valid(); valIter.Next() {
addrs := stakingtypes.ValAddresses{}
app.appCodec.MustUnmarshal(valIter.Value(), &addrs)

vals := map[string]bool{}
for _, valAddr := range addrs.Addresses {
vals[valAddr] = true
}

unique_addrs := []string{}

Check warning on line 120 in app/forks.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: don't use underscores in Go names; var unique_addrs should be uniqueAddrs (revive)

Check warning on line 120 in app/forks.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: don't use underscores in Go names; var unique_addrs should be uniqueAddrs (revive)
for valAddr, _ := range vals {

Check failure on line 121 in app/forks.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed (gofumpt)

Check failure on line 121 in app/forks.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed (gofumpt)
unique_addrs = append(unique_addrs, valAddr)
}
sort.Strings(unique_addrs)

ctx.KVStore(app.GetKey(stakingtypes.StoreKey)).Set(valIter.Key(), app.appCodec.MustMarshal(&stakingtypes.ValAddresses{Addresses: unique_addrs}))
}
}

func removeDuplicateValueUnbondingQueueKey(app *RealioNetwork, ctx sdk.Context) {
// Get Staking keeper, codec and staking store
sk := app.StakingKeeper
cdc := app.AppCodec()
store := ctx.KVStore(app.keys[stakingtypes.ModuleName])

// remove duplicate UnbondingQueueKey
ubdTime := sk.UnbondingTime(ctx)
currTime := ctx.BlockTime()

unbondingTimesliceIterator := sk.UBDQueueIterator(ctx, currTime.Add(ubdTime)) // make sure to iterate all queue
defer unbondingTimesliceIterator.Close()

for ; unbondingTimesliceIterator.Valid(); unbondingTimesliceIterator.Next() {
timeslice := stakingtypes.DVPairs{}
value := unbondingTimesliceIterator.Value()
cdc.MustUnmarshal(value, &timeslice)

dvPairs := removeDuplicatesDVPairs(timeslice.Pairs)
bz := cdc.MustMarshal(&stakingtypes.DVPairs{Pairs: dvPairs})

store.Set(unbondingTimesliceIterator.Key(), bz)
}
}

func removeDuplicatesDVPairs(dvPairs []stakingtypes.DVPair) []stakingtypes.DVPair {
var list []stakingtypes.DVPair
for _, item := range dvPairs {
if !containsDVPairs(list, item) {
list = append(list, item)
}
}
return list
}

func containsDVPairs(s []stakingtypes.DVPair, e stakingtypes.DVPair) bool {
for _, a := range s {
if a.DelegatorAddress == e.DelegatorAddress &&
a.ValidatorAddress == e.ValidatorAddress {
return true
}
}
return false
}

0 comments on commit 8675108

Please sign in to comment.