Skip to content

Commit

Permalink
feat: add max voting power per pool (#191)
Browse files Browse the repository at this point in the history
  • Loading branch information
shifty11 authored May 27, 2024
1 parent f41fbb8 commit 0823dd8
Show file tree
Hide file tree
Showing 14 changed files with 368 additions and 74 deletions.
2 changes: 2 additions & 0 deletions app/upgrades/v1_5/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ func CreateUpgradeHandler(mm *module.Manager, configurator module.Configurator,

// TODO: migrate network fee and whitelist weights

// TODO: migrate MaxVotingPowerPerPool in pool params

return mm.RunMigrations(ctx, configurator, fromVM)
}
}
Expand Down
3 changes: 3 additions & 0 deletions docs/static/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4731,6 +4731,9 @@ paths:
pool_inflation_payout_rate:
type: string
description: pool_inflation_payout_rate ...
max_voting_power_per_pool:
type: string
description: max_voting_power_per_pool ...
funders_params:
description: funders_params ...
type: object
Expand Down
6 changes: 6 additions & 0 deletions proto/kyve/pool/v1beta1/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,10 @@ message Params {
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];

// max_voting_power_per_pool ...
string max_voting_power_per_pool = 3 [
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
}
8 changes: 4 additions & 4 deletions x/bundles/keeper/abci_protocol_split_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ var _ = Describe("abci.go", Ordered, func() {
s = i.NewCleanChain()
gov = s.App().GovKeeper.GetGovernanceAccount(s.Ctx()).GetAddress().String()

s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("0.1"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.1"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0.1")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.1")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// create clean pool for every test case
msg := &pooltypes.MsgCreatePool{
Expand Down
96 changes: 48 additions & 48 deletions x/bundles/keeper/keeper_suite_inflation_splitting_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ var _ = Describe("inflation splitting", Ordered, func() {

It("Produce a valid bundle with no funders and 0% inflation splitting", func() {
// ARRANGE
s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("0"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.1"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.1")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// mine some blocks
for i := 1; i < 100; i++ {
Expand Down Expand Up @@ -194,10 +194,10 @@ var _ = Describe("inflation splitting", Ordered, func() {

It("Produce a valid bundle with no funders and 10% inflation splitting", func() {
// ARRANGE
s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("0.1"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.1"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0.1")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.1")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// mine some blocks
for i := 1; i < 100; i++ {
Expand Down Expand Up @@ -287,10 +287,10 @@ var _ = Describe("inflation splitting", Ordered, func() {

It("Produce a valid bundle with no funders and 100% inflation splitting", func() {
// ARRANGE
s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("1"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.2"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0.1")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.2")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// mine some blocks
for i := 1; i < 100; i++ {
Expand Down Expand Up @@ -380,10 +380,10 @@ var _ = Describe("inflation splitting", Ordered, func() {

It("Produce a valid bundle with sufficient funders and 0% inflation splitting", func() {
// ARRANGE
s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("0"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.1"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.1")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// mine some blocks
for i := 1; i < 100; i++ {
Expand Down Expand Up @@ -486,10 +486,10 @@ var _ = Describe("inflation splitting", Ordered, func() {

It("Produce a valid bundle with sufficient funders and 10% inflation splitting", func() {
// ARRANGE
s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("0.1"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.3"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0.1")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.3")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// mine some blocks
for i := 1; i < 100; i++ {
Expand Down Expand Up @@ -593,10 +593,10 @@ var _ = Describe("inflation splitting", Ordered, func() {

It("Produce a valid bundle with sufficient funders and 100% inflation splitting", func() {
// ARRANGE
s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("1"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.1"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("1")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.1")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// mine some blocks
for i := 1; i < 100; i++ {
Expand Down Expand Up @@ -700,10 +700,10 @@ var _ = Describe("inflation splitting", Ordered, func() {

It("Produce a valid bundle with insufficient funders and 0% inflation splitting", func() {
// ARRANGE
s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("0"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.1"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.1")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// mine some blocks
for i := 1; i < 100; i++ {
Expand Down Expand Up @@ -805,10 +805,10 @@ var _ = Describe("inflation splitting", Ordered, func() {

It("Produce a valid bundle with insufficient funders and 30% inflation splitting", func() {
// ARRANGE
s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("0.1"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.3"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0.1")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.3")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// mine some blocks
for i := 1; i < 100; i++ {
Expand Down Expand Up @@ -912,10 +912,10 @@ var _ = Describe("inflation splitting", Ordered, func() {

It("Produce a valid bundle with insufficient funders and 10% inflation splitting", func() {
// ARRANGE
s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("1"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.1"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("1")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.1")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// mine some blocks
for i := 1; i < 100; i++ {
Expand Down Expand Up @@ -1019,10 +1019,10 @@ var _ = Describe("inflation splitting", Ordered, func() {

It("Produce a valid bundle with some insufficient funders and 0% inflation splitting", func() {
// ARRANGE
s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("0"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.1"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.1")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// mine some blocks
for i := 1; i < 100; i++ {
Expand Down Expand Up @@ -1124,10 +1124,10 @@ var _ = Describe("inflation splitting", Ordered, func() {

It("Produce a valid bundle with some insufficient funders and 30% inflation splitting", func() {
// ARRANGE
s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("0.1"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.3"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0.1")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.3")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// mine some blocks
for i := 1; i < 100; i++ {
Expand Down Expand Up @@ -1231,10 +1231,10 @@ var _ = Describe("inflation splitting", Ordered, func() {

It("Produce a valid bundle with some insufficient funders and 10% inflation splitting", func() {
// ARRANGE
s.App().PoolKeeper.SetParams(s.Ctx(), pooltypes.Params{
ProtocolInflationShare: math.LegacyMustNewDecFromStr("1"),
PoolInflationPayoutRate: math.LegacyMustNewDecFromStr("0.1"),
})
params := pooltypes.DefaultParams()
params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("1")
params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.1")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

// mine some blocks
for i := 1; i < 100; i++ {
Expand Down
7 changes: 5 additions & 2 deletions x/bundles/keeper/logic_bundles.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@ func (k Keeper) AssertPoolCanRun(ctx sdk.Context, poolId uint64) error {
return types.ErrMinDelegationNotReached
}

// Error if the top staker has more than 50%
if highestDelegation*2 > totalDelegation {
maxVotingPower := k.poolKeeper.GetMaxVotingPowerPerPool(ctx)
maxDelegation := uint64(maxVotingPower.MulInt64(int64(totalDelegation)).TruncateInt64())

// Error if highest delegation exceeds max voting power
if highestDelegation > maxDelegation {
return types.ErrVotingPowerTooHigh
}

Expand Down
134 changes: 134 additions & 0 deletions x/bundles/keeper/logic_bundles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper_test

import (
"cosmossdk.io/errors"
"cosmossdk.io/math"
i "github.com/KYVENetwork/chain/testutil/integration"
bundlesTypes "github.com/KYVENetwork/chain/x/bundles/types"
funderstypes "github.com/KYVENetwork/chain/x/funders/types"
Expand All @@ -18,6 +19,9 @@ TEST CASES - logic_bundles.go
* Assert pool can run while pool is upgrading
* Assert pool can run while pool is disabled
* Assert pool can run while min delegation is not reached
* Assert pool can run while voting power of one node is too high
* Assert pool can run while voting power of one node is 40%
* Assert pool can run while voting power of one node exceeds 40%
* Assert pool can run
* Assert pool can run while pool has no funds
* Assert pool can run when endKey is reached
Expand Down Expand Up @@ -248,6 +252,136 @@ var _ = Describe("logic_bundles.go", Ordered, func() {
Expect(err).To(Equal(bundlesTypes.ErrVotingPowerTooHigh))
})

It("Assert pool can run while voting power of one node is 40%", func() {
// ARRANGE
msg := &pooltypes.MsgCreatePool{
Authority: gov,
Name: "PoolTest",
Runtime: "@kyve/test",
Logo: "ar://Tewyv2P5VEG8EJ6AUQORdqNTectY9hlOrWPK8wwo-aU",
Config: "ar://DgdB-2hLrxjhyEEbCML__dgZN5_uS7T6Z5XDkaFh3P0",
StartKey: "0",
UploadInterval: 60,
InflationShareWeight: 10_000,
MinDelegation: 100 * i.KYVE,
MaxBundleSize: 100,
Version: "0.0.0",
Binaries: "{}",
StorageProviderId: 2,
CompressionId: 1,
}
s.RunTxPoolSuccess(msg)

s.RunTxStakersSuccess(&stakertypes.MsgCreateStaker{
Creator: i.STAKER_0,
Amount: 300 * i.KYVE,
})

s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{
Creator: i.STAKER_0,
PoolId: 0,
Valaddress: i.VALADDRESS_0_A,
Amount: 0,
})

s.RunTxStakersSuccess(&stakertypes.MsgCreateStaker{
Creator: i.STAKER_1,
Amount: 300 * i.KYVE,
})

s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{
Creator: i.STAKER_1,
PoolId: 0,
Valaddress: i.VALADDRESS_1_A,
Amount: 0,
})

s.RunTxStakersSuccess(&stakertypes.MsgCreateStaker{
Creator: i.STAKER_2,
Amount: 400 * i.KYVE,
})

s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{
Creator: i.STAKER_2,
PoolId: 0,
Valaddress: i.VALADDRESS_2_A,
Amount: 0,
})

// ACT
err := s.App().BundlesKeeper.AssertPoolCanRun(s.Ctx(), 0)

// ASSERT
Expect(err).NotTo(HaveOccurred())
})

It("Assert pool can run while voting power of one node exceeds 40%", func() {
// ARRANGE
params := s.App().PoolKeeper.GetParams(s.Ctx())
params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("0.4")
s.App().PoolKeeper.SetParams(s.Ctx(), params)

msg := &pooltypes.MsgCreatePool{
Authority: gov,
Name: "PoolTest",
Runtime: "@kyve/test",
Logo: "ar://Tewyv2P5VEG8EJ6AUQORdqNTectY9hlOrWPK8wwo-aU",
Config: "ar://DgdB-2hLrxjhyEEbCML__dgZN5_uS7T6Z5XDkaFh3P0",
StartKey: "0",
UploadInterval: 60,
InflationShareWeight: 10_000,
MinDelegation: 100 * i.KYVE,
MaxBundleSize: 100,
Version: "0.0.0",
Binaries: "{}",
StorageProviderId: 2,
CompressionId: 1,
}
s.RunTxPoolSuccess(msg)

s.RunTxStakersSuccess(&stakertypes.MsgCreateStaker{
Creator: i.STAKER_0,
Amount: 300 * i.KYVE,
})

s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{
Creator: i.STAKER_0,
PoolId: 0,
Valaddress: i.VALADDRESS_0_A,
Amount: 0,
})

s.RunTxStakersSuccess(&stakertypes.MsgCreateStaker{
Creator: i.STAKER_1,
Amount: 300 * i.KYVE,
})

s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{
Creator: i.STAKER_1,
PoolId: 0,
Valaddress: i.VALADDRESS_1_A,
Amount: 0,
})

s.RunTxStakersSuccess(&stakertypes.MsgCreateStaker{
Creator: i.STAKER_2,
Amount: 401 * i.KYVE,
})

s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{
Creator: i.STAKER_2,
PoolId: 0,
Valaddress: i.VALADDRESS_2_A,
Amount: 0,
})

// ACT
err := s.App().BundlesKeeper.AssertPoolCanRun(s.Ctx(), 0)

// ASSERT
Expect(err).To(Equal(bundlesTypes.ErrVotingPowerTooHigh))
})

It("Assert pool can run", func() {
// ARRANGE
s.RunTxStakersSuccess(&stakertypes.MsgCreateStaker{
Expand Down
Loading

0 comments on commit 0823dd8

Please sign in to comment.