From 9846ea7c6fef189d40a63ae40b7c177476728d0a Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Fri, 13 Dec 2024 10:25:54 +0100 Subject: [PATCH 01/15] feat: pool commission & stake fraction --- docs/static/openapi.yml | 32 + proto/kyve/stakers/v1beta1/events.proto | 28 +- proto/kyve/stakers/v1beta1/genesis.proto | 4 + proto/kyve/stakers/v1beta1/params.proto | 19 + proto/kyve/stakers/v1beta1/stakers.proto | 39 +- proto/kyve/stakers/v1beta1/tx.proto | 45 +- testutil/integration/checks.go | 21 +- testutil/integration/integration.go | 34 + util/expected_keepers.go | 5 +- x/bundles/keeper/abci_protocol_split_test.go | 64 +- x/bundles/keeper/keeper.go | 27 +- .../keeper_suite_dropped_bundles_test.go | 24 +- .../keeper_suite_funding_bundles_test.go | 16 +- .../keeper_suite_inflation_splitting_test.go | 81 +- .../keeper_suite_invalid_bundles_test.go | 72 +- x/bundles/keeper/keeper_suite_points_test.go | 30 +- .../keeper/keeper_suite_stakers_leave_test.go | 98 ++- .../keeper/keeper_suite_valid_bundles_test.go | 54 +- .../keeper_suite_zero_delegation_test.go | 144 ++-- x/bundles/keeper/logic_bundles.go | 62 +- x/bundles/keeper/logic_bundles_test.go | 410 ++++++---- .../logic_end_block_handle_upload_timeout.go | 4 +- ...ic_end_block_handle_upload_timeout_test.go | 145 ++-- x/bundles/keeper/logic_round_robin.go | 2 +- x/bundles/keeper/logic_round_robin_test.go | 10 +- .../msg_server_claim_uploader_role_test.go | 24 +- .../msg_server_skip_uploader_role_test.go | 24 +- .../msg_server_submit_bundle_proposal_test.go | 16 +- .../msg_server_vote_bundle_proposal_test.go | 24 +- x/bundles/module.go | 2 - x/bundles/types/expected_keepers.go | 19 +- .../keeper/msg_server_redelegate_test.go | 10 +- .../keeper/msg_server_undelegate_test.go | 10 +- x/pool/keeper/msg_server_disable_pool_test.go | 70 +- .../keeper/grpc_account_redelegation_test.go | 10 +- x/query/keeper/grpc_query_can_propose_test.go | 20 +- .../keeper/grpc_query_can_validate_test.go | 20 +- x/query/keeper/grpc_query_can_vote_test.go | 20 +- x/stakers/client/cli/tx.go | 1 + x/stakers/client/cli/tx_join_pool.go | 25 +- x/stakers/client/cli/tx_update_commission.go | 15 +- .../client/cli/tx_update_stake_fraction.go | 51 ++ x/stakers/genesis.go | 9 + x/stakers/keeper/exported_functions.go | 97 ++- x/stakers/keeper/getters_commission.go | 10 +- x/stakers/keeper/getters_params.go | 34 + x/stakers/keeper/getters_stake_fraction.go | 90 +++ x/stakers/keeper/getters_staker.go | 29 +- x/stakers/keeper/getters_valaccount.go | 49 +- x/stakers/keeper/logic_commission.go | 21 +- x/stakers/keeper/logic_leave.go | 6 +- x/stakers/keeper/logic_stake_fraction.go | 70 ++ x/stakers/keeper/logic_stakers.go | 17 +- x/stakers/keeper/msg_server_join_pool.go | 16 +- x/stakers/keeper/msg_server_join_pool_test.go | 593 +++++++++++---- x/stakers/keeper/msg_server_leave_pool.go | 4 +- .../keeper/msg_server_leave_pool_test.go | 82 +- .../keeper/msg_server_update_commission.go | 14 +- .../msg_server_update_commission_test.go | 281 +++++++ .../keeper/msg_server_update_params_test.go | 289 +++++++ .../msg_server_update_stake_fraction.go | 51 ++ .../msg_server_update_stake_fraction_test.go | 407 ++++++++++ x/stakers/module.go | 1 + x/stakers/types/codec.go | 2 + x/stakers/types/errors.go | 1 + x/stakers/types/events.pb.go | 467 +++++++++++- x/stakers/types/genesis.go | 18 + x/stakers/types/genesis.pb.go | 176 ++++- x/stakers/types/keys.go | 24 +- x/stakers/types/message_join_pool.go | 8 + .../types/message_update_stake_fraction.go | 48 ++ x/stakers/types/params.go | 45 +- x/stakers/types/params.pb.go | 220 +++++- x/stakers/types/stakers.pb.go | 571 ++++++++++++-- x/stakers/types/tx.pb.go | 714 ++++++++++++++++-- 75 files changed, 5124 insertions(+), 1171 deletions(-) create mode 100644 x/stakers/client/cli/tx_update_stake_fraction.go create mode 100644 x/stakers/keeper/getters_stake_fraction.go create mode 100644 x/stakers/keeper/logic_stake_fraction.go create mode 100644 x/stakers/keeper/msg_server_update_commission_test.go create mode 100644 x/stakers/keeper/msg_server_update_stake_fraction.go create mode 100644 x/stakers/keeper/msg_server_update_stake_fraction_test.go create mode 100644 x/stakers/types/message_update_stake_fraction.go diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index b7527647..13f9bec0 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -4698,6 +4698,19 @@ paths: type: string format: uint64 description: commission_change_time ... + stake_fraction_change_time: + type: string + format: uint64 + description: stake_fraction_change_time ... + vote_slash: + type: string + description: vote_slash ... + upload_slash: + type: string + description: upload_slash ... + timeout_slash: + type: string + description: timeout_slash ... pool_params: description: pool_params ... type: object @@ -7545,6 +7558,12 @@ paths: description: >- isLeaving indicates if a staker is leaving the given pool. + commission: + type: string + description: commission ... + stake_fraction: + type: string + description: stake_fraction ... description: StakerPoolResponse ... description: stakers ... description: >- @@ -9899,6 +9918,19 @@ paths: type: string format: uint64 description: commission_change_time ... + stake_fraction_change_time: + type: string + format: uint64 + description: stake_fraction_change_time ... + vote_slash: + type: string + description: vote_slash ... + upload_slash: + type: string + description: upload_slash ... + timeout_slash: + type: string + description: timeout_slash ... description: >- QueryParamsResponse is response type for the Query/Params RPC method. diff --git a/proto/kyve/stakers/v1beta1/events.proto b/proto/kyve/stakers/v1beta1/events.proto index 381f358e..78a7313a 100644 --- a/proto/kyve/stakers/v1beta1/events.proto +++ b/proto/kyve/stakers/v1beta1/events.proto @@ -24,8 +24,24 @@ message EventUpdateParams { message EventUpdateCommission { // staker is the account address of the protocol node. string staker = 1; + // pool_id ... + uint64 pool_id = 2; // commission ... - string commission = 2 [ + string commission = 3 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; +} + +// EventUpdateCommission ... +// emitted_by: MsgUpdateStakeFraction, EndBlock +message EventUpdateStakeFraction { + // staker is the account address of the protocol node. + string staker = 1; + // pool_id ... + uint64 pool_id = 2; + // stake_fraction ... + string stake_fraction = 3 [ (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", (gogoproto.nullable) = false ]; @@ -52,6 +68,16 @@ message EventJoinPool { string valaddress = 3; // amount is the amount of funds transferred to the valaddress uint64 amount = 4; + // commission ... + string commission = 5 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; + // stake_fraction ... + string stake_fraction = 6 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; } // EventLeavePool ... diff --git a/proto/kyve/stakers/v1beta1/genesis.proto b/proto/kyve/stakers/v1beta1/genesis.proto index 7c85c711..01c285e8 100644 --- a/proto/kyve/stakers/v1beta1/genesis.proto +++ b/proto/kyve/stakers/v1beta1/genesis.proto @@ -24,4 +24,8 @@ message GenesisState { repeated LeavePoolEntry leave_pool_entries = 6 [(gogoproto.nullable) = false]; // queue_state_leave ... QueueState queue_state_leave = 7 [(gogoproto.nullable) = false]; + // stake_fraction_change_entries ... + repeated StakeFractionChangeEntry stake_fraction_change_entries = 8 [(gogoproto.nullable) = false]; + // queue_state_state_fraction ... + QueueState queue_state_state_fraction = 9 [(gogoproto.nullable) = false]; } diff --git a/proto/kyve/stakers/v1beta1/params.proto b/proto/kyve/stakers/v1beta1/params.proto index 551c9e54..4a524231 100644 --- a/proto/kyve/stakers/v1beta1/params.proto +++ b/proto/kyve/stakers/v1beta1/params.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package kyve.stakers.v1beta1; +import "gogoproto/gogo.proto"; + option go_package = "github.com/KYVENetwork/chain/x/stakers/types"; // Params defines the stakers module parameters. @@ -10,4 +12,21 @@ message Params { uint64 commission_change_time = 1; // commission_change_time ... uint64 leave_pool_time = 2; + // stake_fraction_change_time ... + uint64 stake_fraction_change_time = 3; + // vote_slash ... + string vote_slash = 4 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; + // upload_slash ... + string upload_slash = 5 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; + // timeout_slash ... + string timeout_slash = 6 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; } diff --git a/proto/kyve/stakers/v1beta1/stakers.proto b/proto/kyve/stakers/v1beta1/stakers.proto index a897ff52..af25cb08 100644 --- a/proto/kyve/stakers/v1beta1/stakers.proto +++ b/proto/kyve/stakers/v1beta1/stakers.proto @@ -54,6 +54,16 @@ message Valaccount { uint64 points = 4; // isLeaving indicates if a staker is leaving the given pool. bool is_leaving = 5; + // commission ... + string commission = 6 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; + // stake_fraction ... + string stake_fraction = 7 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; } // CommissionChangeEntry stores the information for an @@ -66,15 +76,40 @@ message CommissionChangeEntry { uint64 index = 1; // staker is the address of the affected staker string staker = 2; + // pool_id ... + uint64 pool_id = 3; // commission is the new commission which will // be applied after the waiting time is over. - string commission = 3 [ + string commission = 4 [ (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", (gogoproto.nullable) = false ]; // creation_date is the UNIX-timestamp in seconds // when the entry was created. - int64 creation_date = 4; + int64 creation_date = 5; +} + +// StakeFractionChangeEntry stores the information for an +// upcoming stake fraction change. A stake fraction change is +// only instant if it gets increased, if it gets decreased +// the staker needs to wait for the stake fraction change time +message StakeFractionChangeEntry { + // index is needed for the queue-algorithm which + // processes the commission changes + uint64 index = 1; + // staker is the address of the affected staker + string staker = 2; + // pool_id ... + uint64 pool_id = 3; + // stake_fraction is the new stake fraction which will + // be applied after the waiting time is over. + string stake_fraction = 4 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; + // creation_date is the UNIX-timestamp in seconds + // when the entry was created. + int64 creation_date = 5; } // LeavePoolEntry stores the information for an upcoming diff --git a/proto/kyve/stakers/v1beta1/tx.proto b/proto/kyve/stakers/v1beta1/tx.proto index 1889f102..d765a2e2 100644 --- a/proto/kyve/stakers/v1beta1/tx.proto +++ b/proto/kyve/stakers/v1beta1/tx.proto @@ -11,25 +11,30 @@ option go_package = "github.com/KYVENetwork/chain/x/stakers/types"; // Msg defines the Msg service. service Msg { option (cosmos.msg.v1.service) = true; - // UpdateCommission ... - rpc UpdateCommission(MsgUpdateCommission) returns (MsgUpdateCommissionResponse); // JoinPool ... rpc JoinPool(MsgJoinPool) returns (MsgJoinPoolResponse); // LeavePool ... rpc LeavePool(MsgLeavePool) returns (MsgLeavePoolResponse); + // UpdateCommission ... + rpc UpdateCommission(MsgUpdateCommission) returns (MsgUpdateCommissionResponse); + // UpdateStakeFraction ... + rpc UpdateStakeFraction(MsgUpdateStakeFraction) returns (MsgUpdateStakeFractionResponse); + // UpdateParams defines a governance operation for updating the x/stakers module // parameters. The authority is hard-coded to the x/gov module account. rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); } -// MsgUpdateCommission ... +// MsgUpdateCommission ... // TODO: create v1 types and rename new to MsgUpdatePoolCommission message MsgUpdateCommission { option (cosmos.msg.v1.signer) = "creator"; // creator ... string creator = 1; + // pool_id ... + uint64 pool_id = 2; // commission ... - string commission = 2 [ + string commission = 3 [ (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", (gogoproto.nullable) = false ]; @@ -38,7 +43,24 @@ message MsgUpdateCommission { // MsgUpdateCommissionResponse ... message MsgUpdateCommissionResponse {} -// MsgJoinPool ... +// MsgUpdateStakeFraction ... +message MsgUpdateStakeFraction { + option (cosmos.msg.v1.signer) = "creator"; + // creator ... + string creator = 1; + // pool_id ... + uint64 pool_id = 2; + // commission ... + string stake_fraction = 3 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; +} + +// MsgUpdateStakeFractionResponse ... +message MsgUpdateStakeFractionResponse {} + +// MsgJoinPool ... // TODO: create v1 types message MsgJoinPool { option (cosmos.msg.v1.signer) = "creator"; // creator ... @@ -49,9 +71,16 @@ message MsgJoinPool { string valaddress = 3; // amount ... uint64 amount = 4; - - // TODO add stake fraction (in next PR) - // TODO add commission (in next PR) + // commission ... + string commission = 5 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; + // stake_fraction ... + string stake_fraction = 6 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; } // MsgJoinPoolResponse ... diff --git a/testutil/integration/checks.go b/testutil/integration/checks.go index cd6b14eb..94c1de37 100644 --- a/testutil/integration/checks.go +++ b/testutil/integration/checks.go @@ -178,7 +178,7 @@ func (suite *KeeperTestSuite) VerifyPoolTotalStake() { actualBalance := suite.App().StakersKeeper.GetDelegationOfPool(suite.Ctx(), pool.Id) for _, stakerAddress := range suite.App().StakersKeeper.GetAllStakerAddressesOfPool(suite.Ctx(), pool.Id) { - expectedBalance += suite.App().StakersKeeper.GetDelegationAmount(suite.Ctx(), stakerAddress) + expectedBalance += suite.App().StakersKeeper.GetValidatorPoolStake(suite.Ctx(), stakerAddress, pool.Id) } Expect(actualBalance).To(Equal(expectedBalance)) @@ -461,20 +461,21 @@ func (suite *KeeperTestSuite) verifyFullStaker(fullStaker querytypes.FullStaker, //Expect(fullStaker.Metadata.Commission).To(Equal(staker.Commission)) //Expect(fullStaker.Metadata.Moniker).To(Equal(staker.Description.Moniker)) - pendingCommissionChange, found := suite.App().StakersKeeper.GetCommissionChangeEntryByIndex2(suite.Ctx(), stakerAddress) - if found { - Expect(fullStaker.Metadata.PendingCommissionChange.Commission).To(Equal(pendingCommissionChange.Commission)) - Expect(fullStaker.Metadata.PendingCommissionChange.CreationDate).To(Equal(pendingCommissionChange.CreationDate)) - } else { - Expect(fullStaker.Metadata.PendingCommissionChange).To(BeNil()) - } + // TODO rework after commission was implemented + //pendingCommissionChange, found := suite.App().StakersKeeper.GetCommissionChangeEntryByIndex2(suite.Ctx(), stakerAddress) + //if found { + // Expect(fullStaker.Metadata.PendingCommissionChange.Commission).To(Equal(pendingCommissionChange.Commission)) + // Expect(fullStaker.Metadata.PendingCommissionChange.CreationDate).To(Equal(pendingCommissionChange.CreationDate)) + //} else { + // Expect(fullStaker.Metadata.PendingCommissionChange).To(BeNil()) + //} poolIds := make(map[uint64]bool) for _, poolMembership := range fullStaker.Pools { poolIds[poolMembership.Pool.Id] = true - valaccount, found := suite.App().StakersKeeper.GetValaccount(suite.Ctx(), poolMembership.Pool.Id, stakerAddress) - Expect(found).To(BeTrue()) + valaccount, active := suite.App().StakersKeeper.GetValaccount(suite.Ctx(), poolMembership.Pool.Id, stakerAddress) + Expect(active).To(BeTrue()) Expect(poolMembership.Valaddress).To(Equal(valaccount.Valaddress)) Expect(poolMembership.IsLeaving).To(Equal(valaccount.IsLeaving)) diff --git a/testutil/integration/integration.go b/testutil/integration/integration.go index e1432bbf..20dc25d9 100644 --- a/testutil/integration/integration.go +++ b/testutil/integration/integration.go @@ -326,6 +326,40 @@ func (suite *KeeperTestSuite) CreateValidatorWithoutCommit(address, moniker stri suite.Commit() } +func (suite *KeeperTestSuite) SelfDelegateValidator(address string, amount uint64) { + valAddress := util.MustValaddressFromOperatorAddress(address) + + msg := stakingtypes.NewMsgDelegate( + address, + valAddress, + sdk.NewInt64Coin(globalTypes.Denom, int64(amount)), + ) + + _, err := suite.RunTx(msg) + if err != nil { + panic(err) + } + + suite.Commit() +} + +func (suite *KeeperTestSuite) SelfUndelegateValidator(address string, amount uint64) { + valAddress := util.MustValaddressFromOperatorAddress(address) + + msg := stakingtypes.NewMsgUndelegate( + address, + valAddress, + sdk.NewInt64Coin(globalTypes.Denom, int64(amount)), + ) + + _, err := suite.RunTx(msg) + if err != nil { + panic(err) + } + + suite.Commit() +} + func (suite *KeeperTestSuite) CreateValidator(address, moniker string, kyveStake int64) { suite.CreateValidatorWithoutCommit(address, moniker, kyveStake) suite.Commit() diff --git a/util/expected_keepers.go b/util/expected_keepers.go index 125f5c3c..2184544a 100644 --- a/util/expected_keepers.go +++ b/util/expected_keepers.go @@ -3,6 +3,7 @@ package util import ( "context" + "cosmossdk.io/core/address" "cosmossdk.io/math" distributionTypes "github.com/cosmos/cosmos-sdk/x/distribution/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -24,12 +25,13 @@ type BankKeeper interface { type DistributionKeeper interface { FundCommunityPool(ctx context.Context, amount sdk.Coins, sender sdk.AccAddress) error - AllocateTokensToValidator(ctx context.Context, val stakingtypes.ValidatorI, tokens sdk.DecCoins) error IncrementValidatorPeriod(ctx context.Context, val stakingtypes.ValidatorI) (uint64, error) CalculateDelegationRewards(ctx context.Context, val stakingtypes.ValidatorI, del stakingtypes.DelegationI, endingPeriod uint64) (rewards sdk.DecCoins, err error) GetValidatorAccumulatedCommission(ctx context.Context, val sdk.ValAddress) (commission distributionTypes.ValidatorAccumulatedCommission, err error) SetValidatorAccumulatedCommission(ctx context.Context, val sdk.ValAddress, commission distributionTypes.ValidatorAccumulatedCommission) error + GetValidatorCurrentRewards(ctx context.Context, val sdk.ValAddress) (rewards distributionTypes.ValidatorCurrentRewards, err error) + SetValidatorCurrentRewards(ctx context.Context, val sdk.ValAddress, rewards distributionTypes.ValidatorCurrentRewards) error GetValidatorOutstandingRewards(ctx context.Context, val sdk.ValAddress) (rewards distributionTypes.ValidatorOutstandingRewards, err error) SetValidatorOutstandingRewards(ctx context.Context, val sdk.ValAddress, rewards distributionTypes.ValidatorOutstandingRewards) error } @@ -41,6 +43,7 @@ type StakingKeeper interface { PowerReduction(ctx context.Context) math.Int SetHooks(sh stakingtypes.StakingHooks) Delegation(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (stakingtypes.DelegationI, error) + ValidatorAddressCodec() address.Codec } type UpgradeKeeper interface { diff --git a/x/bundles/keeper/abci_protocol_split_test.go b/x/bundles/keeper/abci_protocol_split_test.go index 9d5c059e..e88ee831 100644 --- a/x/bundles/keeper/abci_protocol_split_test.go +++ b/x/bundles/keeper/abci_protocol_split_test.go @@ -81,17 +81,21 @@ var _ = Describe("abci.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) b1, b2 := uint64(0), uint64(0) @@ -133,27 +137,35 @@ var _ = Describe("abci.go", Ordered, func() { s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 1, - Valaddress: i.VALADDRESS_0_B, + Creator: i.STAKER_0, + PoolId: 1, + Valaddress: i.VALADDRESS_0_B, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 1, - Valaddress: i.VALADDRESS_1_B, + Creator: i.STAKER_1, + PoolId: 1, + Valaddress: i.VALADDRESS_1_B, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -192,17 +204,21 @@ var _ = Describe("abci.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT diff --git a/x/bundles/keeper/keeper.go b/x/bundles/keeper/keeper.go index d3d863aa..d1d151ee 100644 --- a/x/bundles/keeper/keeper.go +++ b/x/bundles/keeper/keeper.go @@ -23,13 +23,12 @@ type ( authority string - accountKeeper types.AccountKeeper - bankKeeper util.BankKeeper - distrkeeper util.DistributionKeeper - poolKeeper types.PoolKeeper - stakerKeeper types.StakerKeeper - delegationKeeper types.DelegationKeeper - fundersKeeper types.FundersKeeper + accountKeeper types.AccountKeeper + bankKeeper util.BankKeeper + distrkeeper util.DistributionKeeper + poolKeeper types.PoolKeeper + stakerKeeper types.StakerKeeper + fundersKeeper types.FundersKeeper Schema collections.Schema BundlesParams collections.Item[types.Params] @@ -49,7 +48,6 @@ func NewKeeper( distrKeeper util.DistributionKeeper, poolKeeper types.PoolKeeper, stakerKeeper types.StakerKeeper, - delegationKeeper types.DelegationKeeper, fundersKeeper types.FundersKeeper, ) Keeper { sb := collections.NewSchemaBuilder(storeService) @@ -61,13 +59,12 @@ func NewKeeper( authority: authority, - accountKeeper: accountKeeper, - bankKeeper: bankKeeper, - distrkeeper: distrKeeper, - poolKeeper: poolKeeper, - stakerKeeper: stakerKeeper, - delegationKeeper: delegationKeeper, - fundersKeeper: fundersKeeper, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + distrkeeper: distrKeeper, + poolKeeper: poolKeeper, + stakerKeeper: stakerKeeper, + fundersKeeper: fundersKeeper, BundlesParams: collections.NewItem(sb, types.ParamsPrefix, "params", codec.CollValue[types.Params](cdc)), } diff --git a/x/bundles/keeper/keeper_suite_dropped_bundles_test.go b/x/bundles/keeper/keeper_suite_dropped_bundles_test.go index 1454c74b..0dd6d57b 100644 --- a/x/bundles/keeper/keeper_suite_dropped_bundles_test.go +++ b/x/bundles/keeper/keeper_suite_dropped_bundles_test.go @@ -68,17 +68,21 @@ var _ = Describe("dropped bundles", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -105,9 +109,11 @@ var _ = Describe("dropped bundles", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_2) diff --git a/x/bundles/keeper/keeper_suite_funding_bundles_test.go b/x/bundles/keeper/keeper_suite_funding_bundles_test.go index 7c34eead..728e34c3 100644 --- a/x/bundles/keeper/keeper_suite_funding_bundles_test.go +++ b/x/bundles/keeper/keeper_suite_funding_bundles_test.go @@ -107,17 +107,21 @@ var _ = Describe("funding bundles", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ diff --git a/x/bundles/keeper/keeper_suite_inflation_splitting_test.go b/x/bundles/keeper/keeper_suite_inflation_splitting_test.go index 2b6c1d65..c3f3b87d 100644 --- a/x/bundles/keeper/keeper_suite_inflation_splitting_test.go +++ b/x/bundles/keeper/keeper_suite_inflation_splitting_test.go @@ -128,17 +128,21 @@ var _ = Describe("inflation splitting", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -322,7 +326,7 @@ var _ = Describe("inflation splitting", Ordered, func() { // (total_bundle_payout - treasury_reward - storage_cost) * commission + storage_cost // storage_cost = byte_size * usd_per_byte / len(coins) * coin_weight // (2471669 - (2471669 * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(2_202_214).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(2_202_215).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -408,7 +412,7 @@ var _ = Describe("inflation splitting", Ordered, func() { // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) // (49433483 - (49433483 * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) // Due to cosmos rounding, the result is a little off. - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(44_045_219).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(44_045_220).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -610,7 +614,7 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), i.STAKER_0).String()).To(Equal(i.KYVECoins(735_121).String())) // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) // (7_415_009 + 10_000 - ((7_415_009 + 10_000) * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(6_615_641).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(6_615_642).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -707,7 +711,7 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), i.STAKER_0).String()).To(Equal(i.KYVECoins(2_447_994).String())) // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) // (2_471_6741 + 10_000 - ((2_471_6741 + 10_000) * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(22_031_497).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(22_031_498).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -803,7 +807,7 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), i.STAKER_0).String()).To(Equal(i.KYVECoins(74).String())) // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) // (300 - (300 * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(222).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(223).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1006,7 +1010,7 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), i.STAKER_0).String()).To(Equal(i.KYVECoins(2_447_033).String())) // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) // (24_716_741 + 300 - ((24_716_741 + 300) * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(22_022_855).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(22_022_856).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1102,7 +1106,7 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), i.STAKER_0).String()).To(Equal(i.KYVECoins(559).String())) // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) // (5_000 + 200 - ((5_000 + 200) * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(4_588).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(4_589).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1207,7 +1211,7 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), i.STAKER_0).String()).To(Equal(i.KYVECoins(734_646).String())) // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) // (7_415_009 + 5_000 + 200 - ((7_415_009 + 5_000 + 200) * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(6_611_364).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(6_611_365).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1402,7 +1406,7 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(1012), i.BCoin(1990)).String())) // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) // (20_000 - (20_000 * 0.01) - _((100 * 0.5) / (2 * coin_weight))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(8887), i.BCoin(17809)).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(8888), i.BCoin(17810)).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1511,7 +1515,7 @@ var _ = Describe("inflation splitting", Ordered, func() { // for kyve coin (7_415_009 - (7_415_009 * 0.01) - _((100 * 0.5) / (3 * 1))_) * (1 - 0.1) // for acoin (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (3 * 1))_) * (1 - 0.1) // for bcoin (20_000 - (20_000 * 0.01) - _((100 * 0.5) / (3 * 2))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.KYVECoin(6_606_762), i.ACoin(8895), i.BCoin(17812)).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.KYVECoin(6_606_763), i.ACoin(8896), i.BCoin(17813)).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1621,7 +1625,7 @@ var _ = Describe("inflation splitting", Ordered, func() { // for kyve coin (24_716_741 - (24_716_741 * 0.01) - _((100 * 0.5) / (3 * 1))_) * (1 - 0.1) // for acoin (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (3 * 1))_) * (1 - 0.1) // for bcoin (20_000 - (20_000 * 0.01) - _((100 * 0.5) / (3 * 2))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.KYVECoin(22_022_618), i.ACoin(8895), i.BCoin(17812)).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.KYVECoin(22_022_619), i.ACoin(8896), i.BCoin(17813)).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1758,14 +1762,18 @@ var _ = Describe("inflation splitting", Ordered, func() { s.RunTxPoolSuccess(msg) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 1, - Valaddress: i.VALADDRESS_0_B, + Creator: i.STAKER_0, + PoolId: 1, + Valaddress: i.VALADDRESS_0_B, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 1, - Valaddress: i.VALADDRESS_1_B, + Creator: i.STAKER_1, + PoolId: 1, + Valaddress: i.VALADDRESS_1_B, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) preMineBalance := s.App().BankKeeper.GetSupply(s.Ctx(), globalTypes.Denom) @@ -1845,7 +1853,6 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(finalBalancePool1).To(Equal(uint64(30919246548))) // assert bundle reward - uploader, _ := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) // the total payout is here just the inflation payout // (inflation - teamRewards)*inflationShare - balancePool0 - balancePool1 @@ -1858,7 +1865,7 @@ var _ = Describe("inflation splitting", Ordered, func() { storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100).TruncateDec() totalUploaderReward := totalPayout.Sub(treasuryReward).Sub(storageReward) - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission.Rate).TruncateDec() + uploaderPayoutReward := totalUploaderReward.Mul(math.LegacyMustNewDecFromStr("0.1")).TruncateDec() uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) // assert commission rewards @@ -1866,7 +1873,7 @@ var _ = Describe("inflation splitting", Ordered, func() { // only the commission-rewards distribution) Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), i.STAKER_0).AmountOf(globalTypes.Denom).String()).To(Equal(uploaderPayoutReward.Add(storageReward).RoundInt().String())) // assert uploader self delegation rewards - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec().Add(math.LegacyOneDec()).String()).To(Equal(uploaderDelegationReward.String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec().String()).To(Equal(uploaderDelegationReward.String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1913,14 +1920,19 @@ var _ = Describe("inflation splitting", Ordered, func() { s.RunTxPoolSuccess(msg) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 1, - Valaddress: i.VALADDRESS_0_B, + Creator: i.STAKER_0, + PoolId: 1, + Valaddress: i.VALADDRESS_0_B, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 1, - Valaddress: i.VALADDRESS_1_B, + Creator: i.STAKER_1, + PoolId: 1, + Valaddress: i.VALADDRESS_1_B, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // Both pools now have inflation_share=1 and zero balance @@ -1998,7 +2010,6 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(finalBalancePool1).To(Equal(uint64(17005585601))) // assert bundle reward - uploader, _ := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) // the total payout is here just the inflation payout totalPayout := math.LegacyNewDec(17005585601 - 13604468481) @@ -2008,13 +2019,13 @@ var _ = Describe("inflation splitting", Ordered, func() { storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100).TruncateDec() totalUploaderReward := totalPayout.Sub(treasuryReward).Sub(storageReward) - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission.Rate).TruncateDec() + uploaderPayoutReward := totalUploaderReward.Mul(math.LegacyMustNewDecFromStr("0.1")).TruncateDec() uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) // assert commission rewards Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec().String()).To(Equal(uploaderPayoutReward.Add(storageReward).String())) // assert uploader self delegation rewards - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec().Add(math.LegacyOneDec()).String()).To(Equal(uploaderDelegationReward.String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec().String()).To(Equal(uploaderDelegationReward.String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) diff --git a/x/bundles/keeper/keeper_suite_invalid_bundles_test.go b/x/bundles/keeper/keeper_suite_invalid_bundles_test.go index 5359c598..32d1f9b0 100644 --- a/x/bundles/keeper/keeper_suite_invalid_bundles_test.go +++ b/x/bundles/keeper/keeper_suite_invalid_bundles_test.go @@ -77,17 +77,21 @@ var _ = Describe("invalid bundles", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -131,9 +135,11 @@ var _ = Describe("invalid bundles", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_2) @@ -205,8 +211,8 @@ var _ = Describe("invalid bundles", Ordered, func() { Expect(bundleProposal.VotersAbstain).To(BeEmpty()) // check uploader status - _, valaccountUploaderFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(valaccountUploaderFound).To(BeFalse()) + _, uploaderActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(uploaderActive).To(BeFalse()) balanceValaddress := s.GetBalanceFromAddress(i.VALADDRESS_0_A) Expect(balanceValaddress).To(Equal(initialBalanceValaddress0)) @@ -220,7 +226,7 @@ var _ = Describe("invalid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(BeEmpty()) // calculate uploader slashes - fraction := s.App().DelegationKeeper.GetUploadSlash(s.Ctx()) + fraction := s.App().StakersKeeper.GetUploadSlash(s.Ctx()) slashAmount := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(100*i.KYVE - slashAmount)) @@ -275,9 +281,11 @@ var _ = Describe("invalid bundles", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxSuccess(stakingTypes.NewMsgDelegate( @@ -369,8 +377,8 @@ var _ = Describe("invalid bundles", Ordered, func() { Expect(bundleProposal.VotersAbstain).To(BeEmpty()) // check uploader status - _, valaccountUploaderFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(valaccountUploaderFound).To(BeFalse()) + _, uploaderActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(uploaderActive).To(BeFalse()) balanceValaddress := s.GetBalanceFromAddress(i.VALADDRESS_0_A) Expect(balanceValaddress).To(Equal(initialBalanceValaddress0)) @@ -385,7 +393,7 @@ var _ = Describe("invalid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(BeEmpty()) // calculate uploader slashes - fraction := s.App().DelegationKeeper.GetUploadSlash(s.Ctx()) + fraction := s.App().StakersKeeper.GetUploadSlash(s.Ctx()) slashAmountUploader := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) slashAmountDelegator := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) @@ -443,9 +451,11 @@ var _ = Describe("invalid bundles", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxSuccess(stakingTypes.NewMsgDelegate( @@ -457,9 +467,11 @@ var _ = Describe("invalid bundles", Ordered, func() { s.CreateValidator(i.STAKER_3, "Staker-3", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_3, - PoolId: 0, - Valaddress: i.VALADDRESS_3_A, + Creator: i.STAKER_3, + PoolId: 0, + Valaddress: i.VALADDRESS_3_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // delegate a bit more so invalid voters have more than 50% @@ -561,8 +573,8 @@ var _ = Describe("invalid bundles", Ordered, func() { Expect(bundleProposal.VotersAbstain).To(BeEmpty()) // check uploader status - _, valaccountUploaderFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(valaccountUploaderFound).To(BeFalse()) + _, uploaderActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(uploaderActive).To(BeFalse()) balanceValaddress := s.GetBalanceFromAddress(i.VALADDRESS_0_A) Expect(balanceValaddress).To(Equal(initialBalanceValaddress0)) @@ -577,7 +589,7 @@ var _ = Describe("invalid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(BeEmpty()) // calculate uploader slashes - fraction := s.App().DelegationKeeper.GetUploadSlash(s.Ctx()) + fraction := s.App().StakersKeeper.GetUploadSlash(s.Ctx()) slashAmountUploader := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) slashAmountDelegator1 := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) @@ -585,7 +597,7 @@ var _ = Describe("invalid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.ALICE)).To(Equal(100*i.KYVE - slashAmountDelegator1)) // calculate voter slashes - fraction = s.App().DelegationKeeper.GetVoteSlash(s.Ctx()) + fraction = s.App().StakersKeeper.GetVoteSlash(s.Ctx()) slashAmountVoter := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) slashAmountDelegator2 := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) @@ -595,8 +607,8 @@ var _ = Describe("invalid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(450 * i.KYVE)) // check voter status - _, valaccountVoterFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) - Expect(valaccountVoterFound).To(BeFalse()) + _, voterActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) + Expect(voterActive).To(BeFalse()) balanceVoterValaddress := s.GetBalanceFromAddress(i.VALADDRESS_1_A) Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress2)) diff --git a/x/bundles/keeper/keeper_suite_points_test.go b/x/bundles/keeper/keeper_suite_points_test.go index e0a6bafb..0f0f23a9 100644 --- a/x/bundles/keeper/keeper_suite_points_test.go +++ b/x/bundles/keeper/keeper_suite_points_test.go @@ -68,25 +68,31 @@ var _ = Describe("points", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_2, "Staker-2", int64(50*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CommitAfterSeconds(60) @@ -346,11 +352,11 @@ var _ = Describe("points", Ordered, func() { _, stakerFound := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_2) Expect(stakerFound).To(BeTrue()) - _, valaccountFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_2) - Expect(valaccountFound).To(BeFalse()) + _, valaccountActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_2) + Expect(valaccountActive).To(BeFalse()) // check if voter got slashed - slashAmountRatio := s.App().DelegationKeeper.GetTimeoutSlash(s.Ctx()) + slashAmountRatio := s.App().StakersKeeper.GetTimeoutSlash(s.Ctx()) expectedBalance := 50*i.KYVE - uint64(math.LegacyNewDec(int64(50*i.KYVE)).Mul(slashAmountRatio).TruncateInt64()) Expect(expectedBalance).To(Equal(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_2, i.STAKER_2))) diff --git a/x/bundles/keeper/keeper_suite_stakers_leave_test.go b/x/bundles/keeper/keeper_suite_stakers_leave_test.go index da4a93f7..29ee4340 100644 --- a/x/bundles/keeper/keeper_suite_stakers_leave_test.go +++ b/x/bundles/keeper/keeper_suite_stakers_leave_test.go @@ -75,17 +75,21 @@ var _ = Describe("stakers leave", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -107,9 +111,11 @@ var _ = Describe("stakers leave", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -131,8 +137,8 @@ var _ = Describe("stakers leave", Ordered, func() { Expect(poolStakers).To(HaveLen(2)) Expect(poolStakers[0]).To(Equal(i.STAKER_1)) - _, valaccountFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(valaccountFound).To(BeFalse()) + _, valaccountActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccountActive).To(BeFalse()) Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) @@ -145,9 +151,11 @@ var _ = Describe("stakers leave", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CommitAfterSeconds(60) @@ -217,8 +225,8 @@ var _ = Describe("stakers leave", Ordered, func() { Expect(poolStakers).To(HaveLen(2)) Expect(poolStakers[0]).To(Equal(i.STAKER_1)) - _, valaccountFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(valaccountFound).To(BeFalse()) + _, valaccountActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccountActive).To(BeFalse()) Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) @@ -227,7 +235,6 @@ var _ = Describe("stakers leave", Ordered, func() { // check if next uploader received the uploader reward pool, _ := s.App().PoolKeeper.GetPool(s.Ctx(), 0) - uploader, _ := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) balanceUploader := s.GetBalanceFromAddress(i.STAKER_0) // calculate uploader rewards @@ -236,12 +243,15 @@ var _ = Describe("stakers leave", Ordered, func() { storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.CurrentStorageProviderId).MulInt64(100) totalUploaderReward := pool.InflationShareWeight.Sub(treasuryReward).Sub(storageReward) - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission.Rate) + uploaderPayoutReward := totalUploaderReward.Mul(math.LegacyMustNewDecFromStr("0.1")) uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)) + // assert payout transfer Expect(balanceUploader).To(Equal(initialBalanceStaker0)) // assert commission rewards + // TODO: fix Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), i.STAKER_0).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderPayoutReward.Add(storageReward).TruncateInt64()))) // assert uploader self delegation rewards Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderDelegationReward.TruncateInt64()))) @@ -252,9 +262,11 @@ var _ = Describe("stakers leave", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CommitAfterSeconds(60) @@ -324,11 +336,11 @@ var _ = Describe("stakers leave", Ordered, func() { Expect(poolStakers).To(HaveLen(2)) Expect(poolStakers[0]).To(Equal(i.STAKER_1)) - _, valaccountFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(valaccountFound).To(BeFalse()) + _, valaccountActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccountActive).To(BeFalse()) // check if next uploader got slashed - fraction := s.App().DelegationKeeper.GetUploadSlash(s.Ctx()) + fraction := s.App().StakersKeeper.GetUploadSlash(s.Ctx()) slashAmount := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(100*i.KYVE - slashAmount)) @@ -348,9 +360,11 @@ var _ = Describe("stakers leave", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CommitAfterSeconds(60) @@ -422,11 +436,11 @@ var _ = Describe("stakers leave", Ordered, func() { Expect(poolStakers).To(HaveLen(2)) Expect(poolStakers[0]).To(Equal(i.STAKER_0)) - _, valaccountFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) - Expect(valaccountFound).To(BeFalse()) + _, valaccountActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) + Expect(valaccountActive).To(BeFalse()) // check if voter got slashed - fraction := s.App().DelegationKeeper.GetVoteSlash(s.Ctx()) + fraction := s.App().StakersKeeper.GetVoteSlash(s.Ctx()) slashAmount := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_1, i.STAKER_1)).To(Equal(100*i.KYVE - slashAmount)) @@ -446,9 +460,11 @@ var _ = Describe("stakers leave", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CommitAfterSeconds(60) @@ -514,8 +530,8 @@ var _ = Describe("stakers leave", Ordered, func() { Expect(poolStakers).To(HaveLen(2)) Expect(poolStakers[0]).To(Equal(i.STAKER_0)) - _, valaccountFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) - Expect(valaccountFound).To(BeFalse()) + _, valaccountActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) + Expect(valaccountActive).To(BeFalse()) // check if voter status @@ -536,9 +552,11 @@ var _ = Describe("stakers leave", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CommitAfterSeconds(60) @@ -608,8 +626,8 @@ var _ = Describe("stakers leave", Ordered, func() { Expect(poolStakers).To(HaveLen(2)) Expect(poolStakers[0]).To(Equal(i.STAKER_0)) - _, valaccountFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) - Expect(valaccountFound).To(BeFalse()) + _, valaccountActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) + Expect(valaccountActive).To(BeFalse()) // check if voter not got slashed Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_1, i.STAKER_1)).To(Equal(100 * i.KYVE)) diff --git a/x/bundles/keeper/keeper_suite_valid_bundles_test.go b/x/bundles/keeper/keeper_suite_valid_bundles_test.go index 430c34ee..b3de63d4 100644 --- a/x/bundles/keeper/keeper_suite_valid_bundles_test.go +++ b/x/bundles/keeper/keeper_suite_valid_bundles_test.go @@ -119,17 +119,21 @@ var _ = Describe("valid bundles", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -452,9 +456,11 @@ var _ = Describe("valid bundles", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxSuccess(stakingTypes.NewMsgDelegate( @@ -616,9 +622,11 @@ var _ = Describe("valid bundles", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxSuccess(stakingTypes.NewMsgDelegate( @@ -788,9 +796,11 @@ var _ = Describe("valid bundles", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxSuccess(stakingTypes.NewMsgDelegate( @@ -905,7 +915,7 @@ var _ = Describe("valid bundles", Ordered, func() { Expect(balanceUploaderValaddress).To(Equal(initialBalanceValaddress0)) // calculate voter slashes - fraction := s.App().DelegationKeeper.GetVoteSlash(s.Ctx()) + fraction := s.App().StakersKeeper.GetVoteSlash(s.Ctx()) slashAmountVoter := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) slashAmountDelegator := uint64(math.LegacyNewDec(int64(300 * i.KYVE)).Mul(fraction).TruncateInt64()) @@ -915,8 +925,8 @@ var _ = Describe("valid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(800 * i.KYVE)) // check voter status - _, valaccountVoterFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_2) - Expect(valaccountVoterFound).To(BeFalse()) + _, voterActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_2) + Expect(voterActive).To(BeFalse()) balanceVoterValaddress := s.GetCoinsFromAddress(i.VALADDRESS_2_A) Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress2)) @@ -1221,7 +1231,7 @@ var _ = Describe("valid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), valaccountUploader.Staker).String()).To(Equal(sdk.NewCoins(i.ACoin(1004), i.BCoin(1987), i.CCoin(2974)).String())) // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) // (coin_amount_per_bundle - (coin_amount_per_bundle * 0.01) - _((100 * 0.5) / (3 * coin_weight))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(8895), i.BCoin(17812), i.CCoin(26725)).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(8896), i.BCoin(17813), i.CCoin(26726)).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1390,7 +1400,7 @@ var _ = Describe("valid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), valaccountUploader.Staker).String()).To(Equal(sdk.NewCoins(i.ACoin(1004), i.BCoin(997), i.CCoin(9900)).String())) // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) // (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (3 * coin_weight))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(8895), i.BCoin(8902)).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(8896), i.BCoin(8903)).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1553,7 +1563,7 @@ var _ = Describe("valid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), valaccountUploader.Staker).String()).To(Equal(sdk.NewCoins(i.ACoin(1012), i.BCoin(1000)).String())) // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) // (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (2 * coin_weight))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(8887), i.BCoin(8899)).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(8888), i.BCoin(8900)).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1750,7 +1760,7 @@ var _ = Describe("valid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), valaccountUploader.Staker).String()).To(Equal(sdk.NewCoins(i.KYVECoin(125_973_187), i.ACoin(99_143), i.BCoin(116_661_015_771_428_571), i.CCoin(100_765)).String())) // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) // (amount_per_bundle - (amount_per_bundle * 0.01) - _((29970208 * 0.000000006288 * 1**coin_decimals) / (4 * coin_weight))_) * (1 - 0.1) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.KYVECoin(864_026_812), i.ACoin(890_856), i.BCoin(873_338_984_228_571_428), i.CCoin(889_234)).String())) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.KYVECoin(864_026_813), i.ACoin(890_857), i.BCoin(873_338_984_228_571_429), i.CCoin(889_235)).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) diff --git a/x/bundles/keeper/keeper_suite_zero_delegation_test.go b/x/bundles/keeper/keeper_suite_zero_delegation_test.go index 5382372a..757de27d 100644 --- a/x/bundles/keeper/keeper_suite_zero_delegation_test.go +++ b/x/bundles/keeper/keeper_suite_zero_delegation_test.go @@ -91,17 +91,21 @@ var _ = Describe("zero delegation", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -138,9 +142,11 @@ var _ = Describe("zero delegation", Ordered, func() { s.CreateZeroDelegationValidator(i.STAKER_2, "Staker-2") s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -186,17 +192,21 @@ var _ = Describe("zero delegation", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -225,9 +235,11 @@ var _ = Describe("zero delegation", Ordered, func() { s.CreateZeroDelegationValidator(i.STAKER_2, "Staker-2") s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -288,27 +300,33 @@ var _ = Describe("zero delegation", Ordered, func() { s.CreateZeroDelegationValidator(i.STAKER_0, "Staker-0") s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // create normal validator s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // create normal validator s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -461,27 +479,33 @@ var _ = Describe("zero delegation", Ordered, func() { s.CreateZeroDelegationValidator(i.STAKER_0, "Staker-0") s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // create normal validator s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // create normal validator s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -579,8 +603,8 @@ var _ = Describe("zero delegation", Ordered, func() { Expect(bundleProposal.VotersAbstain).To(BeEmpty()) // check uploader status - _, valaccountUploaderFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(valaccountUploaderFound).To(BeFalse()) + _, uploaderActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(uploaderActive).To(BeFalse()) balanceValaddress := s.GetBalanceFromAddress(i.VALADDRESS_0_A) Expect(balanceValaddress).To(Equal(initialBalanceValaddress0)) @@ -624,27 +648,33 @@ var _ = Describe("zero delegation", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // create zero delegation validator s.CreateZeroDelegationValidator(i.STAKER_1, "Staker-1") s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // create normal validator s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -722,8 +752,8 @@ var _ = Describe("zero delegation", Ordered, func() { _, stakerFound := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(stakerFound).To(BeTrue()) - _, valaccountFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) - Expect(valaccountFound).To(BeFalse()) + _, valaccountActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) + Expect(valaccountActive).To(BeFalse()) // check if voter got slashed slashAmountRatio := s.App().DelegationKeeper.GetTimeoutSlash(s.Ctx()) @@ -737,17 +767,21 @@ var _ = Describe("zero delegation", Ordered, func() { s.CreateZeroDelegationValidator(i.STAKER_0, "Staker-0") s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateZeroDelegationValidator(i.STAKER_1, "Staker-1") s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ diff --git a/x/bundles/keeper/logic_bundles.go b/x/bundles/keeper/logic_bundles.go index 07c7cf00..1a6c68ea 100644 --- a/x/bundles/keeper/logic_bundles.go +++ b/x/bundles/keeper/logic_bundles.go @@ -5,8 +5,7 @@ import ( "cosmossdk.io/math" globalTypes "github.com/KYVENetwork/chain/x/global/types" poolTypes "github.com/KYVENetwork/chain/x/pool/types" - - delegationTypes "github.com/KYVENetwork/chain/x/delegation/types" + stakersTypes "github.com/KYVENetwork/chain/x/stakers/types" "github.com/KYVENetwork/chain/util" "github.com/KYVENetwork/chain/x/bundles/types" @@ -169,20 +168,8 @@ func (k Keeper) validateSubmitBundleArgs(ctx sdk.Context, bundleProposal *types. // slashDelegatorsAndRemoveStaker slashes a staker with a certain slashType and all including // delegators and removes him from the storage pool -func (k Keeper) slashDelegatorsAndRemoveStaker(ctx sdk.Context, poolId uint64, stakerAddress string, slashType delegationTypes.SlashType) { - slashAmountRatio := math.LegacyZeroDec() - - // TODO move the delegation Slash types to the Stakers module - switch slashType { - case delegationTypes.SLASH_TYPE_TIMEOUT: - slashAmountRatio = k.delegationKeeper.GetTimeoutSlash(ctx) - case delegationTypes.SLASH_TYPE_VOTE: - slashAmountRatio = k.delegationKeeper.GetVoteSlash(ctx) - case delegationTypes.SLASH_TYPE_UPLOAD: - slashAmountRatio = k.delegationKeeper.GetUploadSlash(ctx) - } - - k.stakerKeeper.Slash(ctx, poolId, stakerAddress, slashAmountRatio) +func (k Keeper) slashDelegatorsAndRemoveStaker(ctx sdk.Context, poolId uint64, stakerAddress string, slashType stakersTypes.SlashType) { + k.stakerKeeper.Slash(ctx, poolId, stakerAddress, slashType) k.stakerKeeper.LeavePool(ctx, stakerAddress, poolId) } @@ -214,7 +201,7 @@ func (k Keeper) addPoint(ctx sdk.Context, poolId uint64, stakerAddress string) { if points >= k.GetMaxPoints(ctx) { // slash all delegators with a timeout slash and remove staker from pool. // points are reset due to the valaccount being deleted while leaving the pool - k.slashDelegatorsAndRemoveStaker(ctx, poolId, stakerAddress, delegationTypes.SLASH_TYPE_TIMEOUT) + k.slashDelegatorsAndRemoveStaker(ctx, poolId, stakerAddress, stakersTypes.SLASH_TYPE_TIMEOUT) } } @@ -255,8 +242,7 @@ func (k Keeper) calculatePayouts(ctx sdk.Context, poolId uint64, totalPayout sdk // are divided between uploader and its delegators based on the uploader's commission. bundleProposal, _ := k.GetBundleProposal(ctx, poolId) - _, found := k.stakerKeeper.GetValidator(ctx, bundleProposal.Uploader) - if !found { + if _, found := k.stakerKeeper.GetValidator(ctx, bundleProposal.Uploader); !found { return } @@ -318,10 +304,9 @@ func (k Keeper) calculatePayouts(ctx sdk.Context, poolId uint64, totalPayout sdk return } - // TODO add custom commission per pool in next PR - // commission := k.stakerKeeper.GetCommission(ctx, bundleProposal.Uploader) - // commissionRewards, _ := sdk.NewDecCoinsFromCoins(totalPayout...).MulDec(commission).TruncateDecimal() - // bundleReward.UploaderCommission = commissionRewards + commission := k.stakerKeeper.GetValidatorPoolCommission(ctx, bundleProposal.Uploader, poolId) + commissionRewards, _ := sdk.NewDecCoinsFromCoins(totalPayout...).MulDec(commission).TruncateDecimal() + bundleReward.UploaderCommission = commissionRewards // the remaining total payout belongs to the delegators totalPayout = totalPayout.Sub(bundleReward.UploaderCommission...) @@ -330,7 +315,7 @@ func (k Keeper) calculatePayouts(ctx sdk.Context, poolId uint64, totalPayout sdk } // if the uploader has no delegators he receives the entire remaining amount - if k.stakerKeeper.GetDelegationAmount(ctx, bundleProposal.Uploader) > 0 { + if k.stakerKeeper.GetValidatorPoolStake(ctx, bundleProposal.Uploader, poolId) > 0 { bundleReward.Delegation = totalPayout } else { bundleReward.UploaderCommission = bundleReward.UploaderCommission.Add(totalPayout...) @@ -528,34 +513,25 @@ func (k Keeper) GetVoteDistribution(ctx sdk.Context, poolId uint64) (voteDistrib // get voting power for valid for _, voter := range bundleProposal.VotersValid { - // valaccount was found the voter is active in the pool - if k.stakerKeeper.DoesValaccountExist(ctx, poolId, voter) { - delegation := k.stakerKeeper.GetDelegationAmount(ctx, voter) - voteDistribution.Valid += k.calculateVotingPower(delegation) - } + delegation := k.stakerKeeper.GetValidatorPoolStake(ctx, voter, poolId) + voteDistribution.Valid += k.calculateVotingPower(delegation) } // get voting power for invalid for _, voter := range bundleProposal.VotersInvalid { - // valaccount was found the voter is active in the pool - if k.stakerKeeper.DoesValaccountExist(ctx, poolId, voter) { - delegation := k.stakerKeeper.GetDelegationAmount(ctx, voter) - voteDistribution.Invalid += k.calculateVotingPower(delegation) - } + delegation := k.stakerKeeper.GetValidatorPoolStake(ctx, voter, poolId) + voteDistribution.Invalid += k.calculateVotingPower(delegation) } // get voting power for abstain for _, voter := range bundleProposal.VotersAbstain { - // valaccount was found the voter is active in the pool - if k.stakerKeeper.DoesValaccountExist(ctx, poolId, voter) { - delegation := k.stakerKeeper.GetDelegationAmount(ctx, voter) - voteDistribution.Abstain += k.calculateVotingPower(delegation) - } + delegation := k.stakerKeeper.GetValidatorPoolStake(ctx, voter, poolId) + voteDistribution.Abstain += k.calculateVotingPower(delegation) } // get total voting power for _, staker := range k.stakerKeeper.GetAllStakerAddressesOfPool(ctx, poolId) { - delegation := k.stakerKeeper.GetDelegationAmount(ctx, staker) + delegation := k.stakerKeeper.GetValidatorPoolStake(ctx, staker, poolId) voteDistribution.Total += k.calculateVotingPower(delegation) } @@ -623,7 +599,7 @@ func (k Keeper) tallyBundleProposal(ctx sdk.Context, bundleProposal types.Bundle // slash stakers who voted incorrectly for _, voter := range bundleProposal.VotersInvalid { - k.slashDelegatorsAndRemoveStaker(ctx, poolId, voter, delegationTypes.SLASH_TYPE_VOTE) + k.slashDelegatorsAndRemoveStaker(ctx, poolId, voter, stakersTypes.SLASH_TYPE_VOTE) } return types.TallyResult{ @@ -642,9 +618,9 @@ func (k Keeper) tallyBundleProposal(ctx sdk.Context, bundleProposal types.Bundle // slash stakers who voted incorrectly - uploader receives upload slash for _, voter := range bundleProposal.VotersValid { if voter == bundleProposal.Uploader { - k.slashDelegatorsAndRemoveStaker(ctx, poolId, voter, delegationTypes.SLASH_TYPE_UPLOAD) + k.slashDelegatorsAndRemoveStaker(ctx, poolId, voter, stakersTypes.SLASH_TYPE_UPLOAD) } else { - k.slashDelegatorsAndRemoveStaker(ctx, poolId, voter, delegationTypes.SLASH_TYPE_VOTE) + k.slashDelegatorsAndRemoveStaker(ctx, poolId, voter, stakersTypes.SLASH_TYPE_VOTE) } } diff --git a/x/bundles/keeper/logic_bundles_test.go b/x/bundles/keeper/logic_bundles_test.go index ee77c5bf..08d19811 100644 --- a/x/bundles/keeper/logic_bundles_test.go +++ b/x/bundles/keeper/logic_bundles_test.go @@ -103,19 +103,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -130,19 +134,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // disable pool @@ -162,19 +170,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(20*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(20*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -207,19 +219,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(101*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -252,28 +268,34 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(300*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(300*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_2, "Staker-2", int64(400*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, - Amount: 0, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -310,28 +332,34 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(300*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(300*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_2, "Staker-2", int64(401*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, - Amount: 0, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -368,10 +396,12 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(300*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -386,19 +416,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(50*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(50*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -431,19 +465,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -474,19 +512,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundlesTypes.MsgClaimUploaderRole{ @@ -527,19 +569,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundlesTypes.MsgClaimUploaderRole{ @@ -580,19 +626,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundlesTypes.MsgClaimUploaderRole{ @@ -632,19 +682,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundlesTypes.MsgClaimUploaderRole{ @@ -693,19 +747,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundlesTypes.MsgClaimUploaderRole{ @@ -754,19 +812,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundlesTypes.MsgClaimUploaderRole{ @@ -809,19 +871,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundlesTypes.MsgClaimUploaderRole{ @@ -845,19 +911,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundlesTypes.MsgClaimUploaderRole{ @@ -881,19 +951,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundlesTypes.MsgClaimUploaderRole{ @@ -920,19 +994,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundlesTypes.MsgClaimUploaderRole{ @@ -956,19 +1034,23 @@ var _ = Describe("logic_bundles.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundlesTypes.MsgClaimUploaderRole{ diff --git a/x/bundles/keeper/logic_end_block_handle_upload_timeout.go b/x/bundles/keeper/logic_end_block_handle_upload_timeout.go index 25d9aedf..338b3e5b 100644 --- a/x/bundles/keeper/logic_end_block_handle_upload_timeout.go +++ b/x/bundles/keeper/logic_end_block_handle_upload_timeout.go @@ -112,8 +112,8 @@ func (k Keeper) HandleUploadTimeout(goCtx context.Context) { } // Now we increase the points of the valaccount - // (if he is still participating in the pool) - if k.stakerKeeper.DoesValaccountExist(ctx, pool.Id, timedoutUploader) { + // (if he is still active in the pool) + if _, active := k.stakerKeeper.GetValaccount(ctx, pool.Id, timedoutUploader); active { k.addPoint(ctx, pool.Id, timedoutUploader) } } diff --git a/x/bundles/keeper/logic_end_block_handle_upload_timeout_test.go b/x/bundles/keeper/logic_end_block_handle_upload_timeout_test.go index ebff4846..ce19c849 100644 --- a/x/bundles/keeper/logic_end_block_handle_upload_timeout_test.go +++ b/x/bundles/keeper/logic_end_block_handle_upload_timeout_test.go @@ -95,15 +95,19 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { s.App().BundlesKeeper.SetBundleProposal(s.Ctx(), originalBundleProposal) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) }) @@ -138,11 +142,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_1)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) }) It("Last staker who joins gets automatically chosen as next uploader", func() { @@ -159,11 +163,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_1)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) }) It("Next uploader gets removed due to pool upgrading", func() { @@ -198,11 +202,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_1)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) }) It("Next uploader gets removed due to pool being disabled", func() { @@ -230,11 +234,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_1)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) }) It("Next uploader gets removed due to pool not reaching min delegation", func() { @@ -270,11 +274,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(20 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(20 * i.KYVE)) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_1)).To(Equal(20 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(20 * i.KYVE)) }) It("Next uploader gets removed due to pool having one node with more than 50% voting power", func() { @@ -304,11 +308,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(101 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(101 * i.KYVE)) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_1)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) }) It("Staker is next uploader of genesis bundle and upload interval and timeout does not pass", func() { @@ -332,11 +336,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_1)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) }) It("Staker is next uploader of genesis bundle and upload timeout does not pass but upload interval passes", func() { @@ -361,11 +365,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_1)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) }) It("Staker is next uploader of genesis bundle and upload timeout does pass together with upload interval", func() { @@ -449,11 +453,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_1)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) }) It("Staker is next uploader of bundle proposal and upload timeout does not pass", func() { @@ -502,11 +506,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_1)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) }) It("Staker is next uploader of bundle proposal and upload timeout passes with the previous bundle being valid", func() { @@ -648,9 +652,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { s.App().BundlesKeeper.SetBundleProposal(s.Ctx(), originalBundleProposal) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -721,7 +727,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { Expect(valaccount.Points).To(Equal(uint64(0))) // check that staker 0 (uploader) got slashed - expectedBalance := 80 * i.KYVE + expectedBalance := 100*i.KYVE - uint64(s.App().StakersKeeper.GetUploadSlash(s.Ctx()).Mul(math.LegacyNewDec(int64(100*i.KYVE))).TruncateInt64()) Expect(expectedBalance).To(Equal(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0))) // check that staker 1 (next uploader) didn't get slashed @@ -743,9 +749,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { s.App().BundlesKeeper.SetBundleProposal(s.Ctx(), originalBundleProposal) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -857,7 +865,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { Expect(expectedBalance).To(Equal(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_1, i.STAKER_1))) // check that staker 2 (next uploader) got slashed - expectedBalance = 98 * i.KYVE + expectedBalance = 100*i.KYVE - uint64(math.LegacyNewDec(int64(100*i.KYVE)).Mul(s.App().StakersKeeper.GetTimeoutSlash(s.Ctx())).TruncateInt64()) Expect(expectedBalance).To(Equal(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_2, i.STAKER_2))) // pool delegations equals delegations of staker 0 & 1 @@ -901,11 +909,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_1)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) }) It("A bundle proposal with no quorum does reach the upload interval", func() { @@ -957,11 +965,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_1)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) }) It("Staker who just left the pool is next uploader of dropped bundle proposal and upload timeout passes", func() { @@ -971,9 +979,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { s.App().BundlesKeeper.SetBundleProposal(s.Ctx(), originalBundleProposal) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -1035,9 +1045,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { s.App().BundlesKeeper.SetBundleProposal(s.Ctx(), originalBundleProposal) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -1121,9 +1133,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { s.App().BundlesKeeper.SetBundleProposal(s.Ctx(), originalBundleProposal) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -1168,8 +1182,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { s.App().StakersKeeper.RemoveValaccountFromPool(s.Ctx(), 0, i.STAKER_0) // ACT - s.CommitAfterSeconds(s.App().BundlesKeeper.GetUploadTimeout(s.Ctx())) - s.CommitAfterSeconds(60) + s.CommitAfterSeconds(s.App().BundlesKeeper.GetUploadTimeout(s.Ctx()) + 60) s.CommitAfterSeconds(1) // ASSERT @@ -1190,8 +1203,8 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) - // check that next uploader got slashed for voting invalid - expectedBalance := 80 * i.KYVE + // check that uploader received upload slash + expectedBalance := 100*i.KYVE - uint64(s.App().StakersKeeper.GetUploadSlash(s.Ctx()).Mul(math.LegacyNewDec(int64(100*i.KYVE))).TruncateInt64()) Expect(expectedBalance).To(Equal(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0))) }) @@ -1228,15 +1241,19 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { }) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 1, - Valaddress: i.VALADDRESS_0_B, + Creator: i.STAKER_0, + PoolId: 1, + Valaddress: i.VALADDRESS_0_B, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 1, - Valaddress: i.VALADDRESS_1_B, + Creator: i.STAKER_1, + PoolId: 1, + Valaddress: i.VALADDRESS_1_B, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) @@ -1246,9 +1263,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { s.App().BundlesKeeper.SetBundleProposal(s.Ctx(), originalBundleProposalPool2) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 1, - Valaddress: i.VALADDRESS_2_B, + Creator: i.STAKER_2, + PoolId: 1, + Valaddress: i.VALADDRESS_2_B, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -1342,8 +1361,8 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { Expect(poolStakers).To(HaveLen(2)) // check if next uploader received a point - _, valaccountFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_2) - Expect(valaccountFound).To(BeFalse()) + _, valaccountActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_2) + Expect(valaccountActive).To(BeFalse()) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_2) Expect(found).To(BeTrue()) @@ -1351,7 +1370,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 1)).To(Equal(200 * i.KYVE)) // check if next uploader not got slashed - slashAmountRatio := s.App().DelegationKeeper.GetTimeoutSlash(s.Ctx()) + slashAmountRatio := s.App().StakersKeeper.GetTimeoutSlash(s.Ctx()) expectedBalance := 100*i.KYVE - uint64(math.LegacyNewDec(int64(100*i.KYVE)).Mul(slashAmountRatio).TruncateInt64()) Expect(expectedBalance).To(Equal(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_2, i.STAKER_2))) diff --git a/x/bundles/keeper/logic_round_robin.go b/x/bundles/keeper/logic_round_robin.go index b34ee522..3edf586d 100644 --- a/x/bundles/keeper/logic_round_robin.go +++ b/x/bundles/keeper/logic_round_robin.go @@ -75,7 +75,7 @@ func (k Keeper) LoadRoundRobinValidatorSet(ctx sdk.Context, poolId uint64) Round newValidators := make(map[string]bool, 0) // Add all current pool validators to the round-robin set for _, address := range k.stakerKeeper.GetAllStakerAddressesOfPool(ctx, poolId) { - delegation := k.stakerKeeper.GetDelegationAmount(ctx, address) + delegation := k.stakerKeeper.GetValidatorPoolStake(ctx, address, poolId) if delegation > 0 { // If a validator has no delegation do not add to the round-robin set. Validator is basically non-existent. vs.Validators = append(vs.Validators, RoundRobinValidatorPower{ diff --git a/x/bundles/keeper/logic_round_robin_test.go b/x/bundles/keeper/logic_round_robin_test.go index 4212287a..09582726 100644 --- a/x/bundles/keeper/logic_round_robin_test.go +++ b/x/bundles/keeper/logic_round_robin_test.go @@ -35,10 +35,12 @@ func joinDummy(s *i.KeeperTestSuite, index, kyveAmount uint64) { s.CreateValidator(i.DUMMY[index], fmt.Sprintf("dummy-%d", index), int64(kyveAmount*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.DUMMY[index], - PoolId: 0, - Valaddress: i.VALDUMMY[index], - Amount: 0, + Creator: i.DUMMY[index], + PoolId: 0, + Valaddress: i.VALDUMMY[index], + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) } diff --git a/x/bundles/keeper/msg_server_claim_uploader_role_test.go b/x/bundles/keeper/msg_server_claim_uploader_role_test.go index b31ba659..3698692b 100644 --- a/x/bundles/keeper/msg_server_claim_uploader_role_test.go +++ b/x/bundles/keeper/msg_server_claim_uploader_role_test.go @@ -61,17 +61,21 @@ var _ = Describe("msg_server_claim_uploader_role.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) }) @@ -200,9 +204,11 @@ var _ = Describe("msg_server_claim_uploader_role.go", Ordered, func() { s.RunTxPoolSuccess(msg) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 1, - Valaddress: i.VALADDRESS_0_B, + Creator: i.STAKER_0, + PoolId: 1, + Valaddress: i.VALADDRESS_0_B, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT diff --git a/x/bundles/keeper/msg_server_skip_uploader_role_test.go b/x/bundles/keeper/msg_server_skip_uploader_role_test.go index e35527b3..ef6fac03 100644 --- a/x/bundles/keeper/msg_server_skip_uploader_role_test.go +++ b/x/bundles/keeper/msg_server_skip_uploader_role_test.go @@ -65,17 +65,21 @@ var _ = Describe("msg_server_skip_uploader_role.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -87,9 +91,11 @@ var _ = Describe("msg_server_skip_uploader_role.go", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.Commit() diff --git a/x/bundles/keeper/msg_server_submit_bundle_proposal_test.go b/x/bundles/keeper/msg_server_submit_bundle_proposal_test.go index 35ebda23..22299c1d 100644 --- a/x/bundles/keeper/msg_server_submit_bundle_proposal_test.go +++ b/x/bundles/keeper/msg_server_submit_bundle_proposal_test.go @@ -71,17 +71,21 @@ var _ = Describe("msg_server_submit_bundle_proposal.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ diff --git a/x/bundles/keeper/msg_server_vote_bundle_proposal_test.go b/x/bundles/keeper/msg_server_vote_bundle_proposal_test.go index d6f25077..a21c2480 100644 --- a/x/bundles/keeper/msg_server_vote_bundle_proposal_test.go +++ b/x/bundles/keeper/msg_server_vote_bundle_proposal_test.go @@ -69,17 +69,21 @@ var _ = Describe("msg_server_vote_bundle_proposal.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ @@ -216,9 +220,11 @@ var _ = Describe("msg_server_vote_bundle_proposal.go", Ordered, func() { s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_2, - PoolId: 0, - Valaddress: i.VALADDRESS_2_A, + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ diff --git a/x/bundles/module.go b/x/bundles/module.go index ee970ea7..15876c00 100644 --- a/x/bundles/module.go +++ b/x/bundles/module.go @@ -218,7 +218,6 @@ type ModuleInputs struct { PoolKeeper types.PoolKeeper TeamKeeper types.TeamKeeper StakersKeeper types.StakerKeeper - DelegationKeeper types.DelegationKeeper FundersKeeper types.FundersKeeper } @@ -246,7 +245,6 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { in.DistributionKeeper, in.PoolKeeper, in.StakersKeeper, - in.DelegationKeeper, in.FundersKeeper, ) m := NewAppModule( diff --git a/x/bundles/types/expected_keepers.go b/x/bundles/types/expected_keepers.go index cd7b06b7..3d9c0ddd 100644 --- a/x/bundles/types/expected_keepers.go +++ b/x/bundles/types/expected_keepers.go @@ -2,8 +2,9 @@ package types import ( "cosmossdk.io/math" - "github.com/KYVENetwork/chain/x/funders/types" + fundersTypes "github.com/KYVENetwork/chain/x/funders/types" pooltypes "github.com/KYVENetwork/chain/x/pool/types" + stakersTypes "github.com/KYVENetwork/chain/x/stakers/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -30,7 +31,7 @@ type StakerKeeper interface { GetAllStakerAddressesOfPool(ctx sdk.Context, poolId uint64) (stakers []string) AssertValaccountAuthorized(ctx sdk.Context, poolId uint64, stakerAddress string, valaddress string) error - DoesValaccountExist(ctx sdk.Context, poolId uint64, stakerAddress string) bool + GetValaccount(ctx sdk.Context, poolId uint64, stakerAddress string) (valaccount stakersTypes.Valaccount, active bool) LeavePool(ctx sdk.Context, staker string, poolId uint64) @@ -38,21 +39,17 @@ type StakerKeeper interface { ResetPoints(ctx sdk.Context, poolId uint64, stakerAddress string) (previousPoints uint64) GetTotalAndHighestDelegationOfPool(ctx sdk.Context, poolId uint64) (totalDelegation, highestDelegation uint64) - GetDelegationAmount(ctx sdk.Context, validator string) uint64 GetValidator(ctx sdk.Context, staker string) (stakingtypes.Validator, bool) - Slash(ctx sdk.Context, poolId uint64, staker string, slashFraction math.LegacyDec) + GetValidatorPoolCommission(ctx sdk.Context, staker string, poolId uint64) math.LegacyDec + GetValidatorPoolStakeFraction(ctx sdk.Context, staker string, poolId uint64) math.LegacyDec + GetValidatorPoolStake(ctx sdk.Context, staker string, poolId uint64) uint64 + Slash(ctx sdk.Context, poolId uint64, staker string, slashType stakersTypes.SlashType) PayoutRewards(ctx sdk.Context, staker string, amount sdk.Coins, payerModuleName string) error PayoutAdditionalCommissionRewards(ctx sdk.Context, validator string, payerModuleName string, amount sdk.Coins) error } -type DelegationKeeper interface { - GetTimeoutSlash(ctx sdk.Context) (res math.LegacyDec) - GetUploadSlash(ctx sdk.Context) (res math.LegacyDec) - GetVoteSlash(ctx sdk.Context) (res math.LegacyDec) -} - type FundersKeeper interface { - GetCoinWhitelistMap(ctx sdk.Context) (whitelist map[string]types.WhitelistCoinEntry) + GetCoinWhitelistMap(ctx sdk.Context) (whitelist map[string]fundersTypes.WhitelistCoinEntry) ChargeFundersOfPool(ctx sdk.Context, poolId uint64, recipient string) (payout sdk.Coins, err error) } diff --git a/x/delegation/keeper/msg_server_redelegate_test.go b/x/delegation/keeper/msg_server_redelegate_test.go index d1f2b153..1be69e61 100644 --- a/x/delegation/keeper/msg_server_redelegate_test.go +++ b/x/delegation/keeper/msg_server_redelegate_test.go @@ -71,10 +71,12 @@ var _ = Describe("Delegation - Redelegation", Ordered, func() { }) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.BOB, - PoolId: 1, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.BOB, + PoolId: 1, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) _, stakerFound := s.App().StakersKeeper.GetValidator(s.Ctx(), i.ALICE) diff --git a/x/delegation/keeper/msg_server_undelegate_test.go b/x/delegation/keeper/msg_server_undelegate_test.go index b47e4a1d..4715def4 100644 --- a/x/delegation/keeper/msg_server_undelegate_test.go +++ b/x/delegation/keeper/msg_server_undelegate_test.go @@ -77,10 +77,12 @@ var _ = Describe("msg_server_undelegate.go", Ordered, func() { s.RunTxPoolSuccess(msg) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.BOB, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.BOB, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) _, aliceFound := s.App().StakersKeeper.GetValidator(s.Ctx(), i.ALICE) diff --git a/x/pool/keeper/msg_server_disable_pool_test.go b/x/pool/keeper/msg_server_disable_pool_test.go index ea86398e..5c3a9fec 100644 --- a/x/pool/keeper/msg_server_disable_pool_test.go +++ b/x/pool/keeper/msg_server_disable_pool_test.go @@ -368,19 +368,23 @@ var _ = Describe("msg_server_disable_pool.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) msgFirstPool := &types.MsgDisablePool{ @@ -430,26 +434,32 @@ var _ = Describe("msg_server_disable_pool.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 1, - Valaddress: i.VALADDRESS_2_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 1, + Valaddress: i.VALADDRESS_2_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) msgFirstPool := &types.MsgDisablePool{ @@ -499,19 +509,23 @@ var _ = Describe("msg_server_disable_pool.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ diff --git a/x/query/keeper/grpc_account_redelegation_test.go b/x/query/keeper/grpc_account_redelegation_test.go index 9915b7d3..4b2a0f01 100644 --- a/x/query/keeper/grpc_account_redelegation_test.go +++ b/x/query/keeper/grpc_account_redelegation_test.go @@ -51,10 +51,12 @@ var _ = Describe("grpc_account_redelegation.go", Ordered, func() { s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxDelegatorSuccess(&delegationtypes.MsgDelegate{ diff --git a/x/query/keeper/grpc_query_can_propose_test.go b/x/query/keeper/grpc_query_can_propose_test.go index fb1fc89f..37db7135 100644 --- a/x/query/keeper/grpc_query_can_propose_test.go +++ b/x/query/keeper/grpc_query_can_propose_test.go @@ -68,19 +68,23 @@ var _ = Describe("grpc_query_can_propose.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ diff --git a/x/query/keeper/grpc_query_can_validate_test.go b/x/query/keeper/grpc_query_can_validate_test.go index e6b46dbd..4900c805 100644 --- a/x/query/keeper/grpc_query_can_validate_test.go +++ b/x/query/keeper/grpc_query_can_validate_test.go @@ -45,19 +45,23 @@ var _ = Describe("grpc_query_can_validate.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 1, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 1, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) }) diff --git a/x/query/keeper/grpc_query_can_vote_test.go b/x/query/keeper/grpc_query_can_vote_test.go index 8bf76d34..465f71e5 100644 --- a/x/query/keeper/grpc_query_can_vote_test.go +++ b/x/query/keeper/grpc_query_can_vote_test.go @@ -69,19 +69,23 @@ var _ = Describe("grpc_query_can_vote.go", Ordered, func() { s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ diff --git a/x/stakers/client/cli/tx.go b/x/stakers/client/cli/tx.go index 5f108690..e1768072 100644 --- a/x/stakers/client/cli/tx.go +++ b/x/stakers/client/cli/tx.go @@ -22,6 +22,7 @@ func GetTxCmd() *cobra.Command { cmd.AddCommand(CmdJoinPool()) cmd.AddCommand(CmdLeavePool()) cmd.AddCommand(CmdUpdateCommission()) + cmd.AddCommand(CmdUpdateStakeFraction()) return cmd } diff --git a/x/stakers/client/cli/tx_join_pool.go b/x/stakers/client/cli/tx_join_pool.go index c69669bf..85bf1988 100644 --- a/x/stakers/client/cli/tx_join_pool.go +++ b/x/stakers/client/cli/tx_join_pool.go @@ -1,6 +1,7 @@ package cli import ( + "cosmossdk.io/math" "github.com/KYVENetwork/chain/x/stakers/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -11,9 +12,9 @@ import ( func CmdJoinPool() *cobra.Command { cmd := &cobra.Command{ - Use: "join-pool [pool_id] [valaddress] [amount]", + Use: "join-pool [pool_id] [valaddress] [amount] [commission] [stake_fraction]", Short: "Broadcast message join-pool", - Args: cobra.ExactArgs(3), + Args: cobra.ExactArgs(5), RunE: func(cmd *cobra.Command, args []string) (err error) { argPoolId, err := cast.ToUint64E(args[0]) if err != nil { @@ -27,16 +28,28 @@ func CmdJoinPool() *cobra.Command { return err } + argCommission, err := math.LegacyNewDecFromStr(args[3]) + if err != nil { + return err + } + + argStakeFraction, err := math.LegacyNewDecFromStr(args[4]) + if err != nil { + return err + } + clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err } msg := types.MsgJoinPool{ - Creator: clientCtx.GetFromAddress().String(), - PoolId: argPoolId, - Valaddress: argValaddress, - Amount: argAmount, + Creator: clientCtx.GetFromAddress().String(), + PoolId: argPoolId, + Valaddress: argValaddress, + Amount: argAmount, + Commission: argCommission, + StakeFraction: argStakeFraction, } if err := msg.ValidateBasic(); err != nil { diff --git a/x/stakers/client/cli/tx_update_commission.go b/x/stakers/client/cli/tx_update_commission.go index 76ac8468..3884e3af 100644 --- a/x/stakers/client/cli/tx_update_commission.go +++ b/x/stakers/client/cli/tx_update_commission.go @@ -6,28 +6,35 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/spf13/cast" "github.com/spf13/cobra" ) func CmdUpdateCommission() *cobra.Command { cmd := &cobra.Command{ - Use: "update-commission [commission]", + Use: "update-commission [pool_id] [commission]", Short: "Broadcast message update-commission", - Args: cobra.ExactArgs(1), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err } - commission, err := math.LegacyNewDecFromStr(args[0]) + argPoolId, err := cast.ToUint64E(args[0]) + if err != nil { + return err + } + + argCommission, err := math.LegacyNewDecFromStr(args[1]) if err != nil { return err } msg := types.MsgUpdateCommission{ Creator: clientCtx.GetFromAddress().String(), - Commission: commission, + PoolId: argPoolId, + Commission: argCommission, } if err := msg.ValidateBasic(); err != nil { diff --git a/x/stakers/client/cli/tx_update_stake_fraction.go b/x/stakers/client/cli/tx_update_stake_fraction.go new file mode 100644 index 00000000..e43cea9f --- /dev/null +++ b/x/stakers/client/cli/tx_update_stake_fraction.go @@ -0,0 +1,51 @@ +package cli + +import ( + "cosmossdk.io/math" + "github.com/KYVENetwork/chain/x/stakers/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/spf13/cast" + "github.com/spf13/cobra" +) + +func CmdUpdateStakeFraction() *cobra.Command { + cmd := &cobra.Command{ + Use: "update-stake-fraction [pool_id] [stake_fraction]", + Short: "Broadcast message update-stake-fraction", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + argPoolId, err := cast.ToUint64E(args[0]) + if err != nil { + return err + } + + argStakeFraction, err := math.LegacyNewDecFromStr(args[1]) + if err != nil { + return err + } + + msg := types.MsgUpdateStakeFraction{ + Creator: clientCtx.GetFromAddress().String(), + PoolId: argPoolId, + StakeFraction: argStakeFraction, + } + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/stakers/genesis.go b/x/stakers/genesis.go index c134b4e8..ad2a5ee0 100644 --- a/x/stakers/genesis.go +++ b/x/stakers/genesis.go @@ -25,8 +25,13 @@ func InitGenesis(ctx sdk.Context, k *keeper.Keeper, genState types.GenesisState) k.SetLeavePoolEntry(ctx, entry) } + for _, entry := range genState.StakeFractionChangeEntries { + k.SetStakeFractionChangeEntry(ctx, entry) + } + k.SetQueueState(ctx, types.QUEUE_IDENTIFIER_COMMISSION, genState.QueueStateCommission) k.SetQueueState(ctx, types.QUEUE_IDENTIFIER_LEAVE, genState.QueueStateLeave) + k.SetQueueState(ctx, types.QUEUE_IDENTIFIER_STAKE_FRACTION, genState.QueueStateStateFraction) } // ExportGenesis returns the capability module's exported genesis. @@ -40,9 +45,13 @@ func ExportGenesis(ctx sdk.Context, k *keeper.Keeper) *types.GenesisState { genesis.LeavePoolEntries = k.GetAllLeavePoolEntries(ctx) + genesis.StakeFractionChangeEntries = k.GetAllStakeFractionChangeEntries(ctx) + genesis.QueueStateCommission = k.GetQueueState(ctx, types.QUEUE_IDENTIFIER_COMMISSION) genesis.QueueStateLeave = k.GetQueueState(ctx, types.QUEUE_IDENTIFIER_LEAVE) + genesis.QueueStateStateFraction = k.GetQueueState(ctx, types.QUEUE_IDENTIFIER_STAKE_FRACTION) + return genesis } diff --git a/x/stakers/keeper/exported_functions.go b/x/stakers/keeper/exported_functions.go index 66da58c8..153c50ed 100644 --- a/x/stakers/keeper/exported_functions.go +++ b/x/stakers/keeper/exported_functions.go @@ -61,9 +61,8 @@ func (k Keeper) GetPaginatedStakersByDelegation(ctx sdk.Context, pagination *que // If the valaddress is not authorized the appropriate error is returned. // Otherwise, it returns `nil` func (k Keeper) AssertValaccountAuthorized(ctx sdk.Context, poolId uint64, stakerAddress string, valaddress string) error { - valaccount, found := k.GetValaccount(ctx, poolId, stakerAddress) - - if !found { + valaccount, active := k.GetValaccount(ctx, poolId, stakerAddress) + if !active { return types.ErrValaccountUnauthorized } @@ -85,7 +84,7 @@ func (k Keeper) GetActiveStakers(ctx sdk.Context) []string { func (k Keeper) GetDelegationOfPool(ctx sdk.Context, poolId uint64) uint64 { totalDelegation := uint64(0) for _, address := range k.GetAllStakerAddressesOfPool(ctx, poolId) { - totalDelegation += k.GetDelegationAmount(ctx, address) + totalDelegation += k.GetValidatorPoolStake(ctx, address, poolId) } return totalDelegation } @@ -94,7 +93,7 @@ func (k Keeper) GetDelegationOfPool(ctx sdk.Context, poolId uint64) uint64 { // with the highest stake and the sum of all stakes. func (k Keeper) GetTotalAndHighestDelegationOfPool(ctx sdk.Context, poolId uint64) (totalDelegation, highestDelegation uint64) { for _, address := range k.GetAllStakerAddressesOfPool(ctx, poolId) { - delegation := k.GetDelegationAmount(ctx, address) + delegation := k.GetValidatorPoolStake(ctx, address, poolId) totalDelegation += delegation if delegation > highestDelegation { @@ -105,20 +104,6 @@ func (k Keeper) GetTotalAndHighestDelegationOfPool(ctx sdk.Context, poolId uint6 return totalDelegation, highestDelegation } -// GetDelegationAmount returns the stake of a given validator in ukyve -func (k Keeper) GetDelegationAmount(ctx sdk.Context, validator string) uint64 { - validatorAddress, err := sdk.ValAddressFromBech32(util.MustValaddressFromOperatorAddress(validator)) - if err != nil { - return 0 - } - chainValidator, err := k.stakingKeeper.GetValidator(ctx, validatorAddress) - if err != nil { - return 0 - } - - return chainValidator.GetBondedTokens().Uint64() -} - // GetValidator returns the Cosmos-validator for a given kyve-address. func (k Keeper) GetValidator(ctx sdk.Context, staker string) (stakingTypes.Validator, bool) { valAddress, err := sdk.ValAddressFromBech32(util.MustValaddressFromOperatorAddress(staker)) @@ -133,6 +118,29 @@ func (k Keeper) GetValidator(ctx sdk.Context, staker string) (stakingTypes.Valid return validator, true } +// GetValidatorPoolCommission returns the commission a validator has inside the pool +func (k Keeper) GetValidatorPoolCommission(ctx sdk.Context, staker string, poolId uint64) math.LegacyDec { + valaccount, _ := k.GetValaccount(ctx, poolId, staker) + return valaccount.Commission +} + +// GetValidatorPoolStakeFraction returns the stake fraction a validator has inside the pool +func (k Keeper) GetValidatorPoolStakeFraction(ctx sdk.Context, staker string, poolId uint64) math.LegacyDec { + valaccount, _ := k.GetValaccount(ctx, poolId, staker) + return valaccount.StakeFraction +} + +// GetValidatorPoolStake returns stake a validator has inside the pool +func (k Keeper) GetValidatorPoolStake(ctx sdk.Context, staker string, poolId uint64) uint64 { + validator, found := k.GetValidator(ctx, staker) + if !found { + return 0 + } + + stakeFraction := k.GetValidatorPoolStakeFraction(ctx, staker, poolId) + return uint64(math.LegacyNewDecFromInt(validator.BondedTokens()).Mul(stakeFraction).TruncateInt64()) +} + // GetOutstandingCommissionRewards returns the outstanding commission rewards for a given validator func (k Keeper) GetOutstandingCommissionRewards(ctx sdk.Context, staker string) sdk.Coins { valAddress, err := sdk.ValAddressFromBech32(util.MustValaddressFromOperatorAddress(staker)) @@ -186,7 +194,7 @@ func (k Keeper) GetOutstandingRewards(orgCtx sdk.Context, staker string, delegat } // Slash reduces the delegation of all delegators of `staker` by fraction. The slash itself is handled by the cosmos-sdk -func (k Keeper) Slash(ctx sdk.Context, poolId uint64, staker string, slashFraction math.LegacyDec) { +func (k Keeper) Slash(ctx sdk.Context, poolId uint64, staker string, slashType types.SlashType) { validator, found := k.GetValidator(ctx, staker) if !found { return @@ -194,16 +202,26 @@ func (k Keeper) Slash(ctx sdk.Context, poolId uint64, staker string, slashFracti consAddrBytes, _ := validator.GetConsAddr() - amount, err := k.stakingKeeper.Slash(ctx, consAddrBytes, ctx.BlockHeight(), validator.GetConsensusPower(math.NewInt(1000000)), slashFraction) + // the validator can only be slashed for his stake fraction in a pool, therefore we update the slash fraction + // accordingly + slashFraction := k.getSlashFraction(ctx, slashType).Mul(k.GetValidatorPoolStakeFraction(ctx, staker, poolId)) + + amount, err := k.stakingKeeper.Slash( + ctx, + consAddrBytes, + ctx.BlockHeight(), + validator.GetConsensusPower(math.NewInt(1000000)), + slashFraction, + ) if err != nil { return } _ = ctx.EventManager().EmitTypedEvent(&types.EventSlash{ - PoolId: poolId, - Staker: staker, - Amount: amount.Uint64(), - // SlashType: slashType, TODO add slash type, once migrated away from delegation module + PoolId: poolId, + Staker: staker, + Amount: amount.Uint64(), + SlashType: slashType, }) } @@ -251,12 +269,39 @@ func (k Keeper) PayoutRewards(ctx sdk.Context, staker string, amount sdk.Coins, } validator, _ := k.GetValidator(ctx, staker) + valBz, err := k.stakingKeeper.ValidatorAddressCodec().StringToBytes(validator.GetOperator()) + if err != nil { + return err + } - err := k.distKeeper.AllocateTokensToValidator(ctx, validator, sdk.NewDecCoinsFromCoins(amount...)) + currentRewards, err := k.distKeeper.GetValidatorCurrentRewards(ctx, valBz) if err != nil { return err } + currentRewards.Rewards = currentRewards.Rewards.Add(sdk.NewDecCoinsFromCoins(amount...)...) + if err := k.distKeeper.SetValidatorCurrentRewards(ctx, valBz, currentRewards); err != nil { + return err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + distrtypes.EventTypeRewards, + sdk.NewAttribute(sdk.AttributeKeyAmount, amount.String()), + sdk.NewAttribute(distrtypes.AttributeKeyValidator, validator.GetOperator()), + ), + ) + + outstanding, err := k.distKeeper.GetValidatorOutstandingRewards(ctx, valBz) + if err != nil { + return err + } + + outstanding.Rewards = outstanding.Rewards.Add(sdk.NewDecCoinsFromCoins(amount...)...) + if err := k.distKeeper.SetValidatorOutstandingRewards(ctx, valBz, outstanding); err != nil { + return err + } + // Transfer tokens to the delegation module if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, payerModuleName, distrtypes.ModuleName, amount); err != nil { return err diff --git a/x/stakers/keeper/getters_commission.go b/x/stakers/keeper/getters_commission.go index 56959744..4457b770 100644 --- a/x/stakers/keeper/getters_commission.go +++ b/x/stakers/keeper/getters_commission.go @@ -24,7 +24,10 @@ func (k Keeper) SetCommissionChangeEntry(ctx sdk.Context, commissionChangeEntry binary.BigEndian.PutUint64(indexBytes, commissionChangeEntry.Index) indexStore := prefix.NewStore(storeAdapter, types.CommissionChangeEntryKeyPrefixIndex2) - indexStore.Set(types.CommissionChangeEntryKeyIndex2(commissionChangeEntry.Staker), indexBytes) + indexStore.Set(types.CommissionChangeEntryKeyIndex2( + commissionChangeEntry.Staker, + commissionChangeEntry.PoolId, + ), indexBytes) } // GetCommissionChangeEntry ... @@ -42,11 +45,11 @@ func (k Keeper) GetCommissionChangeEntry(ctx sdk.Context, index uint64) (val typ } // GetCommissionChangeEntryByIndex2 returns a pending commission change entry by staker address (if there is one) -func (k Keeper) GetCommissionChangeEntryByIndex2(ctx sdk.Context, staker string) (val types.CommissionChangeEntry, found bool) { +func (k Keeper) GetCommissionChangeEntryByIndex2(ctx sdk.Context, staker string, poolId uint64) (val types.CommissionChangeEntry, found bool) { storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) store := prefix.NewStore(storeAdapter, types.CommissionChangeEntryKeyPrefixIndex2) - b := store.Get(types.CommissionChangeEntryKeyIndex2(staker)) + b := store.Get(types.CommissionChangeEntryKeyIndex2(staker, poolId)) if b == nil { return val, false } @@ -65,6 +68,7 @@ func (k Keeper) RemoveCommissionChangeEntry(ctx sdk.Context, commissionChangeEnt indexStore := prefix.NewStore(storeAdapter, types.CommissionChangeEntryKeyPrefixIndex2) indexStore.Delete(types.CommissionChangeEntryKeyIndex2( commissionChangeEntry.Staker, + commissionChangeEntry.PoolId, )) } diff --git a/x/stakers/keeper/getters_params.go b/x/stakers/keeper/getters_params.go index bec033fb..8a2864f2 100644 --- a/x/stakers/keeper/getters_params.go +++ b/x/stakers/keeper/getters_params.go @@ -1,6 +1,7 @@ package keeper import ( + "cosmossdk.io/math" "github.com/KYVENetwork/chain/x/stakers/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" @@ -29,6 +30,39 @@ func (k Keeper) GetLeavePoolTime(ctx sdk.Context) (res uint64) { return k.GetParams(ctx).LeavePoolTime } +// GetStakeFractionChangeTime returns the StakeFractionChangeTime param +func (k Keeper) GetStakeFractionChangeTime(ctx sdk.Context) (res uint64) { + return k.GetParams(ctx).StakeFractionChangeTime +} + +// GetVoteSlash returns the VoteSlash param +func (k Keeper) GetVoteSlash(ctx sdk.Context) (res math.LegacyDec) { + return k.GetParams(ctx).VoteSlash +} + +// GetUploadSlash returns the UploadSlash param +func (k Keeper) GetUploadSlash(ctx sdk.Context) (res math.LegacyDec) { + return k.GetParams(ctx).UploadSlash +} + +// GetTimeoutSlash returns the TimeoutSlash param +func (k Keeper) GetTimeoutSlash(ctx sdk.Context) (res math.LegacyDec) { + return k.GetParams(ctx).TimeoutSlash +} + +func (k Keeper) getSlashFraction(ctx sdk.Context, slashType types.SlashType) (slashAmountRatio math.LegacyDec) { + // Retrieve slash fraction from params + switch slashType { + case types.SLASH_TYPE_TIMEOUT: + slashAmountRatio = k.GetTimeoutSlash(ctx) + case types.SLASH_TYPE_VOTE: + slashAmountRatio = k.GetVoteSlash(ctx) + case types.SLASH_TYPE_UPLOAD: + slashAmountRatio = k.GetUploadSlash(ctx) + } + return +} + // SetParams sets the x/stakers module parameters. func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) diff --git a/x/stakers/keeper/getters_stake_fraction.go b/x/stakers/keeper/getters_stake_fraction.go new file mode 100644 index 00000000..cab95cb3 --- /dev/null +++ b/x/stakers/keeper/getters_stake_fraction.go @@ -0,0 +1,90 @@ +package keeper + +import ( + "encoding/binary" + + storeTypes "cosmossdk.io/store/types" + + "github.com/cosmos/cosmos-sdk/runtime" + + "cosmossdk.io/store/prefix" + "github.com/KYVENetwork/chain/x/stakers/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// SetStakeFractionChangeEntry ... +func (k Keeper) SetStakeFractionChangeEntry(ctx sdk.Context, stakeFractionChangeEntry types.StakeFractionChangeEntry) { + storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + store := prefix.NewStore(storeAdapter, types.StakeFractionChangeEntryKeyPrefix) + b := k.cdc.MustMarshal(&stakeFractionChangeEntry) + store.Set(types.StakeFractionChangeEntryKey(stakeFractionChangeEntry.Index), b) + + // Insert the same entry with a different key prefix for query lookup + indexBytes := make([]byte, 8) + binary.BigEndian.PutUint64(indexBytes, stakeFractionChangeEntry.Index) + + indexStore := prefix.NewStore(storeAdapter, types.StakeFractionChangeKeyPrefixIndex2) + indexStore.Set(types.StakeFractionChangeEntryKeyIndex2( + stakeFractionChangeEntry.Staker, + stakeFractionChangeEntry.PoolId, + ), indexBytes) +} + +// GetStakeFractionChangeEntry ... +func (k Keeper) GetStakeFractionChangeEntry(ctx sdk.Context, index uint64) (val types.StakeFractionChangeEntry, found bool) { + storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + store := prefix.NewStore(storeAdapter, types.StakeFractionChangeEntryKeyPrefix) + + b := store.Get(types.StakeFractionChangeEntryKey(index)) + if b == nil { + return val, false + } + + k.cdc.MustUnmarshal(b, &val) + return val, true +} + +// GetStakeFractionChangeEntryByIndex2 returns a pending stake fraction change entry by staker address (if there is one) +func (k Keeper) GetStakeFractionChangeEntryByIndex2(ctx sdk.Context, staker string, poolId uint64) (val types.StakeFractionChangeEntry, found bool) { + storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + store := prefix.NewStore(storeAdapter, types.StakeFractionChangeKeyPrefixIndex2) + + b := store.Get(types.StakeFractionChangeEntryKeyIndex2(staker, poolId)) + if b == nil { + return val, false + } + + index := binary.BigEndian.Uint64(b) + + return k.GetStakeFractionChangeEntry(ctx, index) +} + +// RemoveStakeFractionEntry ... +func (k Keeper) RemoveStakeFractionEntry(ctx sdk.Context, stakeFractionChangeEntry *types.StakeFractionChangeEntry) { + storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + store := prefix.NewStore(storeAdapter, types.StakeFractionChangeEntryKeyPrefix) + store.Delete(types.StakeFractionChangeEntryKey(stakeFractionChangeEntry.Index)) + + indexStore := prefix.NewStore(storeAdapter, types.StakeFractionChangeEntryKeyPrefix) + indexStore.Delete(types.StakeFractionChangeEntryKeyIndex2( + stakeFractionChangeEntry.Staker, + stakeFractionChangeEntry.PoolId, + )) +} + +// GetAllStakeFractionChangeEntries returns all pending stake fraction change entries of all stakers +func (k Keeper) GetAllStakeFractionChangeEntries(ctx sdk.Context) (list []types.StakeFractionChangeEntry) { + storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + store := prefix.NewStore(storeAdapter, types.StakeFractionChangeEntryKeyPrefix) + iterator := storeTypes.KVStorePrefixIterator(store, []byte{}) + + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var val types.StakeFractionChangeEntry + k.cdc.MustUnmarshal(iterator.Value(), &val) + list = append(list, val) + } + + return +} diff --git a/x/stakers/keeper/getters_staker.go b/x/stakers/keeper/getters_staker.go index 9cc09a75..ffa270e9 100644 --- a/x/stakers/keeper/getters_staker.go +++ b/x/stakers/keeper/getters_staker.go @@ -3,6 +3,8 @@ package keeper import ( "encoding/binary" + "cosmossdk.io/math" + stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types" storeTypes "cosmossdk.io/store/types" @@ -19,14 +21,16 @@ import ( ) // AddValaccountToPool adds a valaccount to a pool. -// If valaccount already belongs to pool, nothing happens. -func (k Keeper) AddValaccountToPool(ctx sdk.Context, poolId uint64, stakerAddress string, valaddress string) { +// If valaccount already active in the to pool nothing happens. +func (k Keeper) AddValaccountToPool(ctx sdk.Context, poolId uint64, stakerAddress, valaddress string, commission, stakeFraction math.LegacyDec) { if _, validatorExists := k.GetValidator(ctx, stakerAddress); validatorExists { - if !k.DoesValaccountExist(ctx, poolId, stakerAddress) { + if _, active := k.GetValaccount(ctx, poolId, stakerAddress); !active { k.SetValaccount(ctx, types.Valaccount{ - PoolId: poolId, - Staker: stakerAddress, - Valaddress: valaddress, + PoolId: poolId, + Staker: stakerAddress, + Valaddress: valaddress, + Commission: commission, + StakeFraction: stakeFraction, }) k.AddOneToCount(ctx, poolId) k.AddActiveStaker(ctx, stakerAddress) @@ -37,13 +41,12 @@ func (k Keeper) AddValaccountToPool(ctx sdk.Context, poolId uint64, stakerAddres // RemoveValaccountFromPool removes a valaccount from a given pool and updates // all aggregated variables. If the valaccount is not in the pool nothing happens. func (k Keeper) RemoveValaccountFromPool(ctx sdk.Context, poolId uint64, stakerAddress string) { - // get valaccount - valaccount, valaccountFound := k.GetValaccount(ctx, poolId, stakerAddress) - - // if valaccount was found on pool continue - if valaccountFound { - // remove valaccount from pool - k.removeValaccount(ctx, valaccount) + if valaccount, active := k.GetValaccount(ctx, poolId, stakerAddress); active { + // remove valaccount from pool by setting valaddress to zero address + valaccount.Valaddress = "" + valaccount.Points = 0 + valaccount.IsLeaving = false + k.SetValaccount(ctx, valaccount) k.subtractOneFromCount(ctx, poolId) k.removeActiveStaker(ctx, stakerAddress) } diff --git a/x/stakers/keeper/getters_valaccount.go b/x/stakers/keeper/getters_valaccount.go index 90595e30..aa307a41 100644 --- a/x/stakers/keeper/getters_valaccount.go +++ b/x/stakers/keeper/getters_valaccount.go @@ -3,6 +3,8 @@ package keeper import ( "encoding/binary" + "cosmossdk.io/math" + storeTypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/runtime" @@ -47,7 +49,10 @@ func (k Keeper) GetAllValaccountsOfPool(ctx sdk.Context, poolId uint64) (val []* for ; iterator.Valid(); iterator.Next() { valaccount := types.Valaccount{} k.cdc.MustUnmarshal(iterator.Value(), &valaccount) - val = append(val, &valaccount) + + if valaccount.Valaddress != "" { + val = append(val, &valaccount) + } } return @@ -63,9 +68,9 @@ func (k Keeper) GetValaccountsFromStaker(ctx sdk.Context, stakerAddress string) for ; iterator.Valid(); iterator.Next() { poolId := binary.BigEndian.Uint64(iterator.Key()[len(stakerAddress) : len(stakerAddress)+8]) - valaccount, valaccountFound := k.GetValaccount(ctx, poolId, stakerAddress) + valaccount, active := k.GetValaccount(ctx, poolId, stakerAddress) - if valaccountFound { + if active { val = append(val, &valaccount) } } @@ -93,11 +98,11 @@ func (k Keeper) GetPoolCount(ctx sdk.Context, stakerAddress string) (poolCount u // DoesValaccountExist only checks if the key is present in the KV-Store // without loading and unmarshalling to full entry -func (k Keeper) DoesValaccountExist(ctx sdk.Context, poolId uint64, stakerAddress string) bool { - storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store := prefix.NewStore(storeAdapter, types.ValaccountPrefix) - return store.Has(types.ValaccountKey(poolId, stakerAddress)) -} +//func (k Keeper) DoesValaccountExist(ctx sdk.Context, poolId uint64, stakerAddress string) bool { +// storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) +// store := prefix.NewStore(storeAdapter, types.ValaccountPrefix) +// return store.Has(types.ValaccountKey(poolId, stakerAddress)) +//} // SetValaccount set a specific Valaccount in the store from its index func (k Keeper) SetValaccount(ctx sdk.Context, valaccount types.Valaccount) { @@ -116,24 +121,8 @@ func (k Keeper) SetValaccount(ctx sdk.Context, valaccount types.Valaccount) { ), []byte{}) } -// removeValaccount removes a Valaccount from the store -func (k Keeper) removeValaccount(ctx sdk.Context, valaccount types.Valaccount) { - storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store := prefix.NewStore(storeAdapter, types.ValaccountPrefix) - store.Delete(types.ValaccountKey( - valaccount.PoolId, - valaccount.Staker, - )) - - storeIndex2 := prefix.NewStore(storeAdapter, types.ValaccountPrefixIndex2) - storeIndex2.Delete(types.ValaccountKeyIndex2( - valaccount.Staker, - valaccount.PoolId, - )) -} - // GetValaccount returns a Valaccount from its index -func (k Keeper) GetValaccount(ctx sdk.Context, poolId uint64, stakerAddress string) (val types.Valaccount, found bool) { +func (k Keeper) GetValaccount(ctx sdk.Context, poolId uint64, stakerAddress string) (val types.Valaccount, active bool) { storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) store := prefix.NewStore(storeAdapter, types.ValaccountPrefix) @@ -142,14 +131,16 @@ func (k Keeper) GetValaccount(ctx sdk.Context, poolId uint64, stakerAddress stri stakerAddress, )) if b == nil { + val.Commission = math.LegacyZeroDec() + val.StakeFraction = math.LegacyZeroDec() return val, false } k.cdc.MustUnmarshal(b, &val) - return val, true + return val, val.Valaddress != "" } -// GetAllValaccounts ... +// GetAllValaccounts returns all active valaccounts func (k Keeper) GetAllValaccounts(ctx sdk.Context) (list []types.Valaccount) { storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) store := prefix.NewStore(storeAdapter, types.ValaccountPrefix) @@ -160,7 +151,9 @@ func (k Keeper) GetAllValaccounts(ctx sdk.Context) (list []types.Valaccount) { for ; iterator.Valid(); iterator.Next() { var val types.Valaccount k.cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) + if val.Valaddress != "" { + list = append(list, val) + } } return diff --git a/x/stakers/keeper/logic_commission.go b/x/stakers/keeper/logic_commission.go index 7071ce9a..f0a6460c 100644 --- a/x/stakers/keeper/logic_commission.go +++ b/x/stakers/keeper/logic_commission.go @@ -6,13 +6,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// OrderNewCommissionChange inserts a new change entry into the queue. +// orderNewCommissionChange inserts a new change entry into the queue. // The queue is checked in every endBlock and when the commissionChangeTime // is over the new commission will be applied to the user. // If another entry is currently in the queue it will be removed. -func (k Keeper) OrderNewCommissionChange(ctx sdk.Context, staker string, commission math.LegacyDec) { +func (k Keeper) orderNewCommissionChange(ctx sdk.Context, staker string, poolId uint64, commission math.LegacyDec) { // Remove existing queue entry - queueEntry, found := k.GetCommissionChangeEntryByIndex2(ctx, staker) + queueEntry, found := k.GetCommissionChangeEntryByIndex2(ctx, staker, poolId) if found { k.RemoveCommissionChangeEntry(ctx, &queueEntry) } @@ -22,6 +22,7 @@ func (k Keeper) OrderNewCommissionChange(ctx sdk.Context, staker string, commiss commissionChangeEntry := types.CommissionChangeEntry{ Index: queueIndex, Staker: staker, + PoolId: poolId, Commission: commission, CreationDate: ctx.BlockTime().Unix(), } @@ -36,18 +37,26 @@ func (k Keeper) ProcessCommissionChangeQueue(ctx sdk.Context) { k.processQueue(ctx, types.QUEUE_IDENTIFIER_COMMISSION, func(index uint64) bool { // Get queue entry in question queueEntry, found := k.GetCommissionChangeEntry(ctx, index) - if !found { // continue with the next entry return true - } else if queueEntry.CreationDate+int64(k.GetCommissionChangeTime(ctx)) <= ctx.BlockTime().Unix() { + } + if queueEntry.CreationDate+int64(k.GetCommissionChangeTime(ctx)) <= ctx.BlockTime().Unix() { k.RemoveCommissionChangeEntry(ctx, &queueEntry) - // TODO no-op + valaccount, valaccountFound := k.GetValaccount(ctx, queueEntry.PoolId, queueEntry.Staker) + if !valaccountFound { + // continue with the next entry + return true + } + + valaccount.Commission = queueEntry.Commission + k.SetValaccount(ctx, valaccount) _ = ctx.EventManager().EmitTypedEvent(&types.EventUpdateCommission{ Staker: queueEntry.Staker, + PoolId: queueEntry.PoolId, Commission: queueEntry.Commission, }) diff --git a/x/stakers/keeper/logic_leave.go b/x/stakers/keeper/logic_leave.go index 108f5f60..4f9dadc0 100644 --- a/x/stakers/keeper/logic_leave.go +++ b/x/stakers/keeper/logic_leave.go @@ -32,17 +32,17 @@ func (k Keeper) ProcessLeavePoolQueue(ctx sdk.Context) { k.processQueue(ctx, types.QUEUE_IDENTIFIER_LEAVE, func(index uint64) bool { // Get queue entry in question queueEntry, found := k.GetLeavePoolEntry(ctx, index) - if !found { // continue with the next entry return true - } else if queueEntry.CreationDate+int64(k.GetLeavePoolTime(ctx)) <= ctx.BlockTime().Unix() { + } + if queueEntry.CreationDate+int64(k.GetLeavePoolTime(ctx)) <= ctx.BlockTime().Unix() { k.RemoveLeavePoolEntry(ctx, &queueEntry) k.LeavePool(ctx, queueEntry.Staker, queueEntry.PoolId) - return true } + return false }) } diff --git a/x/stakers/keeper/logic_stake_fraction.go b/x/stakers/keeper/logic_stake_fraction.go new file mode 100644 index 00000000..45cc9142 --- /dev/null +++ b/x/stakers/keeper/logic_stake_fraction.go @@ -0,0 +1,70 @@ +package keeper + +import ( + "cosmossdk.io/math" + "github.com/KYVENetwork/chain/x/stakers/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// orderNewStakeFractionChange inserts a new change entry into the queue. +// The queue is checked in every endBlock and when the stakeFractionChangeTime +// is over the new stake fraction will be applied to the user. +// If another entry is currently in the queue it will be removed. +func (k Keeper) orderNewStakeFractionChange(ctx sdk.Context, staker string, poolId uint64, stakeFraction math.LegacyDec) { + // Remove existing queue entry + queueEntry, found := k.GetStakeFractionChangeEntryByIndex2(ctx, staker, poolId) + if found { + k.RemoveStakeFractionEntry(ctx, &queueEntry) + } + + queueIndex := k.getNextQueueSlot(ctx, types.QUEUE_IDENTIFIER_STAKE_FRACTION) + + stakeFractionChangeEntry := types.StakeFractionChangeEntry{ + Index: queueIndex, + Staker: staker, + PoolId: poolId, + StakeFraction: stakeFraction, + CreationDate: ctx.BlockTime().Unix(), + } + + k.SetStakeFractionChangeEntry(ctx, stakeFractionChangeEntry) +} + +// ProcessStakeFractionChangeQueue checks the queue for entries which are due +// and can be executed. If this is the case, the new stake fraction +// will be applied to the staker and the pool +func (k Keeper) ProcessStakeFractionChangeQueue(ctx sdk.Context) { + k.processQueue(ctx, types.QUEUE_IDENTIFIER_STAKE_FRACTION, func(index uint64) bool { + // Get queue entry in question + queueEntry, found := k.GetStakeFractionChangeEntry(ctx, index) + if !found { + // continue with the next entry + return true + } + + if queueEntry.CreationDate+int64(k.GetStakeFractionChangeTime(ctx)) <= ctx.BlockTime().Unix() { + k.RemoveStakeFractionEntry(ctx, &queueEntry) + + valaccount, valaccountFound := k.GetValaccount(ctx, queueEntry.PoolId, queueEntry.Staker) + if !valaccountFound { + // continue with the next entry + return true + } + + valaccount.StakeFraction = queueEntry.StakeFraction + k.SetValaccount(ctx, valaccount) + + _ = ctx.EventManager().EmitTypedEvent(&types.EventUpdateStakeFraction{ + Staker: queueEntry.Staker, + PoolId: queueEntry.PoolId, + StakeFraction: queueEntry.StakeFraction, + }) + + // Continue with next entry + return true + } + + // Stop queue processing + return false + }) +} diff --git a/x/stakers/keeper/logic_stakers.go b/x/stakers/keeper/logic_stakers.go index 74e6d110..22009d1f 100644 --- a/x/stakers/keeper/logic_stakers.go +++ b/x/stakers/keeper/logic_stakers.go @@ -1,7 +1,9 @@ package keeper import ( - "math" + m "math" + + "cosmossdk.io/math" "github.com/KYVENetwork/chain/util" stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -18,10 +20,10 @@ import ( // If all pool slots are taken, this is the staker who then // gets kicked out. func (k Keeper) getLowestStaker(ctx sdk.Context, poolId uint64) (val stakingTypes.Validator, found bool) { - var minAmount uint64 = math.MaxUint64 + var minAmount uint64 = m.MaxUint64 for _, staker := range k.getAllStakersOfPool(ctx, poolId) { - delegationAmount := k.GetDelegationAmount(ctx, util.MustAccountAddressFromValAddress(staker.OperatorAddress)) + delegationAmount := k.GetValidatorPoolStake(ctx, util.MustAccountAddressFromValAddress(staker.OperatorAddress), poolId) if delegationAmount < minAmount { minAmount = delegationAmount val = staker @@ -39,16 +41,17 @@ func (k Keeper) getLowestStaker(ctx sdk.Context, poolId uint64) (val stakingType // than the current lowest staker in that pool. // If so, the lowest staker gets removed from the pool, so that the // new staker can join. -func (k Keeper) ensureFreeSlot(ctx sdk.Context, poolId uint64, stakerAddress string) error { +func (k Keeper) ensureFreeSlot(ctx sdk.Context, poolId uint64, stakerAddress string, stakeFraction math.LegacyDec) error { // check if slots are still available if k.GetStakerCountOfPool(ctx, poolId) >= types.MaxStakers { // if not - get lowest staker lowestStaker, _ := k.getLowestStaker(ctx, poolId) lowestStakerAddress := util.MustAccountAddressFromValAddress(lowestStaker.OperatorAddress) - // if new pool joiner has more stake than lowest staker kick him out - newAmount := k.GetDelegationAmount(ctx, stakerAddress) - lowestAmount := k.GetDelegationAmount(ctx, lowestStakerAddress) + // if new pool joiner would have more stake than lowest staker kick him out + newStaker, _ := k.GetValidator(ctx, stakerAddress) + newAmount := uint64(math.LegacyNewDecFromInt(newStaker.GetBondedTokens()).Mul(stakeFraction).TruncateInt64()) + lowestAmount := k.GetValidatorPoolStake(ctx, lowestStakerAddress, poolId) if newAmount > lowestAmount { // remove lowest staker from pool k.LeavePool(ctx, lowestStakerAddress, poolId) diff --git a/x/stakers/keeper/msg_server_join_pool.go b/x/stakers/keeper/msg_server_join_pool.go index 25c9a320..c745550d 100644 --- a/x/stakers/keeper/msg_server_join_pool.go +++ b/x/stakers/keeper/msg_server_join_pool.go @@ -54,7 +54,7 @@ func (k msgServer) JoinPool(goCtx context.Context, msg *types.MsgJoinPool) (*typ } // Only join if it is possible - if errFreeSlot := k.ensureFreeSlot(ctx, msg.PoolId, msg.Creator); errFreeSlot != nil { + if errFreeSlot := k.ensureFreeSlot(ctx, msg.PoolId, msg.Creator, msg.StakeFraction); errFreeSlot != nil { return nil, errFreeSlot } @@ -76,17 +76,21 @@ func (k msgServer) JoinPool(goCtx context.Context, msg *types.MsgJoinPool) (*typ } } - k.AddValaccountToPool(ctx, msg.PoolId, msg.Creator, msg.Valaddress) + // TODO: check here if validator with his stake fraction is over the maximum join limit + + k.AddValaccountToPool(ctx, msg.PoolId, msg.Creator, msg.Valaddress, msg.Commission, msg.StakeFraction) if err := util.TransferFromAddressToAddress(k.bankKeeper, ctx, msg.Creator, msg.Valaddress, msg.Amount); err != nil { return nil, err } _ = ctx.EventManager().EmitTypedEvent(&types.EventJoinPool{ - PoolId: msg.PoolId, - Staker: msg.Creator, - Valaddress: msg.Valaddress, - Amount: msg.Amount, + PoolId: msg.PoolId, + Staker: msg.Creator, + Valaddress: msg.Valaddress, + Amount: msg.Amount, + Commission: msg.Commission, + StakeFraction: msg.StakeFraction, }) return &types.MsgJoinPoolResponse{}, nil diff --git a/x/stakers/keeper/msg_server_join_pool_test.go b/x/stakers/keeper/msg_server_join_pool_test.go index 1d3e6000..85d7f519 100644 --- a/x/stakers/keeper/msg_server_join_pool_test.go +++ b/x/stakers/keeper/msg_server_join_pool_test.go @@ -32,6 +32,9 @@ TEST CASES - msg_server_join_pool.go * Try to join another pool with the same valaddress again * Try to join another pool with a valaddress that is already used by another staker * Try to join another pool with a different valaddress +* Try to join pool with empty valaddress +* Try to join pool with empty commission +* Try to join pool with empty stake fraction * Join a pool with a valaddress which does not exist on chain yet * Join a pool with a valaddress which does not exist on chain yet and send 0 funds * Join a pool with an invalid valaddress @@ -40,6 +43,8 @@ TEST CASES - msg_server_join_pool.go * Fail to kick out lowest staker because not enough stake * Kick out lowest staker with respect to stake + delegation * Fail to kick out lowest staker because not enough stake + delegation +* Join pool again with same valaddress after staker has left pool +* Join pool again with different valaddress after staker has left pool */ @@ -48,6 +53,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { initialBalanceStaker0 := uint64(0) initialBalanceValaddress0 := uint64(0) + initialBalanceValaddress1 := uint64(0) gov := s.App().GovKeeper.GetGovernanceAccount(s.Ctx()).GetAddress().String() @@ -69,6 +75,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) initialBalanceValaddress0 = s.GetBalanceFromAddress(i.VALADDRESS_0_A) + initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_0_B) }) AfterEach(func() { @@ -84,10 +91,12 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { It("Join the first pool as the first staker to a newly created pool", func() { // ACT s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -101,9 +110,9 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(HaveLen(1)) - valaccount, found := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + valaccount, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(found).To(BeTrue()) + Expect(active).To(BeTrue()) Expect(valaccount.Staker).To(Equal(i.STAKER_0)) Expect(valaccount.PoolId).To(BeZero()) @@ -118,7 +127,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(totalStakeOfPool)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(totalStakeOfPool)) }) @@ -140,10 +149,12 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { // ACT _, err := s.RunTx(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 1, - Valaddress: i.VALADDRESS_0_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 1, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) Expect(err.Error()).To(Equal("can not join disabled pool: internal logic error")) @@ -159,9 +170,9 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(HaveLen(0)) - _, found := s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) + _, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) - Expect(found).To(BeFalse()) + Expect(active).To(BeFalse()) valaccountsOfPool := s.App().StakersKeeper.GetAllValaccountsOfPool(s.Ctx(), 1) @@ -170,7 +181,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 1) Expect(totalStakeOfPool).To(Equal(0 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 1)).To(Equal(0 * i.KYVE)) Expect(s.App().StakersKeeper.GetActiveStakers(s.Ctx())).To(HaveLen(0)) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(100 * i.KYVE)) }) @@ -180,18 +191,22 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0 * i.KYVE, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 0 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 0 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -205,9 +220,9 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(HaveLen(1)) - valaccount, found := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + valaccount, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(found).To(BeTrue()) + Expect(active).To(BeTrue()) Expect(valaccount.Staker).To(Equal(i.STAKER_0)) Expect(valaccount.PoolId).To(BeZero()) @@ -222,17 +237,19 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(200 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(100 * i.KYVE)) }) It("Self-Delegate more KYVE after joining a pool", func() { // ARRANGE s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) @@ -250,9 +267,9 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(HaveLen(1)) - valaccount, found := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + valaccount, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(found).To(BeTrue()) + Expect(active).To(BeTrue()) Expect(valaccount.Staker).To(Equal(i.STAKER_0)) Expect(valaccount.PoolId).To(BeZero()) @@ -268,25 +285,29 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(totalStakeOfPool).To(Equal(150 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(totalStakeOfPool)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(totalStakeOfPool)) }) It("Try to join the same pool with the same valaddress again", func() { // ARRANGE s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT s.RunTxStakersError(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -298,10 +319,12 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { It("join a pool with the same valaddress as the staker address", func() { // ACT s.RunTxStakersError(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.STAKER_0, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.STAKER_0, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -313,18 +336,22 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { It("Try to join the same pool with a different valaddress", func() { // ARRANGE s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT s.RunTxStakersError(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -336,10 +363,12 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { It("Try to join another pool with the same valaddress again", func() { // ARRANGE s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) msg := &pooltypes.MsgCreatePool{ @@ -353,10 +382,12 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { // ACT s.RunTxStakersError(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 1, - Valaddress: i.VALADDRESS_0_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 1, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -378,18 +409,22 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 1, - Valaddress: i.VALADDRESS_1_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_1, + PoolId: 1, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -400,20 +435,24 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { It("Try to join pool with a valaddress that is already used by another staker", func() { // ARRANGE s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) // ACT s.RunTxStakersError(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -424,10 +463,12 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { It("Try to join another pool with a different valaddress", func() { // ARRANGE s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) msg := &pooltypes.MsgCreatePool{ @@ -441,9 +482,11 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { // ACT s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 1, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_0, + PoolId: 1, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -451,13 +494,61 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(HaveLen(2)) }) - It("Join a pool with a valaddress which does not exist on chain yet", func() { + It("Try to join pool with empty valaddress", func() { // ACT - s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + s.RunTxStakersError(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: "", + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // ASSERT + valaccountsOfStaker := s.App().StakersKeeper.GetValaccountsFromStaker(s.Ctx(), i.STAKER_0) + Expect(valaccountsOfStaker).To(BeEmpty()) + }) + + It("Try to join pool with empty commission", func() { + // ACT + s.RunTxStakersError(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // ASSERT + valaccountsOfStaker := s.App().StakersKeeper.GetValaccountsFromStaker(s.Ctx(), i.STAKER_0) + Expect(valaccountsOfStaker).To(BeEmpty()) + }) + + It("Try to join pool with empty stake fraction", func() { + // ACT + s.RunTxStakersError(&stakerstypes.MsgJoinPool{ Creator: i.STAKER_0, PoolId: 0, - Valaddress: "kyve1dx0nvx7y9d44jvr2dr6r2p636jea3f9827rn0x", + Valaddress: i.VALADDRESS_0_A, Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + }) + + // ASSERT + valaccountsOfStaker := s.App().StakersKeeper.GetValaccountsFromStaker(s.Ctx(), i.STAKER_0) + Expect(valaccountsOfStaker).To(BeEmpty()) + }) + + It("Join a pool with a valaddress which does not exist on chain yet", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: "kyve1dx0nvx7y9d44jvr2dr6r2p636jea3f9827rn0x", + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -471,9 +562,9 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(HaveLen(1)) - valaccount, found := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + valaccount, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(found).To(BeTrue()) + Expect(active).To(BeTrue()) Expect(valaccount.Staker).To(Equal(i.STAKER_0)) Expect(valaccount.PoolId).To(BeZero()) @@ -488,17 +579,19 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(totalStakeOfPool)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(totalStakeOfPool)) }) It("Join a pool with a valaddress which does not exist on chain yet and send 0 funds", func() { // ACT s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: "kyve1dx0nvx7y9d44jvr2dr6r2p636jea3f9827rn0x", - Amount: 0 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: "kyve1dx0nvx7y9d44jvr2dr6r2p636jea3f9827rn0x", + Amount: 0 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -512,9 +605,9 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(HaveLen(1)) - valaccount, found := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + valaccount, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(found).To(BeTrue()) + Expect(active).To(BeTrue()) Expect(valaccount.Staker).To(Equal(i.STAKER_0)) Expect(valaccount.PoolId).To(BeZero()) @@ -529,17 +622,19 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(totalStakeOfPool)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(totalStakeOfPool)) }) It("Join a pool with an invalid valaddress", func() { // ACT s.RunTxStakersError(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: "invalid_valaddress", - Amount: 100 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: "invalid_valaddress", + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -551,10 +646,12 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { It("Join a pool and fund the valaddress with more KYVE than available in balance", func() { // ACT s.RunTxStakersError(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: "invalid_valaddress", - Amount: initialBalanceStaker0 + 1, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: "invalid_valaddress", + Amount: initialBalanceStaker0 + 1, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -568,19 +665,23 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(stakerstypes.MaxStakers).To(Equal(50)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 1, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 1, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) for k := 0; k < 49; k++ { s.CreateValidator(i.DUMMY[k], fmt.Sprintf("dummy-%d", k), int64(150*i.KYVE)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.DUMMY[k], - PoolId: 0, - Valaddress: i.VALDUMMY[k], - Amount: 1, + Creator: i.DUMMY[k], + PoolId: 0, + Valaddress: i.VALDUMMY[k], + Amount: 1, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) } @@ -591,10 +692,12 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { // Act s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 1, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 1, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // Assert @@ -607,19 +710,23 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(stakerstypes.MaxStakers).To(Equal(50)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 1, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 1, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) for k := 0; k < 49; k++ { s.CreateValidator(i.DUMMY[k], fmt.Sprintf("dummy-%d", k), int64(150*i.KYVE)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.DUMMY[k], - PoolId: 0, - Valaddress: i.VALDUMMY[k], - Amount: 1, + Creator: i.DUMMY[k], + PoolId: 0, + Valaddress: i.VALDUMMY[k], + Amount: 1, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) } @@ -630,10 +737,12 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { // Act s.RunTxStakersError(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 1, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 1, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // Assert @@ -647,19 +756,23 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(stakerstypes.MaxStakers).To(Equal(50)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 1 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 1 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) for k := 0; k < 49; k++ { s.CreateValidator(i.DUMMY[k], fmt.Sprintf("dummy-%d", k), int64(150*i.KYVE)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.DUMMY[k], - PoolId: 0, - Valaddress: i.VALDUMMY[k], - Amount: 1 * i.KYVE, + Creator: i.DUMMY[k], + PoolId: 0, + Valaddress: i.VALDUMMY[k], + Amount: 1 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) } @@ -676,10 +789,12 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { // ACT s.RunTxStakersError(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 1, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 1, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -693,19 +808,23 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(stakerstypes.MaxStakers).To(Equal(50)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 1, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 1, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) for k := 0; k < 49; k++ { s.CreateValidator(i.DUMMY[k], fmt.Sprintf("dummy-%d", k), int64(150*i.KYVE)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.DUMMY[k], - PoolId: 0, - Valaddress: i.VALDUMMY[k], - Amount: 1, + Creator: i.DUMMY[k], + PoolId: 0, + Valaddress: i.VALDUMMY[k], + Amount: 1, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) } @@ -716,10 +835,12 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { // Act s.RunTxStakersError(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 1, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 1, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // Assert @@ -733,19 +854,23 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(stakerstypes.MaxStakers).To(Equal(50)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, - Amount: 1 * i.KYVE, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 1 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) for k := 0; k < 49; k++ { s.CreateValidator(i.DUMMY[k], fmt.Sprintf("dummy-%d", k), int64(150*i.KYVE)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.DUMMY[k], - PoolId: 0, - Valaddress: i.VALDUMMY[k], - Amount: 1 * i.KYVE, + Creator: i.DUMMY[k], + PoolId: 0, + Valaddress: i.VALDUMMY[k], + Amount: 1 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) } @@ -762,10 +887,12 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { // ACT s.RunTxStakersError(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 0, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ASSERT @@ -773,4 +900,142 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0)).To(ContainElement(i.STAKER_0)) Expect(s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0)).NotTo(ContainElement(i.STAKER_1)) }) + + It("Join pool again with same valaddress after staker has left pool", func() { + // ARRANGE + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.RunTxStakersSuccess(&stakerstypes.MsgLeavePool{ + Creator: i.STAKER_0, + PoolId: 0, + }) + + // wait for leave pool + s.CommitAfterSeconds(s.App().StakersKeeper.GetLeavePoolTime(s.Ctx())) + s.CommitAfterSeconds(1) + + _, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(active).To(BeFalse()) + + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 50 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.2"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // ASSERT + balanceAfterStaker0 := s.GetBalanceFromAddress(i.STAKER_0) + balanceAfterValaddress0 := s.GetBalanceFromAddress(i.VALADDRESS_0_A) + + Expect(initialBalanceStaker0 - balanceAfterStaker0).To(Equal(150 * i.KYVE)) + Expect(balanceAfterValaddress0 - initialBalanceValaddress0).To(Equal(150 * i.KYVE)) + + valaccountsOfStaker := s.App().StakersKeeper.GetValaccountsFromStaker(s.Ctx(), i.STAKER_0) + + Expect(valaccountsOfStaker).To(HaveLen(1)) + + valaccount, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + + Expect(active).To(BeTrue()) + + Expect(valaccount.Staker).To(Equal(i.STAKER_0)) + Expect(valaccount.PoolId).To(BeZero()) + Expect(valaccount.Valaddress).To(Equal(i.VALADDRESS_0_A)) + Expect(valaccount.Points).To(BeZero()) + Expect(valaccount.IsLeaving).To(BeFalse()) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.2"))) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("1"))) + + valaccountsOfPool := s.App().StakersKeeper.GetAllValaccountsOfPool(s.Ctx(), 0) + + Expect(valaccountsOfPool).To(HaveLen(1)) + + totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + + Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) + + Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(totalStakeOfPool)) + }) + + It("Join pool again with different valaddress after staker has left pool", func() { + // ARRANGE + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.RunTxStakersSuccess(&stakerstypes.MsgLeavePool{ + Creator: i.STAKER_0, + PoolId: 0, + }) + + // wait for leave pool + s.CommitAfterSeconds(s.App().StakersKeeper.GetLeavePoolTime(s.Ctx())) + s.CommitAfterSeconds(1) + + _, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(active).To(BeFalse()) + + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_B, + Amount: 50 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.2"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // ASSERT + balanceAfterStaker0 := s.GetBalanceFromAddress(i.STAKER_0) + balanceAfterValaddress0 := s.GetBalanceFromAddress(i.VALADDRESS_0_A) + balanceAfterValaddress1 := s.GetBalanceFromAddress(i.VALADDRESS_0_B) + + Expect(initialBalanceStaker0 - balanceAfterStaker0).To(Equal(150 * i.KYVE)) + Expect(balanceAfterValaddress0 - initialBalanceValaddress0).To(Equal(100 * i.KYVE)) + Expect(balanceAfterValaddress1 - initialBalanceValaddress1).To(Equal(50 * i.KYVE)) + + valaccountsOfStaker := s.App().StakersKeeper.GetValaccountsFromStaker(s.Ctx(), i.STAKER_0) + + Expect(valaccountsOfStaker).To(HaveLen(1)) + + valaccount, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + + Expect(active).To(BeTrue()) + + Expect(valaccount.Staker).To(Equal(i.STAKER_0)) + Expect(valaccount.PoolId).To(BeZero()) + Expect(valaccount.Valaddress).To(Equal(i.VALADDRESS_0_B)) + Expect(valaccount.Points).To(BeZero()) + Expect(valaccount.IsLeaving).To(BeFalse()) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.2"))) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("1"))) + + valaccountsOfPool := s.App().StakersKeeper.GetAllValaccountsOfPool(s.Ctx(), 0) + + Expect(valaccountsOfPool).To(HaveLen(1)) + + totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + + Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) + + Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(totalStakeOfPool)) + }) }) diff --git a/x/stakers/keeper/msg_server_leave_pool.go b/x/stakers/keeper/msg_server_leave_pool.go index bee131ad..75627d3c 100644 --- a/x/stakers/keeper/msg_server_leave_pool.go +++ b/x/stakers/keeper/msg_server_leave_pool.go @@ -16,8 +16,8 @@ import ( func (k msgServer) LeavePool(goCtx context.Context, msg *types.MsgLeavePool) (*types.MsgLeavePoolResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - valaccount, valaccountFound := k.GetValaccount(ctx, msg.PoolId, msg.Creator) - if !valaccountFound { + valaccount, active := k.GetValaccount(ctx, msg.PoolId, msg.Creator) + if !active { return nil, errors.Wrapf(errorsTypes.ErrInvalidRequest, types.ErrAlreadyLeftPool.Error()) } diff --git a/x/stakers/keeper/msg_server_leave_pool_test.go b/x/stakers/keeper/msg_server_leave_pool_test.go index 05f76838..80e5bfad 100644 --- a/x/stakers/keeper/msg_server_leave_pool_test.go +++ b/x/stakers/keeper/msg_server_leave_pool_test.go @@ -45,9 +45,11 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { // join pool s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 0, - Valaddress: i.VALADDRESS_0_A, + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) }) @@ -68,15 +70,17 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(HaveLen(1)) - valaccount, found := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + valaccount, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(found).To(BeTrue()) + Expect(active).To(BeTrue()) Expect(valaccount.Staker).To(Equal(i.STAKER_0)) Expect(valaccount.PoolId).To(BeZero()) Expect(valaccount.Valaddress).To(Equal(i.VALADDRESS_0_A)) Expect(valaccount.Points).To(BeZero()) Expect(valaccount.IsLeaving).To(BeTrue()) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("1"))) valaccountsOfPool := s.App().StakersKeeper.GetAllValaccountsOfPool(s.Ctx(), 0) @@ -85,7 +89,7 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(totalStakeOfPool)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(totalStakeOfPool)) s.PerformValidityChecks() @@ -98,9 +102,9 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(BeEmpty()) - _, found = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + valaccount, active = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(found).To(BeFalse()) + Expect(active).To(BeFalse()) valaccountsOfPool = s.App().StakersKeeper.GetAllValaccountsOfPool(s.Ctx(), 0) @@ -108,6 +112,10 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { totalStakeOfPool = s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(BeZero()) + + // check if commission and stake fraction is still available + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("1"))) }) It("Leave a pool multiple other stakers have joined previously", func() { @@ -115,10 +123,12 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_1, - PoolId: 0, - Valaddress: i.VALADDRESS_1_A, - Amount: 100 * i.KYVE, + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) // ACT @@ -133,15 +143,17 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(HaveLen(1)) - valaccount, found := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + valaccount, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(found).To(BeTrue()) + Expect(active).To(BeTrue()) Expect(valaccount.Staker).To(Equal(i.STAKER_0)) Expect(valaccount.PoolId).To(BeZero()) Expect(valaccount.Valaddress).To(Equal(i.VALADDRESS_0_A)) Expect(valaccount.Points).To(BeZero()) Expect(valaccount.IsLeaving).To(BeTrue()) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("1"))) valaccountsOfPool := s.App().StakersKeeper.GetAllValaccountsOfPool(s.Ctx(), 0) @@ -150,7 +162,7 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(200 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(100 * i.KYVE)) s.PerformValidityChecks() @@ -163,9 +175,9 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(BeEmpty()) - _, found = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + valaccount, active = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(found).To(BeFalse()) + Expect(active).To(BeFalse()) valaccountsOfPool = s.App().StakersKeeper.GetAllValaccountsOfPool(s.Ctx(), 0) @@ -173,6 +185,10 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { totalStakeOfPool = s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) + + // check if commission and stake fraction is still available + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("1"))) }) It("Try to leave a pool again", func() { @@ -213,9 +229,11 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { s.RunTxPoolSuccess(msg) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ - Creator: i.STAKER_0, - PoolId: 1, - Valaddress: i.VALADDRESS_1_A, + Creator: i.STAKER_0, + PoolId: 1, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), }) s.PerformValidityChecks() @@ -230,15 +248,17 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(HaveLen(2)) - valaccount, found := s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) + valaccount, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) - Expect(found).To(BeTrue()) + Expect(active).To(BeTrue()) Expect(valaccount.Staker).To(Equal(i.STAKER_0)) Expect(valaccount.PoolId).To(Equal(uint64(1))) Expect(valaccount.Valaddress).To(Equal(i.VALADDRESS_1_A)) Expect(valaccount.Points).To(BeZero()) Expect(valaccount.IsLeaving).To(BeTrue()) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("1"))) valaccountsOfPool := s.App().StakersKeeper.GetAllValaccountsOfPool(s.Ctx(), 1) @@ -247,7 +267,7 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 1) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationAmount(s.Ctx(), i.STAKER_0)).To(Equal(totalStakeOfPool)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(totalStakeOfPool)) // wait for leave pool @@ -258,9 +278,9 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { Expect(valaccountsOfStaker).To(HaveLen(1)) - _, found = s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) + valaccount, active = s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) - Expect(found).To(BeFalse()) + Expect(active).To(BeFalse()) valaccountsOfPool = s.App().StakersKeeper.GetAllValaccountsOfPool(s.Ctx(), 1) @@ -268,6 +288,10 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { totalStakeOfPool = s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 1) Expect(totalStakeOfPool).To(BeZero()) + + // check if commission and stake fraction is still available + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("1"))) }) It("Leave a pool a staker has never joined", func() { @@ -290,5 +314,13 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { valaccountsOfStaker = s.App().StakersKeeper.GetValaccountsFromStaker(s.Ctx(), i.STAKER_1) Expect(valaccountsOfStaker).To(BeEmpty()) + + valaccount, active := s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) + + Expect(active).To(BeFalse()) + + // check if commission and stake fraction is still available + Expect(valaccount.Commission).To(Equal(math.LegacyZeroDec())) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyZeroDec())) }) }) diff --git a/x/stakers/keeper/msg_server_update_commission.go b/x/stakers/keeper/msg_server_update_commission.go index e303078d..7b84fd63 100644 --- a/x/stakers/keeper/msg_server_update_commission.go +++ b/x/stakers/keeper/msg_server_update_commission.go @@ -3,6 +3,10 @@ package keeper import ( "context" + sdk "github.com/cosmos/cosmos-sdk/types" + errorsTypes "github.com/cosmos/cosmos-sdk/types/errors" + + "cosmossdk.io/errors" "github.com/KYVENetwork/chain/x/stakers/types" ) @@ -11,7 +15,15 @@ import ( // If an update is currently in the queue it will get removed from the queue // and the user needs to wait again for the full time to pass. func (k msgServer) UpdateCommission(goCtx context.Context, msg *types.MsgUpdateCommission) (*types.MsgUpdateCommissionResponse, error) { - // TODO no-op, will be replaced by a per pool commission + ctx := sdk.UnwrapSDKContext(goCtx) + + // Check if creator is active in the pool + if _, active := k.GetValaccount(ctx, msg.PoolId, msg.Creator); !active { + return nil, errors.Wrap(errorsTypes.ErrUnauthorized, types.ErrNoStaker.Error()) + } + + // Insert commission change into queue + k.orderNewCommissionChange(ctx, msg.Creator, msg.PoolId, msg.Commission) return &types.MsgUpdateCommissionResponse{}, nil } diff --git a/x/stakers/keeper/msg_server_update_commission_test.go b/x/stakers/keeper/msg_server_update_commission_test.go new file mode 100644 index 00000000..89dac8e5 --- /dev/null +++ b/x/stakers/keeper/msg_server_update_commission_test.go @@ -0,0 +1,281 @@ +package keeper_test + +import ( + "cosmossdk.io/math" + pooltypes "github.com/KYVENetwork/chain/x/pool/types" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + i "github.com/KYVENetwork/chain/testutil/integration" + stakerstypes "github.com/KYVENetwork/chain/x/stakers/types" +) + +/* + +TEST CASES - msg_server_update_commission.go + +* Check if initial commission is correct +* Update commission to 50% from previous commission +* Update commission to 0% from previous commission +* Update commission to 100% from previous commission +* Update commission with a negative number from previous commission +* Update commission with a too high number from previous commission +* Update commission multiple times during the commission change time +* Update commission multiple times during the commission change time with the same value +* Update commission with multiple pools + +*/ + +var _ = Describe("msg_server_update_commission.go", Ordered, func() { + s := i.NewCleanChain() + + gov := s.App().GovKeeper.GetGovernanceAccount(s.Ctx()).GetAddress().String() + + BeforeEach(func() { + // init new clean chain + s = i.NewCleanChain() + + // create pool + msg := &pooltypes.MsgCreatePool{ + Authority: gov, + UploadInterval: 60, + MaxBundleSize: 100, + InflationShareWeight: math.LegacyZeroDec(), + Binaries: "{}", + } + s.RunTxPoolSuccess(msg) + + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + }) + + AfterEach(func() { + s.PerformValidityChecks() + }) + + It("Get the default commission from a newly joined pool", func() { + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + }) + + It("Update commission to 50% from previous commission", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 0, + Commission: math.LegacyMustNewDecFromStr("0.5"), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + + // wait for update + s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) + s.CommitAfterSeconds(1) + + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) + }) + + It("Update commission to 0% from previous commission", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 0, + Commission: math.LegacyZeroDec(), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + + // wait for update + s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) + s.CommitAfterSeconds(1) + + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyZeroDec())) + }) + + It("Update commission to 100% from previous commission", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 0, + Commission: math.LegacyOneDec(), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + + // wait for update + s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) + s.CommitAfterSeconds(1) + + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyOneDec())) + }) + + It("Update commission with a negative number from previous commission", func() { + // ACT + s.RunTxStakersError(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 0, + Commission: math.LegacyMustNewDecFromStr("-0.5"), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + }) + + It("Update commission with a too high number from previous commission", func() { + // ACT + s.RunTxStakersError(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 0, + Commission: math.LegacyNewDec(2), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + }) + + It("Update commission multiple times during the commission change time", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 0, + Commission: math.LegacyMustNewDecFromStr("0.5"), + }) + s.PerformValidityChecks() + + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 0, + Commission: math.LegacyMustNewDecFromStr("0.2"), + }) + s.PerformValidityChecks() + + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 0, + Commission: math.LegacyMustNewDecFromStr("0.3"), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + + // wait for update + s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) + s.CommitAfterSeconds(1) + + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.3"))) + }) + + It("Update commission multiple times during the commission change time with the same value", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 0, + Commission: math.LegacyMustNewDecFromStr("0.5"), + }) + + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 0, + Commission: math.LegacyMustNewDecFromStr("0.2"), + }) + + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 0, + Commission: math.LegacyMustNewDecFromStr("0.1"), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + + // wait for update + s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) + s.CommitAfterSeconds(1) + + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + }) + + It("Update commission with multiple pools", func() { + // ARRANGE + msg := &pooltypes.MsgCreatePool{ + Authority: gov, + UploadInterval: 60, + MaxBundleSize: 100, + InflationShareWeight: math.LegacyZeroDec(), + Binaries: "{}", + } + s.RunTxPoolSuccess(msg) + + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 1, + Valaddress: i.VALADDRESS_0_B, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 0, + Commission: math.LegacyMustNewDecFromStr("0.5"), + }) + + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateCommission{ + Creator: i.STAKER_0, + PoolId: 1, + Commission: math.LegacyMustNewDecFromStr("0.5"), + }) + + s.PerformValidityChecks() + + // ASSERT + valaccount0, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount0.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + + valaccount1, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) + Expect(valaccount1.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + + // wait for update + s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) + s.CommitAfterSeconds(1) + + valaccount0, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount0.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) + + valaccount1, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) + Expect(valaccount1.Commission).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) + }) +}) diff --git a/x/stakers/keeper/msg_server_update_params_test.go b/x/stakers/keeper/msg_server_update_params_test.go index a0914713..89b47d11 100644 --- a/x/stakers/keeper/msg_server_update_params_test.go +++ b/x/stakers/keeper/msg_server_update_params_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "cosmossdk.io/math" i "github.com/KYVENetwork/chain/testutil/integration" sdk "github.com/cosmos/cosmos-sdk/types" @@ -33,6 +34,18 @@ TEST CASES - msg_server_update_params.go * Update leave pool time * Update leave pool time with invalid value +* Update stake fraction change time +* Update stake fraction change time with invalid value + +* Update vote slash +* Update vote slash with invalid value + +* Update upload slash +* Update upload slash with invalid value + +* Update timeout slash +* Update timeout slash with invalid value + */ var _ = Describe("msg_server_update_params.go", Ordered, func() { @@ -234,6 +247,7 @@ var _ = Describe("msg_server_update_params.go", Ordered, func() { Expect(updatedParams.CommissionChangeTime).To(Equal(uint64(5))) Expect(updatedParams.LeavePoolTime).To(Equal(types.DefaultLeavePoolTime)) + Expect(updatedParams.StakeFractionChangeTime).To(Equal(types.DefaultStakeFractionChangeTime)) }) It("Update commission change time with invalid value", func() { @@ -264,6 +278,7 @@ var _ = Describe("msg_server_update_params.go", Ordered, func() { Expect(updatedParams.CommissionChangeTime).To(Equal(types.DefaultCommissionChangeTime)) Expect(updatedParams.LeavePoolTime).To(Equal(types.DefaultLeavePoolTime)) + Expect(updatedParams.StakeFractionChangeTime).To(Equal(types.DefaultStakeFractionChangeTime)) }) It("Update leave pool time", func() { @@ -300,6 +315,7 @@ var _ = Describe("msg_server_update_params.go", Ordered, func() { Expect(updatedParams.CommissionChangeTime).To(Equal(types.DefaultCommissionChangeTime)) Expect(updatedParams.LeavePoolTime).To(Equal(uint64(5))) + Expect(updatedParams.StakeFractionChangeTime).To(Equal(types.DefaultStakeFractionChangeTime)) }) It("Update leave pool time with invalid value", func() { @@ -330,5 +346,278 @@ var _ = Describe("msg_server_update_params.go", Ordered, func() { Expect(updatedParams.CommissionChangeTime).To(Equal(types.DefaultCommissionChangeTime)) Expect(updatedParams.LeavePoolTime).To(Equal(types.DefaultLeavePoolTime)) + Expect(updatedParams.StakeFractionChangeTime).To(Equal(types.DefaultStakeFractionChangeTime)) + }) + + It("Update stake fraction change time", func() { + // ARRANGE + payload := `{ + "stake_fraction_change_time": 5 + }` + + msg := &types.MsgUpdateParams{ + Authority: gov, + Payload: payload, + } + + proposal, _ := govV1Types.NewMsgSubmitProposal( + []sdk.Msg{msg}, minDeposit, i.DUMMY[0], "", "title", "summary", false, + ) + + vote := govV1Types.NewMsgVote( + voter, 1, govV1Types.VoteOption_VOTE_OPTION_YES, "", + ) + + // ACT + _, submitErr := s.RunTx(proposal) + _, voteErr := s.RunTx(vote) + + s.CommitAfter(*votingPeriod) + s.Commit() + + // ASSERT + updatedParams := s.App().StakersKeeper.GetParams(s.Ctx()) + + Expect(submitErr).NotTo(HaveOccurred()) + Expect(voteErr).NotTo(HaveOccurred()) + + Expect(updatedParams.CommissionChangeTime).To(Equal(types.DefaultCommissionChangeTime)) + Expect(updatedParams.LeavePoolTime).To(Equal(types.DefaultLeavePoolTime)) + Expect(updatedParams.StakeFractionChangeTime).To(Equal(uint64(5))) + }) + + It("Update stake fraction change time with invalid value", func() { + // ARRANGE + payload := `{ + "stake_fraction_change_time": "5" + }` + + msg := &types.MsgUpdateParams{ + Authority: gov, + Payload: payload, + } + + proposal, _ := govV1Types.NewMsgSubmitProposal( + []sdk.Msg{msg}, minDeposit, i.DUMMY[0], "", "title", "summary", false, + ) + + // ACT + _, submitErr := s.RunTx(proposal) + + s.CommitAfter(*votingPeriod) + s.Commit() + + // ASSERT + updatedParams := s.App().StakersKeeper.GetParams(s.Ctx()) + + Expect(submitErr).To(HaveOccurred()) + + Expect(updatedParams.CommissionChangeTime).To(Equal(types.DefaultCommissionChangeTime)) + Expect(updatedParams.LeavePoolTime).To(Equal(types.DefaultLeavePoolTime)) + Expect(updatedParams.StakeFractionChangeTime).To(Equal(types.DefaultStakeFractionChangeTime)) + }) + + It("Update vote slash", func() { + // ARRANGE + payload := `{ + "vote_slash": "0.05" + }` + + msg := &types.MsgUpdateParams{ + Authority: gov, + Payload: payload, + } + + proposal, _ := govV1Types.NewMsgSubmitProposal( + []sdk.Msg{msg}, minDeposit, i.DUMMY[0], "", "title", "summary", false, + ) + + vote := govV1Types.NewMsgVote( + voter, 1, govV1Types.VoteOption_VOTE_OPTION_YES, "", + ) + + // ACT + _, submitErr := s.RunTx(proposal) + _, voteErr := s.RunTx(vote) + + s.CommitAfter(*votingPeriod) + s.Commit() + + // ASSERT + updatedParams := s.App().StakersKeeper.GetParams(s.Ctx()) + + Expect(submitErr).NotTo(HaveOccurred()) + Expect(voteErr).NotTo(HaveOccurred()) + + Expect(updatedParams.UploadSlash).To(Equal(types.DefaultUploadSlash)) + Expect(updatedParams.TimeoutSlash).To(Equal(types.DefaultTimeoutSlash)) + Expect(updatedParams.VoteSlash).To(Equal(math.LegacyMustNewDecFromStr("0.05"))) + }) + + It("Update vote slash with invalid value", func() { + // ARRANGE + payload := `{ + "vote_slash": "invalid" + }` + + msg := &types.MsgUpdateParams{ + Authority: gov, + Payload: payload, + } + + proposal, _ := govV1Types.NewMsgSubmitProposal( + []sdk.Msg{msg}, minDeposit, i.DUMMY[0], "", "title", "summary", false, + ) + + // ACT + _, submitErr := s.RunTx(proposal) + + s.CommitAfter(*votingPeriod) + s.Commit() + + // ASSERT + updatedParams := s.App().StakersKeeper.GetParams(s.Ctx()) + + Expect(submitErr).To(HaveOccurred()) + + Expect(updatedParams.UploadSlash).To(Equal(types.DefaultUploadSlash)) + Expect(updatedParams.TimeoutSlash).To(Equal(types.DefaultTimeoutSlash)) + Expect(updatedParams.VoteSlash).To(Equal(types.DefaultVoteSlash)) + }) + + It("Update upload slash", func() { + // ARRANGE + payload := `{ + "upload_slash": "0.05" + }` + + msg := &types.MsgUpdateParams{ + Authority: gov, + Payload: payload, + } + + proposal, _ := govV1Types.NewMsgSubmitProposal( + []sdk.Msg{msg}, minDeposit, i.DUMMY[0], "", "title", "summary", false, + ) + + vote := govV1Types.NewMsgVote( + voter, 1, govV1Types.VoteOption_VOTE_OPTION_YES, "", + ) + + // ACT + _, submitErr := s.RunTx(proposal) + _, voteErr := s.RunTx(vote) + + s.CommitAfter(*votingPeriod) + s.Commit() + + // ASSERT + updatedParams := s.App().StakersKeeper.GetParams(s.Ctx()) + + Expect(submitErr).NotTo(HaveOccurred()) + Expect(voteErr).NotTo(HaveOccurred()) + + Expect(updatedParams.UploadSlash).To(Equal(math.LegacyMustNewDecFromStr("0.05"))) + Expect(updatedParams.TimeoutSlash).To(Equal(types.DefaultTimeoutSlash)) + Expect(updatedParams.VoteSlash).To(Equal(types.DefaultVoteSlash)) + }) + + It("Update upload slash with invalid value", func() { + // ARRANGE + payload := `{ + "upload_slash": "1.5" + }` + + msg := &types.MsgUpdateParams{ + Authority: gov, + Payload: payload, + } + + proposal, _ := govV1Types.NewMsgSubmitProposal( + []sdk.Msg{msg}, minDeposit, i.DUMMY[0], "", "title", "summary", false, + ) + + // ACT + _, submitErr := s.RunTx(proposal) + + s.CommitAfter(*votingPeriod) + s.Commit() + + // ASSERT + updatedParams := s.App().StakersKeeper.GetParams(s.Ctx()) + + Expect(submitErr).To(HaveOccurred()) + + Expect(updatedParams.UploadSlash).To(Equal(types.DefaultUploadSlash)) + Expect(updatedParams.TimeoutSlash).To(Equal(types.DefaultTimeoutSlash)) + Expect(updatedParams.VoteSlash).To(Equal(types.DefaultVoteSlash)) + }) + + It("Update timeout slash", func() { + // ARRANGE + payload := `{ + "timeout_slash": "0.05" + }` + + msg := &types.MsgUpdateParams{ + Authority: gov, + Payload: payload, + } + + proposal, _ := govV1Types.NewMsgSubmitProposal( + []sdk.Msg{msg}, minDeposit, i.DUMMY[0], "", "title", "summary", false, + ) + + vote := govV1Types.NewMsgVote( + voter, 1, govV1Types.VoteOption_VOTE_OPTION_YES, "", + ) + + // ACT + _, submitErr := s.RunTx(proposal) + _, voteErr := s.RunTx(vote) + + s.CommitAfter(*votingPeriod) + s.Commit() + + // ASSERT + updatedParams := s.App().StakersKeeper.GetParams(s.Ctx()) + + Expect(submitErr).NotTo(HaveOccurred()) + Expect(voteErr).NotTo(HaveOccurred()) + + Expect(updatedParams.UploadSlash).To(Equal(types.DefaultUploadSlash)) + Expect(updatedParams.TimeoutSlash).To(Equal(math.LegacyMustNewDecFromStr("0.05"))) + Expect(updatedParams.VoteSlash).To(Equal(types.DefaultVoteSlash)) + }) + + It("Update timeout slash with invalid value", func() { + // ARRANGE + payload := `{ + "upload_slash": "-0.5" + }` + + msg := &types.MsgUpdateParams{ + Authority: gov, + Payload: payload, + } + + proposal, _ := govV1Types.NewMsgSubmitProposal( + []sdk.Msg{msg}, minDeposit, i.DUMMY[0], "", "title", "summary", false, + ) + + // ACT + _, submitErr := s.RunTx(proposal) + + s.CommitAfter(*votingPeriod) + s.Commit() + + // ASSERT + updatedParams := s.App().StakersKeeper.GetParams(s.Ctx()) + + Expect(submitErr).To(HaveOccurred()) + + Expect(updatedParams.UploadSlash).To(Equal(types.DefaultUploadSlash)) + Expect(updatedParams.TimeoutSlash).To(Equal(types.DefaultTimeoutSlash)) + Expect(updatedParams.VoteSlash).To(Equal(types.DefaultVoteSlash)) }) }) diff --git a/x/stakers/keeper/msg_server_update_stake_fraction.go b/x/stakers/keeper/msg_server_update_stake_fraction.go new file mode 100644 index 00000000..8c10db46 --- /dev/null +++ b/x/stakers/keeper/msg_server_update_stake_fraction.go @@ -0,0 +1,51 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + errorsTypes "github.com/cosmos/cosmos-sdk/types/errors" + + "cosmossdk.io/errors" + "github.com/KYVENetwork/chain/x/stakers/types" +) + +// UpdateStakeFraction updates the stake fraction of a validator in the specified pool. +// If the validator wants to increase their stake fraction we can do this immediately +// since there are no security risks involved there. If the validator wants +// to decrease it however we do that only after the stake fraction change time +// so validators can not decrease their stake before e.g. doing something maliciously +func (k msgServer) UpdateStakeFraction(goCtx context.Context, msg *types.MsgUpdateStakeFraction) (*types.MsgUpdateStakeFractionResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + valaccount, active := k.GetValaccount(ctx, msg.PoolId, msg.Creator) + if !active { + return nil, errors.Wrap(errorsTypes.ErrUnauthorized, types.ErrNoValaccount.Error()) + } + + // if the validator wants to decrease their stake fraction in a pool we have + // to do that in the bonding time + if msg.StakeFraction.LT(valaccount.StakeFraction) { + // Insert commission change into queue + k.orderNewStakeFractionChange(ctx, msg.Creator, msg.PoolId, msg.StakeFraction) + return &types.MsgUpdateStakeFractionResponse{}, nil + } + + // if the validator wants to increase their stake fraction we can do this immediately. + // Before we clear any change entries if there are currently bonding + queueEntry, found := k.GetStakeFractionChangeEntryByIndex2(ctx, msg.Creator, msg.PoolId) + if found { + k.RemoveStakeFractionEntry(ctx, &queueEntry) + } + + valaccount.StakeFraction = msg.StakeFraction + k.SetValaccount(ctx, valaccount) + + _ = ctx.EventManager().EmitTypedEvent(&types.EventUpdateStakeFraction{ + Staker: msg.Creator, + PoolId: msg.PoolId, + StakeFraction: msg.StakeFraction, + }) + + return &types.MsgUpdateStakeFractionResponse{}, nil +} diff --git a/x/stakers/keeper/msg_server_update_stake_fraction_test.go b/x/stakers/keeper/msg_server_update_stake_fraction_test.go new file mode 100644 index 00000000..e406f7a9 --- /dev/null +++ b/x/stakers/keeper/msg_server_update_stake_fraction_test.go @@ -0,0 +1,407 @@ +package keeper_test + +import ( + "cosmossdk.io/math" + pooltypes "github.com/KYVENetwork/chain/x/pool/types" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + i "github.com/KYVENetwork/chain/testutil/integration" + stakerstypes "github.com/KYVENetwork/chain/x/stakers/types" +) + +/* + +TEST CASES - msg_server_update_stake_fraction.go + +* Get the default stake fraction from a newly joined pool +* Increase stake fraction to 50% from previous stake fraction +* Decrease stake fraction to 0% from previous stake fraction +* Decrease stake fraction to 1% from previous stake fraction +* Increase stake fraction to 100% from previous stake fraction +* Update stake fraction to same value from previous stake fraction +* Update stake fraction with a negative number from previous stake fraction +* Update stake fraction with a too high number from previous stake fraction +* Increase stake fraction after stake fraction has been decreased before during change time +* Decrease stake fraction after stake fraction has been decreased before during change time +* Decrease stake fraction after stake fraction has been increased before +* Update stake fraction with multiple pools +* Validator stake increases while stake fraction stays the same +* Validator stake decreases while stake fraction stays the same + +*/ + +var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { + s := i.NewCleanChain() + + gov := s.App().GovKeeper.GetGovernanceAccount(s.Ctx()).GetAddress().String() + + BeforeEach(func() { + // init new clean chain + s = i.NewCleanChain() + + // create pool + msg := &pooltypes.MsgCreatePool{ + Authority: gov, + UploadInterval: 60, + MaxBundleSize: 100, + InflationShareWeight: math.LegacyZeroDec(), + Binaries: "{}", + } + s.RunTxPoolSuccess(msg) + + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.1"), + }) + }) + + AfterEach(func() { + s.PerformValidityChecks() + }) + + It("Get the default stake fraction from a newly joined pool", func() { + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + }) + + It("Increase stake fraction to 50% from previous stake fraction", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("0.5"), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(50 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) + }) + + It("Decrease stake fraction to 0% from previous stake fraction", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("0"), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) + + // wait for update + s.CommitAfterSeconds(s.App().StakersKeeper.GetStakeFractionChangeTime(s.Ctx())) + s.CommitAfterSeconds(1) + + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(BeZero()) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(BeZero()) + }) + + It("Decrease stake fraction to 1% from previous stake fraction", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("0.01"), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + + // wait for update + s.CommitAfterSeconds(s.App().StakersKeeper.GetStakeFractionChangeTime(s.Ctx())) + s.CommitAfterSeconds(1) + + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.01"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(1 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(1 * i.KYVE)) + }) + + It("Increase stake fraction to 100% from previous stake fraction", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(100 * i.KYVE)) + }) + + It("Update stake fraction to same value from previous stake fraction", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("0.1"), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + }) + + It("Update stake fraction with a negative number from previous stake fraction", func() { + // ACT + s.RunTxStakersError(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("-0.5"), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + }) + + It("Update stake fraction with a too high number from previous stake fraction during change time", func() { + // ACT + s.RunTxStakersError(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("2"), + }) + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + }) + + It("Increase stake fraction after stake fraction has been decreased before during change time", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("0.05"), + }) + + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("0.2"), + }) + + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.2"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(20 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(20 * i.KYVE)) + + // wait for update + s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) + s.CommitAfterSeconds(1) + + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.2"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(20 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(20 * i.KYVE)) + }) + + It("Decrease stake fraction after stake fraction has been decreased before during change time", func() { + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("0.05"), + }) + + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("0.01"), + }) + + s.PerformValidityChecks() + + // ASSERT + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + + // wait for update + s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) + s.CommitAfterSeconds(1) + + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.01"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(1 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(1 * i.KYVE)) + }) + + It("Decrease stake fraction after stake fraction has been increased before", func() { + // ARRANGE + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("0.5"), + }) + + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(50 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) + + s.PerformValidityChecks() + + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("0.02"), + }) + + // ASSERT + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(50 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) + + // wait for update + s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) + s.CommitAfterSeconds(1) + + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.02"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(2 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(2 * i.KYVE)) + }) + + It("Update stake fraction with multiple pools", func() { + // ARRANGE + msg := &pooltypes.MsgCreatePool{ + Authority: gov, + UploadInterval: 60, + MaxBundleSize: 100, + InflationShareWeight: math.LegacyZeroDec(), + Binaries: "{}", + } + s.RunTxPoolSuccess(msg) + + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 1, + Valaddress: i.VALADDRESS_0_B, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.1"), + }) + + // ACT + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 0, + StakeFraction: math.LegacyMustNewDecFromStr("0.5"), + }) + + s.RunTxStakersSuccess(&stakerstypes.MsgUpdateStakeFraction{ + Creator: i.STAKER_0, + PoolId: 1, + StakeFraction: math.LegacyMustNewDecFromStr("0.03"), + }) + + s.PerformValidityChecks() + + // ASSERT + valaccount0, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount0.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(50 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) + + valaccount1, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) + Expect(valaccount1.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 1)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 1)).To(Equal(10 * i.KYVE)) + + // wait for update + s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) + s.CommitAfterSeconds(1) + + valaccount0, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount0.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(50 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) + + valaccount1, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) + Expect(valaccount1.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.03"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 1)).To(Equal(3 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 1)).To(Equal(3 * i.KYVE)) + }) + + It("Validator stake increases while stake fraction stays the same", func() { + // ARRANGE + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + + // ACT + s.SelfDelegateValidator(i.STAKER_0, 50*i.KYVE) + + // ASSERT + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(15 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(15 * i.KYVE)) + }) + + It("Validator stake decreases while stake fraction stays the same", func() { + // ARRANGE + valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + + // ACT + s.SelfUndelegateValidator(i.STAKER_0, 50*i.KYVE) + + // wait for update + unbondingTime, _ := s.App().StakingKeeper.UnbondingTime(s.Ctx()) + s.CommitAfterSeconds(uint64(unbondingTime.Seconds())) + s.CommitAfterSeconds(1) + + // ASSERT + valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(5 * i.KYVE)) + Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(5 * i.KYVE)) + }) +}) diff --git a/x/stakers/module.go b/x/stakers/module.go index 597eb916..75ebc471 100644 --- a/x/stakers/module.go +++ b/x/stakers/module.go @@ -156,6 +156,7 @@ func (am AppModule) BeginBlock(ctx context.Context) error { sdkCtx := sdk.UnwrapSDKContext(ctx) am.keeper.ProcessCommissionChangeQueue(sdkCtx) am.keeper.ProcessLeavePoolQueue(sdkCtx) + am.keeper.ProcessStakeFractionChangeQueue(sdkCtx) return nil } diff --git a/x/stakers/types/codec.go b/x/stakers/types/codec.go index 5adbe9cb..686e887f 100644 --- a/x/stakers/types/codec.go +++ b/x/stakers/types/codec.go @@ -9,6 +9,7 @@ import ( func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgUpdateCommission{}, "kyve/stakers/MsgUpdateCommission", nil) + cdc.RegisterConcrete(&MsgUpdateStakeFraction{}, "kyve/stakers/MsgUpdateStakeFraction", nil) cdc.RegisterConcrete(&MsgJoinPool{}, "kyve/stakers/MsgJoinPool", nil) cdc.RegisterConcrete(&MsgLeavePool{}, "kyve/stakers/MsgLeavePool", nil) cdc.RegisterConcrete(&MsgUpdateParams{}, "kyve/stakers/MsgUpdateParams", nil) @@ -16,6 +17,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { func RegisterInterfaces(registry codecTypes.InterfaceRegistry) { registry.RegisterImplementations((*sdk.Msg)(nil), &MsgUpdateCommission{}) + registry.RegisterImplementations((*sdk.Msg)(nil), &MsgUpdateStakeFraction{}) registry.RegisterImplementations((*sdk.Msg)(nil), &MsgJoinPool{}) registry.RegisterImplementations((*sdk.Msg)(nil), &MsgLeavePool{}) registry.RegisterImplementations((*sdk.Msg)(nil), &MsgUpdateParams{}) diff --git a/x/stakers/types/errors.go b/x/stakers/types/errors.go index 46b346ce..c68a8119 100644 --- a/x/stakers/types/errors.go +++ b/x/stakers/types/errors.go @@ -22,4 +22,5 @@ var ( ErrPoolLeaveAlreadyInProgress = errors.Register(ModuleName, 1117, "Pool leave is already in progress") ErrValaccountUnauthorized = errors.Register(ModuleName, 1118, "valaccount unauthorized") ErrValidatorJailed = errors.Register(ModuleName, 1119, "validator jailed") + ErrNoValaccount = errors.Register(ModuleName, 1120, "sender has no valaccount") ) diff --git a/x/stakers/types/events.pb.go b/x/stakers/types/events.pb.go index 2347afee..445aa39b 100644 --- a/x/stakers/types/events.pb.go +++ b/x/stakers/types/events.pb.go @@ -94,8 +94,10 @@ func (m *EventUpdateParams) GetPayload() string { type EventUpdateCommission struct { // staker is the account address of the protocol node. Staker string `protobuf:"bytes,1,opt,name=staker,proto3" json:"staker,omitempty"` + // pool_id ... + PoolId uint64 `protobuf:"varint,2,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` // commission ... - Commission cosmossdk_io_math.LegacyDec `protobuf:"bytes,2,opt,name=commission,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"commission"` + Commission cosmossdk_io_math.LegacyDec `protobuf:"bytes,3,opt,name=commission,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"commission"` } func (m *EventUpdateCommission) Reset() { *m = EventUpdateCommission{} } @@ -138,6 +140,71 @@ func (m *EventUpdateCommission) GetStaker() string { return "" } +func (m *EventUpdateCommission) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +// EventUpdateCommission ... +// emitted_by: MsgUpdateStakeFraction, EndBlock +type EventUpdateStakeFraction struct { + // staker is the account address of the protocol node. + Staker string `protobuf:"bytes,1,opt,name=staker,proto3" json:"staker,omitempty"` + // pool_id ... + PoolId uint64 `protobuf:"varint,2,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // stake_fraction ... + StakeFraction cosmossdk_io_math.LegacyDec `protobuf:"bytes,3,opt,name=stake_fraction,json=stakeFraction,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"stake_fraction"` +} + +func (m *EventUpdateStakeFraction) Reset() { *m = EventUpdateStakeFraction{} } +func (m *EventUpdateStakeFraction) String() string { return proto.CompactTextString(m) } +func (*EventUpdateStakeFraction) ProtoMessage() {} +func (*EventUpdateStakeFraction) Descriptor() ([]byte, []int) { + return fileDescriptor_7a1b3dc9634155a0, []int{2} +} +func (m *EventUpdateStakeFraction) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventUpdateStakeFraction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventUpdateStakeFraction.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *EventUpdateStakeFraction) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventUpdateStakeFraction.Merge(m, src) +} +func (m *EventUpdateStakeFraction) XXX_Size() int { + return m.Size() +} +func (m *EventUpdateStakeFraction) XXX_DiscardUnknown() { + xxx_messageInfo_EventUpdateStakeFraction.DiscardUnknown(m) +} + +var xxx_messageInfo_EventUpdateStakeFraction proto.InternalMessageInfo + +func (m *EventUpdateStakeFraction) GetStaker() string { + if m != nil { + return m.Staker + } + return "" +} + +func (m *EventUpdateStakeFraction) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + // EventClaimCommissionRewards ... // emitted_by: MsgClaimCommissionRewards type EventClaimCommissionRewards struct { @@ -151,7 +218,7 @@ func (m *EventClaimCommissionRewards) Reset() { *m = EventClaimCommissio func (m *EventClaimCommissionRewards) String() string { return proto.CompactTextString(m) } func (*EventClaimCommissionRewards) ProtoMessage() {} func (*EventClaimCommissionRewards) Descriptor() ([]byte, []int) { - return fileDescriptor_7a1b3dc9634155a0, []int{2} + return fileDescriptor_7a1b3dc9634155a0, []int{3} } func (m *EventClaimCommissionRewards) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -206,13 +273,17 @@ type EventJoinPool struct { Valaddress string `protobuf:"bytes,3,opt,name=valaddress,proto3" json:"valaddress,omitempty"` // amount is the amount of funds transferred to the valaddress Amount uint64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"` + // commission ... + Commission cosmossdk_io_math.LegacyDec `protobuf:"bytes,5,opt,name=commission,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"commission"` + // stake_fraction ... + StakeFraction cosmossdk_io_math.LegacyDec `protobuf:"bytes,6,opt,name=stake_fraction,json=stakeFraction,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"stake_fraction"` } func (m *EventJoinPool) Reset() { *m = EventJoinPool{} } func (m *EventJoinPool) String() string { return proto.CompactTextString(m) } func (*EventJoinPool) ProtoMessage() {} func (*EventJoinPool) Descriptor() ([]byte, []int) { - return fileDescriptor_7a1b3dc9634155a0, []int{3} + return fileDescriptor_7a1b3dc9634155a0, []int{4} } func (m *EventJoinPool) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -282,7 +353,7 @@ func (m *EventLeavePool) Reset() { *m = EventLeavePool{} } func (m *EventLeavePool) String() string { return proto.CompactTextString(m) } func (*EventLeavePool) ProtoMessage() {} func (*EventLeavePool) Descriptor() ([]byte, []int) { - return fileDescriptor_7a1b3dc9634155a0, []int{4} + return fileDescriptor_7a1b3dc9634155a0, []int{5} } func (m *EventLeavePool) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -342,7 +413,7 @@ func (m *EventSlash) Reset() { *m = EventSlash{} } func (m *EventSlash) String() string { return proto.CompactTextString(m) } func (*EventSlash) ProtoMessage() {} func (*EventSlash) Descriptor() ([]byte, []int) { - return fileDescriptor_7a1b3dc9634155a0, []int{5} + return fileDescriptor_7a1b3dc9634155a0, []int{6} } func (m *EventSlash) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -402,6 +473,7 @@ func (m *EventSlash) GetSlashType() SlashType { func init() { proto.RegisterType((*EventUpdateParams)(nil), "kyve.stakers.v1beta1.EventUpdateParams") proto.RegisterType((*EventUpdateCommission)(nil), "kyve.stakers.v1beta1.EventUpdateCommission") + proto.RegisterType((*EventUpdateStakeFraction)(nil), "kyve.stakers.v1beta1.EventUpdateStakeFraction") proto.RegisterType((*EventClaimCommissionRewards)(nil), "kyve.stakers.v1beta1.EventClaimCommissionRewards") proto.RegisterType((*EventJoinPool)(nil), "kyve.stakers.v1beta1.EventJoinPool") proto.RegisterType((*EventLeavePool)(nil), "kyve.stakers.v1beta1.EventLeavePool") @@ -411,37 +483,41 @@ func init() { func init() { proto.RegisterFile("kyve/stakers/v1beta1/events.proto", fileDescriptor_7a1b3dc9634155a0) } var fileDescriptor_7a1b3dc9634155a0 = []byte{ - // 478 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xcf, 0x6a, 0xd4, 0x50, - 0x14, 0xc6, 0x27, 0xed, 0x30, 0x43, 0x8e, 0x58, 0x30, 0x54, 0x0d, 0x53, 0xc9, 0xd4, 0xb8, 0xe9, - 0x42, 0x12, 0x5a, 0xf7, 0x42, 0x67, 0xac, 0xa0, 0x16, 0x2d, 0xf1, 0x0f, 0xe8, 0x66, 0xb8, 0x93, - 0x7b, 0x98, 0x09, 0x93, 0xe4, 0x84, 0xdc, 0xdb, 0x4c, 0xf3, 0x16, 0x6e, 0x7c, 0x12, 0x5f, 0xa2, - 0xcb, 0x2e, 0xc5, 0x45, 0x91, 0x99, 0x17, 0x91, 0xdc, 0x24, 0x9d, 0x08, 0x11, 0xb4, 0xbb, 0x7b, - 0xc2, 0x77, 0x7e, 0xdf, 0x8f, 0x4b, 0x2e, 0x3c, 0x5e, 0xe4, 0x19, 0xba, 0x42, 0xb2, 0x05, 0xa6, - 0xc2, 0xcd, 0x0e, 0xa7, 0x28, 0xd9, 0xa1, 0x8b, 0x19, 0xc6, 0x52, 0x38, 0x49, 0x4a, 0x92, 0x8c, - 0xdd, 0x22, 0xe2, 0x54, 0x11, 0xa7, 0x8a, 0x0c, 0x76, 0x67, 0x34, 0x23, 0x15, 0x70, 0x8b, 0x53, - 0x99, 0x1d, 0xb4, 0xe3, 0x12, 0x96, 0xb2, 0xa8, 0xc2, 0x0d, 0xec, 0xd6, 0x48, 0x8d, 0x57, 0x19, - 0xfb, 0xbb, 0x06, 0xf7, 0x4e, 0x0a, 0x87, 0x8f, 0x09, 0x67, 0x12, 0xcf, 0xd4, 0xbe, 0x71, 0x0c, - 0x40, 0x21, 0x9f, 0x94, 0x34, 0x53, 0xdb, 0xd7, 0x0e, 0xee, 0x1c, 0x3d, 0x72, 0xda, 0xec, 0x9c, - 0x72, 0x63, 0xd4, 0xbd, 0xbc, 0x1e, 0x76, 0x3c, 0x9d, 0x42, 0xbe, 0x41, 0xc4, 0xb8, 0xac, 0x11, - 0x5b, 0xff, 0x8e, 0x88, 0x71, 0x59, 0x21, 0x4c, 0xe8, 0x27, 0x2c, 0x0f, 0x89, 0x71, 0x73, 0x7b, - 0x5f, 0x3b, 0xd0, 0xbd, 0x7a, 0xb4, 0x25, 0xdc, 0x6f, 0x48, 0x8f, 0x29, 0x8a, 0x02, 0x21, 0x02, - 0x8a, 0x8d, 0x07, 0xd0, 0x2b, 0xe9, 0x4a, 0x5a, 0xf7, 0xaa, 0xc9, 0x18, 0x03, 0xf8, 0x37, 0x29, - 0x65, 0xa3, 0x8f, 0x9e, 0x14, 0x7d, 0x3f, 0xaf, 0x87, 0x7b, 0x3e, 0x89, 0x88, 0x84, 0xe0, 0x0b, - 0x27, 0x20, 0x37, 0x62, 0x72, 0xee, 0x9c, 0xe2, 0x8c, 0xf9, 0xf9, 0x0b, 0xf4, 0xbd, 0xc6, 0x9a, - 0xfd, 0x0e, 0xf6, 0x54, 0xeb, 0x38, 0x64, 0x41, 0xb4, 0x29, 0xf5, 0x70, 0xc9, 0x52, 0x2e, 0xfe, - 0xda, 0x6d, 0x42, 0x9f, 0x45, 0x74, 0x1e, 0xcb, 0xf2, 0x1a, 0x74, 0xaf, 0x1e, 0xed, 0x0b, 0xb8, - 0xab, 0x80, 0xaf, 0x29, 0x88, 0xcf, 0x88, 0x42, 0xe3, 0x21, 0xf4, 0x13, 0xa2, 0x70, 0x12, 0x70, - 0xc5, 0xe8, 0x7a, 0xbd, 0x62, 0x7c, 0xc5, 0x1b, 0xec, 0xad, 0x3f, 0xd8, 0x16, 0x40, 0xc6, 0x42, - 0xc6, 0x79, 0x8a, 0x42, 0x54, 0xb7, 0xd4, 0xf8, 0x52, 0xec, 0x95, 0x65, 0x66, 0xb7, 0xe4, 0x95, - 0x93, 0x7d, 0x0c, 0x3b, 0xaa, 0xf9, 0x14, 0x59, 0x86, 0xb7, 0xaa, 0xb6, 0xbf, 0x69, 0x00, 0x8a, - 0xf1, 0x3e, 0x64, 0x62, 0xfe, 0xff, 0xea, 0x1b, 0xb5, 0xed, 0xa6, 0x9a, 0xf1, 0x1c, 0x40, 0x14, - 0xc4, 0x89, 0xcc, 0x13, 0x54, 0xda, 0x3b, 0x47, 0xc3, 0xf6, 0x1f, 0x47, 0x35, 0x7f, 0xc8, 0x13, - 0xf4, 0x74, 0x51, 0x1f, 0x47, 0x2f, 0x2f, 0x57, 0x96, 0x76, 0xb5, 0xb2, 0xb4, 0x5f, 0x2b, 0x4b, - 0xfb, 0xba, 0xb6, 0x3a, 0x57, 0x6b, 0xab, 0xf3, 0x63, 0x6d, 0x75, 0xbe, 0x3c, 0x9d, 0x05, 0x72, - 0x7e, 0x3e, 0x75, 0x7c, 0x8a, 0xdc, 0x37, 0x9f, 0x3f, 0x9d, 0xbc, 0x45, 0xb9, 0xa4, 0x74, 0xe1, - 0xfa, 0x73, 0x16, 0xc4, 0xee, 0xc5, 0xcd, 0x4b, 0x29, 0x8a, 0xc5, 0xb4, 0xa7, 0x1e, 0xc8, 0xb3, - 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x6c, 0x29, 0x77, 0x9c, 0xb8, 0x03, 0x00, 0x00, + // 532 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xc1, 0x6e, 0xd3, 0x40, + 0x10, 0x86, 0xb3, 0x69, 0x48, 0x94, 0x41, 0x8d, 0x44, 0x54, 0xc0, 0x4a, 0x91, 0x53, 0xcc, 0xa5, + 0x07, 0x64, 0xab, 0xe5, 0x8e, 0xd4, 0x84, 0x56, 0xa2, 0x54, 0x50, 0xb9, 0x80, 0x04, 0x97, 0x68, + 0xe3, 0x5d, 0x12, 0x2b, 0xb6, 0xc7, 0xf2, 0x6e, 0x13, 0xfc, 0x08, 0x1c, 0x90, 0xb8, 0x20, 0x1e, + 0x84, 0x97, 0xe8, 0xb1, 0x47, 0xc4, 0xa1, 0x42, 0xc9, 0x8b, 0x20, 0xaf, 0xed, 0xc6, 0x41, 0x46, + 0x6a, 0x73, 0xdb, 0xb1, 0xfe, 0xf9, 0xe6, 0xdf, 0x7f, 0xe4, 0x85, 0xc7, 0x93, 0x78, 0xca, 0x2d, + 0x21, 0xe9, 0x84, 0x47, 0xc2, 0x9a, 0xee, 0x0d, 0xb9, 0xa4, 0x7b, 0x16, 0x9f, 0xf2, 0x40, 0x0a, + 0x33, 0x8c, 0x50, 0x62, 0x7b, 0x2b, 0x91, 0x98, 0x99, 0xc4, 0xcc, 0x24, 0x9d, 0xad, 0x11, 0x8e, + 0x50, 0x09, 0xac, 0xe4, 0x94, 0x6a, 0x3b, 0xe5, 0xb8, 0x90, 0x46, 0xd4, 0xcf, 0x70, 0x1d, 0xa3, + 0x54, 0x92, 0xe3, 0x95, 0xc6, 0xf8, 0x49, 0xe0, 0xde, 0x61, 0xe2, 0xe1, 0x5d, 0xc8, 0xa8, 0xe4, + 0xa7, 0xaa, 0xbf, 0x7d, 0x00, 0x80, 0x1e, 0x1b, 0xa4, 0x34, 0x8d, 0xec, 0x90, 0xdd, 0xbb, 0xfb, + 0x8f, 0xcc, 0x32, 0x77, 0x66, 0xda, 0xd1, 0xab, 0x5d, 0x5c, 0x75, 0x2b, 0x76, 0x13, 0x3d, 0xb6, + 0x44, 0x04, 0x7c, 0x96, 0x23, 0xaa, 0x37, 0x47, 0x04, 0x7c, 0x96, 0x21, 0x34, 0x68, 0x84, 0x34, + 0xf6, 0x90, 0x32, 0x6d, 0x63, 0x87, 0xec, 0x36, 0xed, 0xbc, 0x34, 0xbe, 0x12, 0xb8, 0x5f, 0x70, + 0xdd, 0x47, 0xdf, 0x77, 0x85, 0x70, 0x31, 0x68, 0x3f, 0x80, 0x7a, 0x8a, 0x57, 0xae, 0x9b, 0x76, + 0x56, 0xb5, 0x1f, 0x42, 0x23, 0x44, 0xf4, 0x06, 0x2e, 0x53, 0x5e, 0x6a, 0x76, 0x3d, 0x29, 0x5f, + 0xb2, 0x76, 0x1f, 0xc0, 0xb9, 0x6e, 0x4f, 0xe7, 0xf4, 0x9e, 0x24, 0x4e, 0x7e, 0x5f, 0x75, 0xb7, + 0x1d, 0x14, 0x3e, 0x0a, 0xc1, 0x26, 0xa6, 0x8b, 0x96, 0x4f, 0xe5, 0xd8, 0x3c, 0xe1, 0x23, 0xea, + 0xc4, 0x2f, 0xb8, 0x63, 0x17, 0xda, 0x8c, 0x1f, 0x04, 0xb4, 0x82, 0x9f, 0xb3, 0x64, 0xe6, 0x51, + 0x44, 0x1d, 0xb9, 0x96, 0xa5, 0x63, 0x68, 0x29, 0xc9, 0xe0, 0x53, 0x86, 0xb8, 0x8d, 0xad, 0x4d, + 0x51, 0x1c, 0x6e, 0xbc, 0x81, 0x6d, 0x65, 0xac, 0xef, 0x51, 0xd7, 0x5f, 0xe6, 0x64, 0xf3, 0x19, + 0x8d, 0x98, 0xf8, 0xaf, 0x37, 0x0d, 0x1a, 0xd4, 0xc7, 0xf3, 0x40, 0xa6, 0xab, 0x6b, 0xda, 0x79, + 0x69, 0x7c, 0xa9, 0xc2, 0xa6, 0x22, 0x1e, 0xa3, 0x1b, 0x9c, 0x22, 0x7a, 0xc5, 0x7b, 0x90, 0x95, + 0x7b, 0x2c, 0xe1, 0xd5, 0x15, 0xb8, 0x0e, 0x30, 0xa5, 0x1e, 0x65, 0x2c, 0xe2, 0x42, 0x64, 0xab, + 0x2d, 0x7c, 0x49, 0xfa, 0xd2, 0x69, 0x5a, 0x2d, 0xe5, 0xa5, 0xd5, 0x3f, 0xab, 0xba, 0xb3, 0xd6, + 0xaa, 0x4a, 0xc2, 0xad, 0xaf, 0x1d, 0xee, 0x01, 0xb4, 0x54, 0x14, 0x27, 0x9c, 0x4e, 0xf9, 0x5a, + 0x59, 0x18, 0xdf, 0x09, 0x80, 0x62, 0x9c, 0x79, 0x54, 0x8c, 0x6f, 0x9f, 0xe5, 0x32, 0xab, 0x8d, + 0x95, 0xac, 0x9e, 0x03, 0x88, 0x84, 0x38, 0x90, 0x71, 0xc8, 0x55, 0x8e, 0xad, 0xfd, 0x6e, 0xf9, + 0xef, 0xa7, 0x26, 0xbf, 0x8d, 0x43, 0x6e, 0x37, 0x45, 0x7e, 0xec, 0x1d, 0x5d, 0xcc, 0x75, 0x72, + 0x39, 0xd7, 0xc9, 0x9f, 0xb9, 0x4e, 0xbe, 0x2d, 0xf4, 0xca, 0xe5, 0x42, 0xaf, 0xfc, 0x5a, 0xe8, + 0x95, 0x8f, 0x4f, 0x47, 0xae, 0x1c, 0x9f, 0x0f, 0x4d, 0x07, 0x7d, 0xeb, 0xd5, 0x87, 0xf7, 0x87, + 0xaf, 0xb9, 0x9c, 0x61, 0x34, 0xb1, 0x9c, 0x31, 0x75, 0x03, 0xeb, 0xf3, 0xf5, 0x7b, 0x93, 0x0c, + 0x16, 0xc3, 0xba, 0x7a, 0x66, 0x9e, 0xfd, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x42, 0x2b, 0x27, 0xf7, + 0xfe, 0x04, 0x00, 0x00, } func (m *EventUpdateParams) Marshal() (dAtA []byte, err error) { @@ -523,7 +599,57 @@ func (m *EventUpdateCommission) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintEvents(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x12 + dAtA[i] = 0x1a + if m.PoolId != 0 { + i = encodeVarintEvents(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Staker) > 0 { + i -= len(m.Staker) + copy(dAtA[i:], m.Staker) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Staker))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventUpdateStakeFraction) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *EventUpdateStakeFraction) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventUpdateStakeFraction) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.StakeFraction.Size() + i -= size + if _, err := m.StakeFraction.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.PoolId != 0 { + i = encodeVarintEvents(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x10 + } if len(m.Staker) > 0 { i -= len(m.Staker) copy(dAtA[i:], m.Staker) @@ -591,6 +717,26 @@ func (m *EventJoinPool) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.StakeFraction.Size() + i -= size + if _, err := m.StakeFraction.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + { + size := m.Commission.Size() + i -= size + if _, err := m.Commission.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a if m.Amount != 0 { i = encodeVarintEvents(dAtA, i, uint64(m.Amount)) i-- @@ -736,11 +882,32 @@ func (m *EventUpdateCommission) Size() (n int) { if l > 0 { n += 1 + l + sovEvents(uint64(l)) } + if m.PoolId != 0 { + n += 1 + sovEvents(uint64(m.PoolId)) + } l = m.Commission.Size() n += 1 + l + sovEvents(uint64(l)) return n } +func (m *EventUpdateStakeFraction) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Staker) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + if m.PoolId != 0 { + n += 1 + sovEvents(uint64(m.PoolId)) + } + l = m.StakeFraction.Size() + n += 1 + l + sovEvents(uint64(l)) + return n +} + func (m *EventClaimCommissionRewards) Size() (n int) { if m == nil { return 0 @@ -778,6 +945,10 @@ func (m *EventJoinPool) Size() (n int) { if m.Amount != 0 { n += 1 + sovEvents(uint64(m.Amount)) } + l = m.Commission.Size() + n += 1 + l + sovEvents(uint64(l)) + l = m.StakeFraction.Size() + n += 1 + l + sovEvents(uint64(l)) return n } @@ -1035,6 +1206,25 @@ func (m *EventUpdateCommission) Unmarshal(dAtA []byte) error { m.Staker = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Commission", wireType) } @@ -1089,6 +1279,141 @@ func (m *EventUpdateCommission) Unmarshal(dAtA []byte) error { } return nil } +func (m *EventUpdateStakeFraction) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EventUpdateStakeFraction: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventUpdateStakeFraction: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Staker", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Staker = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakeFraction", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StakeFraction.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *EventClaimCommissionRewards) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -1334,6 +1659,74 @@ func (m *EventJoinPool) Unmarshal(dAtA []byte) error { break } } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Commission", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Commission.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakeFraction", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StakeFraction.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipEvents(dAtA[iNdEx:]) diff --git a/x/stakers/types/genesis.go b/x/stakers/types/genesis.go index dc1f54b3..a17aca21 100644 --- a/x/stakers/types/genesis.go +++ b/x/stakers/types/genesis.go @@ -65,5 +65,23 @@ func (gs GenesisState) Validate() error { } } + // Stake Fraction Change + stakeFractionChangeMap := make(map[string]struct{}) + + for _, elem := range gs.StakeFractionChangeEntries { + index := string(StakeFractionChangeEntryKey(elem.Index)) + if _, ok := stakeFractionChangeMap[index]; ok { + return fmt.Errorf("duplicated index for stake fraction change entry %v", elem) + } + if elem.Index > gs.QueueStateStateFraction.HighIndex { + return fmt.Errorf("stake fraction change entry index too high: %v", elem) + } + if elem.Index < gs.QueueStateStateFraction.LowIndex { + return fmt.Errorf("stake fraction change entry index too low: %v", elem) + } + + stakeFractionChangeMap[index] = struct{}{} + } + return gs.Params.Validate() } diff --git a/x/stakers/types/genesis.pb.go b/x/stakers/types/genesis.pb.go index 4786bc8f..ea526ff1 100644 --- a/x/stakers/types/genesis.pb.go +++ b/x/stakers/types/genesis.pb.go @@ -39,6 +39,10 @@ type GenesisState struct { LeavePoolEntries []LeavePoolEntry `protobuf:"bytes,6,rep,name=leave_pool_entries,json=leavePoolEntries,proto3" json:"leave_pool_entries"` // queue_state_leave ... QueueStateLeave QueueState `protobuf:"bytes,7,opt,name=queue_state_leave,json=queueStateLeave,proto3" json:"queue_state_leave"` + // stake_fraction_change_entries ... + StakeFractionChangeEntries []StakeFractionChangeEntry `protobuf:"bytes,8,rep,name=stake_fraction_change_entries,json=stakeFractionChangeEntries,proto3" json:"stake_fraction_change_entries"` + // queue_state_state_fraction ... + QueueStateStateFraction QueueState `protobuf:"bytes,9,opt,name=queue_state_state_fraction,json=queueStateStateFraction,proto3" json:"queue_state_state_fraction"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -123,6 +127,20 @@ func (m *GenesisState) GetQueueStateLeave() QueueState { return QueueState{} } +func (m *GenesisState) GetStakeFractionChangeEntries() []StakeFractionChangeEntry { + if m != nil { + return m.StakeFractionChangeEntries + } + return nil +} + +func (m *GenesisState) GetQueueStateStateFraction() QueueState { + if m != nil { + return m.QueueStateStateFraction + } + return QueueState{} +} + func init() { proto.RegisterType((*GenesisState)(nil), "kyve.stakers.v1beta1.GenesisState") } @@ -132,34 +150,37 @@ func init() { } var fileDescriptor_0deb2ee89d595051 = []byte{ - // 417 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0x51, 0x6b, 0xda, 0x50, - 0x14, 0xc7, 0x93, 0xe9, 0x1c, 0x5c, 0xc7, 0xdc, 0x82, 0x6c, 0x99, 0x8c, 0xcc, 0xc9, 0x1e, 0x06, - 0x1b, 0x09, 0x6e, 0x6f, 0x7b, 0x54, 0x6c, 0x1f, 0x2a, 0xad, 0x55, 0x90, 0xb6, 0x14, 0xc2, 0x35, - 0x1c, 0xe2, 0xc5, 0x24, 0x37, 0xe6, 0xde, 0xa4, 0xf5, 0x5b, 0xf4, 0x63, 0xf9, 0xe8, 0x63, 0xa1, - 0x50, 0x8a, 0x7e, 0x91, 0x92, 0x9b, 0xdb, 0xc4, 0x87, 0xf8, 0xd0, 0x37, 0xbd, 0xe7, 0x77, 0x7e, - 0xe7, 0x7f, 0x6e, 0x2e, 0xea, 0x2c, 0x56, 0x09, 0x58, 0x8c, 0xe3, 0x05, 0x44, 0xcc, 0x4a, 0xba, - 0x33, 0xe0, 0xb8, 0x6b, 0xb9, 0x10, 0x00, 0x23, 0xcc, 0x0c, 0x23, 0xca, 0xa9, 0xd6, 0x4c, 0x19, - 0x53, 0x32, 0xa6, 0x64, 0x5a, 0x4d, 0x97, 0xba, 0x54, 0x00, 0x56, 0xfa, 0x2b, 0x63, 0x5b, 0x3f, - 0x4a, 0x7d, 0x21, 0x8e, 0xb0, 0x2f, 0x75, 0xad, 0xf2, 0x91, 0x2f, 0x7a, 0xc1, 0x74, 0x1e, 0xaa, - 0xe8, 0xfd, 0x71, 0x16, 0x62, 0xc2, 0x31, 0x07, 0xed, 0x3f, 0xaa, 0x65, 0x12, 0x5d, 0x6d, 0xab, - 0xbf, 0xea, 0x7f, 0xbf, 0x99, 0x65, 0xa1, 0xcc, 0x91, 0x60, 0x7a, 0xd5, 0xf5, 0xe3, 0x77, 0x65, - 0x2c, 0x3b, 0xb4, 0x3e, 0xaa, 0x67, 0x9c, 0xed, 0x11, 0xc6, 0xf5, 0x37, 0xed, 0xca, 0x61, 0xc1, - 0x44, 0xfc, 0x97, 0x02, 0x94, 0x55, 0x87, 0x84, 0x71, 0xed, 0x0c, 0x35, 0x12, 0xec, 0x61, 0xc7, - 0xa1, 0x71, 0xc0, 0x33, 0x51, 0x45, 0x88, 0xda, 0xe5, 0xa2, 0x69, 0x0e, 0x4b, 0xd9, 0x87, 0xa2, - 0x5d, 0x08, 0x7d, 0xf4, 0xd5, 0xa1, 0xbe, 0x4f, 0x18, 0x23, 0x34, 0xb0, 0x9d, 0x39, 0x0e, 0x5c, - 0xb0, 0x21, 0xe0, 0x11, 0x01, 0xa6, 0x57, 0x85, 0xfa, 0x77, 0xb9, 0xba, 0x9f, 0xb7, 0xf5, 0x45, - 0xd7, 0x20, 0xe0, 0xd1, 0x4a, 0x4e, 0xf9, 0xe2, 0x94, 0x14, 0x09, 0x30, 0xed, 0x1a, 0x7d, 0x5e, - 0xc6, 0x10, 0x83, 0xcd, 0xd2, 0xfb, 0xb4, 0x0b, 0x4c, 0x7f, 0x2b, 0x2e, 0xf4, 0xc0, 0x1a, 0xe7, - 0x69, 0x8f, 0xf8, 0x04, 0x72, 0x40, 0x73, 0x99, 0x9f, 0x14, 0x39, 0xb4, 0x0b, 0xa4, 0x79, 0x80, - 0x13, 0xb0, 0x43, 0x4a, 0xbd, 0x7c, 0x8b, 0x9a, 0xd8, 0xe2, 0x67, 0xb9, 0x79, 0x98, 0xf2, 0x23, - 0x4a, 0xbd, 0xfd, 0xf8, 0x1f, 0xbd, 0xfd, 0xd3, 0x34, 0xf7, 0x18, 0x7d, 0xda, 0xcf, 0x2d, 0xea, - 0xfa, 0xbb, 0x57, 0x45, 0x6e, 0x14, 0x91, 0xc5, 0xd0, 0xde, 0xd1, 0x7a, 0x6b, 0xa8, 0x9b, 0xad, - 0xa1, 0x3e, 0x6d, 0x0d, 0xf5, 0x6e, 0x67, 0x28, 0x9b, 0x9d, 0xa1, 0xdc, 0xef, 0x0c, 0xe5, 0xea, - 0x8f, 0x4b, 0xf8, 0x3c, 0x9e, 0x99, 0x0e, 0xf5, 0xad, 0x93, 0xcb, 0xe9, 0xe0, 0x14, 0xf8, 0x0d, - 0x8d, 0x16, 0x96, 0x33, 0xc7, 0x24, 0xb0, 0x6e, 0xf3, 0x57, 0xcb, 0x57, 0x21, 0xb0, 0x59, 0x4d, - 0x3c, 0xd6, 0x7f, 0xcf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x65, 0x34, 0xdb, 0xba, 0x45, 0x03, 0x00, - 0x00, + // 468 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0x41, 0x6f, 0xd3, 0x30, + 0x14, 0xc7, 0x1b, 0x36, 0x0a, 0x78, 0x88, 0x81, 0x55, 0xb1, 0x10, 0x41, 0x28, 0x13, 0x07, 0x24, + 0x50, 0xa2, 0xc1, 0x8d, 0xe3, 0xaa, 0x8d, 0x03, 0x13, 0x8c, 0x4d, 0x9a, 0x00, 0x21, 0x45, 0xae, + 0xf5, 0x48, 0xad, 0x26, 0x71, 0x17, 0x3b, 0x19, 0xfd, 0x16, 0x7c, 0x1d, 0xbe, 0xc1, 0x8e, 0x3b, + 0x72, 0x42, 0xa8, 0xfd, 0x22, 0x28, 0x2f, 0x6e, 0x12, 0x09, 0x6f, 0xd2, 0x2e, 0x56, 0xeb, 0xf7, + 0x7f, 0xbf, 0xf7, 0xff, 0xdb, 0x31, 0xd9, 0x9e, 0xce, 0x4b, 0x08, 0x95, 0x66, 0x53, 0xc8, 0x55, + 0x58, 0xee, 0x8c, 0x41, 0xb3, 0x9d, 0x30, 0x86, 0x0c, 0x94, 0x50, 0xc1, 0x2c, 0x97, 0x5a, 0xd2, + 0x41, 0xa5, 0x09, 0x8c, 0x26, 0x30, 0x1a, 0x6f, 0x10, 0xcb, 0x58, 0xa2, 0x20, 0xac, 0x7e, 0xd5, + 0x5a, 0xef, 0x99, 0x95, 0x37, 0x63, 0x39, 0x4b, 0x0d, 0xce, 0xb3, 0x8f, 0x5c, 0xe1, 0x51, 0xb3, + 0xfd, 0xab, 0x4f, 0xee, 0xbe, 0xab, 0x4d, 0x1c, 0x6b, 0xa6, 0x81, 0xbe, 0x25, 0xfd, 0x1a, 0xe2, + 0x3a, 0x43, 0xe7, 0xc5, 0xc6, 0xeb, 0xc7, 0x81, 0xcd, 0x54, 0x70, 0x88, 0x9a, 0xdd, 0xf5, 0xf3, + 0x3f, 0x4f, 0x7b, 0x47, 0xa6, 0x83, 0x8e, 0xc8, 0x46, 0xad, 0x8b, 0x12, 0xa1, 0xb4, 0x7b, 0x63, + 0xb8, 0x76, 0x39, 0xe0, 0x18, 0xff, 0x1b, 0x00, 0xa9, 0xab, 0x07, 0x42, 0x69, 0xfa, 0x91, 0x6c, + 0x96, 0x2c, 0x61, 0x9c, 0xcb, 0x22, 0xd3, 0x35, 0x68, 0x0d, 0x41, 0x43, 0x3b, 0xe8, 0xa4, 0x11, + 0x1b, 0xd8, 0xbd, 0xb6, 0x1d, 0x81, 0x29, 0x79, 0xc4, 0x65, 0x9a, 0x0a, 0xa5, 0x84, 0xcc, 0x22, + 0x3e, 0x61, 0x59, 0x0c, 0x11, 0x64, 0x3a, 0x17, 0xa0, 0xdc, 0x75, 0x44, 0xbf, 0xb4, 0xa3, 0x47, + 0x4d, 0xdb, 0x08, 0xbb, 0xf6, 0x32, 0x9d, 0xcf, 0xcd, 0x94, 0x2d, 0x6e, 0x29, 0x0a, 0x50, 0xf4, + 0x1b, 0x79, 0x78, 0x5a, 0x40, 0x01, 0x91, 0xaa, 0xce, 0x33, 0x6a, 0x65, 0xee, 0x4d, 0x3c, 0xd0, + 0x4b, 0x62, 0x7c, 0xaa, 0x7a, 0xf0, 0x0a, 0xcc, 0x80, 0xc1, 0x69, 0xb3, 0xd3, 0xfa, 0xa0, 0x9f, + 0x09, 0x4d, 0x80, 0x95, 0x10, 0xcd, 0xa4, 0x4c, 0x9a, 0x14, 0x7d, 0x4c, 0xf1, 0xdc, 0x4e, 0x3e, + 0xa8, 0xf4, 0x87, 0x52, 0x26, 0x5d, 0xfb, 0xf7, 0x93, 0xee, 0x6e, 0xe5, 0xfb, 0x88, 0x3c, 0xe8, + 0xfa, 0xc6, 0xba, 0x7b, 0xeb, 0x5a, 0x96, 0x37, 0x5b, 0xcb, 0x38, 0x94, 0x9e, 0x91, 0x27, 0xd8, + 0x14, 0x7d, 0xcf, 0x19, 0xd7, 0x96, 0xe3, 0xbf, 0x8d, 0xc6, 0x83, 0x2b, 0x3e, 0x91, 0x7d, 0xd3, + 0xf9, 0xff, 0x0d, 0x78, 0xca, 0x5e, 0xaf, 0xc2, 0x70, 0xe2, 0x75, 0xc3, 0xd4, 0xeb, 0xca, 0x84, + 0x7b, 0xe7, 0x5a, 0xa9, 0xb6, 0xda, 0x54, 0xb8, 0xac, 0x26, 0xee, 0xee, 0x9f, 0x2f, 0x7c, 0xe7, + 0x62, 0xe1, 0x3b, 0x7f, 0x17, 0xbe, 0xf3, 0x73, 0xe9, 0xf7, 0x2e, 0x96, 0x7e, 0xef, 0xf7, 0xd2, + 0xef, 0x7d, 0x7d, 0x15, 0x0b, 0x3d, 0x29, 0xc6, 0x01, 0x97, 0x69, 0xf8, 0xfe, 0xcb, 0xc9, 0xde, + 0x07, 0xd0, 0x67, 0x32, 0x9f, 0x86, 0x7c, 0xc2, 0x44, 0x16, 0xfe, 0x68, 0xde, 0xa4, 0x9e, 0xcf, + 0x40, 0x8d, 0xfb, 0xf8, 0x14, 0xdf, 0xfc, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x96, 0xd7, 0xc8, 0x9f, + 0x23, 0x04, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -182,6 +203,30 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.QueueStateStateFraction.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + if len(m.StakeFractionChangeEntries) > 0 { + for iNdEx := len(m.StakeFractionChangeEntries) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.StakeFractionChangeEntries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } { size, err := m.QueueStateLeave.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -318,6 +363,14 @@ func (m *GenesisState) Size() (n int) { } l = m.QueueStateLeave.Size() n += 1 + l + sovGenesis(uint64(l)) + if len(m.StakeFractionChangeEntries) > 0 { + for _, e := range m.StakeFractionChangeEntries { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + l = m.QueueStateStateFraction.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -591,6 +644,73 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakeFractionChangeEntries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StakeFractionChangeEntries = append(m.StakeFractionChangeEntries, StakeFractionChangeEntry{}) + if err := m.StakeFractionChangeEntries[len(m.StakeFractionChangeEntries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QueueStateStateFraction", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.QueueStateStateFraction.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/stakers/types/keys.go b/x/stakers/types/keys.go index 70a5045a..6607fef1 100644 --- a/x/stakers/types/keys.go +++ b/x/stakers/types/keys.go @@ -36,7 +36,7 @@ var ( // CommissionChangeEntryKeyPrefix | CommissionChangeEntryKeyPrefix = []byte{4, 0} - // CommissionChangeEntryKeyPrefixIndex2 | + // CommissionChangeEntryKeyPrefixIndex2 | | CommissionChangeEntryKeyPrefixIndex2 = []byte{4, 1} // LeavePoolEntryKeyPrefix | @@ -45,6 +45,11 @@ var ( LeavePoolEntryKeyPrefixIndex2 = []byte{5, 1} ActiveStakerIndex = []byte{6} + + // StakeFractionChangeEntryKeyPrefix | + StakeFractionChangeEntryKeyPrefix = []byte{7, 0} + // StakeFractionChangeKeyPrefixIndex2 | | + StakeFractionChangeKeyPrefixIndex2 = []byte{7, 1} ) // ENUM aggregated data types @@ -56,8 +61,9 @@ var STAKER_STATS_COUNT STAKER_STATS = "total_stakers" type QUEUE_IDENTIFIER []byte var ( - QUEUE_IDENTIFIER_COMMISSION QUEUE_IDENTIFIER = []byte{30, 2} - QUEUE_IDENTIFIER_LEAVE QUEUE_IDENTIFIER = []byte{30, 3} + QUEUE_IDENTIFIER_COMMISSION QUEUE_IDENTIFIER = []byte{30, 2} + QUEUE_IDENTIFIER_LEAVE QUEUE_IDENTIFIER = []byte{30, 3} + QUEUE_IDENTIFIER_STAKE_FRACTION QUEUE_IDENTIFIER = []byte{30, 4} ) const MaxStakers = 50 @@ -82,8 +88,8 @@ func CommissionChangeEntryKey(index uint64) []byte { } // Important: only one queue entry per staker is allowed at a time. -func CommissionChangeEntryKeyIndex2(staker string) []byte { - return util.GetByteKey(staker) +func CommissionChangeEntryKeyIndex2(staker string, poolId uint64) []byte { + return util.GetByteKey(staker, poolId) } func LeavePoolEntryKey(index uint64) []byte { @@ -97,3 +103,11 @@ func LeavePoolEntryKeyIndex2(staker string, poolId uint64) []byte { func ActiveStakerKeyIndex(staker string) []byte { return util.GetByteKey(staker) } + +func StakeFractionChangeEntryKey(index uint64) []byte { + return util.GetByteKey(index) +} + +func StakeFractionChangeEntryKeyIndex2(staker string, poolId uint64) []byte { + return util.GetByteKey(staker, poolId) +} diff --git a/x/stakers/types/message_join_pool.go b/x/stakers/types/message_join_pool.go index 121adbfc..54cee98d 100644 --- a/x/stakers/types/message_join_pool.go +++ b/x/stakers/types/message_join_pool.go @@ -48,5 +48,13 @@ func (msg *MsgJoinPool) ValidateBasic() error { return errors.Wrapf(errorsTypes.ErrInvalidRequest, "invalid amount") } + if util.ValidatePercentage(msg.Commission) != nil { + return errors.Wrapf(errorsTypes.ErrInvalidRequest, "invalid commission") + } + + if util.ValidatePercentage(msg.StakeFraction) != nil { + return errors.Wrapf(errorsTypes.ErrInvalidRequest, "invalid stake fraction") + } + return nil } diff --git a/x/stakers/types/message_update_stake_fraction.go b/x/stakers/types/message_update_stake_fraction.go new file mode 100644 index 00000000..19341f15 --- /dev/null +++ b/x/stakers/types/message_update_stake_fraction.go @@ -0,0 +1,48 @@ +package types + +import ( + "cosmossdk.io/errors" + "github.com/KYVENetwork/chain/util" + sdk "github.com/cosmos/cosmos-sdk/types" + errorsTypes "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" +) + +var ( + _ legacytx.LegacyMsg = &MsgUpdateStakeFraction{} + _ sdk.Msg = &MsgUpdateStakeFraction{} +) + +func (msg *MsgUpdateStakeFraction) GetSignBytes() []byte { + bz := Amino.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgUpdateStakeFraction) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + + return []sdk.AccAddress{creator} +} + +func (msg *MsgUpdateStakeFraction) Route() string { + return RouterKey +} + +func (msg *MsgUpdateStakeFraction) Type() string { + return "kyve/stakers/MsgUpdateStakeFraction" +} + +func (msg *MsgUpdateStakeFraction) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Creator); err != nil { + return errors.Wrapf(errorsTypes.ErrInvalidAddress, "invalid validator address: %s", err) + } + + if util.ValidatePercentage(msg.StakeFraction) != nil { + return errors.Wrapf(errorsTypes.ErrInvalidRequest, "invalid stake fraction") + } + + return nil +} diff --git a/x/stakers/types/params.go b/x/stakers/types/params.go index 2ecb0884..e2fdd5ab 100644 --- a/x/stakers/types/params.go +++ b/x/stakers/types/params.go @@ -1,6 +1,7 @@ package types import ( + "cosmossdk.io/math" "github.com/KYVENetwork/chain/util" ) @@ -10,14 +11,34 @@ var DefaultCommissionChangeTime = uint64(60 * 60 * 24 * 5) // DefaultLeavePoolTime ... var DefaultLeavePoolTime = uint64(60 * 60 * 24 * 5) +// DefaultStakeFractionChangeTime ... +var DefaultStakeFractionChangeTime = uint64(60 * 60 * 24 * 5) + +// DefaultVoteSlash ... +var DefaultVoteSlash = math.LegacyMustNewDecFromStr("0.01") + +// DefaultUploadSlash ... +var DefaultUploadSlash = math.LegacyMustNewDecFromStr("0.02") + +// DefaultTimeoutSlash ... +var DefaultTimeoutSlash = math.LegacyMustNewDecFromStr("0.002") + // NewParams creates a new Params instance func NewParams( commissionChangeTime uint64, leavePoolTime uint64, + stakeFractionChangeTime uint64, + voteSlash math.LegacyDec, + uploadSlash math.LegacyDec, + timeoutSlash math.LegacyDec, ) Params { return Params{ - CommissionChangeTime: commissionChangeTime, - LeavePoolTime: leavePoolTime, + CommissionChangeTime: commissionChangeTime, + LeavePoolTime: leavePoolTime, + StakeFractionChangeTime: stakeFractionChangeTime, + VoteSlash: voteSlash, + UploadSlash: uploadSlash, + TimeoutSlash: timeoutSlash, } } @@ -26,6 +47,10 @@ func DefaultParams() Params { return NewParams( DefaultCommissionChangeTime, DefaultLeavePoolTime, + DefaultStakeFractionChangeTime, + DefaultVoteSlash, + DefaultUploadSlash, + DefaultTimeoutSlash, ) } @@ -39,5 +64,21 @@ func (p Params) Validate() error { return err } + if err := util.ValidateNumber(p.StakeFractionChangeTime); err != nil { + return err + } + + if err := util.ValidatePercentage(p.VoteSlash); err != nil { + return err + } + + if err := util.ValidatePercentage(p.UploadSlash); err != nil { + return err + } + + if err := util.ValidatePercentage(p.TimeoutSlash); err != nil { + return err + } + return nil } diff --git a/x/stakers/types/params.pb.go b/x/stakers/types/params.pb.go index 44ba4821..b2cd010d 100644 --- a/x/stakers/types/params.pb.go +++ b/x/stakers/types/params.pb.go @@ -4,7 +4,9 @@ package types import ( + cosmossdk_io_math "cosmossdk.io/math" fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" io "io" math "math" @@ -28,6 +30,14 @@ type Params struct { CommissionChangeTime uint64 `protobuf:"varint,1,opt,name=commission_change_time,json=commissionChangeTime,proto3" json:"commission_change_time,omitempty"` // commission_change_time ... LeavePoolTime uint64 `protobuf:"varint,2,opt,name=leave_pool_time,json=leavePoolTime,proto3" json:"leave_pool_time,omitempty"` + // stake_fraction_change_time ... + StakeFractionChangeTime uint64 `protobuf:"varint,3,opt,name=stake_fraction_change_time,json=stakeFractionChangeTime,proto3" json:"stake_fraction_change_time,omitempty"` + // vote_slash ... + VoteSlash cosmossdk_io_math.LegacyDec `protobuf:"bytes,4,opt,name=vote_slash,json=voteSlash,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"vote_slash"` + // upload_slash ... + UploadSlash cosmossdk_io_math.LegacyDec `protobuf:"bytes,5,opt,name=upload_slash,json=uploadSlash,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"upload_slash"` + // timeout_slash ... + TimeoutSlash cosmossdk_io_math.LegacyDec `protobuf:"bytes,6,opt,name=timeout_slash,json=timeoutSlash,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"timeout_slash"` } func (m *Params) Reset() { *m = Params{} } @@ -77,6 +87,13 @@ func (m *Params) GetLeavePoolTime() uint64 { return 0 } +func (m *Params) GetStakeFractionChangeTime() uint64 { + if m != nil { + return m.StakeFractionChangeTime + } + return 0 +} + func init() { proto.RegisterType((*Params)(nil), "kyve.stakers.v1beta1.Params") } @@ -84,21 +101,29 @@ func init() { func init() { proto.RegisterFile("kyve/stakers/v1beta1/params.proto", fileDescriptor_405cabd7005fc18b) } var fileDescriptor_405cabd7005fc18b = []byte{ - // 219 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xcc, 0xae, 0x2c, 0x4b, - 0xd5, 0x2f, 0x2e, 0x49, 0xcc, 0x4e, 0x2d, 0x2a, 0xd6, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, - 0xd4, 0x2f, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x01, - 0x29, 0xd1, 0x83, 0x2a, 0xd1, 0x83, 0x2a, 0x51, 0x4a, 0xe3, 0x62, 0x0b, 0x00, 0xab, 0x12, 0x32, - 0xe1, 0x12, 0x4b, 0xce, 0xcf, 0xcd, 0xcd, 0x2c, 0x2e, 0xce, 0xcc, 0xcf, 0x8b, 0x4f, 0xce, 0x48, - 0xcc, 0x4b, 0x4f, 0x8d, 0x2f, 0xc9, 0xcc, 0x4d, 0x95, 0x60, 0x54, 0x60, 0xd4, 0x60, 0x09, 0x12, - 0x41, 0xc8, 0x3a, 0x83, 0x25, 0x43, 0x32, 0x73, 0x53, 0x85, 0xd4, 0xb8, 0xf8, 0x73, 0x52, 0x13, - 0xcb, 0x52, 0xe3, 0x0b, 0xf2, 0xf3, 0x73, 0x20, 0xca, 0x99, 0xc0, 0xca, 0x79, 0xc1, 0xc2, 0x01, - 0xf9, 0xf9, 0x39, 0x20, 0x75, 0x4e, 0x6e, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, - 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, - 0x10, 0xa5, 0x93, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0xef, 0x1d, 0x19, - 0xe6, 0xea, 0x97, 0x5a, 0x52, 0x9e, 0x5f, 0x94, 0xad, 0x9f, 0x9c, 0x91, 0x98, 0x99, 0xa7, 0x5f, - 0x01, 0xf7, 0x54, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0xd8, 0x33, 0xc6, 0x80, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x44, 0x61, 0x13, 0x9a, 0xf1, 0x00, 0x00, 0x00, + // 347 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0x41, 0x4b, 0xc3, 0x30, + 0x14, 0x80, 0xdb, 0x39, 0x07, 0x8b, 0x1b, 0x42, 0x19, 0x3a, 0x26, 0x74, 0x53, 0x41, 0x76, 0x90, + 0x86, 0xa1, 0x37, 0x6f, 0x53, 0x87, 0xa0, 0xc8, 0x98, 0x22, 0xe8, 0xa5, 0x64, 0x59, 0x6c, 0x43, + 0x9b, 0xbd, 0xd2, 0x64, 0xd5, 0xfd, 0x0b, 0x7f, 0xd6, 0x8e, 0x3b, 0x8a, 0x87, 0x21, 0xdb, 0xaf, + 0xf0, 0x26, 0x4d, 0x8b, 0x8a, 0xa7, 0xdd, 0x4a, 0xf3, 0x7d, 0xdf, 0x7b, 0xf0, 0xd0, 0x7e, 0x30, + 0x4d, 0x18, 0x96, 0x8a, 0x04, 0x2c, 0x96, 0x38, 0xe9, 0x0c, 0x99, 0x22, 0x1d, 0x1c, 0x91, 0x98, + 0x08, 0xe9, 0x44, 0x31, 0x28, 0xb0, 0x6a, 0x29, 0xe2, 0xe4, 0x88, 0x93, 0x23, 0x8d, 0x9a, 0x07, + 0x1e, 0x68, 0x00, 0xa7, 0x5f, 0x19, 0x7b, 0xf0, 0x55, 0x40, 0xa5, 0xbe, 0x96, 0xad, 0x53, 0xb4, + 0x43, 0x41, 0x08, 0x2e, 0x25, 0x87, 0xb1, 0x4b, 0x7d, 0x32, 0xf6, 0x98, 0xab, 0xb8, 0x60, 0x75, + 0xb3, 0x65, 0xb6, 0x8b, 0x83, 0xda, 0xef, 0xeb, 0xb9, 0x7e, 0xbc, 0xe7, 0x82, 0x59, 0x47, 0x68, + 0x3b, 0x64, 0x24, 0x61, 0x6e, 0x04, 0x10, 0x66, 0x78, 0x41, 0xe3, 0x55, 0xfd, 0xbb, 0x0f, 0x10, + 0x6a, 0xee, 0x0c, 0x35, 0xf4, 0x46, 0xee, 0x73, 0x4c, 0xa8, 0xfa, 0x3f, 0x61, 0x43, 0x2b, 0xbb, + 0x9a, 0xe8, 0xe5, 0xc0, 0x9f, 0x21, 0x5d, 0x84, 0x12, 0x50, 0xcc, 0x95, 0x21, 0x91, 0x7e, 0xbd, + 0xd8, 0x32, 0xdb, 0xe5, 0xee, 0xe1, 0x6c, 0xd1, 0x34, 0x3e, 0x16, 0xcd, 0x3d, 0x0a, 0x52, 0x80, + 0x94, 0xa3, 0xc0, 0xe1, 0x80, 0x05, 0x51, 0xbe, 0x73, 0xc3, 0x3c, 0x42, 0xa7, 0x17, 0x8c, 0x0e, + 0xca, 0xa9, 0x76, 0x97, 0x5a, 0x56, 0x0f, 0x55, 0x26, 0x51, 0x08, 0x64, 0x94, 0x57, 0x36, 0xd7, + 0xaf, 0x6c, 0x65, 0x62, 0xd6, 0xb9, 0x42, 0xd5, 0x74, 0x65, 0x98, 0xa8, 0x3c, 0x54, 0x5a, 0x3f, + 0x54, 0xc9, 0x4d, 0x5d, 0xea, 0xf6, 0x66, 0x4b, 0xdb, 0x9c, 0x2f, 0x6d, 0xf3, 0x73, 0x69, 0x9b, + 0x6f, 0x2b, 0xdb, 0x98, 0xaf, 0x6c, 0xe3, 0x7d, 0x65, 0x1b, 0x4f, 0xc7, 0x1e, 0x57, 0xfe, 0x64, + 0xe8, 0x50, 0x10, 0xf8, 0xfa, 0xf1, 0xe1, 0xf2, 0x96, 0xa9, 0x17, 0x88, 0x03, 0x4c, 0x7d, 0xc2, + 0xc7, 0xf8, 0xf5, 0xe7, 0xfc, 0x6a, 0x1a, 0x31, 0x39, 0x2c, 0xe9, 0x53, 0x9e, 0x7c, 0x07, 0x00, + 0x00, 0xff, 0xff, 0xc8, 0xcb, 0x77, 0x48, 0x1b, 0x02, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -121,6 +146,41 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.TimeoutSlash.Size() + i -= size + if _, err := m.TimeoutSlash.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + { + size := m.UploadSlash.Size() + i -= size + if _, err := m.UploadSlash.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + { + size := m.VoteSlash.Size() + i -= size + if _, err := m.VoteSlash.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if m.StakeFractionChangeTime != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.StakeFractionChangeTime)) + i-- + dAtA[i] = 0x18 + } if m.LeavePoolTime != 0 { i = encodeVarintParams(dAtA, i, uint64(m.LeavePoolTime)) i-- @@ -157,6 +217,15 @@ func (m *Params) Size() (n int) { if m.LeavePoolTime != 0 { n += 1 + sovParams(uint64(m.LeavePoolTime)) } + if m.StakeFractionChangeTime != 0 { + n += 1 + sovParams(uint64(m.StakeFractionChangeTime)) + } + l = m.VoteSlash.Size() + n += 1 + l + sovParams(uint64(l)) + l = m.UploadSlash.Size() + n += 1 + l + sovParams(uint64(l)) + l = m.TimeoutSlash.Size() + n += 1 + l + sovParams(uint64(l)) return n } @@ -233,6 +302,127 @@ func (m *Params) Unmarshal(dAtA []byte) error { break } } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StakeFractionChangeTime", wireType) + } + m.StakeFractionChangeTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StakeFractionChangeTime |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VoteSlash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.VoteSlash.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UploadSlash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.UploadSlash.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeoutSlash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TimeoutSlash.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) diff --git a/x/stakers/types/stakers.pb.go b/x/stakers/types/stakers.pb.go index 58491d2b..b82f2d01 100644 --- a/x/stakers/types/stakers.pb.go +++ b/x/stakers/types/stakers.pb.go @@ -184,6 +184,10 @@ type Valaccount struct { Points uint64 `protobuf:"varint,4,opt,name=points,proto3" json:"points,omitempty"` // isLeaving indicates if a staker is leaving the given pool. IsLeaving bool `protobuf:"varint,5,opt,name=is_leaving,json=isLeaving,proto3" json:"is_leaving,omitempty"` + // commission ... + Commission cosmossdk_io_math.LegacyDec `protobuf:"bytes,6,opt,name=commission,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"commission"` + // stake_fraction ... + StakeFraction cosmossdk_io_math.LegacyDec `protobuf:"bytes,7,opt,name=stake_fraction,json=stakeFraction,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"stake_fraction"` } func (m *Valaccount) Reset() { *m = Valaccount{} } @@ -264,12 +268,14 @@ type CommissionChangeEntry struct { Index uint64 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` // staker is the address of the affected staker Staker string `protobuf:"bytes,2,opt,name=staker,proto3" json:"staker,omitempty"` + // pool_id ... + PoolId uint64 `protobuf:"varint,3,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` // commission is the new commission which will // be applied after the waiting time is over. - Commission cosmossdk_io_math.LegacyDec `protobuf:"bytes,3,opt,name=commission,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"commission"` + Commission cosmossdk_io_math.LegacyDec `protobuf:"bytes,4,opt,name=commission,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"commission"` // creation_date is the UNIX-timestamp in seconds // when the entry was created. - CreationDate int64 `protobuf:"varint,4,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` + CreationDate int64 `protobuf:"varint,5,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` } func (m *CommissionChangeEntry) Reset() { *m = CommissionChangeEntry{} } @@ -319,6 +325,13 @@ func (m *CommissionChangeEntry) GetStaker() string { return "" } +func (m *CommissionChangeEntry) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + func (m *CommissionChangeEntry) GetCreationDate() int64 { if m != nil { return m.CreationDate @@ -326,6 +339,87 @@ func (m *CommissionChangeEntry) GetCreationDate() int64 { return 0 } +// StakeFractionChangeEntry stores the information for an +// upcoming stake fraction change. A stake fraction change is +// only instant if it gets increased, if it gets decreased +// the staker needs to wait for the stake fraction change time +type StakeFractionChangeEntry struct { + // index is needed for the queue-algorithm which + // processes the commission changes + Index uint64 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` + // staker is the address of the affected staker + Staker string `protobuf:"bytes,2,opt,name=staker,proto3" json:"staker,omitempty"` + // pool_id ... + PoolId uint64 `protobuf:"varint,3,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // stake_fraction is the new stake fraction which will + // be applied after the waiting time is over. + StakeFraction cosmossdk_io_math.LegacyDec `protobuf:"bytes,4,opt,name=stake_fraction,json=stakeFraction,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"stake_fraction"` + // creation_date is the UNIX-timestamp in seconds + // when the entry was created. + CreationDate int64 `protobuf:"varint,5,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` +} + +func (m *StakeFractionChangeEntry) Reset() { *m = StakeFractionChangeEntry{} } +func (m *StakeFractionChangeEntry) String() string { return proto.CompactTextString(m) } +func (*StakeFractionChangeEntry) ProtoMessage() {} +func (*StakeFractionChangeEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_d209d1a2a74d375d, []int{3} +} +func (m *StakeFractionChangeEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StakeFractionChangeEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StakeFractionChangeEntry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StakeFractionChangeEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_StakeFractionChangeEntry.Merge(m, src) +} +func (m *StakeFractionChangeEntry) XXX_Size() int { + return m.Size() +} +func (m *StakeFractionChangeEntry) XXX_DiscardUnknown() { + xxx_messageInfo_StakeFractionChangeEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_StakeFractionChangeEntry proto.InternalMessageInfo + +func (m *StakeFractionChangeEntry) GetIndex() uint64 { + if m != nil { + return m.Index + } + return 0 +} + +func (m *StakeFractionChangeEntry) GetStaker() string { + if m != nil { + return m.Staker + } + return "" +} + +func (m *StakeFractionChangeEntry) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *StakeFractionChangeEntry) GetCreationDate() int64 { + if m != nil { + return m.CreationDate + } + return 0 +} + // LeavePoolEntry stores the information for an upcoming // pool leave. A staker can't leave a pool instantly. // Instead a the `LeaveTime` needs to be awaited. @@ -348,7 +442,7 @@ func (m *LeavePoolEntry) Reset() { *m = LeavePoolEntry{} } func (m *LeavePoolEntry) String() string { return proto.CompactTextString(m) } func (*LeavePoolEntry) ProtoMessage() {} func (*LeavePoolEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_d209d1a2a74d375d, []int{3} + return fileDescriptor_d209d1a2a74d375d, []int{4} } func (m *LeavePoolEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -420,7 +514,7 @@ func (m *QueueState) Reset() { *m = QueueState{} } func (m *QueueState) String() string { return proto.CompactTextString(m) } func (*QueueState) ProtoMessage() {} func (*QueueState) Descriptor() ([]byte, []int) { - return fileDescriptor_d209d1a2a74d375d, []int{4} + return fileDescriptor_d209d1a2a74d375d, []int{5} } func (m *QueueState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -468,6 +562,7 @@ func init() { proto.RegisterType((*Staker)(nil), "kyve.stakers.v1beta1.Staker") proto.RegisterType((*Valaccount)(nil), "kyve.stakers.v1beta1.Valaccount") proto.RegisterType((*CommissionChangeEntry)(nil), "kyve.stakers.v1beta1.CommissionChangeEntry") + proto.RegisterType((*StakeFractionChangeEntry)(nil), "kyve.stakers.v1beta1.StakeFractionChangeEntry") proto.RegisterType((*LeavePoolEntry)(nil), "kyve.stakers.v1beta1.LeavePoolEntry") proto.RegisterType((*QueueState)(nil), "kyve.stakers.v1beta1.QueueState") } @@ -477,51 +572,54 @@ func init() { } var fileDescriptor_d209d1a2a74d375d = []byte{ - // 696 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x41, 0x4f, 0x13, 0x4f, - 0x14, 0xef, 0xb6, 0x50, 0xda, 0xf7, 0xff, 0x2b, 0x65, 0x04, 0x5c, 0x4b, 0x58, 0x48, 0xb9, 0x20, - 0xd1, 0xdd, 0xa0, 0xf1, 0x03, 0x40, 0x5b, 0x42, 0x63, 0x85, 0xba, 0x2d, 0x24, 0x78, 0x69, 0xa6, - 0xbb, 0x93, 0x76, 0xd2, 0xed, 0x4e, 0xdd, 0x99, 0xb6, 0x34, 0x31, 0xf1, 0xea, 0xd1, 0x83, 0xdf, - 0xc0, 0x8b, 0xf1, 0xa2, 0x1f, 0x83, 0x23, 0x47, 0xe3, 0x01, 0x0d, 0x1c, 0xfc, 0x14, 0x26, 0x66, - 0x67, 0xb6, 0x65, 0x39, 0x98, 0x18, 0x2e, 0xbb, 0xf3, 0xfb, 0xfd, 0xde, 0xbc, 0xf7, 0xe6, 0x37, - 0x2f, 0x03, 0x85, 0xee, 0x78, 0x48, 0x2c, 0x2e, 0x70, 0x97, 0x04, 0xdc, 0x1a, 0x6e, 0xb7, 0x88, - 0xc0, 0xdb, 0x13, 0x6c, 0xf6, 0x03, 0x26, 0x18, 0x5a, 0x0c, 0x63, 0xcc, 0x09, 0x17, 0xc5, 0xe4, - 0x17, 0x70, 0x8f, 0xfa, 0xcc, 0x92, 0x5f, 0x15, 0x98, 0x37, 0x1c, 0xc6, 0x7b, 0x8c, 0x5b, 0x2d, - 0xcc, 0xc9, 0x34, 0x97, 0xc3, 0xa8, 0x1f, 0xe9, 0x8b, 0x6d, 0xd6, 0x66, 0x72, 0x69, 0x85, 0x2b, - 0xc5, 0x16, 0x7e, 0x27, 0x21, 0x5d, 0x97, 0xc9, 0x91, 0x0e, 0x73, 0xd8, 0x75, 0x03, 0xc2, 0xb9, - 0xae, 0xad, 0x6b, 0x9b, 0x59, 0x7b, 0x02, 0x51, 0x11, 0xc0, 0x61, 0xbd, 0x1e, 0xe5, 0x9c, 0x32, - 0x5f, 0x4f, 0x86, 0xe2, 0xee, 0xc6, 0xd9, 0xc5, 0x5a, 0xe2, 0xfb, 0xc5, 0xda, 0x8a, 0x2a, 0xcb, - 0xdd, 0xae, 0x49, 0x99, 0xd5, 0xc3, 0xa2, 0x63, 0x56, 0x49, 0x1b, 0x3b, 0xe3, 0x12, 0x71, 0xec, - 0xd8, 0xb6, 0x30, 0x7d, 0x8f, 0xf9, 0xb4, 0x4b, 0x02, 0x3d, 0xa5, 0xd2, 0x47, 0x30, 0x54, 0x46, - 0xa4, 0xc5, 0xa9, 0x20, 0xfa, 0x8c, 0x52, 0x22, 0x88, 0xf2, 0x90, 0xa1, 0x2e, 0xf1, 0x05, 0x15, - 0x63, 0x7d, 0x56, 0x4a, 0x53, 0x8c, 0x1e, 0x42, 0x8e, 0x13, 0x67, 0x10, 0x50, 0x31, 0x6e, 0x3a, - 0xcc, 0x17, 0xd8, 0x11, 0x7a, 0x5a, 0xc6, 0xcc, 0x4f, 0xf8, 0xa2, 0xa2, 0xc3, 0x02, 0x2e, 0x11, - 0x98, 0x7a, 0x5c, 0x9f, 0x53, 0x05, 0x22, 0x88, 0xde, 0x02, 0xba, 0x6e, 0xb1, 0x19, 0x90, 0x11, - 0x0e, 0x5c, 0xae, 0x67, 0xd6, 0x53, 0x9b, 0xff, 0x3d, 0x79, 0x60, 0xaa, 0xa3, 0x99, 0xa1, 0xa3, - 0x13, 0xe7, 0xcd, 0x22, 0xa3, 0xfe, 0xee, 0xb3, 0xf0, 0xf0, 0x9f, 0x7f, 0xac, 0x6d, 0xb6, 0xa9, - 0xe8, 0x0c, 0x5a, 0xa6, 0xc3, 0x7a, 0x56, 0x64, 0xbf, 0xfa, 0x3d, 0xe6, 0x6e, 0xd7, 0x12, 0xe3, - 0x3e, 0xe1, 0x72, 0x03, 0xff, 0xf4, 0xeb, 0xeb, 0x96, 0x66, 0x2f, 0x5c, 0xd7, 0xb2, 0x55, 0xa9, - 0xc2, 0x07, 0x0d, 0xe0, 0x18, 0x7b, 0xd8, 0x71, 0xd8, 0xc0, 0x17, 0xe8, 0x3e, 0xcc, 0xf5, 0x19, - 0xf3, 0x9a, 0xd4, 0x95, 0x77, 0x30, 0x63, 0xa7, 0x43, 0x58, 0x71, 0xd1, 0x32, 0xa4, 0xd5, 0x0c, - 0x28, 0xfb, 0xed, 0x08, 0x21, 0x03, 0x60, 0x88, 0xbd, 0xc9, 0xbd, 0x29, 0x63, 0x63, 0x4c, 0xb8, - 0xaf, 0xcf, 0xa8, 0x2f, 0xb8, 0xb4, 0x56, 0xe6, 0x0b, 0x11, 0x5a, 0x05, 0xa0, 0xbc, 0xe9, 0x11, - 0x3c, 0xa4, 0x7e, 0x5b, 0x7a, 0x9b, 0xb1, 0xb3, 0x94, 0x57, 0x15, 0x51, 0xf8, 0xa2, 0xc1, 0x52, - 0x71, 0xda, 0x6c, 0xb1, 0x83, 0xfd, 0x36, 0x29, 0xfb, 0x22, 0x18, 0xa3, 0x45, 0x98, 0xa5, 0xbe, - 0x4b, 0x4e, 0xa3, 0xfe, 0x14, 0xf8, 0x6b, 0x7b, 0x37, 0x27, 0x27, 0x75, 0xbb, 0xc9, 0xd9, 0x80, - 0x3b, 0x4e, 0x40, 0xb0, 0x08, 0xaf, 0xc8, 0xc5, 0xd1, 0x94, 0xa4, 0xec, 0xff, 0x27, 0x64, 0x09, - 0x0b, 0x52, 0x78, 0x03, 0x77, 0xc3, 0xe6, 0x49, 0x8d, 0x31, 0xef, 0x36, 0x9d, 0xc6, 0x9c, 0x4f, - 0xdd, 0x70, 0xfe, 0x9f, 0xaa, 0xef, 0x03, 0xbc, 0x1c, 0x90, 0x01, 0xa9, 0x0b, 0x2c, 0x08, 0x5a, - 0x81, 0xac, 0xc7, 0x46, 0xcd, 0x78, 0xf5, 0x8c, 0xc7, 0x46, 0x15, 0xd9, 0xc0, 0x2a, 0x40, 0x87, - 0xb6, 0x3b, 0x91, 0x9a, 0x94, 0x6a, 0x36, 0x64, 0xa4, 0xbc, 0xf5, 0x1a, 0xb2, 0x75, 0x0f, 0xf3, - 0x4e, 0x63, 0xdc, 0x0f, 0xe7, 0x7f, 0xb9, 0x5e, 0xdd, 0xa9, 0xef, 0x37, 0x1b, 0x27, 0xb5, 0x72, - 0xf3, 0xe8, 0xa0, 0x5e, 0x2b, 0x17, 0x2b, 0x7b, 0x95, 0x72, 0x29, 0x97, 0x40, 0xcb, 0x80, 0x62, - 0x5a, 0xa3, 0xf2, 0xa2, 0x7c, 0x78, 0xd4, 0xc8, 0x69, 0xe8, 0x1e, 0xcc, 0xc7, 0xf8, 0xe3, 0xc3, - 0x46, 0x39, 0x97, 0x44, 0x4b, 0xb0, 0x10, 0x4f, 0x54, 0xab, 0x1e, 0xee, 0x94, 0x72, 0xa9, 0xfc, - 0xcc, 0xbb, 0x8f, 0x46, 0x62, 0x77, 0xef, 0xec, 0xd2, 0xd0, 0xce, 0x2f, 0x0d, 0xed, 0xe7, 0xa5, - 0xa1, 0xbd, 0xbf, 0x32, 0x12, 0xe7, 0x57, 0x46, 0xe2, 0xdb, 0x95, 0x91, 0x78, 0xf5, 0x28, 0x36, - 0xdf, 0xcf, 0x4f, 0x8e, 0xcb, 0x07, 0x44, 0x8c, 0x58, 0xd0, 0xb5, 0x9c, 0x0e, 0xa6, 0xbe, 0x75, - 0x3a, 0x7d, 0xba, 0xe4, 0xa4, 0xb7, 0xd2, 0xf2, 0x49, 0x79, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, - 0x5f, 0xcc, 0xa7, 0xe7, 0xd7, 0x04, 0x00, 0x00, + // 750 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x4f, 0x4f, 0xdb, 0x48, + 0x1c, 0x8d, 0x93, 0x90, 0x3f, 0xb3, 0x0b, 0x84, 0x59, 0x60, 0xbd, 0x41, 0x18, 0x14, 0x2e, 0x2c, + 0xda, 0xb5, 0x45, 0xab, 0x7e, 0x00, 0x48, 0x82, 0x48, 0x9b, 0x42, 0xea, 0x04, 0x24, 0x7a, 0xb1, + 0x26, 0xf6, 0x34, 0x19, 0xc5, 0xf1, 0xa4, 0x9e, 0x49, 0x42, 0xa4, 0x4a, 0xbd, 0xf6, 0xd8, 0xef, + 0x50, 0x55, 0xaa, 0x7a, 0xea, 0xc7, 0xe0, 0x88, 0x7a, 0xaa, 0x7a, 0xa0, 0x15, 0x1c, 0xfa, 0x29, + 0x2a, 0x55, 0x33, 0x76, 0x82, 0x29, 0xad, 0x84, 0x50, 0x7b, 0x49, 0xfc, 0xde, 0x9b, 0xdf, 0xfb, + 0xcd, 0xef, 0x8d, 0x35, 0x06, 0x85, 0xce, 0x68, 0x80, 0x0d, 0xc6, 0x51, 0x07, 0xfb, 0xcc, 0x18, + 0x6c, 0x36, 0x31, 0x47, 0x9b, 0x63, 0xac, 0xf7, 0x7c, 0xca, 0x29, 0x9c, 0x17, 0x6b, 0xf4, 0x31, + 0x17, 0xae, 0xc9, 0xcf, 0xa1, 0x2e, 0xf1, 0xa8, 0x21, 0x7f, 0x83, 0x85, 0x79, 0xcd, 0xa6, 0xac, + 0x4b, 0x99, 0xd1, 0x44, 0x0c, 0x4f, 0xbc, 0x6c, 0x4a, 0xbc, 0x50, 0x9f, 0x6f, 0xd1, 0x16, 0x95, + 0x8f, 0x86, 0x78, 0x0a, 0xd8, 0xc2, 0xd7, 0x38, 0x48, 0xd5, 0xa5, 0x39, 0x54, 0x41, 0x1a, 0x39, + 0x8e, 0x8f, 0x19, 0x53, 0x95, 0x55, 0x65, 0x3d, 0x6b, 0x8e, 0x21, 0x2c, 0x02, 0x60, 0xd3, 0x6e, + 0x97, 0x30, 0x46, 0xa8, 0xa7, 0xc6, 0x85, 0xb8, 0xbd, 0x76, 0x72, 0xb6, 0x12, 0xfb, 0x78, 0xb6, + 0xb2, 0x14, 0xb4, 0x65, 0x4e, 0x47, 0x27, 0xd4, 0xe8, 0x22, 0xde, 0xd6, 0xab, 0xb8, 0x85, 0xec, + 0x51, 0x09, 0xdb, 0x66, 0xa4, 0x4c, 0xd8, 0x77, 0xa9, 0x47, 0x3a, 0xd8, 0x57, 0x13, 0x81, 0x7d, + 0x08, 0x85, 0x32, 0xc4, 0x4d, 0x46, 0x38, 0x56, 0x93, 0x81, 0x12, 0x42, 0x98, 0x07, 0x19, 0xe2, + 0x60, 0x8f, 0x13, 0x3e, 0x52, 0xa7, 0xa4, 0x34, 0xc1, 0xf0, 0x5f, 0x90, 0x63, 0xd8, 0xee, 0xfb, + 0x84, 0x8f, 0x2c, 0x9b, 0x7a, 0x1c, 0xd9, 0x5c, 0x4d, 0xc9, 0x35, 0xb3, 0x63, 0xbe, 0x18, 0xd0, + 0xa2, 0x81, 0x83, 0x39, 0x22, 0x2e, 0x53, 0xd3, 0x41, 0x83, 0x10, 0xc2, 0xe7, 0x00, 0x5e, 0x6e, + 0xd1, 0xf2, 0xf1, 0x10, 0xf9, 0x0e, 0x53, 0x33, 0xab, 0x89, 0xf5, 0x3f, 0xee, 0xfc, 0xa3, 0x07, + 0xa3, 0xe9, 0x22, 0xd1, 0x71, 0xf2, 0x7a, 0x91, 0x12, 0x6f, 0xfb, 0x9e, 0x18, 0xfe, 0xed, 0xa7, + 0x95, 0xf5, 0x16, 0xe1, 0xed, 0x7e, 0x53, 0xb7, 0x69, 0xd7, 0x08, 0xe3, 0x0f, 0xfe, 0xfe, 0x67, + 0x4e, 0xc7, 0xe0, 0xa3, 0x1e, 0x66, 0xb2, 0x80, 0xbd, 0xf9, 0xf2, 0x6e, 0x43, 0x31, 0xe7, 0x2e, + 0x7b, 0x99, 0x41, 0xab, 0xc2, 0xeb, 0x38, 0x00, 0x87, 0xc8, 0x45, 0xb6, 0x4d, 0xfb, 0x1e, 0x87, + 0x7f, 0x83, 0x74, 0x8f, 0x52, 0xd7, 0x22, 0x8e, 0x3c, 0x83, 0xa4, 0x99, 0x12, 0xb0, 0xe2, 0xc0, + 0x45, 0x90, 0x0a, 0xde, 0x81, 0x20, 0x7e, 0x33, 0x44, 0x50, 0x03, 0x60, 0x80, 0xdc, 0xf1, 0xb9, + 0x05, 0xc1, 0x46, 0x18, 0x51, 0xd7, 0xa3, 0xc4, 0xe3, 0x4c, 0x46, 0x2b, 0xfd, 0x04, 0x82, 0xcb, + 0x00, 0x10, 0x66, 0xb9, 0x18, 0x0d, 0x88, 0xd7, 0x92, 0xd9, 0x66, 0xcc, 0x2c, 0x61, 0xd5, 0x80, + 0xf8, 0xee, 0xc4, 0x53, 0xb7, 0x3b, 0xf1, 0xfb, 0x60, 0x46, 0xee, 0xd2, 0x7a, 0xe2, 0x23, 0x9b, + 0x0b, 0xa3, 0xf4, 0xcd, 0x8d, 0xa6, 0x65, 0xe9, 0x4e, 0x58, 0x59, 0x38, 0x51, 0xc0, 0x42, 0x71, + 0x62, 0x5d, 0x6c, 0x23, 0xaf, 0x85, 0xcb, 0x1e, 0xf7, 0x47, 0x70, 0x1e, 0x4c, 0x11, 0xcf, 0xc1, + 0xc7, 0x61, 0x60, 0x01, 0xf8, 0x69, 0x5e, 0x91, 0x80, 0x13, 0x57, 0x02, 0xbe, 0x3a, 0x71, 0xf2, + 0x76, 0x13, 0xaf, 0x81, 0x69, 0xdb, 0xc7, 0x48, 0xec, 0xd8, 0x72, 0x10, 0xc7, 0x32, 0xd8, 0x84, + 0xf9, 0xe7, 0x98, 0x2c, 0x21, 0x8e, 0x0b, 0xef, 0x15, 0xa0, 0xd6, 0xa3, 0xc3, 0xfd, 0x86, 0x69, + 0xae, 0x47, 0x9f, 0xbc, 0x6d, 0xf4, 0x37, 0x1b, 0xea, 0x19, 0x98, 0x11, 0xef, 0x0e, 0xae, 0x51, + 0xea, 0xfe, 0xd2, 0x49, 0xae, 0x75, 0x4f, 0xfe, 0xa0, 0xfb, 0x2e, 0x00, 0x8f, 0xfa, 0xb8, 0x8f, + 0xeb, 0x1c, 0x71, 0x0c, 0x97, 0x40, 0xd6, 0xa5, 0x43, 0x2b, 0xda, 0x3d, 0xe3, 0xd2, 0x61, 0x45, + 0x6e, 0x60, 0x19, 0x80, 0x36, 0x69, 0xb5, 0x43, 0x35, 0x2e, 0xd5, 0xac, 0x60, 0xa4, 0xbc, 0xf1, + 0x14, 0x64, 0xeb, 0x2e, 0x62, 0xed, 0xc6, 0xa8, 0x27, 0xae, 0x9f, 0xc5, 0x7a, 0x75, 0xab, 0xbe, + 0x6b, 0x35, 0x8e, 0x6a, 0x65, 0xeb, 0x60, 0xaf, 0x5e, 0x2b, 0x17, 0x2b, 0x3b, 0x95, 0x72, 0x29, + 0x17, 0x83, 0x8b, 0x00, 0x46, 0xb4, 0x46, 0xe5, 0x61, 0x79, 0xff, 0xa0, 0x91, 0x53, 0xe0, 0x5f, + 0x60, 0x36, 0xc2, 0x1f, 0xee, 0x37, 0xca, 0xb9, 0x38, 0x5c, 0x00, 0x73, 0x51, 0xa3, 0x5a, 0x75, + 0x7f, 0xab, 0x94, 0x4b, 0xe4, 0x93, 0x2f, 0x5e, 0x69, 0xb1, 0xed, 0x9d, 0x93, 0x73, 0x4d, 0x39, + 0x3d, 0xd7, 0x94, 0xcf, 0xe7, 0x9a, 0xf2, 0xf2, 0x42, 0x8b, 0x9d, 0x5e, 0x68, 0xb1, 0x0f, 0x17, + 0x5a, 0xec, 0xf1, 0x7f, 0x91, 0xeb, 0xe5, 0xc1, 0xd1, 0x61, 0x79, 0x0f, 0xf3, 0x21, 0xf5, 0x3b, + 0x86, 0xdd, 0x46, 0xc4, 0x33, 0x8e, 0x27, 0x5f, 0x0e, 0x79, 0xd1, 0x34, 0x53, 0xf2, 0x46, 0xbf, + 0xfb, 0x2d, 0x00, 0x00, 0xff, 0xff, 0x03, 0xe9, 0xa2, 0x1f, 0x56, 0x06, 0x00, 0x00, } func (m *Staker) Marshal() (dAtA []byte, err error) { @@ -633,6 +731,26 @@ func (m *Valaccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.StakeFraction.Size() + i -= size + if _, err := m.StakeFraction.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakers(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + { + size := m.Commission.Size() + i -= size + if _, err := m.Commission.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakers(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 if m.IsLeaving { i-- if m.IsLeaving { @@ -693,7 +811,7 @@ func (m *CommissionChangeEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { if m.CreationDate != 0 { i = encodeVarintStakers(dAtA, i, uint64(m.CreationDate)) i-- - dAtA[i] = 0x20 + dAtA[i] = 0x28 } { size := m.Commission.Size() @@ -704,7 +822,67 @@ func (m *CommissionChangeEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintStakers(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a + dAtA[i] = 0x22 + if m.PoolId != 0 { + i = encodeVarintStakers(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x18 + } + if len(m.Staker) > 0 { + i -= len(m.Staker) + copy(dAtA[i:], m.Staker) + i = encodeVarintStakers(dAtA, i, uint64(len(m.Staker))) + i-- + dAtA[i] = 0x12 + } + if m.Index != 0 { + i = encodeVarintStakers(dAtA, i, uint64(m.Index)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *StakeFractionChangeEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StakeFractionChangeEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StakeFractionChangeEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CreationDate != 0 { + i = encodeVarintStakers(dAtA, i, uint64(m.CreationDate)) + i-- + dAtA[i] = 0x28 + } + { + size := m.StakeFraction.Size() + i -= size + if _, err := m.StakeFraction.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakers(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if m.PoolId != 0 { + i = encodeVarintStakers(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x18 + } if len(m.Staker) > 0 { i -= len(m.Staker) copy(dAtA[i:], m.Staker) @@ -873,6 +1051,10 @@ func (m *Valaccount) Size() (n int) { if m.IsLeaving { n += 2 } + l = m.Commission.Size() + n += 1 + l + sovStakers(uint64(l)) + l = m.StakeFraction.Size() + n += 1 + l + sovStakers(uint64(l)) return n } @@ -889,6 +1071,9 @@ func (m *CommissionChangeEntry) Size() (n int) { if l > 0 { n += 1 + l + sovStakers(uint64(l)) } + if m.PoolId != 0 { + n += 1 + sovStakers(uint64(m.PoolId)) + } l = m.Commission.Size() n += 1 + l + sovStakers(uint64(l)) if m.CreationDate != 0 { @@ -897,6 +1082,30 @@ func (m *CommissionChangeEntry) Size() (n int) { return n } +func (m *StakeFractionChangeEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Index != 0 { + n += 1 + sovStakers(uint64(m.Index)) + } + l = len(m.Staker) + if l > 0 { + n += 1 + l + sovStakers(uint64(l)) + } + if m.PoolId != 0 { + n += 1 + sovStakers(uint64(m.PoolId)) + } + l = m.StakeFraction.Size() + n += 1 + l + sovStakers(uint64(l)) + if m.CreationDate != 0 { + n += 1 + sovStakers(uint64(m.CreationDate)) + } + return n +} + func (m *LeavePoolEntry) Size() (n int) { if m == nil { return 0 @@ -1401,6 +1610,74 @@ func (m *Valaccount) Unmarshal(dAtA []byte) error { } } m.IsLeaving = bool(v != 0) + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Commission", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakers + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStakers + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakers + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Commission.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakeFraction", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakers + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStakers + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakers + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StakeFraction.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipStakers(dAtA[iNdEx:]) @@ -1503,6 +1780,25 @@ func (m *CommissionChangeEntry) Unmarshal(dAtA []byte) error { m.Staker = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakers + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Commission", wireType) } @@ -1536,7 +1832,180 @@ func (m *CommissionChangeEntry) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CreationDate", wireType) + } + m.CreationDate = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakers + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CreationDate |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipStakers(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthStakers + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StakeFractionChangeEntry) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakers + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StakeFractionChangeEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StakeFractionChangeEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + m.Index = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakers + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Index |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Staker", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakers + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStakers + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakers + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Staker = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakers + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakeFraction", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakers + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStakers + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakers + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StakeFraction.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field CreationDate", wireType) } diff --git a/x/stakers/types/tx.pb.go b/x/stakers/types/tx.pb.go index c349403f..8a4695c8 100644 --- a/x/stakers/types/tx.pb.go +++ b/x/stakers/types/tx.pb.go @@ -31,12 +31,14 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// MsgUpdateCommission ... +// MsgUpdateCommission ... // TODO: create v1 types and rename new to MsgUpdatePoolCommission type MsgUpdateCommission struct { // creator ... Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + // pool_id ... + PoolId uint64 `protobuf:"varint,2,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` // commission ... - Commission cosmossdk_io_math.LegacyDec `protobuf:"bytes,2,opt,name=commission,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"commission"` + Commission cosmossdk_io_math.LegacyDec `protobuf:"bytes,3,opt,name=commission,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"commission"` } func (m *MsgUpdateCommission) Reset() { *m = MsgUpdateCommission{} } @@ -79,6 +81,13 @@ func (m *MsgUpdateCommission) GetCreator() string { return "" } +func (m *MsgUpdateCommission) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + // MsgUpdateCommissionResponse ... type MsgUpdateCommissionResponse struct { } @@ -116,7 +125,101 @@ func (m *MsgUpdateCommissionResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUpdateCommissionResponse proto.InternalMessageInfo -// MsgJoinPool ... +// MsgUpdateStakeFraction ... +type MsgUpdateStakeFraction struct { + // creator ... + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + // pool_id ... + PoolId uint64 `protobuf:"varint,2,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // commission ... + StakeFraction cosmossdk_io_math.LegacyDec `protobuf:"bytes,3,opt,name=stake_fraction,json=stakeFraction,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"stake_fraction"` +} + +func (m *MsgUpdateStakeFraction) Reset() { *m = MsgUpdateStakeFraction{} } +func (m *MsgUpdateStakeFraction) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateStakeFraction) ProtoMessage() {} +func (*MsgUpdateStakeFraction) Descriptor() ([]byte, []int) { + return fileDescriptor_f52b730e69b9fb06, []int{2} +} +func (m *MsgUpdateStakeFraction) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateStakeFraction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateStakeFraction.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateStakeFraction) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateStakeFraction.Merge(m, src) +} +func (m *MsgUpdateStakeFraction) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateStakeFraction) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateStakeFraction.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateStakeFraction proto.InternalMessageInfo + +func (m *MsgUpdateStakeFraction) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgUpdateStakeFraction) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +// MsgUpdateStakeFractionResponse ... +type MsgUpdateStakeFractionResponse struct { +} + +func (m *MsgUpdateStakeFractionResponse) Reset() { *m = MsgUpdateStakeFractionResponse{} } +func (m *MsgUpdateStakeFractionResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateStakeFractionResponse) ProtoMessage() {} +func (*MsgUpdateStakeFractionResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f52b730e69b9fb06, []int{3} +} +func (m *MsgUpdateStakeFractionResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateStakeFractionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateStakeFractionResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateStakeFractionResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateStakeFractionResponse.Merge(m, src) +} +func (m *MsgUpdateStakeFractionResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateStakeFractionResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateStakeFractionResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateStakeFractionResponse proto.InternalMessageInfo + +// MsgJoinPool ... // TODO: create v1 types type MsgJoinPool struct { // creator ... Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` @@ -126,13 +229,17 @@ type MsgJoinPool struct { Valaddress string `protobuf:"bytes,3,opt,name=valaddress,proto3" json:"valaddress,omitempty"` // amount ... Amount uint64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"` + // commission ... + Commission cosmossdk_io_math.LegacyDec `protobuf:"bytes,5,opt,name=commission,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"commission"` + // stake_fraction ... + StakeFraction cosmossdk_io_math.LegacyDec `protobuf:"bytes,6,opt,name=stake_fraction,json=stakeFraction,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"stake_fraction"` } func (m *MsgJoinPool) Reset() { *m = MsgJoinPool{} } func (m *MsgJoinPool) String() string { return proto.CompactTextString(m) } func (*MsgJoinPool) ProtoMessage() {} func (*MsgJoinPool) Descriptor() ([]byte, []int) { - return fileDescriptor_f52b730e69b9fb06, []int{2} + return fileDescriptor_f52b730e69b9fb06, []int{4} } func (m *MsgJoinPool) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -197,7 +304,7 @@ func (m *MsgJoinPoolResponse) Reset() { *m = MsgJoinPoolResponse{} } func (m *MsgJoinPoolResponse) String() string { return proto.CompactTextString(m) } func (*MsgJoinPoolResponse) ProtoMessage() {} func (*MsgJoinPoolResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f52b730e69b9fb06, []int{3} + return fileDescriptor_f52b730e69b9fb06, []int{5} } func (m *MsgJoinPoolResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -238,7 +345,7 @@ func (m *MsgLeavePool) Reset() { *m = MsgLeavePool{} } func (m *MsgLeavePool) String() string { return proto.CompactTextString(m) } func (*MsgLeavePool) ProtoMessage() {} func (*MsgLeavePool) Descriptor() ([]byte, []int) { - return fileDescriptor_f52b730e69b9fb06, []int{4} + return fileDescriptor_f52b730e69b9fb06, []int{6} } func (m *MsgLeavePool) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -289,7 +396,7 @@ func (m *MsgLeavePoolResponse) Reset() { *m = MsgLeavePoolResponse{} } func (m *MsgLeavePoolResponse) String() string { return proto.CompactTextString(m) } func (*MsgLeavePoolResponse) ProtoMessage() {} func (*MsgLeavePoolResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f52b730e69b9fb06, []int{5} + return fileDescriptor_f52b730e69b9fb06, []int{7} } func (m *MsgLeavePoolResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -330,7 +437,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_f52b730e69b9fb06, []int{6} + return fileDescriptor_f52b730e69b9fb06, []int{8} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -381,7 +488,7 @@ func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParamsResponse) ProtoMessage() {} func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f52b730e69b9fb06, []int{7} + return fileDescriptor_f52b730e69b9fb06, []int{9} } func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -413,6 +520,8 @@ var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo func init() { proto.RegisterType((*MsgUpdateCommission)(nil), "kyve.stakers.v1beta1.MsgUpdateCommission") proto.RegisterType((*MsgUpdateCommissionResponse)(nil), "kyve.stakers.v1beta1.MsgUpdateCommissionResponse") + proto.RegisterType((*MsgUpdateStakeFraction)(nil), "kyve.stakers.v1beta1.MsgUpdateStakeFraction") + proto.RegisterType((*MsgUpdateStakeFractionResponse)(nil), "kyve.stakers.v1beta1.MsgUpdateStakeFractionResponse") proto.RegisterType((*MsgJoinPool)(nil), "kyve.stakers.v1beta1.MsgJoinPool") proto.RegisterType((*MsgJoinPoolResponse)(nil), "kyve.stakers.v1beta1.MsgJoinPoolResponse") proto.RegisterType((*MsgLeavePool)(nil), "kyve.stakers.v1beta1.MsgLeavePool") @@ -424,42 +533,46 @@ func init() { func init() { proto.RegisterFile("kyve/stakers/v1beta1/tx.proto", fileDescriptor_f52b730e69b9fb06) } var fileDescriptor_f52b730e69b9fb06 = []byte{ - // 549 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x4d, 0x6f, 0xd3, 0x40, - 0x10, 0x8d, 0x49, 0x49, 0xc9, 0x10, 0x01, 0x32, 0xa1, 0x71, 0x5d, 0xd5, 0x85, 0x20, 0x24, 0x1a, - 0x51, 0x5b, 0x01, 0x89, 0x43, 0x6f, 0xa4, 0x80, 0x04, 0x34, 0x50, 0x19, 0x81, 0xf8, 0x38, 0x54, - 0x1b, 0x7b, 0xb5, 0xb1, 0x12, 0x7b, 0x2c, 0xef, 0x26, 0x34, 0x37, 0xd4, 0x03, 0x67, 0xee, 0xfc, - 0x89, 0x1e, 0xf8, 0x11, 0x3d, 0x56, 0x9c, 0x10, 0x87, 0x0a, 0x25, 0x87, 0xfe, 0x0d, 0xe4, 0x6c, - 0xec, 0x84, 0x90, 0x92, 0xaa, 0x27, 0xfb, 0xed, 0x7b, 0x33, 0xef, 0xed, 0xce, 0x6a, 0x61, 0xb5, - 0xd5, 0xeb, 0x52, 0x8b, 0x0b, 0xd2, 0xa2, 0x11, 0xb7, 0xba, 0xd5, 0x06, 0x15, 0xa4, 0x6a, 0x89, - 0x3d, 0x33, 0x8c, 0x50, 0xa0, 0x5a, 0x8c, 0x69, 0x73, 0x44, 0x9b, 0x23, 0x5a, 0x2f, 0x39, 0xc8, - 0x7d, 0xe4, 0x96, 0xcf, 0x99, 0xd5, 0xad, 0xc6, 0x1f, 0x29, 0xd7, 0x97, 0x25, 0xb1, 0x3b, 0x44, - 0x96, 0x04, 0x23, 0xaa, 0xc8, 0x90, 0xa1, 0x5c, 0x8f, 0xff, 0xe4, 0x6a, 0x79, 0x5f, 0x81, 0xeb, - 0x75, 0xce, 0xde, 0x84, 0x2e, 0x11, 0x74, 0x0b, 0x7d, 0xdf, 0xe3, 0xdc, 0xc3, 0x40, 0xd5, 0x60, - 0xd1, 0x89, 0x28, 0x11, 0x18, 0x69, 0xca, 0x4d, 0xe5, 0x6e, 0xde, 0x4e, 0xa0, 0xba, 0x05, 0xe0, - 0xa4, 0x3a, 0xed, 0x42, 0x4c, 0xd6, 0x6e, 0x1f, 0x1e, 0xaf, 0x65, 0x7e, 0x1d, 0xaf, 0xad, 0x48, - 0x47, 0xee, 0xb6, 0x4c, 0x0f, 0x2d, 0x9f, 0x88, 0xa6, 0xb9, 0x4d, 0x19, 0x71, 0x7a, 0x8f, 0xa9, - 0x63, 0x4f, 0x94, 0x6d, 0x16, 0xf6, 0x4f, 0x0e, 0x2a, 0x49, 0xcb, 0xf2, 0x2a, 0xac, 0xcc, 0xc8, - 0x60, 0x53, 0x1e, 0x62, 0xc0, 0x69, 0xf9, 0x8b, 0x02, 0x97, 0xeb, 0x9c, 0x3d, 0x47, 0x2f, 0xd8, - 0x41, 0x6c, 0xff, 0x27, 0x5b, 0x09, 0x16, 0x43, 0xc4, 0xf6, 0xae, 0xe7, 0x0e, 0x83, 0x2d, 0xd8, - 0xb9, 0x18, 0x3e, 0x73, 0x55, 0x03, 0xa0, 0x4b, 0xda, 0xc4, 0x75, 0x23, 0xca, 0xb9, 0x96, 0x1d, - 0x56, 0x4d, 0xac, 0xa8, 0x4b, 0x90, 0x23, 0x3e, 0x76, 0x02, 0xa1, 0x2d, 0xc8, 0x3a, 0x89, 0xa6, - 0x72, 0xde, 0x18, 0x9e, 0x55, 0x92, 0x23, 0xcd, 0xf7, 0x0a, 0x0a, 0x75, 0xce, 0xb6, 0x29, 0xe9, - 0xd2, 0x73, 0xe6, 0x9b, 0xf2, 0x59, 0x82, 0xe2, 0x64, 0xc3, 0xd4, 0x88, 0xc3, 0xd5, 0xf4, 0x9c, - 0x76, 0x48, 0x44, 0x7c, 0xae, 0x3e, 0x84, 0x3c, 0xe9, 0x88, 0x26, 0x46, 0x9e, 0xe8, 0x49, 0xb7, - 0x9a, 0xf6, 0xe3, 0xfb, 0x46, 0x71, 0x34, 0xfa, 0x47, 0x72, 0x7f, 0xaf, 0x45, 0xe4, 0x05, 0xcc, - 0x1e, 0x4b, 0xe3, 0x8c, 0x21, 0xe9, 0xb5, 0x91, 0xc8, 0x24, 0x79, 0x3b, 0x81, 0x9b, 0x57, 0xe2, - 0x28, 0x63, 0x65, 0x79, 0x19, 0x4a, 0x53, 0xa6, 0x49, 0x9e, 0xfb, 0xdf, 0xb2, 0x90, 0xad, 0x73, - 0xa6, 0x86, 0x70, 0xed, 0x9f, 0x0b, 0xb4, 0x6e, 0xce, 0xba, 0xb9, 0xe6, 0x8c, 0x39, 0xeb, 0xd5, - 0x33, 0x4b, 0x13, 0x67, 0xf5, 0x1d, 0x5c, 0x4a, 0xaf, 0xc3, 0xad, 0x53, 0xcb, 0x13, 0x89, 0xbe, - 0x3e, 0x57, 0x92, 0x76, 0xfe, 0x08, 0xf9, 0xf1, 0x24, 0xcb, 0xa7, 0xd6, 0xa5, 0x1a, 0xbd, 0x32, - 0x5f, 0x93, 0x36, 0x77, 0xa1, 0xf0, 0xd7, 0xf4, 0xee, 0xcc, 0xd9, 0xb9, 0x94, 0xe9, 0x1b, 0x67, - 0x92, 0x25, 0x2e, 0xfa, 0xc5, 0xcf, 0x27, 0x07, 0x15, 0xa5, 0xf6, 0xf4, 0xb0, 0x6f, 0x28, 0x47, - 0x7d, 0x43, 0xf9, 0xdd, 0x37, 0x94, 0xaf, 0x03, 0x23, 0x73, 0x34, 0x30, 0x32, 0x3f, 0x07, 0x46, - 0xe6, 0xc3, 0x3d, 0xe6, 0x89, 0x66, 0xa7, 0x61, 0x3a, 0xe8, 0x5b, 0x2f, 0xde, 0xbf, 0x7d, 0xf2, - 0x92, 0x8a, 0x4f, 0x18, 0xb5, 0x2c, 0xa7, 0x49, 0xbc, 0xc0, 0xda, 0x4b, 0x5f, 0x23, 0xd1, 0x0b, - 0x29, 0x6f, 0xe4, 0x86, 0x2f, 0xc5, 0x83, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xe4, 0xbe, 0x16, - 0xb1, 0xaa, 0x04, 0x00, 0x00, + // 622 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x4d, 0x6f, 0xd3, 0x40, + 0x10, 0x8d, 0xfb, 0x91, 0x92, 0xa1, 0x14, 0xe4, 0x86, 0xd6, 0x75, 0x55, 0xb7, 0x04, 0x21, 0x95, + 0xaa, 0xb5, 0x15, 0x40, 0x1c, 0x7a, 0x23, 0x85, 0x4a, 0x94, 0x06, 0x2a, 0x57, 0x20, 0x3e, 0x0e, + 0xd1, 0xc6, 0x5e, 0x1c, 0x2b, 0xb1, 0xd7, 0xf2, 0x6e, 0x42, 0x7d, 0x43, 0xfc, 0x02, 0x4e, 0x70, + 0xe0, 0xcc, 0xbd, 0x07, 0x7e, 0x44, 0x8f, 0x15, 0x27, 0xc4, 0xa1, 0x42, 0xc9, 0xa1, 0x7f, 0x03, + 0x39, 0x1b, 0x6f, 0xd2, 0x90, 0x2a, 0x6d, 0xc4, 0x29, 0x99, 0x9d, 0x37, 0xf3, 0xde, 0xbe, 0x5d, + 0xcf, 0xc2, 0x52, 0x35, 0x6a, 0x60, 0x83, 0x32, 0x54, 0xc5, 0x21, 0x35, 0x1a, 0xf9, 0x32, 0x66, + 0x28, 0x6f, 0xb0, 0x03, 0x3d, 0x08, 0x09, 0x23, 0x72, 0x36, 0x4e, 0xeb, 0x9d, 0xb4, 0xde, 0x49, + 0xab, 0xf3, 0x16, 0xa1, 0x1e, 0xa1, 0x86, 0x47, 0x1d, 0xa3, 0x91, 0x8f, 0x7f, 0x38, 0x5c, 0x5d, + 0xe0, 0x89, 0x52, 0x3b, 0x32, 0x78, 0xd0, 0x49, 0x65, 0x1d, 0xe2, 0x10, 0xbe, 0x1e, 0xff, 0xe3, + 0xab, 0xb9, 0x6f, 0x12, 0xcc, 0x16, 0xa9, 0xf3, 0x32, 0xb0, 0x11, 0xc3, 0x5b, 0xc4, 0xf3, 0x5c, + 0x4a, 0x5d, 0xe2, 0xcb, 0x0a, 0x4c, 0x59, 0x21, 0x46, 0x8c, 0x84, 0x8a, 0xb4, 0x22, 0xad, 0x66, + 0xcc, 0x24, 0x94, 0xe7, 0x61, 0x2a, 0x20, 0xa4, 0x56, 0x72, 0x6d, 0x65, 0x6c, 0x45, 0x5a, 0x9d, + 0x30, 0xd3, 0x71, 0xf8, 0xd4, 0x96, 0xb7, 0x00, 0x2c, 0xd1, 0x40, 0x19, 0x8f, 0xab, 0x0a, 0xb7, + 0x8f, 0x4e, 0x96, 0x53, 0xbf, 0x4f, 0x96, 0x17, 0xb9, 0x14, 0x6a, 0x57, 0x75, 0x97, 0x18, 0x1e, + 0x62, 0x15, 0x7d, 0x17, 0x3b, 0xc8, 0x8a, 0x1e, 0x63, 0xcb, 0xec, 0x29, 0xdb, 0x9c, 0xfe, 0x74, + 0x7a, 0xb8, 0x96, 0x70, 0xe5, 0x96, 0x60, 0x71, 0x80, 0x38, 0x13, 0xd3, 0x80, 0xf8, 0x14, 0xe7, + 0xbe, 0x4b, 0x30, 0x27, 0xf2, 0xfb, 0xb1, 0x47, 0xdb, 0x21, 0xb2, 0xd8, 0x88, 0xfa, 0x77, 0x60, + 0xa6, 0xed, 0x73, 0xe9, 0x7d, 0xa7, 0xc9, 0x65, 0xf6, 0x70, 0x8d, 0xf6, 0xd2, 0xf7, 0x6d, 0x63, + 0x05, 0xb4, 0xc1, 0x32, 0xc5, 0x4e, 0xbe, 0x8e, 0xc1, 0xd5, 0x22, 0x75, 0x76, 0x88, 0xeb, 0xef, + 0x11, 0x52, 0x1b, 0x45, 0xbe, 0x06, 0xd0, 0x40, 0x35, 0x64, 0xdb, 0x21, 0xa6, 0x94, 0x4b, 0x37, + 0x7b, 0x56, 0xe4, 0x39, 0x48, 0x23, 0x8f, 0xd4, 0x7d, 0xa6, 0x4c, 0xf0, 0x3a, 0x1e, 0xf5, 0x1d, + 0xdb, 0xe4, 0x48, 0xc7, 0x36, 0xc0, 0xbb, 0xf4, 0x7f, 0xf2, 0xee, 0x66, 0xfb, 0x7e, 0x26, 0xc6, + 0x08, 0xc3, 0x5e, 0xc0, 0x74, 0x91, 0x3a, 0xbb, 0x18, 0x35, 0xf0, 0x88, 0x86, 0xf5, 0xf1, 0xcc, + 0x41, 0xb6, 0xb7, 0xa1, 0x20, 0xa2, 0x70, 0x5d, 0x9c, 0xdd, 0x1e, 0x0a, 0x91, 0x47, 0xe5, 0x87, + 0x90, 0x41, 0x75, 0x56, 0x21, 0xa1, 0xcb, 0x22, 0xce, 0x56, 0x50, 0x7e, 0xfe, 0xd8, 0xc8, 0x76, + 0x3e, 0xb7, 0x47, 0xdc, 0xf0, 0x7d, 0x16, 0xba, 0xbe, 0x63, 0x76, 0xa1, 0xb1, 0xc6, 0x00, 0x45, + 0x35, 0x82, 0xb8, 0x92, 0x8c, 0x99, 0x84, 0x9b, 0x33, 0xb1, 0x94, 0x2e, 0x32, 0xb7, 0x00, 0xf3, + 0x7d, 0xa4, 0x89, 0x9e, 0x7b, 0x5f, 0x26, 0x60, 0xbc, 0x48, 0x1d, 0xf9, 0x35, 0x5c, 0x11, 0xb7, + 0xe5, 0x96, 0x3e, 0x68, 0x4a, 0xe8, 0x3d, 0xbe, 0xa9, 0x77, 0x87, 0x42, 0x12, 0x06, 0xf9, 0x1d, + 0x64, 0xba, 0xbe, 0xe6, 0xce, 0xad, 0x13, 0x18, 0x75, 0x6d, 0x38, 0x46, 0x34, 0x0f, 0xe0, 0xc6, + 0x3f, 0xb3, 0xe6, 0x7c, 0x6d, 0xfd, 0x50, 0x35, 0x7f, 0x61, 0xa8, 0x60, 0x8c, 0x60, 0x76, 0xd0, + 0x80, 0x58, 0x1f, 0xd2, 0xe9, 0x0c, 0x5a, 0x7d, 0x70, 0x19, 0xb4, 0xa0, 0xb6, 0x61, 0xfa, 0xcc, + 0xc5, 0xb9, 0x33, 0xa4, 0x0b, 0x87, 0xa9, 0x1b, 0x17, 0x82, 0x25, 0x2c, 0xea, 0xe4, 0xc7, 0xd3, + 0xc3, 0x35, 0xa9, 0xb0, 0x7d, 0xd4, 0xd4, 0xa4, 0xe3, 0xa6, 0x26, 0xfd, 0x69, 0x6a, 0xd2, 0xe7, + 0x96, 0x96, 0x3a, 0x6e, 0x69, 0xa9, 0x5f, 0x2d, 0x2d, 0xf5, 0x76, 0xdd, 0x71, 0x59, 0xa5, 0x5e, + 0xd6, 0x2d, 0xe2, 0x19, 0xcf, 0xde, 0xbc, 0x7a, 0xf2, 0x1c, 0xb3, 0x0f, 0x24, 0xac, 0x1a, 0x56, + 0x05, 0xb9, 0xbe, 0x71, 0x20, 0x1e, 0x1f, 0x16, 0x05, 0x98, 0x96, 0xd3, 0xed, 0x87, 0xe1, 0xfe, + 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x79, 0x09, 0x6c, 0x2c, 0x99, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -474,12 +587,14 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type MsgClient interface { - // UpdateCommission ... - UpdateCommission(ctx context.Context, in *MsgUpdateCommission, opts ...grpc.CallOption) (*MsgUpdateCommissionResponse, error) // JoinPool ... JoinPool(ctx context.Context, in *MsgJoinPool, opts ...grpc.CallOption) (*MsgJoinPoolResponse, error) // LeavePool ... LeavePool(ctx context.Context, in *MsgLeavePool, opts ...grpc.CallOption) (*MsgLeavePoolResponse, error) + // UpdateCommission ... + UpdateCommission(ctx context.Context, in *MsgUpdateCommission, opts ...grpc.CallOption) (*MsgUpdateCommissionResponse, error) + // UpdateStakeFraction ... + UpdateStakeFraction(ctx context.Context, in *MsgUpdateStakeFraction, opts ...grpc.CallOption) (*MsgUpdateStakeFractionResponse, error) // UpdateParams defines a governance operation for updating the x/stakers module // parameters. The authority is hard-coded to the x/gov module account. UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) @@ -493,15 +608,6 @@ func NewMsgClient(cc grpc1.ClientConn) MsgClient { return &msgClient{cc} } -func (c *msgClient) UpdateCommission(ctx context.Context, in *MsgUpdateCommission, opts ...grpc.CallOption) (*MsgUpdateCommissionResponse, error) { - out := new(MsgUpdateCommissionResponse) - err := c.cc.Invoke(ctx, "/kyve.stakers.v1beta1.Msg/UpdateCommission", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *msgClient) JoinPool(ctx context.Context, in *MsgJoinPool, opts ...grpc.CallOption) (*MsgJoinPoolResponse, error) { out := new(MsgJoinPoolResponse) err := c.cc.Invoke(ctx, "/kyve.stakers.v1beta1.Msg/JoinPool", in, out, opts...) @@ -520,6 +626,24 @@ func (c *msgClient) LeavePool(ctx context.Context, in *MsgLeavePool, opts ...grp return out, nil } +func (c *msgClient) UpdateCommission(ctx context.Context, in *MsgUpdateCommission, opts ...grpc.CallOption) (*MsgUpdateCommissionResponse, error) { + out := new(MsgUpdateCommissionResponse) + err := c.cc.Invoke(ctx, "/kyve.stakers.v1beta1.Msg/UpdateCommission", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateStakeFraction(ctx context.Context, in *MsgUpdateStakeFraction, opts ...grpc.CallOption) (*MsgUpdateStakeFractionResponse, error) { + out := new(MsgUpdateStakeFractionResponse) + err := c.cc.Invoke(ctx, "/kyve.stakers.v1beta1.Msg/UpdateStakeFraction", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { out := new(MsgUpdateParamsResponse) err := c.cc.Invoke(ctx, "/kyve.stakers.v1beta1.Msg/UpdateParams", in, out, opts...) @@ -531,12 +655,14 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts // MsgServer is the server API for Msg service. type MsgServer interface { - // UpdateCommission ... - UpdateCommission(context.Context, *MsgUpdateCommission) (*MsgUpdateCommissionResponse, error) // JoinPool ... JoinPool(context.Context, *MsgJoinPool) (*MsgJoinPoolResponse, error) // LeavePool ... LeavePool(context.Context, *MsgLeavePool) (*MsgLeavePoolResponse, error) + // UpdateCommission ... + UpdateCommission(context.Context, *MsgUpdateCommission) (*MsgUpdateCommissionResponse, error) + // UpdateStakeFraction ... + UpdateStakeFraction(context.Context, *MsgUpdateStakeFraction) (*MsgUpdateStakeFractionResponse, error) // UpdateParams defines a governance operation for updating the x/stakers module // parameters. The authority is hard-coded to the x/gov module account. UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) @@ -546,15 +672,18 @@ type MsgServer interface { type UnimplementedMsgServer struct { } -func (*UnimplementedMsgServer) UpdateCommission(ctx context.Context, req *MsgUpdateCommission) (*MsgUpdateCommissionResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpdateCommission not implemented") -} func (*UnimplementedMsgServer) JoinPool(ctx context.Context, req *MsgJoinPool) (*MsgJoinPoolResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method JoinPool not implemented") } func (*UnimplementedMsgServer) LeavePool(ctx context.Context, req *MsgLeavePool) (*MsgLeavePoolResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method LeavePool not implemented") } +func (*UnimplementedMsgServer) UpdateCommission(ctx context.Context, req *MsgUpdateCommission) (*MsgUpdateCommissionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateCommission not implemented") +} +func (*UnimplementedMsgServer) UpdateStakeFraction(ctx context.Context, req *MsgUpdateStakeFraction) (*MsgUpdateStakeFractionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateStakeFraction not implemented") +} func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") } @@ -563,56 +692,74 @@ func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) } -func _Msg_UpdateCommission_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgUpdateCommission) +func _Msg_JoinPool_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgJoinPool) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).UpdateCommission(ctx, in) + return srv.(MsgServer).JoinPool(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/kyve.stakers.v1beta1.Msg/UpdateCommission", + FullMethod: "/kyve.stakers.v1beta1.Msg/JoinPool", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).UpdateCommission(ctx, req.(*MsgUpdateCommission)) + return srv.(MsgServer).JoinPool(ctx, req.(*MsgJoinPool)) } return interceptor(ctx, in, info, handler) } -func _Msg_JoinPool_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgJoinPool) +func _Msg_LeavePool_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgLeavePool) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).JoinPool(ctx, in) + return srv.(MsgServer).LeavePool(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/kyve.stakers.v1beta1.Msg/JoinPool", + FullMethod: "/kyve.stakers.v1beta1.Msg/LeavePool", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).JoinPool(ctx, req.(*MsgJoinPool)) + return srv.(MsgServer).LeavePool(ctx, req.(*MsgLeavePool)) } return interceptor(ctx, in, info, handler) } -func _Msg_LeavePool_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgLeavePool) +func _Msg_UpdateCommission_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateCommission) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).LeavePool(ctx, in) + return srv.(MsgServer).UpdateCommission(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/kyve.stakers.v1beta1.Msg/LeavePool", + FullMethod: "/kyve.stakers.v1beta1.Msg/UpdateCommission", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).LeavePool(ctx, req.(*MsgLeavePool)) + return srv.(MsgServer).UpdateCommission(ctx, req.(*MsgUpdateCommission)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateStakeFraction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateStakeFraction) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateStakeFraction(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kyve.stakers.v1beta1.Msg/UpdateStakeFraction", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateStakeFraction(ctx, req.(*MsgUpdateStakeFraction)) } return interceptor(ctx, in, info, handler) } @@ -640,10 +787,6 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "kyve.stakers.v1beta1.Msg", HandlerType: (*MsgServer)(nil), Methods: []grpc.MethodDesc{ - { - MethodName: "UpdateCommission", - Handler: _Msg_UpdateCommission_Handler, - }, { MethodName: "JoinPool", Handler: _Msg_JoinPool_Handler, @@ -652,6 +795,14 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "LeavePool", Handler: _Msg_LeavePool_Handler, }, + { + MethodName: "UpdateCommission", + Handler: _Msg_UpdateCommission_Handler, + }, + { + MethodName: "UpdateStakeFraction", + Handler: _Msg_UpdateStakeFraction_Handler, + }, { MethodName: "UpdateParams", Handler: _Msg_UpdateParams_Handler, @@ -690,7 +841,12 @@ func (m *MsgUpdateCommission) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTx(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x12 + dAtA[i] = 0x1a + if m.PoolId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x10 + } if len(m.Creator) > 0 { i -= len(m.Creator) copy(dAtA[i:], m.Creator) @@ -724,6 +880,74 @@ func (m *MsgUpdateCommissionResponse) MarshalToSizedBuffer(dAtA []byte) (int, er return len(dAtA) - i, nil } +func (m *MsgUpdateStakeFraction) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateStakeFraction) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateStakeFraction) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.StakeFraction.Size() + i -= size + if _, err := m.StakeFraction.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.PoolId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateStakeFractionResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateStakeFractionResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateStakeFractionResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func (m *MsgJoinPool) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -744,6 +968,26 @@ func (m *MsgJoinPool) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.StakeFraction.Size() + i -= size + if _, err := m.StakeFraction.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + { + size := m.Commission.Size() + i -= size + if _, err := m.Commission.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a if m.Amount != 0 { i = encodeVarintTx(dAtA, i, uint64(m.Amount)) i-- @@ -933,6 +1177,9 @@ func (m *MsgUpdateCommission) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + if m.PoolId != 0 { + n += 1 + sovTx(uint64(m.PoolId)) + } l = m.Commission.Size() n += 1 + l + sovTx(uint64(l)) return n @@ -947,7 +1194,34 @@ func (m *MsgUpdateCommissionResponse) Size() (n int) { return n } -func (m *MsgJoinPool) Size() (n int) { +func (m *MsgUpdateStakeFraction) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.PoolId != 0 { + n += 1 + sovTx(uint64(m.PoolId)) + } + l = m.StakeFraction.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateStakeFractionResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgJoinPool) Size() (n int) { if m == nil { return 0 } @@ -967,6 +1241,10 @@ func (m *MsgJoinPool) Size() (n int) { if m.Amount != 0 { n += 1 + sovTx(uint64(m.Amount)) } + l = m.Commission.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.StakeFraction.Size() + n += 1 + l + sovTx(uint64(l)) return n } @@ -1098,6 +1376,25 @@ func (m *MsgUpdateCommission) Unmarshal(dAtA []byte) error { m.Creator = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Commission", wireType) } @@ -1202,6 +1499,191 @@ func (m *MsgUpdateCommissionResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgUpdateStakeFraction) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateStakeFraction: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateStakeFraction: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakeFraction", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StakeFraction.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateStakeFractionResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateStakeFractionResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateStakeFractionResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MsgJoinPool) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -1333,6 +1815,74 @@ func (m *MsgJoinPool) Unmarshal(dAtA []byte) error { break } } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Commission", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Commission.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakeFraction", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StakeFraction.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) From d68da89a8dc090b18e14b404007632b411c12529 Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Fri, 13 Dec 2024 15:29:24 +0100 Subject: [PATCH 02/15] chore: implemented effective stake --- proto/kyve/stakers/v1beta1/events.proto | 10 +- x/bundles/keeper/logic_bundles.go | 28 +++--- x/bundles/types/expected_keepers.go | 1 + x/pool/types/params.go | 5 + x/stakers/keeper/exported_functions.go | 94 +++++++++++++++--- x/stakers/types/events.pb.go | 121 +++++++++++++++++------- x/stakers/types/expected_keepers.go | 2 + 7 files changed, 194 insertions(+), 67 deletions(-) diff --git a/proto/kyve/stakers/v1beta1/events.proto b/proto/kyve/stakers/v1beta1/events.proto index 78a7313a..9abf0df3 100644 --- a/proto/kyve/stakers/v1beta1/events.proto +++ b/proto/kyve/stakers/v1beta1/events.proto @@ -96,8 +96,14 @@ message EventSlash { uint64 pool_id = 1; // staker is the account address of the protocol node. string staker = 2; - // amount ... + // amount is the total amount that got slashed uint64 amount = 3; - // slash_type + // slash_type is the type of the protocol slash SlashType slash_type = 4; + // stake_fraction is the percentage of how much of the validators total + // bonded amount was under risk for slashing + string stake_fraction = 5 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; } diff --git a/x/bundles/keeper/logic_bundles.go b/x/bundles/keeper/logic_bundles.go index 1a6c68ea..2968e783 100644 --- a/x/bundles/keeper/logic_bundles.go +++ b/x/bundles/keeper/logic_bundles.go @@ -3,12 +3,11 @@ package keeper import ( "cosmossdk.io/errors" "cosmossdk.io/math" + "github.com/KYVENetwork/chain/util" + "github.com/KYVENetwork/chain/x/bundles/types" globalTypes "github.com/KYVENetwork/chain/x/global/types" poolTypes "github.com/KYVENetwork/chain/x/pool/types" stakersTypes "github.com/KYVENetwork/chain/x/stakers/types" - - "github.com/KYVENetwork/chain/util" - "github.com/KYVENetwork/chain/x/bundles/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -38,18 +37,19 @@ func (k Keeper) AssertPoolCanRun(ctx sdk.Context, poolId uint64) error { } // Get the total and the highest delegation of a single validator in the pool - totalDelegation, highestDelegation := k.stakerKeeper.GetTotalAndHighestDelegationOfPool(ctx, poolId) + totalDelegation, _ := k.stakerKeeper.GetTotalAndHighestDelegationOfPool(ctx, poolId) // Error if min delegation is not reached if totalDelegation < pool.MinDelegation { return types.ErrMinDelegationNotReached } + stakers := int64(len(k.stakerKeeper.GetAllStakerAddressesOfPool(ctx, poolId))) maxVotingPower := k.poolKeeper.GetMaxVotingPowerPerPool(ctx) - maxDelegation := uint64(maxVotingPower.MulInt64(int64(totalDelegation)).TruncateInt64()) - // Error if highest delegation exceeds max voting power - if highestDelegation > maxDelegation { + // Error if max voting power is not achievable because there are not enough stakers + // in the pool + if math.LegacyOneDec().Quo(maxVotingPower).GT(math.LegacyNewDec(stakers)) { return types.ErrVotingPowerTooHigh } @@ -511,28 +511,26 @@ func (k Keeper) GetVoteDistribution(ctx sdk.Context, poolId uint64) (voteDistrib return } + effectiveStakes := k.stakerKeeper.GetEffectiveValidatorStakes(ctx, poolId) + // get voting power for valid for _, voter := range bundleProposal.VotersValid { - delegation := k.stakerKeeper.GetValidatorPoolStake(ctx, voter, poolId) - voteDistribution.Valid += k.calculateVotingPower(delegation) + voteDistribution.Valid += effectiveStakes[voter] } // get voting power for invalid for _, voter := range bundleProposal.VotersInvalid { - delegation := k.stakerKeeper.GetValidatorPoolStake(ctx, voter, poolId) - voteDistribution.Invalid += k.calculateVotingPower(delegation) + voteDistribution.Invalid += effectiveStakes[voter] } // get voting power for abstain for _, voter := range bundleProposal.VotersAbstain { - delegation := k.stakerKeeper.GetValidatorPoolStake(ctx, voter, poolId) - voteDistribution.Abstain += k.calculateVotingPower(delegation) + voteDistribution.Abstain += effectiveStakes[voter] } // get total voting power for _, staker := range k.stakerKeeper.GetAllStakerAddressesOfPool(ctx, poolId) { - delegation := k.stakerKeeper.GetValidatorPoolStake(ctx, staker, poolId) - voteDistribution.Total += k.calculateVotingPower(delegation) + voteDistribution.Total += effectiveStakes[staker] } if voteDistribution.Total == 0 { diff --git a/x/bundles/types/expected_keepers.go b/x/bundles/types/expected_keepers.go index 3d9c0ddd..5ba661b8 100644 --- a/x/bundles/types/expected_keepers.go +++ b/x/bundles/types/expected_keepers.go @@ -46,6 +46,7 @@ type StakerKeeper interface { Slash(ctx sdk.Context, poolId uint64, staker string, slashType stakersTypes.SlashType) PayoutRewards(ctx sdk.Context, staker string, amount sdk.Coins, payerModuleName string) error PayoutAdditionalCommissionRewards(ctx sdk.Context, validator string, payerModuleName string, amount sdk.Coins) error + GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64) (effectiveStake map[string]uint64) } type FundersKeeper interface { diff --git a/x/pool/types/params.go b/x/pool/types/params.go index 2585ca6e..aa4f257e 100644 --- a/x/pool/types/params.go +++ b/x/pool/types/params.go @@ -2,6 +2,7 @@ package types import ( "cosmossdk.io/math" + "errors" "github.com/KYVENetwork/chain/util" ) @@ -50,5 +51,9 @@ func (p Params) Validate() error { return err } + if p.MaxVotingPowerPerPool.IsZero() { + return errors.New("max voting power per pool cannot be zero") + } + return nil } diff --git a/x/stakers/keeper/exported_functions.go b/x/stakers/keeper/exported_functions.go index 153c50ed..afb451c9 100644 --- a/x/stakers/keeper/exported_functions.go +++ b/x/stakers/keeper/exported_functions.go @@ -2,7 +2,6 @@ package keeper import ( "context" - "cosmossdk.io/errors" "cosmossdk.io/math" "github.com/KYVENetwork/chain/util" @@ -11,8 +10,10 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "sort" + // Stakers - "github.com/KYVENetwork/chain/x/stakers/types" + stakertypes "github.com/KYVENetwork/chain/x/stakers/types" ) // These functions are meant to be called from external modules. @@ -25,7 +26,7 @@ import ( func (k Keeper) LeavePool(ctx sdk.Context, staker string, poolId uint64) { k.RemoveValaccountFromPool(ctx, poolId, staker) - _ = ctx.EventManager().EmitTypedEvent(&types.EventLeavePool{ + _ = ctx.EventManager().EmitTypedEvent(&stakertypes.EventLeavePool{ PoolId: poolId, Staker: staker, }) @@ -63,11 +64,11 @@ func (k Keeper) GetPaginatedStakersByDelegation(ctx sdk.Context, pagination *que func (k Keeper) AssertValaccountAuthorized(ctx sdk.Context, poolId uint64, stakerAddress string, valaddress string) error { valaccount, active := k.GetValaccount(ctx, poolId, stakerAddress) if !active { - return types.ErrValaccountUnauthorized + return stakertypes.ErrValaccountUnauthorized } if valaccount.Valaddress != valaddress { - return types.ErrValaccountUnauthorized + return stakertypes.ErrValaccountUnauthorized } return nil @@ -193,8 +194,68 @@ func (k Keeper) GetOutstandingRewards(orgCtx sdk.Context, staker string, delegat return util.TruncateDecCoins(rewards) } +// GetEffectiveValidatorStakes returns a map for all pool stakers their effective stake. Effective stake +// is the actual stake at risk for a validator, it can be lower than the provided stake because +// of the max voting power per pool parameter, but it can never be higher. Thus, if the effective +// stake is lower than the provided one the slash +// TODO: explain or link to formula +func (k Keeper) GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64) (effectiveStakes map[string]uint64) { + type ValidatorStake struct { + Address string + Stake uint64 + } + + alpha := k.poolKeeper.GetMaxVotingPowerPerPool(ctx) + validators := make([]ValidatorStake, 0) + + for _, address := range k.GetAllStakerAddressesOfPool(ctx, poolId) { + stake := k.GetValidatorPoolStake(ctx, address, poolId) + effectiveStakes[address] = stake + validators = append(validators, ValidatorStake{ + Address: address, + Stake: stake, + }) + } + + // sort ascending based on stake + sort.Slice(validators, func(i, j int) bool { + return validators[i].Stake < validators[j].Stake + }) + + // return if max voting power can not be undercut because there are not enough stakers + // in the pool + if math.LegacyOneDec().Quo(alpha).GT(math.LegacyNewDec(int64(len(validators)))) { + return + } + + x := func(i int) uint64 { + totalStake := int64(0) + + for _, validator := range validators[i+1:] { + totalStake += int64(validator.Stake) + } + + return uint64(alpha.MulInt64(totalStake).Quo(math.LegacyOneDec().Sub(alpha.Mul(math.LegacyNewDec(int64(i)).Add(math.LegacyOneDec())))).TruncateInt64()) + } + + for i := range validators { + M := x(i) + + if validators[i].Stake >= M && M >= validators[i+1].Stake { + for _, v := range validators { + if v.Stake > M { + effectiveStakes[v.Address] = M + } + } + return + } + } + + return +} + // Slash reduces the delegation of all delegators of `staker` by fraction. The slash itself is handled by the cosmos-sdk -func (k Keeper) Slash(ctx sdk.Context, poolId uint64, staker string, slashType types.SlashType) { +func (k Keeper) Slash(ctx sdk.Context, poolId uint64, staker string, slashType stakertypes.SlashType) { validator, found := k.GetValidator(ctx, staker) if !found { return @@ -202,9 +263,13 @@ func (k Keeper) Slash(ctx sdk.Context, poolId uint64, staker string, slashType t consAddrBytes, _ := validator.GetConsAddr() - // the validator can only be slashed for his stake fraction in a pool, therefore we update the slash fraction - // accordingly - slashFraction := k.getSlashFraction(ctx, slashType).Mul(k.GetValidatorPoolStakeFraction(ctx, staker, poolId)) + // get real stake fraction from the effective stake which is truly at risk for getting slashed + // by dividing it with the total bonded stake from the validator + stakeFraction := math.LegacyNewDec(int64(k.GetEffectiveValidatorStakes(ctx, poolId)[staker])).QuoInt(validator.GetBondedTokens()) + + // the validator can only be slashed for his effective stake fraction in a pool, therefore we + // update the slash fraction accordingly + slashFraction := k.getSlashFraction(ctx, slashType).Mul(stakeFraction) amount, err := k.stakingKeeper.Slash( ctx, @@ -217,11 +282,12 @@ func (k Keeper) Slash(ctx sdk.Context, poolId uint64, staker string, slashType t return } - _ = ctx.EventManager().EmitTypedEvent(&types.EventSlash{ - PoolId: poolId, - Staker: staker, - Amount: amount.Uint64(), - SlashType: slashType, + _ = ctx.EventManager().EmitTypedEvent(&stakertypes.EventSlash{ + PoolId: poolId, + Staker: staker, + Amount: amount.Uint64(), + SlashType: slashType, + StakeFraction: stakeFraction, }) } diff --git a/x/stakers/types/events.pb.go b/x/stakers/types/events.pb.go index 445aa39b..393ad404 100644 --- a/x/stakers/types/events.pb.go +++ b/x/stakers/types/events.pb.go @@ -403,10 +403,13 @@ type EventSlash struct { PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` // staker is the account address of the protocol node. Staker string `protobuf:"bytes,2,opt,name=staker,proto3" json:"staker,omitempty"` - // amount ... + // amount is the total amount that got slashed Amount uint64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"` - // slash_type + // slash_type is the type of the protocol slash SlashType SlashType `protobuf:"varint,4,opt,name=slash_type,json=slashType,proto3,enum=kyve.stakers.v1beta1.SlashType" json:"slash_type,omitempty"` + // stake_fraction is the percentage of how much of the validators total + // bonded amount was under risk for slashing + StakeFraction cosmossdk_io_math.LegacyDec `protobuf:"bytes,5,opt,name=stake_fraction,json=stakeFraction,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"stake_fraction"` } func (m *EventSlash) Reset() { *m = EventSlash{} } @@ -483,41 +486,41 @@ func init() { func init() { proto.RegisterFile("kyve/stakers/v1beta1/events.proto", fileDescriptor_7a1b3dc9634155a0) } var fileDescriptor_7a1b3dc9634155a0 = []byte{ - // 532 bytes of a gzipped FileDescriptorProto + // 537 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xc1, 0x6e, 0xd3, 0x40, - 0x10, 0x86, 0xb3, 0x69, 0x48, 0x94, 0x41, 0x8d, 0x44, 0x54, 0xc0, 0x4a, 0x91, 0x53, 0xcc, 0xa5, - 0x07, 0x64, 0xab, 0xe5, 0x8e, 0xd4, 0x84, 0x56, 0xa2, 0x54, 0x50, 0xb9, 0x80, 0x04, 0x97, 0x68, - 0xe3, 0x5d, 0x12, 0x2b, 0xb6, 0xc7, 0xf2, 0x6e, 0x13, 0xfc, 0x08, 0x1c, 0x90, 0xb8, 0x20, 0x1e, - 0x84, 0x97, 0xe8, 0xb1, 0x47, 0xc4, 0xa1, 0x42, 0xc9, 0x8b, 0x20, 0xaf, 0xed, 0xc6, 0x41, 0x46, - 0x6a, 0x73, 0xdb, 0xb1, 0xfe, 0xf9, 0xe6, 0xdf, 0x7f, 0xe4, 0x85, 0xc7, 0x93, 0x78, 0xca, 0x2d, - 0x21, 0xe9, 0x84, 0x47, 0xc2, 0x9a, 0xee, 0x0d, 0xb9, 0xa4, 0x7b, 0x16, 0x9f, 0xf2, 0x40, 0x0a, - 0x33, 0x8c, 0x50, 0x62, 0x7b, 0x2b, 0x91, 0x98, 0x99, 0xc4, 0xcc, 0x24, 0x9d, 0xad, 0x11, 0x8e, - 0x50, 0x09, 0xac, 0xe4, 0x94, 0x6a, 0x3b, 0xe5, 0xb8, 0x90, 0x46, 0xd4, 0xcf, 0x70, 0x1d, 0xa3, - 0x54, 0x92, 0xe3, 0x95, 0xc6, 0xf8, 0x49, 0xe0, 0xde, 0x61, 0xe2, 0xe1, 0x5d, 0xc8, 0xa8, 0xe4, - 0xa7, 0xaa, 0xbf, 0x7d, 0x00, 0x80, 0x1e, 0x1b, 0xa4, 0x34, 0x8d, 0xec, 0x90, 0xdd, 0xbb, 0xfb, - 0x8f, 0xcc, 0x32, 0x77, 0x66, 0xda, 0xd1, 0xab, 0x5d, 0x5c, 0x75, 0x2b, 0x76, 0x13, 0x3d, 0xb6, - 0x44, 0x04, 0x7c, 0x96, 0x23, 0xaa, 0x37, 0x47, 0x04, 0x7c, 0x96, 0x21, 0x34, 0x68, 0x84, 0x34, - 0xf6, 0x90, 0x32, 0x6d, 0x63, 0x87, 0xec, 0x36, 0xed, 0xbc, 0x34, 0xbe, 0x12, 0xb8, 0x5f, 0x70, - 0xdd, 0x47, 0xdf, 0x77, 0x85, 0x70, 0x31, 0x68, 0x3f, 0x80, 0x7a, 0x8a, 0x57, 0xae, 0x9b, 0x76, - 0x56, 0xb5, 0x1f, 0x42, 0x23, 0x44, 0xf4, 0x06, 0x2e, 0x53, 0x5e, 0x6a, 0x76, 0x3d, 0x29, 0x5f, - 0xb2, 0x76, 0x1f, 0xc0, 0xb9, 0x6e, 0x4f, 0xe7, 0xf4, 0x9e, 0x24, 0x4e, 0x7e, 0x5f, 0x75, 0xb7, - 0x1d, 0x14, 0x3e, 0x0a, 0xc1, 0x26, 0xa6, 0x8b, 0x96, 0x4f, 0xe5, 0xd8, 0x3c, 0xe1, 0x23, 0xea, - 0xc4, 0x2f, 0xb8, 0x63, 0x17, 0xda, 0x8c, 0x1f, 0x04, 0xb4, 0x82, 0x9f, 0xb3, 0x64, 0xe6, 0x51, - 0x44, 0x1d, 0xb9, 0x96, 0xa5, 0x63, 0x68, 0x29, 0xc9, 0xe0, 0x53, 0x86, 0xb8, 0x8d, 0xad, 0x4d, - 0x51, 0x1c, 0x6e, 0xbc, 0x81, 0x6d, 0x65, 0xac, 0xef, 0x51, 0xd7, 0x5f, 0xe6, 0x64, 0xf3, 0x19, - 0x8d, 0x98, 0xf8, 0xaf, 0x37, 0x0d, 0x1a, 0xd4, 0xc7, 0xf3, 0x40, 0xa6, 0xab, 0x6b, 0xda, 0x79, - 0x69, 0x7c, 0xa9, 0xc2, 0xa6, 0x22, 0x1e, 0xa3, 0x1b, 0x9c, 0x22, 0x7a, 0xc5, 0x7b, 0x90, 0x95, - 0x7b, 0x2c, 0xe1, 0xd5, 0x15, 0xb8, 0x0e, 0x30, 0xa5, 0x1e, 0x65, 0x2c, 0xe2, 0x42, 0x64, 0xab, - 0x2d, 0x7c, 0x49, 0xfa, 0xd2, 0x69, 0x5a, 0x2d, 0xe5, 0xa5, 0xd5, 0x3f, 0xab, 0xba, 0xb3, 0xd6, - 0xaa, 0x4a, 0xc2, 0xad, 0xaf, 0x1d, 0xee, 0x01, 0xb4, 0x54, 0x14, 0x27, 0x9c, 0x4e, 0xf9, 0x5a, - 0x59, 0x18, 0xdf, 0x09, 0x80, 0x62, 0x9c, 0x79, 0x54, 0x8c, 0x6f, 0x9f, 0xe5, 0x32, 0xab, 0x8d, - 0x95, 0xac, 0x9e, 0x03, 0x88, 0x84, 0x38, 0x90, 0x71, 0xc8, 0x55, 0x8e, 0xad, 0xfd, 0x6e, 0xf9, - 0xef, 0xa7, 0x26, 0xbf, 0x8d, 0x43, 0x6e, 0x37, 0x45, 0x7e, 0xec, 0x1d, 0x5d, 0xcc, 0x75, 0x72, - 0x39, 0xd7, 0xc9, 0x9f, 0xb9, 0x4e, 0xbe, 0x2d, 0xf4, 0xca, 0xe5, 0x42, 0xaf, 0xfc, 0x5a, 0xe8, - 0x95, 0x8f, 0x4f, 0x47, 0xae, 0x1c, 0x9f, 0x0f, 0x4d, 0x07, 0x7d, 0xeb, 0xd5, 0x87, 0xf7, 0x87, - 0xaf, 0xb9, 0x9c, 0x61, 0x34, 0xb1, 0x9c, 0x31, 0x75, 0x03, 0xeb, 0xf3, 0xf5, 0x7b, 0x93, 0x0c, - 0x16, 0xc3, 0xba, 0x7a, 0x66, 0x9e, 0xfd, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x42, 0x2b, 0x27, 0xf7, - 0xfe, 0x04, 0x00, 0x00, + 0x10, 0x86, 0xb3, 0x69, 0x9a, 0x28, 0x83, 0x1a, 0x89, 0xa8, 0x80, 0x95, 0x22, 0xa7, 0x98, 0x4b, + 0x0f, 0xc8, 0x56, 0xcb, 0x1d, 0xa9, 0x09, 0xad, 0x44, 0xa9, 0xa0, 0x72, 0x01, 0x09, 0x2e, 0xd1, + 0xc6, 0xbb, 0x24, 0x56, 0x6c, 0x8f, 0xe5, 0xdd, 0x26, 0xe4, 0x11, 0x38, 0x20, 0x71, 0xe3, 0x41, + 0x78, 0x89, 0x1e, 0x7b, 0x44, 0x1c, 0x2a, 0x48, 0x5e, 0x04, 0x79, 0x6d, 0x37, 0x0e, 0x32, 0x12, + 0xf5, 0x6d, 0xc7, 0xfa, 0xe7, 0x9b, 0x7f, 0xff, 0x91, 0x17, 0x1e, 0x4d, 0xe6, 0x53, 0x6e, 0x09, + 0x49, 0x27, 0x3c, 0x12, 0xd6, 0x74, 0x7f, 0xc8, 0x25, 0xdd, 0xb7, 0xf8, 0x94, 0x07, 0x52, 0x98, + 0x61, 0x84, 0x12, 0xdb, 0xdb, 0xb1, 0xc4, 0x4c, 0x25, 0x66, 0x2a, 0xe9, 0x6c, 0x8f, 0x70, 0x84, + 0x4a, 0x60, 0xc5, 0xa7, 0x44, 0xdb, 0x29, 0xc6, 0x85, 0x34, 0xa2, 0x7e, 0x8a, 0xeb, 0x18, 0x85, + 0x92, 0x0c, 0xaf, 0x34, 0xc6, 0x77, 0x02, 0x77, 0x8f, 0x62, 0x0f, 0x6f, 0x43, 0x46, 0x25, 0x3f, + 0x53, 0xfd, 0xed, 0x43, 0x00, 0xf4, 0xd8, 0x20, 0xa1, 0x69, 0x64, 0x97, 0xec, 0xdd, 0x39, 0x78, + 0x68, 0x16, 0xb9, 0x33, 0x93, 0x8e, 0x5e, 0xed, 0xf2, 0xba, 0x5b, 0xb1, 0x9b, 0xe8, 0xb1, 0x15, + 0x22, 0xe0, 0xb3, 0x0c, 0x51, 0xfd, 0x7f, 0x44, 0xc0, 0x67, 0x29, 0x42, 0x83, 0x46, 0x48, 0xe7, + 0x1e, 0x52, 0xa6, 0x6d, 0xec, 0x92, 0xbd, 0xa6, 0x9d, 0x95, 0xc6, 0x17, 0x02, 0xf7, 0x72, 0xae, + 0xfb, 0xe8, 0xfb, 0xae, 0x10, 0x2e, 0x06, 0xed, 0xfb, 0x50, 0x4f, 0xf0, 0xca, 0x75, 0xd3, 0x4e, + 0xab, 0xf6, 0x03, 0x68, 0x84, 0x88, 0xde, 0xc0, 0x65, 0xca, 0x4b, 0xcd, 0xae, 0xc7, 0xe5, 0x0b, + 0xd6, 0xee, 0x03, 0x38, 0x37, 0xed, 0xc9, 0x9c, 0xde, 0xe3, 0xd8, 0xc9, 0xcf, 0xeb, 0xee, 0x8e, + 0x83, 0xc2, 0x47, 0x21, 0xd8, 0xc4, 0x74, 0xd1, 0xf2, 0xa9, 0x1c, 0x9b, 0xa7, 0x7c, 0x44, 0x9d, + 0xf9, 0x73, 0xee, 0xd8, 0xb9, 0x36, 0xe3, 0x1b, 0x01, 0x2d, 0xe7, 0xe7, 0x3c, 0x9e, 0x79, 0x1c, + 0x51, 0x47, 0x96, 0xb2, 0x74, 0x02, 0x2d, 0x25, 0x19, 0x7c, 0x4c, 0x11, 0xb7, 0xb1, 0xb5, 0x25, + 0xf2, 0xc3, 0x8d, 0xd7, 0xb0, 0xa3, 0x8c, 0xf5, 0x3d, 0xea, 0xfa, 0xab, 0x9c, 0x6c, 0x3e, 0xa3, + 0x11, 0x13, 0xff, 0xf4, 0xa6, 0x41, 0x83, 0xfa, 0x78, 0x11, 0xc8, 0x64, 0x75, 0x4d, 0x3b, 0x2b, + 0x8d, 0xcf, 0x55, 0xd8, 0x52, 0xc4, 0x13, 0x74, 0x83, 0x33, 0x44, 0x2f, 0x7f, 0x0f, 0xb2, 0x76, + 0x8f, 0x15, 0xbc, 0xba, 0x06, 0xd7, 0x01, 0xa6, 0xd4, 0xa3, 0x8c, 0x45, 0x5c, 0x88, 0x74, 0xb5, + 0xb9, 0x2f, 0x71, 0x5f, 0x32, 0x4d, 0xab, 0x25, 0xbc, 0xa4, 0xfa, 0x6b, 0x55, 0x9b, 0xa5, 0x56, + 0x55, 0x10, 0x6e, 0xbd, 0x74, 0xb8, 0x87, 0xd0, 0x52, 0x51, 0x9c, 0x72, 0x3a, 0xe5, 0xa5, 0xb2, + 0x30, 0x7e, 0x13, 0x00, 0xc5, 0x38, 0xf7, 0xa8, 0x18, 0xdf, 0x3e, 0xcb, 0x55, 0x56, 0x1b, 0x6b, + 0x59, 0x3d, 0x03, 0x10, 0x31, 0x71, 0x20, 0xe7, 0x21, 0x57, 0x39, 0xb6, 0x0e, 0xba, 0xc5, 0xbf, + 0x9f, 0x9a, 0xfc, 0x66, 0x1e, 0x72, 0xbb, 0x29, 0xb2, 0x63, 0x41, 0x4c, 0x9b, 0x65, 0x63, 0xea, + 0x1d, 0x5f, 0x2e, 0x74, 0x72, 0xb5, 0xd0, 0xc9, 0xaf, 0x85, 0x4e, 0xbe, 0x2e, 0xf5, 0xca, 0xd5, + 0x52, 0xaf, 0xfc, 0x58, 0xea, 0x95, 0x0f, 0x4f, 0x46, 0xae, 0x1c, 0x5f, 0x0c, 0x4d, 0x07, 0x7d, + 0xeb, 0xe5, 0xfb, 0x77, 0x47, 0xaf, 0xb8, 0x9c, 0x61, 0x34, 0xb1, 0x9c, 0x31, 0x75, 0x03, 0xeb, + 0xd3, 0xcd, 0xdb, 0x15, 0x5f, 0x42, 0x0c, 0xeb, 0xea, 0xc9, 0x7a, 0xfa, 0x27, 0x00, 0x00, 0xff, + 0xff, 0x4e, 0xa8, 0x49, 0x66, 0x4a, 0x05, 0x00, 0x00, } func (m *EventUpdateParams) Marshal() (dAtA []byte, err error) { @@ -819,6 +822,16 @@ func (m *EventSlash) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.StakeFraction.Size() + i -= size + if _, err := m.StakeFraction.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a if m.SlashType != 0 { i = encodeVarintEvents(dAtA, i, uint64(m.SlashType)) i-- @@ -987,6 +1000,8 @@ func (m *EventSlash) Size() (n int) { if m.SlashType != 0 { n += 1 + sovEvents(uint64(m.SlashType)) } + l = m.StakeFraction.Size() + n += 1 + l + sovEvents(uint64(l)) return n } @@ -1967,6 +1982,40 @@ func (m *EventSlash) Unmarshal(dAtA []byte) error { break } } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakeFraction", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StakeFraction.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipEvents(dAtA[iNdEx:]) diff --git a/x/stakers/types/expected_keepers.go b/x/stakers/types/expected_keepers.go index b489cdd2..ab86eabb 100644 --- a/x/stakers/types/expected_keepers.go +++ b/x/stakers/types/expected_keepers.go @@ -1,11 +1,13 @@ package types import ( + "cosmossdk.io/math" poolTypes "github.com/KYVENetwork/chain/x/pool/types" sdk "github.com/cosmos/cosmos-sdk/types" ) type PoolKeeper interface { + GetMaxVotingPowerPerPool(ctx sdk.Context) (res math.LegacyDec) AssertPoolExists(ctx sdk.Context, poolId uint64) error GetPoolWithError(ctx sdk.Context, poolId uint64) (poolTypes.Pool, error) } From 61e11149ff9e2a6683559b9bf6b060682c45114b Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Fri, 13 Dec 2024 15:33:48 +0100 Subject: [PATCH 03/15] chore: allow zero for max pool stake --- x/bundles/keeper/logic_bundles.go | 4 ++++ x/pool/types/params.go | 5 ----- x/stakers/keeper/exported_functions.go | 4 ++++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/x/bundles/keeper/logic_bundles.go b/x/bundles/keeper/logic_bundles.go index 2968e783..ae700c4e 100644 --- a/x/bundles/keeper/logic_bundles.go +++ b/x/bundles/keeper/logic_bundles.go @@ -47,6 +47,10 @@ func (k Keeper) AssertPoolCanRun(ctx sdk.Context, poolId uint64) error { stakers := int64(len(k.stakerKeeper.GetAllStakerAddressesOfPool(ctx, poolId))) maxVotingPower := k.poolKeeper.GetMaxVotingPowerPerPool(ctx) + if maxVotingPower.IsZero() { + return nil + } + // Error if max voting power is not achievable because there are not enough stakers // in the pool if math.LegacyOneDec().Quo(maxVotingPower).GT(math.LegacyNewDec(stakers)) { diff --git a/x/pool/types/params.go b/x/pool/types/params.go index aa4f257e..2585ca6e 100644 --- a/x/pool/types/params.go +++ b/x/pool/types/params.go @@ -2,7 +2,6 @@ package types import ( "cosmossdk.io/math" - "errors" "github.com/KYVENetwork/chain/util" ) @@ -51,9 +50,5 @@ func (p Params) Validate() error { return err } - if p.MaxVotingPowerPerPool.IsZero() { - return errors.New("max voting power per pool cannot be zero") - } - return nil } diff --git a/x/stakers/keeper/exported_functions.go b/x/stakers/keeper/exported_functions.go index afb451c9..ba769d9c 100644 --- a/x/stakers/keeper/exported_functions.go +++ b/x/stakers/keeper/exported_functions.go @@ -222,6 +222,10 @@ func (k Keeper) GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64) (eff return validators[i].Stake < validators[j].Stake }) + if alpha.IsZero() { + return + } + // return if max voting power can not be undercut because there are not enough stakers // in the pool if math.LegacyOneDec().Quo(alpha).GT(math.LegacyNewDec(int64(len(validators)))) { From ea3b51cc1da051b99f2dad15a9ee99f38dc24fbb Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Fri, 13 Dec 2024 17:31:48 +0100 Subject: [PATCH 04/15] chore: added required stakers --- util/arrays.go | 12 ++++ x/bundles/keeper/logic_bundles.go | 8 --- x/bundles/keeper/logic_bundles_test.go | 4 +- ...ic_end_block_handle_upload_timeout_test.go | 6 +- x/bundles/types/expected_keepers.go | 2 +- x/stakers/keeper/exported_functions.go | 60 ++++++++++--------- 6 files changed, 49 insertions(+), 43 deletions(-) diff --git a/util/arrays.go b/util/arrays.go index 8cf4815b..fd948cdc 100644 --- a/util/arrays.go +++ b/util/arrays.go @@ -38,3 +38,15 @@ func ContainsString(array []string, match string) bool { } return false } + +func RemoveDuplicateStrings(strSlice []string) []string { + allKeys := make(map[string]bool) + list := []string{} + for _, item := range strSlice { + if _, value := allKeys[item]; !value { + allKeys[item] = true + list = append(list, item) + } + } + return list +} diff --git a/x/bundles/keeper/logic_bundles.go b/x/bundles/keeper/logic_bundles.go index ae700c4e..93cb5aec 100644 --- a/x/bundles/keeper/logic_bundles.go +++ b/x/bundles/keeper/logic_bundles.go @@ -468,14 +468,6 @@ func (k Keeper) dropCurrentBundleProposal(ctx sdk.Context, poolId uint64, voteDi k.SetBundleProposal(ctx, bundleProposal) } -// calculateVotingPower calculates the voting power one staker has in a -// storage pool based only on the total delegation this staker has -func (k Keeper) calculateVotingPower(delegation uint64) (votingPower uint64) { - // voting power is linear - votingPower = delegation - return -} - // chooseNextUploader selects the next uploader based on a fixed set of stakers in a pool. // It is guaranteed that someone is chosen deterministically if the round-robin set itself is not empty. func (k Keeper) chooseNextUploader(ctx sdk.Context, poolId uint64, excluded ...string) (nextUploader string) { diff --git a/x/bundles/keeper/logic_bundles_test.go b/x/bundles/keeper/logic_bundles_test.go index 08d19811..9d3a0885 100644 --- a/x/bundles/keeper/logic_bundles_test.go +++ b/x/bundles/keeper/logic_bundles_test.go @@ -242,7 +242,7 @@ var _ = Describe("logic_bundles.go", Ordered, func() { err := s.App().BundlesKeeper.AssertPoolCanRun(s.Ctx(), 0) // ASSERT - Expect(err).To(Equal(bundlesTypes.ErrVotingPowerTooHigh)) + Expect(err).To(BeNil()) }) It("Assert pool can run while voting power of one node is 40%", func() { @@ -366,7 +366,7 @@ var _ = Describe("logic_bundles.go", Ordered, func() { err := s.App().BundlesKeeper.AssertPoolCanRun(s.Ctx(), 0) // ASSERT - Expect(err).To(Equal(bundlesTypes.ErrVotingPowerTooHigh)) + Expect(err).To(BeNil()) }) It("Assert pool can run with a single staker while voting power is 100%", func() { diff --git a/x/bundles/keeper/logic_end_block_handle_upload_timeout_test.go b/x/bundles/keeper/logic_end_block_handle_upload_timeout_test.go index ce19c849..8776dda3 100644 --- a/x/bundles/keeper/logic_end_block_handle_upload_timeout_test.go +++ b/x/bundles/keeper/logic_end_block_handle_upload_timeout_test.go @@ -24,7 +24,7 @@ TEST CASES - logic_end_block_handle_upload_timeout.go * Next uploader gets removed due to pool upgrading * Next uploader gets removed due to pool being disabled * Next uploader gets removed due to pool not reaching min delegation -* Next uploader gets removed due to pool having one node with more than 50% voting power +* Next uploader gets not removed although pool having one node with more than 50% voting power * Staker is next uploader of genesis bundle and upload interval and timeout does not pass * Staker is next uploader of genesis bundle and upload timeout does not pass but upload interval passes * Staker is next uploader of genesis bundle and upload timeout does pass together with upload interval @@ -281,7 +281,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(20 * i.KYVE)) }) - It("Next uploader gets removed due to pool having one node with more than 50% voting power", func() { + It("Next uploader gets not removed although pool having one node with more than 50% voting power", func() { // ARRANGE s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ Creator: i.VALADDRESS_0_A, @@ -300,7 +300,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { // ASSERT bundleProposal, _ := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) - Expect(bundleProposal.NextUploader).To(BeEmpty()) + Expect(bundleProposal.NextUploader).To(Equal("kyve1htgfatqevuvfzvl0sxp97ywteqhg5leha9emf4")) Expect(bundleProposal.StorageId).To(BeEmpty()) poolStakers := s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0) diff --git a/x/bundles/types/expected_keepers.go b/x/bundles/types/expected_keepers.go index 5ba661b8..0b41d0ef 100644 --- a/x/bundles/types/expected_keepers.go +++ b/x/bundles/types/expected_keepers.go @@ -46,7 +46,7 @@ type StakerKeeper interface { Slash(ctx sdk.Context, poolId uint64, staker string, slashType stakersTypes.SlashType) PayoutRewards(ctx sdk.Context, staker string, amount sdk.Coins, payerModuleName string) error PayoutAdditionalCommissionRewards(ctx sdk.Context, validator string, payerModuleName string, amount sdk.Coins) error - GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64) (effectiveStake map[string]uint64) + GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64, mustIncludeStakers ...string) (effectiveStake map[string]uint64) } type FundersKeeper interface { diff --git a/x/stakers/keeper/exported_functions.go b/x/stakers/keeper/exported_functions.go index ba769d9c..0e8795e7 100644 --- a/x/stakers/keeper/exported_functions.go +++ b/x/stakers/keeper/exported_functions.go @@ -2,6 +2,8 @@ package keeper import ( "context" + "sort" + "cosmossdk.io/errors" "cosmossdk.io/math" "github.com/KYVENetwork/chain/util" @@ -10,7 +12,6 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "sort" // Stakers stakertypes "github.com/KYVENetwork/chain/x/stakers/types" @@ -199,60 +200,61 @@ func (k Keeper) GetOutstandingRewards(orgCtx sdk.Context, staker string, delegat // of the max voting power per pool parameter, but it can never be higher. Thus, if the effective // stake is lower than the provided one the slash // TODO: explain or link to formula -func (k Keeper) GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64) (effectiveStakes map[string]uint64) { +func (k Keeper) GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64, mustIncludeStakers ...string) (effectiveStakes map[string]uint64) { type ValidatorStake struct { Address string Stake uint64 } - alpha := k.poolKeeper.GetMaxVotingPowerPerPool(ctx) + addresses := util.RemoveDuplicateStrings(append(k.GetAllStakerAddressesOfPool(ctx, poolId), mustIncludeStakers...)) + maxVotingPower := k.poolKeeper.GetMaxVotingPowerPerPool(ctx) + effectiveStakes = make(map[string]uint64) validators := make([]ValidatorStake, 0) + totalStake := int64(0) - for _, address := range k.GetAllStakerAddressesOfPool(ctx, poolId) { + for _, address := range addresses { stake := k.GetValidatorPoolStake(ctx, address, poolId) effectiveStakes[address] = stake validators = append(validators, ValidatorStake{ Address: address, Stake: stake, }) + totalStake += int64(stake) } - // sort ascending based on stake + totalStakeRemainder := totalStake + + // sort descending based on stake sort.Slice(validators, func(i, j int) bool { - return validators[i].Stake < validators[j].Stake + return validators[i].Stake > validators[j].Stake }) - if alpha.IsZero() { + if maxVotingPower.IsZero() { return } - // return if max voting power can not be undercut because there are not enough stakers - // in the pool - if math.LegacyOneDec().Quo(alpha).GT(math.LegacyNewDec(int64(len(validators)))) { - return - } + for i, validator := range validators { + if math.LegacyNewDec(int64(effectiveStakes[validator.Address])).QuoInt64(totalStake).GT(maxVotingPower) { + amount := math.LegacyNewDec(int64(effectiveStakes[validator.Address])).Sub(maxVotingPower.MulInt64(totalStake)).TruncateInt64() - x := func(i int) uint64 { - totalStake := int64(0) + totalStakeRemainder -= int64(validator.Stake) + effectiveStakes[validator.Address] -= uint64(amount) - for _, validator := range validators[i+1:] { - totalStake += int64(validator.Stake) + for _, v := range validators[i+1:] { + effectiveStakes[v.Address] += uint64(math.LegacyNewDec(int64(effectiveStakes[v.Address])).QuoInt64(totalStakeRemainder).MulInt64(amount).TruncateInt64()) + } } - - return uint64(alpha.MulInt64(totalStake).Quo(math.LegacyOneDec().Sub(alpha.Mul(math.LegacyNewDec(int64(i)).Add(math.LegacyOneDec())))).TruncateInt64()) } - for i := range validators { - M := x(i) + lowestValidator := validators[len(validators)-1] + scaleFactor := math.LegacyZeroDec() - if validators[i].Stake >= M && M >= validators[i+1].Stake { - for _, v := range validators { - if v.Stake > M { - effectiveStakes[v.Address] = M - } - } - return - } + if effectiveStakes[lowestValidator.Address] > 0 { + scaleFactor = math.LegacyNewDec(int64(lowestValidator.Stake)).QuoInt64(int64(effectiveStakes[lowestValidator.Address])) + } + + for _, validator := range validators { + effectiveStakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(effectiveStakes[validator.Address])).TruncateInt64()) } return @@ -269,7 +271,7 @@ func (k Keeper) Slash(ctx sdk.Context, poolId uint64, staker string, slashType s // get real stake fraction from the effective stake which is truly at risk for getting slashed // by dividing it with the total bonded stake from the validator - stakeFraction := math.LegacyNewDec(int64(k.GetEffectiveValidatorStakes(ctx, poolId)[staker])).QuoInt(validator.GetBondedTokens()) + stakeFraction := math.LegacyNewDec(int64(k.GetEffectiveValidatorStakes(ctx, poolId, staker)[staker])).QuoInt(validator.GetBondedTokens()) // the validator can only be slashed for his effective stake fraction in a pool, therefore we // update the slash fraction accordingly From aeeb14667d70b674ded383c0f714bfd754af022d Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Mon, 16 Dec 2024 11:19:54 +0100 Subject: [PATCH 05/15] chore: continued with tests --- .../keeper_suite_zero_delegation_test.go | 10 ++++++++++ x/bundles/keeper/logic_round_robin.go | 8 ++++---- x/bundles/keeper/logic_round_robin_test.go | 18 ++++++++++-------- x/stakers/keeper/exported_functions.go | 1 + 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/x/bundles/keeper/keeper_suite_zero_delegation_test.go b/x/bundles/keeper/keeper_suite_zero_delegation_test.go index 757de27d..f087c71f 100644 --- a/x/bundles/keeper/keeper_suite_zero_delegation_test.go +++ b/x/bundles/keeper/keeper_suite_zero_delegation_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "cosmossdk.io/math" + "fmt" i "github.com/KYVENetwork/chain/testutil/integration" bundletypes "github.com/KYVENetwork/chain/x/bundles/types" funderstypes "github.com/KYVENetwork/chain/x/funders/types" @@ -164,8 +165,17 @@ var _ = Describe("zero delegation", Ordered, func() { Expect(bundleProposal.VotersInvalid).NotTo(ContainElement(i.STAKER_2)) Expect(bundleProposal.VotersAbstain).NotTo(ContainElement(i.STAKER_2)) + fmt.Println(bundleProposal) + effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) + fmt.Println(effectiveStakes) + + fmt.Println("wait 60 seconds") s.CommitAfterSeconds(60) + bundleProposal, _ = s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) + fmt.Println(bundleProposal) + + // TODO: fails here s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ Creator: i.VALADDRESS_1_A, Staker: i.STAKER_1, diff --git a/x/bundles/keeper/logic_round_robin.go b/x/bundles/keeper/logic_round_robin.go index 3edf586d..6c561fbe 100644 --- a/x/bundles/keeper/logic_round_robin.go +++ b/x/bundles/keeper/logic_round_robin.go @@ -75,15 +75,15 @@ func (k Keeper) LoadRoundRobinValidatorSet(ctx sdk.Context, poolId uint64) Round newValidators := make(map[string]bool, 0) // Add all current pool validators to the round-robin set for _, address := range k.stakerKeeper.GetAllStakerAddressesOfPool(ctx, poolId) { - delegation := k.stakerKeeper.GetValidatorPoolStake(ctx, address, poolId) - if delegation > 0 { + effectiveStakes := k.stakerKeeper.GetEffectiveValidatorStakes(ctx, poolId) + if effectiveStakes[address] > 0 { // If a validator has no delegation do not add to the round-robin set. Validator is basically non-existent. vs.Validators = append(vs.Validators, RoundRobinValidatorPower{ Address: address, - Power: int64(delegation), + Power: int64(effectiveStakes[address]), }) vs.Progress[address] = 0 - totalDelegation += int64(delegation) + totalDelegation += int64(effectiveStakes[address]) newValidators[address] = true } } diff --git a/x/bundles/keeper/logic_round_robin_test.go b/x/bundles/keeper/logic_round_robin_test.go index 09582726..040005b4 100644 --- a/x/bundles/keeper/logic_round_robin_test.go +++ b/x/bundles/keeper/logic_round_robin_test.go @@ -182,6 +182,8 @@ var _ = Describe("logic_round_robin.go", Ordered, func() { It("Frequency analysis", func() { // ARRANGE + // NOTE that dummy with index 2 has more than 50% voting power, so his effective stake + // will be lower joinDummy(s, 0, 2) joinDummy(s, 1, 31) joinDummy(s, 2, 67) @@ -207,16 +209,16 @@ var _ = Describe("logic_round_robin.go", Ordered, func() { // ASSERT Expect(frequency1[i.DUMMY[0]]).To(Equal(0)) - Expect(frequency1[i.DUMMY[1]]).To(Equal(3)) - Expect(frequency1[i.DUMMY[2]]).To(Equal(7)) + Expect(frequency1[i.DUMMY[1]]).To(Equal(5)) + Expect(frequency1[i.DUMMY[2]]).To(Equal(5)) - Expect(frequency2[i.DUMMY[0]]).To(Equal(2)) - Expect(frequency2[i.DUMMY[1]]).To(Equal(31)) - Expect(frequency2[i.DUMMY[2]]).To(Equal(67)) + Expect(frequency2[i.DUMMY[0]]).To(Equal(3)) + Expect(frequency2[i.DUMMY[1]]).To(Equal(47)) + Expect(frequency2[i.DUMMY[2]]).To(Equal(50)) - Expect(frequency3[i.DUMMY[0]]).To(Equal(2000)) - Expect(frequency3[i.DUMMY[1]]).To(Equal(31000)) - Expect(frequency3[i.DUMMY[2]]).To(Equal(67000)) + Expect(frequency3[i.DUMMY[0]]).To(Equal(3031)) // 2/66 + Expect(frequency3[i.DUMMY[1]]).To(Equal(46969)) // 31/66 + Expect(frequency3[i.DUMMY[2]]).To(Equal(50000)) // 33/66 }) It("Frequency analysis (rounding)", func() { diff --git a/x/stakers/keeper/exported_functions.go b/x/stakers/keeper/exported_functions.go index 0e8795e7..05d9d5cd 100644 --- a/x/stakers/keeper/exported_functions.go +++ b/x/stakers/keeper/exported_functions.go @@ -246,6 +246,7 @@ func (k Keeper) GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64, must } } + // TODO: take lowest validator with effective stake bigger than zero lowestValidator := validators[len(validators)-1] scaleFactor := math.LegacyZeroDec() From 2487d71fc046d4cd3952e5f994d88a74fb511ed9 Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Mon, 16 Dec 2024 12:29:45 +0100 Subject: [PATCH 06/15] test: fixed existing zero delegation tests --- .../keeper_suite_zero_delegation_test.go | 138 +++--------------- x/bundles/keeper/logic_bundles.go | 3 + x/bundles/types/errors.go | 1 + x/stakers/keeper/exported_functions.go | 24 ++- 4 files changed, 38 insertions(+), 128 deletions(-) diff --git a/x/bundles/keeper/keeper_suite_zero_delegation_test.go b/x/bundles/keeper/keeper_suite_zero_delegation_test.go index f087c71f..eca7fa70 100644 --- a/x/bundles/keeper/keeper_suite_zero_delegation_test.go +++ b/x/bundles/keeper/keeper_suite_zero_delegation_test.go @@ -2,7 +2,6 @@ package keeper_test import ( "cosmossdk.io/math" - "fmt" i "github.com/KYVENetwork/chain/testutil/integration" bundletypes "github.com/KYVENetwork/chain/x/bundles/types" funderstypes "github.com/KYVENetwork/chain/x/funders/types" @@ -165,17 +164,8 @@ var _ = Describe("zero delegation", Ordered, func() { Expect(bundleProposal.VotersInvalid).NotTo(ContainElement(i.STAKER_2)) Expect(bundleProposal.VotersAbstain).NotTo(ContainElement(i.STAKER_2)) - fmt.Println(bundleProposal) - effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) - fmt.Println(effectiveStakes) - - fmt.Println("wait 60 seconds") s.CommitAfterSeconds(60) - bundleProposal, _ = s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) - fmt.Println(bundleProposal) - - // TODO: fails here s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ Creator: i.VALADDRESS_1_A, Staker: i.STAKER_1, @@ -339,11 +329,10 @@ var _ = Describe("zero delegation", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ - Creator: i.VALADDRESS_0_A, - Staker: i.STAKER_0, - PoolId: 0, - }) + // manually set next uploader + bundleProposal, _ := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) + bundleProposal.NextUploader = i.STAKER_0 + s.App().BundlesKeeper.SetBundleProposal(s.Ctx(), bundleProposal) s.CommitAfterSeconds(60) @@ -432,7 +421,7 @@ var _ = Describe("zero delegation", Ordered, func() { Expect(bundleProposal.PoolId).To(Equal(uint64(0))) Expect(bundleProposal.StorageId).To(Equal("P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg")) Expect(bundleProposal.Uploader).To(Equal(i.STAKER_1)) - Expect(bundleProposal.NextUploader).To(Equal(i.STAKER_2)) + Expect(bundleProposal.NextUploader).To(Equal(i.STAKER_1)) Expect(bundleProposal.DataSize).To(Equal(uint64(100))) Expect(bundleProposal.DataHash).To(Equal("test_hash2")) Expect(bundleProposal.BundleSize).To(Equal(uint64(100))) @@ -518,11 +507,10 @@ var _ = Describe("zero delegation", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ - Creator: i.VALADDRESS_0_A, - Staker: i.STAKER_0, - PoolId: 0, - }) + // manually set next uploader + bundleProposal, _ := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) + bundleProposal.NextUploader = i.STAKER_0 + s.App().BundlesKeeper.SetBundleProposal(s.Ctx(), bundleProposal) s.CommitAfterSeconds(60) @@ -687,11 +675,10 @@ var _ = Describe("zero delegation", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ - Creator: i.VALADDRESS_0_A, - Staker: i.STAKER_0, - PoolId: 0, - }) + // manually set next uploader + bundleProposal, _ := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) + bundleProposal.NextUploader = i.STAKER_0 + s.App().BundlesKeeper.SetBundleProposal(s.Ctx(), bundleProposal) s.CommitAfterSeconds(60) @@ -794,15 +781,14 @@ var _ = Describe("zero delegation", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ - Creator: i.VALADDRESS_0_A, - Staker: i.STAKER_0, - PoolId: 0, - }) + // manually set next uploader + bundleProposal, _ := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) + bundleProposal.NextUploader = i.STAKER_0 + s.App().BundlesKeeper.SetBundleProposal(s.Ctx(), bundleProposal) s.CommitAfterSeconds(60) - s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + s.RunTxBundlesError(&bundletypes.MsgSubmitBundleProposal{ Creator: i.VALADDRESS_0_A, Staker: i.STAKER_0, PoolId: 0, @@ -815,93 +801,5 @@ var _ = Describe("zero delegation", Ordered, func() { ToKey: "99", BundleSummary: "test_value", }) - - s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ - Creator: i.VALADDRESS_1_A, - Staker: i.STAKER_1, - PoolId: 0, - StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", - Vote: bundletypes.VOTE_TYPE_VALID, - }) - - initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) - initialBalanceValaddress0 = s.GetBalanceFromAddress(i.VALADDRESS_0_A) - - initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) - initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) - - // manually set next staker - bundleProposal, _ := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) - Expect(bundleProposal.NextUploader).To(BeEmpty()) - bundleProposal.NextUploader = i.STAKER_1 - s.App().BundlesKeeper.SetBundleProposal(s.Ctx(), bundleProposal) - - // ACT - s.CommitAfterSeconds(60) - s.CommitAfterSeconds(1) - - // ASSERT - // check if bundle got not finalized on pool - pool, poolFound := s.App().PoolKeeper.GetPool(s.Ctx(), 0) - Expect(poolFound).To(BeTrue()) - - Expect(pool.CurrentKey).To(Equal("")) - Expect(pool.CurrentSummary).To(BeEmpty()) - Expect(pool.CurrentIndex).To(BeZero()) - Expect(pool.TotalBundles).To(BeZero()) - - // check if finalized bundle exists - _, finalizedBundleFound := s.App().BundlesKeeper.GetFinalizedBundle(s.Ctx(), 0, 0) - Expect(finalizedBundleFound).To(BeFalse()) - - // check if bundle proposal got dropped - bundleProposal, bundleProposalFound := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) - Expect(bundleProposalFound).To(BeTrue()) - - Expect(bundleProposal.PoolId).To(Equal(uint64(0))) - Expect(bundleProposal.StorageId).To(BeEmpty()) - Expect(bundleProposal.Uploader).To(BeEmpty()) - Expect(bundleProposal.NextUploader).To(BeEmpty()) - Expect(bundleProposal.DataSize).To(BeZero()) - Expect(bundleProposal.DataHash).To(BeEmpty()) - Expect(bundleProposal.BundleSize).To(BeZero()) - Expect(bundleProposal.FromKey).To(BeEmpty()) - Expect(bundleProposal.ToKey).To(BeEmpty()) - Expect(bundleProposal.BundleSummary).To(BeEmpty()) - Expect(bundleProposal.UpdatedAt).NotTo(BeZero()) - Expect(bundleProposal.VotersValid).To(BeEmpty()) - Expect(bundleProposal.VotersInvalid).To(BeEmpty()) - Expect(bundleProposal.VotersAbstain).To(BeEmpty()) - - // check uploader status - valaccountUploader, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) - Expect(valaccountUploader.Points).To(BeZero()) - - balanceValaddress := s.GetBalanceFromAddress(valaccountUploader.Valaddress) - Expect(balanceValaddress).To(Equal(initialBalanceValaddress0)) - - balanceUploader := s.GetBalanceFromAddress(valaccountUploader.Staker) - - Expect(balanceUploader).To(Equal(initialBalanceStaker0)) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(BeEmpty()) - - // check voter status - valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) - Expect(valaccountVoter.Points).To(BeZero()) - - balanceVoterValaddress := s.GetBalanceFromAddress(valaccountVoter.Valaddress) - Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) - - balanceVoter := s.GetBalanceFromAddress(valaccountVoter.Staker) - Expect(balanceVoter).To(Equal(initialBalanceStaker1)) - - Expect(balanceVoter).To(Equal(initialBalanceStaker1)) - Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_1, i.STAKER_1)).To(BeEmpty()) - - fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) - - // assert total pool funds - Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100 * i.KYVE)) - Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) }) }) diff --git a/x/bundles/keeper/logic_bundles.go b/x/bundles/keeper/logic_bundles.go index 93cb5aec..9b318558 100644 --- a/x/bundles/keeper/logic_bundles.go +++ b/x/bundles/keeper/logic_bundles.go @@ -38,6 +38,9 @@ func (k Keeper) AssertPoolCanRun(ctx sdk.Context, poolId uint64) error { // Get the total and the highest delegation of a single validator in the pool totalDelegation, _ := k.stakerKeeper.GetTotalAndHighestDelegationOfPool(ctx, poolId) + if totalDelegation == 0 { + return types.ErrPoolHasZeroDelegation + } // Error if min delegation is not reached if totalDelegation < pool.MinDelegation { diff --git a/x/bundles/types/errors.go b/x/bundles/types/errors.go index 557386d6..64e00ba9 100644 --- a/x/bundles/types/errors.go +++ b/x/bundles/types/errors.go @@ -24,4 +24,5 @@ var ( ErrAlreadyVotedAbstain = errors.Register(ModuleName, 1206, "already voted abstain on bundle proposal") ErrVotingPowerTooHigh = errors.Register(ModuleName, 1207, "staker in pool has too much voting power") ErrEndKeyReached = errors.Register(ModuleName, 1208, "end key reached") + ErrPoolHasZeroDelegation = errors.Register(ModuleName, 1209, "pool has zero delegation") ) diff --git a/x/stakers/keeper/exported_functions.go b/x/stakers/keeper/exported_functions.go index 05d9d5cd..4f216fbd 100644 --- a/x/stakers/keeper/exported_functions.go +++ b/x/stakers/keeper/exported_functions.go @@ -229,7 +229,7 @@ func (k Keeper) GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64, must return validators[i].Stake > validators[j].Stake }) - if maxVotingPower.IsZero() { + if totalStake == 0 || maxVotingPower.IsZero() { return } @@ -240,20 +240,24 @@ func (k Keeper) GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64, must totalStakeRemainder -= int64(validator.Stake) effectiveStakes[validator.Address] -= uint64(amount) - for _, v := range validators[i+1:] { - effectiveStakes[v.Address] += uint64(math.LegacyNewDec(int64(effectiveStakes[v.Address])).QuoInt64(totalStakeRemainder).MulInt64(amount).TruncateInt64()) + if totalStakeRemainder > 0 { + for _, v := range validators[i+1:] { + effectiveStakes[v.Address] += uint64(math.LegacyNewDec(int64(effectiveStakes[v.Address])).QuoInt64(totalStakeRemainder).MulInt64(amount).TruncateInt64()) + } } } } - // TODO: take lowest validator with effective stake bigger than zero - lowestValidator := validators[len(validators)-1] scaleFactor := math.LegacyZeroDec() - if effectiveStakes[lowestValidator.Address] > 0 { - scaleFactor = math.LegacyNewDec(int64(lowestValidator.Stake)).QuoInt64(int64(effectiveStakes[lowestValidator.Address])) + // get lowest validator with effective stake still bigger than zero + for i := len(validators) - 1; i >= 0; i-- { + if effectiveStakes[validators[i].Address] > 0 { + scaleFactor = math.LegacyNewDec(int64(validators[i].Stake)).QuoInt64(int64(effectiveStakes[validators[i].Address])) + } } + // scale all effective stakes down to scale factor for _, validator := range validators { effectiveStakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(effectiveStakes[validator.Address])).TruncateInt64()) } @@ -272,7 +276,11 @@ func (k Keeper) Slash(ctx sdk.Context, poolId uint64, staker string, slashType s // get real stake fraction from the effective stake which is truly at risk for getting slashed // by dividing it with the total bonded stake from the validator - stakeFraction := math.LegacyNewDec(int64(k.GetEffectiveValidatorStakes(ctx, poolId, staker)[staker])).QuoInt(validator.GetBondedTokens()) + stakeFraction := math.LegacyZeroDec() + + if !validator.GetBondedTokens().IsZero() { + stakeFraction = math.LegacyNewDec(int64(k.GetEffectiveValidatorStakes(ctx, poolId, staker)[staker])).QuoInt(validator.GetBondedTokens()) + } // the validator can only be slashed for his effective stake fraction in a pool, therefore we // update the slash fraction accordingly From 29ff7b08b4200d6dd483172384fa0a112241bc2f Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Mon, 16 Dec 2024 15:04:20 +0100 Subject: [PATCH 07/15] test: added effective stake tests --- x/stakers/keeper/exported_functions.go | 24 +- .../keeper_suite_effective_stake_test.go | 318 ++++++++++++++++++ 2 files changed, 338 insertions(+), 4 deletions(-) create mode 100644 x/stakers/keeper/keeper_suite_effective_stake_test.go diff --git a/x/stakers/keeper/exported_functions.go b/x/stakers/keeper/exported_functions.go index 4f216fbd..84b428e6 100644 --- a/x/stakers/keeper/exported_functions.go +++ b/x/stakers/keeper/exported_functions.go @@ -91,6 +91,16 @@ func (k Keeper) GetDelegationOfPool(ctx sdk.Context, poolId uint64) uint64 { return totalDelegation } +// GetPoolTotalStake returns the amount in uykve which actively secures +// the given pool +func (k Keeper) GetPoolTotalStake(ctx sdk.Context, poolId uint64) (totalStake uint64) { + effectiveStakes := k.GetEffectiveValidatorStakes(ctx, poolId) + for _, stake := range effectiveStakes { + totalStake += stake + } + return +} + // GetTotalAndHighestDelegationOfPool iterates all validators of a given pool and returns the stake of the validator // with the highest stake and the sum of all stakes. func (k Keeper) GetTotalAndHighestDelegationOfPool(ctx sdk.Context, poolId uint64) (totalDelegation, highestDelegation uint64) { @@ -230,11 +240,15 @@ func (k Keeper) GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64, must }) if totalStake == 0 || maxVotingPower.IsZero() { - return + return make(map[string]uint64) + } + + if math.LegacyOneDec().Quo(maxVotingPower).GT(math.LegacyNewDec(int64(len(addresses)))) { + return make(map[string]uint64) } for i, validator := range validators { - if math.LegacyNewDec(int64(effectiveStakes[validator.Address])).QuoInt64(totalStake).GT(maxVotingPower) { + if math.LegacyNewDec(int64(effectiveStakes[validator.Address])).GT(maxVotingPower.MulInt64(totalStake)) { amount := math.LegacyNewDec(int64(effectiveStakes[validator.Address])).Sub(maxVotingPower.MulInt64(totalStake)).TruncateInt64() totalStakeRemainder -= int64(validator.Stake) @@ -242,7 +256,7 @@ func (k Keeper) GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64, must if totalStakeRemainder > 0 { for _, v := range validators[i+1:] { - effectiveStakes[v.Address] += uint64(math.LegacyNewDec(int64(effectiveStakes[v.Address])).QuoInt64(totalStakeRemainder).MulInt64(amount).TruncateInt64()) + effectiveStakes[v.Address] += uint64(math.LegacyNewDec(int64(v.Stake)).QuoInt64(totalStakeRemainder).MulInt64(amount).TruncateInt64()) } } } @@ -254,12 +268,14 @@ func (k Keeper) GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64, must for i := len(validators) - 1; i >= 0; i-- { if effectiveStakes[validators[i].Address] > 0 { scaleFactor = math.LegacyNewDec(int64(validators[i].Stake)).QuoInt64(int64(effectiveStakes[validators[i].Address])) + break } } // scale all effective stakes down to scale factor for _, validator := range validators { - effectiveStakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(effectiveStakes[validator.Address])).TruncateInt64()) + // TODO: is rounding here fine? + effectiveStakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(effectiveStakes[validator.Address])).RoundInt64()) } return diff --git a/x/stakers/keeper/keeper_suite_effective_stake_test.go b/x/stakers/keeper/keeper_suite_effective_stake_test.go new file mode 100644 index 00000000..0314ead5 --- /dev/null +++ b/x/stakers/keeper/keeper_suite_effective_stake_test.go @@ -0,0 +1,318 @@ +package keeper_test + +import ( + "cosmossdk.io/math" + stakerstypes "github.com/KYVENetwork/chain/x/stakers/types" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + i "github.com/KYVENetwork/chain/testutil/integration" + pooltypes "github.com/KYVENetwork/chain/x/pool/types" +) + +/* + +TEST CASES - keeper_suite_effective_stake_test.go + +* Test effective stake with all validators below the max pool voting power +* Test effective stake with one validator above the max pool voting power +* Test effective stake with multiple validators above the max pool voting power +* Test effective stake with fewer validators than required to undercut the max pool voting power +* Test effective stake with some validators having zero delegation +* Test effective stake with all validators having zero delegation + +*/ + +var _ = Describe("keeper_suite_effective_stake_test.go", Ordered, func() { + s := i.NewCleanChain() + + gov := s.App().GovKeeper.GetGovernanceAccount(s.Ctx()).GetAddress().String() + + BeforeEach(func() { + // init new clean chain + s = i.NewCleanChain() + + // create pool + msg := &pooltypes.MsgCreatePool{ + Authority: gov, + UploadInterval: 60, + MaxBundleSize: 100, + InflationShareWeight: math.LegacyZeroDec(), + Binaries: "{}", + } + s.RunTxPoolSuccess(msg) + + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("0.5") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + }) + + AfterEach(func() { + s.PerformValidityChecks() + }) + + It("Test effective stake with all validators below the max pool voting power", func() { + // ARRANGE + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // ACT + effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) + + // ASSERT + Expect(len(effectiveStakes)).To(Equal(3)) + Expect(effectiveStakes[i.STAKER_0]).To(Equal(100 * i.KYVE)) + Expect(effectiveStakes[i.STAKER_1]).To(Equal(100 * i.KYVE)) + Expect(effectiveStakes[i.STAKER_2]).To(Equal(100 * i.KYVE)) + + Expect(s.App().StakersKeeper.GetPoolTotalStake(s.Ctx(), 0)).To(Equal(300 * i.KYVE)) + }) + + It("Test effective stake with one validator above the max pool voting power", func() { + // ARRANGE + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(250*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // ACT + effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) + + // ASSERT + Expect(len(effectiveStakes)).To(Equal(3)) + Expect(effectiveStakes[i.STAKER_0]).To(Equal(100 * i.KYVE)) + Expect(effectiveStakes[i.STAKER_1]).To(Equal(200 * i.KYVE)) + Expect(effectiveStakes[i.STAKER_2]).To(Equal(100 * i.KYVE)) + + Expect(s.App().StakersKeeper.GetPoolTotalStake(s.Ctx(), 0)).To(Equal(400 * i.KYVE)) + }) + + It("Test effective stake with multiple validators above the max pool voting power", func() { + // ARRANGE + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("0.35") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + + s.CreateValidator(i.STAKER_0, "Staker-0", int64(600*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(500*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(120*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // ACT + effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) + + // ASSERT + Expect(len(effectiveStakes)).To(Equal(3)) + Expect(effectiveStakes[i.STAKER_0]).To(Equal(140 * i.KYVE)) + Expect(effectiveStakes[i.STAKER_1]).To(Equal(140 * i.KYVE)) + Expect(effectiveStakes[i.STAKER_2]).To(Equal(120 * i.KYVE)) + + Expect(s.App().StakersKeeper.GetPoolTotalStake(s.Ctx(), 0)).To(Equal(400 * i.KYVE)) + }) + + It("Test effective stake with fewer validators than required to undercut the max pool voting power", func() { + // ARRANGE + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("0.2") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // ACT + effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) + + // ASSERT + Expect(len(effectiveStakes)).To(BeZero()) + Expect(s.App().StakersKeeper.GetPoolTotalStake(s.Ctx(), 0)).To(BeZero()) + }) + + It("Test effective stake with some validators having zero delegation", func() { + // ARRANGE + s.CreateValidator(i.STAKER_0, "Staker-0", int64(200*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateZeroDelegationValidator(i.STAKER_1, "Staker-1") + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // ACT + effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) + + // ASSERT + Expect(len(effectiveStakes)).To(Equal(3)) + Expect(effectiveStakes[i.STAKER_0]).To(Equal(100 * i.KYVE)) + Expect(effectiveStakes[i.STAKER_1]).To(Equal(0 * i.KYVE)) + Expect(effectiveStakes[i.STAKER_2]).To(Equal(100 * i.KYVE)) + + Expect(s.App().StakersKeeper.GetPoolTotalStake(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + }) + + It("Test effective stake with all validators having zero delegation", func() { + // ARRANGE + s.CreateZeroDelegationValidator(i.STAKER_0, "Staker-0") + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateZeroDelegationValidator(i.STAKER_1, "Staker-1") + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateZeroDelegationValidator(i.STAKER_2, "Staker-2") + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // ACT + effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) + + // ASSERT + Expect(len(effectiveStakes)).To(BeZero()) + Expect(s.App().StakersKeeper.GetPoolTotalStake(s.Ctx(), 0)).To(BeZero()) + }) +}) From 36f8f1649297e13325350a35c6481644afa56c3b Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Mon, 16 Dec 2024 16:52:35 +0100 Subject: [PATCH 08/15] test: fixed existing tests --- testutil/integration/checks.go | 4 +- .../keeper_suite_invalid_bundles_test.go | 28 ++-- .../keeper/keeper_suite_stakers_leave_test.go | 12 +- .../keeper/keeper_suite_valid_bundles_test.go | 2 +- .../keeper_suite_zero_delegation_test.go | 4 +- x/bundles/keeper/logic_bundles.go | 33 ++--- ...ic_end_block_handle_upload_timeout_test.go | 36 +++-- x/bundles/keeper/logic_round_robin.go | 8 +- x/bundles/types/expected_keepers.go | 5 +- x/query/keeper/grpc_query_pool.go | 2 +- x/query/keeper/helper.go | 13 +- x/stakers/keeper/exported_functions.go | 129 ++--------------- .../keeper_suite_effective_stake_test.go | 136 +++++++++++++----- x/stakers/keeper/logic_stakers.go | 86 ++++++++++- x/stakers/keeper/msg_server_join_pool_test.go | 42 +++--- .../keeper/msg_server_leave_pool_test.go | 16 ++- .../msg_server_update_stake_fraction_test.go | 52 +++---- 17 files changed, 316 insertions(+), 292 deletions(-) diff --git a/testutil/integration/checks.go b/testutil/integration/checks.go index 94c1de37..b76c5fdf 100644 --- a/testutil/integration/checks.go +++ b/testutil/integration/checks.go @@ -101,7 +101,7 @@ func (suite *KeeperTestSuite) VerifyPoolQueries() { for i := range poolsState { bundleProposalState, _ := suite.App().BundlesKeeper.GetBundleProposal(suite.Ctx(), poolsState[i].Id) stakersState := suite.App().StakersKeeper.GetAllStakerAddressesOfPool(suite.Ctx(), poolsState[i].Id) - totalDelegationState := suite.App().StakersKeeper.GetDelegationOfPool(suite.Ctx(), poolsState[i].Id) + totalDelegationState := suite.App().StakersKeeper.GetTotalStakeOfPool(suite.Ctx(), poolsState[i].Id) Expect(poolsQuery[i].Id).To(Equal(poolsState[i].Id)) Expect(*poolsQuery[i].Data).To(Equal(poolsState[i])) @@ -175,7 +175,7 @@ func (suite *KeeperTestSuite) VerifyStakersModuleAssetsIntegrity() { func (suite *KeeperTestSuite) VerifyPoolTotalStake() { for _, pool := range suite.App().PoolKeeper.GetAllPools(suite.Ctx()) { expectedBalance := uint64(0) - actualBalance := suite.App().StakersKeeper.GetDelegationOfPool(suite.Ctx(), pool.Id) + actualBalance := suite.App().StakersKeeper.GetTotalStakeOfPool(suite.Ctx(), pool.Id) for _, stakerAddress := range suite.App().StakersKeeper.GetAllStakerAddressesOfPool(suite.Ctx(), pool.Id) { expectedBalance += suite.App().StakersKeeper.GetValidatorPoolStake(suite.Ctx(), stakerAddress, pool.Id) diff --git a/x/bundles/keeper/keeper_suite_invalid_bundles_test.go b/x/bundles/keeper/keeper_suite_invalid_bundles_test.go index 32d1f9b0..3208c8e2 100644 --- a/x/bundles/keeper/keeper_suite_invalid_bundles_test.go +++ b/x/bundles/keeper/keeper_suite_invalid_bundles_test.go @@ -62,6 +62,10 @@ var _ = Describe("invalid bundles", Ordered, func() { } s.RunTxPoolSuccess(msg) + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("1") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + s.RunTxFundersSuccess(&funderstypes.MsgCreateFunder{ Creator: i.ALICE, Moniker: "Alice", @@ -94,12 +98,6 @@ var _ = Describe("invalid bundles", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ - Creator: i.VALADDRESS_0_A, - Staker: i.STAKER_0, - PoolId: 0, - }) - initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) initialBalanceValaddress0 = s.GetBalanceFromAddress(i.VALADDRESS_0_A) @@ -164,8 +162,8 @@ var _ = Describe("invalid bundles", Ordered, func() { s.CommitAfterSeconds(60) s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ - Creator: i.VALADDRESS_1_A, - Staker: i.STAKER_1, + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, PoolId: 0, StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", DataSize: 100, @@ -230,7 +228,7 @@ var _ = Describe("invalid bundles", Ordered, func() { slashAmount := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(100*i.KYVE - slashAmount)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) // check voter status valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) @@ -330,8 +328,8 @@ var _ = Describe("invalid bundles", Ordered, func() { s.CommitAfterSeconds(60) s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ - Creator: i.VALADDRESS_1_A, - Staker: i.STAKER_1, + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, PoolId: 0, StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", DataSize: 100, @@ -400,7 +398,7 @@ var _ = Describe("invalid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(100*i.KYVE - slashAmountUploader)) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.ALICE)).To(Equal(100*i.KYVE - slashAmountDelegator)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(400 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(400 * i.KYVE)) // check voter status valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) @@ -526,8 +524,8 @@ var _ = Describe("invalid bundles", Ordered, func() { s.CommitAfterSeconds(60) s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ - Creator: i.VALADDRESS_3_A, - Staker: i.STAKER_3, + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, PoolId: 0, StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", DataSize: 100, @@ -604,7 +602,7 @@ var _ = Describe("invalid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_1, i.STAKER_1)).To(Equal(100*i.KYVE - slashAmountVoter)) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_1, i.BOB)).To(Equal(100*i.KYVE - slashAmountDelegator2)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(450 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(450 * i.KYVE)) // check voter status _, voterActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) diff --git a/x/bundles/keeper/keeper_suite_stakers_leave_test.go b/x/bundles/keeper/keeper_suite_stakers_leave_test.go index 29ee4340..f42c26d1 100644 --- a/x/bundles/keeper/keeper_suite_stakers_leave_test.go +++ b/x/bundles/keeper/keeper_suite_stakers_leave_test.go @@ -140,7 +140,7 @@ var _ = Describe("stakers leave", Ordered, func() { _, valaccountActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccountActive).To(BeFalse()) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) // check if next uploader got not slashed Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(100 * i.KYVE)) @@ -228,7 +228,7 @@ var _ = Describe("stakers leave", Ordered, func() { _, valaccountActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccountActive).To(BeFalse()) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) // check if next uploader got not slashed Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(100 * i.KYVE)) @@ -344,7 +344,7 @@ var _ = Describe("stakers leave", Ordered, func() { slashAmount := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(100*i.KYVE - slashAmount)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) // check if next uploader did not receive the uploader reward balanceUploader := s.GetBalanceFromAddress(i.STAKER_0) @@ -444,7 +444,7 @@ var _ = Describe("stakers leave", Ordered, func() { slashAmount := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_1, i.STAKER_1)).To(Equal(100*i.KYVE - slashAmount)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) // check if next uploader did not receive any rewards balanceVoter := s.GetBalanceFromAddress(i.STAKER_1) @@ -536,7 +536,7 @@ var _ = Describe("stakers leave", Ordered, func() { // check if voter status Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_1, i.STAKER_1)).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) // check if next uploader did not receive any rewards balanceVoter := s.GetBalanceFromAddress(i.STAKER_1) @@ -631,7 +631,7 @@ var _ = Describe("stakers leave", Ordered, func() { // check if voter not got slashed Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_1, i.STAKER_1)).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) // check if next uploader did not receive any rewards balanceVoter := s.GetBalanceFromAddress(i.STAKER_1) diff --git a/x/bundles/keeper/keeper_suite_valid_bundles_test.go b/x/bundles/keeper/keeper_suite_valid_bundles_test.go index b3de63d4..17e5b636 100644 --- a/x/bundles/keeper/keeper_suite_valid_bundles_test.go +++ b/x/bundles/keeper/keeper_suite_valid_bundles_test.go @@ -922,7 +922,7 @@ var _ = Describe("valid bundles", Ordered, func() { Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_2, i.STAKER_2)).To(Equal(100*i.KYVE - slashAmountVoter)) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_2, i.CHARLIE)).To(Equal(300*i.KYVE - slashAmountDelegator)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(800 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(800 * i.KYVE)) // check voter status _, voterActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_2) diff --git a/x/bundles/keeper/keeper_suite_zero_delegation_test.go b/x/bundles/keeper/keeper_suite_zero_delegation_test.go index eca7fa70..7a8585f5 100644 --- a/x/bundles/keeper/keeper_suite_zero_delegation_test.go +++ b/x/bundles/keeper/keeper_suite_zero_delegation_test.go @@ -291,7 +291,7 @@ var _ = Describe("zero delegation", Ordered, func() { slashAmountVoter := uint64(math.LegacyNewDec(int64(0 * i.KYVE)).Mul(fraction).TruncateInt64()) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_2, i.STAKER_2)).To(Equal(0*i.KYVE - slashAmountVoter)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200*i.KYVE - slashAmountVoter)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200*i.KYVE - slashAmountVoter)) }) It("Staker submit bundle proposal with zero delegation", func() { @@ -619,7 +619,7 @@ var _ = Describe("zero delegation", Ordered, func() { slashAmount := uint64(math.LegacyNewDec(int64(0 * i.KYVE)).Mul(fraction).TruncateInt64()) Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(0*i.KYVE - slashAmount)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200*i.KYVE - slashAmount)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200*i.KYVE - slashAmount)) // check voter status valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) diff --git a/x/bundles/keeper/logic_bundles.go b/x/bundles/keeper/logic_bundles.go index 9b318558..cfa4a035 100644 --- a/x/bundles/keeper/logic_bundles.go +++ b/x/bundles/keeper/logic_bundles.go @@ -36,30 +36,17 @@ func (k Keeper) AssertPoolCanRun(ctx sdk.Context, poolId uint64) error { return types.ErrEndKeyReached } - // Get the total and the highest delegation of a single validator in the pool - totalDelegation, _ := k.stakerKeeper.GetTotalAndHighestDelegationOfPool(ctx, poolId) - if totalDelegation == 0 { - return types.ErrPoolHasZeroDelegation + // Error if max voting power is not achievable because there are not enough stakers + // in the pool + if k.stakerKeeper.IsVotingPowerTooHigh(ctx, poolId) { + return types.ErrVotingPowerTooHigh } // Error if min delegation is not reached - if totalDelegation < pool.MinDelegation { + if k.stakerKeeper.GetTotalStakeOfPool(ctx, poolId) < pool.MinDelegation { return types.ErrMinDelegationNotReached } - stakers := int64(len(k.stakerKeeper.GetAllStakerAddressesOfPool(ctx, poolId))) - maxVotingPower := k.poolKeeper.GetMaxVotingPowerPerPool(ctx) - - if maxVotingPower.IsZero() { - return nil - } - - // Error if max voting power is not achievable because there are not enough stakers - // in the pool - if math.LegacyOneDec().Quo(maxVotingPower).GT(math.LegacyNewDec(stakers)) { - return types.ErrVotingPowerTooHigh - } - return nil } @@ -510,26 +497,24 @@ func (k Keeper) GetVoteDistribution(ctx sdk.Context, poolId uint64) (voteDistrib return } - effectiveStakes := k.stakerKeeper.GetEffectiveValidatorStakes(ctx, poolId) - // get voting power for valid for _, voter := range bundleProposal.VotersValid { - voteDistribution.Valid += effectiveStakes[voter] + voteDistribution.Valid += k.stakerKeeper.GetValidatorPoolStake(ctx, voter, poolId) } // get voting power for invalid for _, voter := range bundleProposal.VotersInvalid { - voteDistribution.Invalid += effectiveStakes[voter] + voteDistribution.Invalid += k.stakerKeeper.GetValidatorPoolStake(ctx, voter, poolId) } // get voting power for abstain for _, voter := range bundleProposal.VotersAbstain { - voteDistribution.Abstain += effectiveStakes[voter] + voteDistribution.Abstain += k.stakerKeeper.GetValidatorPoolStake(ctx, voter, poolId) } // get total voting power for _, staker := range k.stakerKeeper.GetAllStakerAddressesOfPool(ctx, poolId) { - voteDistribution.Total += effectiveStakes[staker] + voteDistribution.Total += k.stakerKeeper.GetValidatorPoolStake(ctx, staker, poolId) } if voteDistribution.Total == 0 { diff --git a/x/bundles/keeper/logic_end_block_handle_upload_timeout_test.go b/x/bundles/keeper/logic_end_block_handle_upload_timeout_test.go index 8776dda3..bdb04f90 100644 --- a/x/bundles/keeper/logic_end_block_handle_upload_timeout_test.go +++ b/x/bundles/keeper/logic_end_block_handle_upload_timeout_test.go @@ -281,7 +281,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(20 * i.KYVE)) }) - It("Next uploader gets not removed although pool having one node with more than 50% voting power", func() { + It("Next uploader gets removed due to pool having validators with too much voting power", func() { // ARRANGE s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ Creator: i.VALADDRESS_0_A, @@ -289,18 +289,16 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { PoolId: 0, }) - s.RunTxSuccess(stakingTypes.NewMsgDelegate( - i.STAKER_0, - util.MustValaddressFromOperatorAddress(i.STAKER_0), - sdk.NewInt64Coin(globalTypes.Denom, int64(1*i.KYVE)), - )) + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("0.2") + s.App().PoolKeeper.SetParams(s.Ctx(), params) // ACT s.CommitAfterSeconds(1) // ASSERT bundleProposal, _ := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) - Expect(bundleProposal.NextUploader).To(Equal("kyve1htgfatqevuvfzvl0sxp97ywteqhg5leha9emf4")) + Expect(bundleProposal.NextUploader).To(BeEmpty()) Expect(bundleProposal.StorageId).To(BeEmpty()) poolStakers := s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0) @@ -308,11 +306,11 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(101 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(BeZero()) _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_1) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(BeZero()) }) It("Staker is next uploader of genesis bundle and upload interval and timeout does not pass", func() { @@ -401,7 +399,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) // check if next uploader not got slashed expectedBalance := 100 * i.KYVE @@ -578,7 +576,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { Expect(expectedBalance).To(Equal(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_1, i.STAKER_1))) // pool delegations equals delegations of staker 0 & 1 - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) }) It("Staker is next uploader of bundle proposal and upload timeout passes with the previous bundle not reaching quorum", func() { @@ -641,7 +639,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { Expect(found).To(BeTrue()) // pool delegations equals delegations of staker 0 & 1 - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) }) It("Staker is next uploader of bundle proposal and upload timeout passes with the previous bundle being invalid", func() { @@ -697,7 +695,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { Vote: bundletypes.VOTE_TYPE_INVALID, }) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(300 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(300 * i.KYVE)) // ACT s.CommitAfterSeconds(s.App().BundlesKeeper.GetUploadTimeout(s.Ctx())) @@ -739,7 +737,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { Expect(expectedBalance).To(Equal(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_2, i.STAKER_2))) // pool delegations equals delegations of staker 1 & 2 - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) }) It("Staker with already max points is next uploader of bundle proposal and upload timeout passes", func() { @@ -869,7 +867,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { Expect(expectedBalance).To(Equal(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_2, i.STAKER_2))) // pool delegations equals delegations of staker 0 & 1 - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) }) It("A bundle proposal with no quorum does not reach the upload interval", func() { @@ -1030,7 +1028,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_2) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) // check if next uploader not got slashed expectedBalance := 100 * i.KYVE @@ -1118,7 +1116,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_2) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) // check if next uploader not got slashed expectedBalance := 100 * i.KYVE @@ -1201,7 +1199,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) // check that uploader received upload slash expectedBalance := 100*i.KYVE - uint64(s.App().StakersKeeper.GetUploadSlash(s.Ctx()).Mul(math.LegacyNewDec(int64(100*i.KYVE))).TruncateInt64()) @@ -1367,7 +1365,7 @@ var _ = Describe("logic_end_block_handle_upload_timeout.go", Ordered, func() { _, found = s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_2) Expect(found).To(BeTrue()) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 1)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 1)).To(Equal(200 * i.KYVE)) // check if next uploader not got slashed slashAmountRatio := s.App().StakersKeeper.GetTimeoutSlash(s.Ctx()) diff --git a/x/bundles/keeper/logic_round_robin.go b/x/bundles/keeper/logic_round_robin.go index 6c561fbe..ea9e99c9 100644 --- a/x/bundles/keeper/logic_round_robin.go +++ b/x/bundles/keeper/logic_round_robin.go @@ -75,15 +75,15 @@ func (k Keeper) LoadRoundRobinValidatorSet(ctx sdk.Context, poolId uint64) Round newValidators := make(map[string]bool, 0) // Add all current pool validators to the round-robin set for _, address := range k.stakerKeeper.GetAllStakerAddressesOfPool(ctx, poolId) { - effectiveStakes := k.stakerKeeper.GetEffectiveValidatorStakes(ctx, poolId) - if effectiveStakes[address] > 0 { + stake := k.stakerKeeper.GetValidatorPoolStake(ctx, address, poolId) + if stake > 0 { // If a validator has no delegation do not add to the round-robin set. Validator is basically non-existent. vs.Validators = append(vs.Validators, RoundRobinValidatorPower{ Address: address, - Power: int64(effectiveStakes[address]), + Power: int64(stake), }) vs.Progress[address] = 0 - totalDelegation += int64(effectiveStakes[address]) + totalDelegation += int64(stake) newValidators[address] = true } } diff --git a/x/bundles/types/expected_keepers.go b/x/bundles/types/expected_keepers.go index 0b41d0ef..7a667f46 100644 --- a/x/bundles/types/expected_keepers.go +++ b/x/bundles/types/expected_keepers.go @@ -38,15 +38,14 @@ type StakerKeeper interface { IncrementPoints(ctx sdk.Context, poolId uint64, stakerAddress string) (newPoints uint64) ResetPoints(ctx sdk.Context, poolId uint64, stakerAddress string) (previousPoints uint64) - GetTotalAndHighestDelegationOfPool(ctx sdk.Context, poolId uint64) (totalDelegation, highestDelegation uint64) GetValidator(ctx sdk.Context, staker string) (stakingtypes.Validator, bool) GetValidatorPoolCommission(ctx sdk.Context, staker string, poolId uint64) math.LegacyDec - GetValidatorPoolStakeFraction(ctx sdk.Context, staker string, poolId uint64) math.LegacyDec GetValidatorPoolStake(ctx sdk.Context, staker string, poolId uint64) uint64 + GetTotalStakeOfPool(ctx sdk.Context, poolId uint64) (totalStake uint64) + IsVotingPowerTooHigh(ctx sdk.Context, poolId uint64) bool Slash(ctx sdk.Context, poolId uint64, staker string, slashType stakersTypes.SlashType) PayoutRewards(ctx sdk.Context, staker string, amount sdk.Coins, payerModuleName string) error PayoutAdditionalCommissionRewards(ctx sdk.Context, validator string, payerModuleName string, amount sdk.Coins) error - GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64, mustIncludeStakers ...string) (effectiveStake map[string]uint64) } type FundersKeeper interface { diff --git a/x/query/keeper/grpc_query_pool.go b/x/query/keeper/grpc_query_pool.go index e940b6c0..6062b54b 100644 --- a/x/query/keeper/grpc_query_pool.go +++ b/x/query/keeper/grpc_query_pool.go @@ -60,7 +60,7 @@ func (k Keeper) parsePoolResponse(ctx sdk.Context, pool *poolTypes.Pool) types.P totalSelfDelegation += k.stakerKeeper.GetDelegationAmountOfDelegator(ctx, address, address) } - totalDelegation := k.stakerKeeper.GetDelegationOfPool(ctx, pool.Id) + totalDelegation := k.stakerKeeper.GetTotalStakeOfPool(ctx, pool.Id) poolAccount := pool.GetPoolAccount() poolBalance := k.bankKeeper.GetBalance(ctx, poolAccount, globalTypes.Denom).Amount.Uint64() diff --git a/x/query/keeper/helper.go b/x/query/keeper/helper.go index 637486c1..364183c5 100644 --- a/x/query/keeper/helper.go +++ b/x/query/keeper/helper.go @@ -40,7 +40,7 @@ func (k Keeper) GetFullStaker(ctx sdk.Context, stakerAddress string) *types.Full InflationShareWeight: pool.InflationShareWeight, UploadInterval: pool.UploadInterval, TotalFunds: k.fundersKeeper.GetTotalActiveFunding(ctx, pool.Id), - TotalDelegation: k.stakerKeeper.GetDelegationOfPool(ctx, pool.Id), + TotalDelegation: k.stakerKeeper.GetTotalStakeOfPool(ctx, pool.Id), Status: k.GetPoolStatus(ctx, &pool), }, Points: valaccount.Points, @@ -67,11 +67,6 @@ func (k Keeper) GetFullStaker(ctx sdk.Context, stakerAddress string) *types.Full } func (k Keeper) GetPoolStatus(ctx sdk.Context, pool *pooltypes.Pool) pooltypes.PoolStatus { - // Get the total and the highest delegation of a single validator in the pool - totalDelegation, highestDelegation := k.stakerKeeper.GetTotalAndHighestDelegationOfPool(ctx, pool.Id) - maxVotingPower := k.poolKeeper.GetMaxVotingPowerPerPool(ctx) - maxDelegation := uint64(maxVotingPower.MulInt64(int64(totalDelegation)).TruncateInt64()) - var poolStatus pooltypes.PoolStatus poolStatus = pooltypes.POOL_STATUS_ACTIVE @@ -81,10 +76,10 @@ func (k Keeper) GetPoolStatus(ctx sdk.Context, pool *pooltypes.Pool) pooltypes.P poolStatus = pooltypes.POOL_STATUS_DISABLED } else if pool.EndKey != "" && pool.EndKey == pool.CurrentKey { poolStatus = pooltypes.POOL_STATUS_END_KEY_REACHED - } else if totalDelegation < pool.MinDelegation { - poolStatus = pooltypes.POOL_STATUS_NOT_ENOUGH_DELEGATION - } else if highestDelegation > maxDelegation { + } else if k.stakerKeeper.IsVotingPowerTooHigh(ctx, pool.Id) { poolStatus = pooltypes.POOL_STATUS_VOTING_POWER_TOO_HIGH + } else if k.stakerKeeper.GetTotalStakeOfPool(ctx, pool.Id) < pool.MinDelegation { + poolStatus = pooltypes.POOL_STATUS_NOT_ENOUGH_DELEGATION } else if k.fundersKeeper.GetTotalActiveFunding(ctx, pool.Id).IsZero() { poolStatus = pooltypes.POOL_STATUS_NO_FUNDS } diff --git a/x/stakers/keeper/exported_functions.go b/x/stakers/keeper/exported_functions.go index 84b428e6..0d31c2e7 100644 --- a/x/stakers/keeper/exported_functions.go +++ b/x/stakers/keeper/exported_functions.go @@ -2,7 +2,6 @@ package keeper import ( "context" - "sort" "cosmossdk.io/errors" "cosmossdk.io/math" @@ -81,39 +80,27 @@ func (k Keeper) GetActiveStakers(ctx sdk.Context) []string { return k.getAllActiveStakers(ctx) } -// GetDelegationOfPool returns the amount of how many ukyve users have delegated -// to stakers that are participating in the given pool -func (k Keeper) GetDelegationOfPool(ctx sdk.Context, poolId uint64) uint64 { - totalDelegation := uint64(0) - for _, address := range k.GetAllStakerAddressesOfPool(ctx, poolId) { - totalDelegation += k.GetValidatorPoolStake(ctx, address, poolId) - } - return totalDelegation -} - -// GetPoolTotalStake returns the amount in uykve which actively secures +// GetTotalStakeOfPool returns the amount in uykve which actively secures // the given pool -func (k Keeper) GetPoolTotalStake(ctx sdk.Context, poolId uint64) (totalStake uint64) { - effectiveStakes := k.GetEffectiveValidatorStakes(ctx, poolId) +func (k Keeper) GetTotalStakeOfPool(ctx sdk.Context, poolId uint64) (totalStake uint64) { + effectiveStakes := k.getEffectiveValidatorStakes(ctx, poolId) for _, stake := range effectiveStakes { totalStake += stake } return } -// GetTotalAndHighestDelegationOfPool iterates all validators of a given pool and returns the stake of the validator -// with the highest stake and the sum of all stakes. -func (k Keeper) GetTotalAndHighestDelegationOfPool(ctx sdk.Context, poolId uint64) (totalDelegation, highestDelegation uint64) { - for _, address := range k.GetAllStakerAddressesOfPool(ctx, poolId) { - delegation := k.GetValidatorPoolStake(ctx, address, poolId) - totalDelegation += delegation +// IsVotingPowerTooHigh returns whether there are enough validators in a pool +// to successfully stay below the max voting power +func (k Keeper) IsVotingPowerTooHigh(ctx sdk.Context, poolId uint64) bool { + addresses := int64(len(k.GetAllStakerAddressesOfPool(ctx, poolId))) + maxVotingPower := k.poolKeeper.GetMaxVotingPowerPerPool(ctx) - if delegation > highestDelegation { - highestDelegation = delegation - } + if maxVotingPower.IsZero() { + return true } - return totalDelegation, highestDelegation + return math.LegacyOneDec().Quo(maxVotingPower).GT(math.LegacyNewDec(addresses)) } // GetValidator returns the Cosmos-validator for a given kyve-address. @@ -136,21 +123,9 @@ func (k Keeper) GetValidatorPoolCommission(ctx sdk.Context, staker string, poolI return valaccount.Commission } -// GetValidatorPoolStakeFraction returns the stake fraction a validator has inside the pool -func (k Keeper) GetValidatorPoolStakeFraction(ctx sdk.Context, staker string, poolId uint64) math.LegacyDec { - valaccount, _ := k.GetValaccount(ctx, poolId, staker) - return valaccount.StakeFraction -} - -// GetValidatorPoolStake returns stake a validator has inside the pool +// GetValidatorPoolStake returns stake a validator has actively and at risk inside the pool func (k Keeper) GetValidatorPoolStake(ctx sdk.Context, staker string, poolId uint64) uint64 { - validator, found := k.GetValidator(ctx, staker) - if !found { - return 0 - } - - stakeFraction := k.GetValidatorPoolStakeFraction(ctx, staker, poolId) - return uint64(math.LegacyNewDecFromInt(validator.BondedTokens()).Mul(stakeFraction).TruncateInt64()) + return k.getEffectiveValidatorStakes(ctx, poolId, staker)[staker] } // GetOutstandingCommissionRewards returns the outstanding commission rewards for a given validator @@ -205,82 +180,6 @@ func (k Keeper) GetOutstandingRewards(orgCtx sdk.Context, staker string, delegat return util.TruncateDecCoins(rewards) } -// GetEffectiveValidatorStakes returns a map for all pool stakers their effective stake. Effective stake -// is the actual stake at risk for a validator, it can be lower than the provided stake because -// of the max voting power per pool parameter, but it can never be higher. Thus, if the effective -// stake is lower than the provided one the slash -// TODO: explain or link to formula -func (k Keeper) GetEffectiveValidatorStakes(ctx sdk.Context, poolId uint64, mustIncludeStakers ...string) (effectiveStakes map[string]uint64) { - type ValidatorStake struct { - Address string - Stake uint64 - } - - addresses := util.RemoveDuplicateStrings(append(k.GetAllStakerAddressesOfPool(ctx, poolId), mustIncludeStakers...)) - maxVotingPower := k.poolKeeper.GetMaxVotingPowerPerPool(ctx) - effectiveStakes = make(map[string]uint64) - validators := make([]ValidatorStake, 0) - totalStake := int64(0) - - for _, address := range addresses { - stake := k.GetValidatorPoolStake(ctx, address, poolId) - effectiveStakes[address] = stake - validators = append(validators, ValidatorStake{ - Address: address, - Stake: stake, - }) - totalStake += int64(stake) - } - - totalStakeRemainder := totalStake - - // sort descending based on stake - sort.Slice(validators, func(i, j int) bool { - return validators[i].Stake > validators[j].Stake - }) - - if totalStake == 0 || maxVotingPower.IsZero() { - return make(map[string]uint64) - } - - if math.LegacyOneDec().Quo(maxVotingPower).GT(math.LegacyNewDec(int64(len(addresses)))) { - return make(map[string]uint64) - } - - for i, validator := range validators { - if math.LegacyNewDec(int64(effectiveStakes[validator.Address])).GT(maxVotingPower.MulInt64(totalStake)) { - amount := math.LegacyNewDec(int64(effectiveStakes[validator.Address])).Sub(maxVotingPower.MulInt64(totalStake)).TruncateInt64() - - totalStakeRemainder -= int64(validator.Stake) - effectiveStakes[validator.Address] -= uint64(amount) - - if totalStakeRemainder > 0 { - for _, v := range validators[i+1:] { - effectiveStakes[v.Address] += uint64(math.LegacyNewDec(int64(v.Stake)).QuoInt64(totalStakeRemainder).MulInt64(amount).TruncateInt64()) - } - } - } - } - - scaleFactor := math.LegacyZeroDec() - - // get lowest validator with effective stake still bigger than zero - for i := len(validators) - 1; i >= 0; i-- { - if effectiveStakes[validators[i].Address] > 0 { - scaleFactor = math.LegacyNewDec(int64(validators[i].Stake)).QuoInt64(int64(effectiveStakes[validators[i].Address])) - break - } - } - - // scale all effective stakes down to scale factor - for _, validator := range validators { - // TODO: is rounding here fine? - effectiveStakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(effectiveStakes[validator.Address])).RoundInt64()) - } - - return -} - // Slash reduces the delegation of all delegators of `staker` by fraction. The slash itself is handled by the cosmos-sdk func (k Keeper) Slash(ctx sdk.Context, poolId uint64, staker string, slashType stakertypes.SlashType) { validator, found := k.GetValidator(ctx, staker) @@ -295,7 +194,7 @@ func (k Keeper) Slash(ctx sdk.Context, poolId uint64, staker string, slashType s stakeFraction := math.LegacyZeroDec() if !validator.GetBondedTokens().IsZero() { - stakeFraction = math.LegacyNewDec(int64(k.GetEffectiveValidatorStakes(ctx, poolId, staker)[staker])).QuoInt(validator.GetBondedTokens()) + stakeFraction = math.LegacyNewDec(int64(k.getEffectiveValidatorStakes(ctx, poolId, staker)[staker])).QuoInt(validator.GetBondedTokens()) } // the validator can only be slashed for his effective stake fraction in a pool, therefore we diff --git a/x/stakers/keeper/keeper_suite_effective_stake_test.go b/x/stakers/keeper/keeper_suite_effective_stake_test.go index 0314ead5..8697929b 100644 --- a/x/stakers/keeper/keeper_suite_effective_stake_test.go +++ b/x/stakers/keeper/keeper_suite_effective_stake_test.go @@ -21,6 +21,8 @@ TEST CASES - keeper_suite_effective_stake_test.go * Test effective stake with fewer validators than required to undercut the max pool voting power * Test effective stake with some validators having zero delegation * Test effective stake with all validators having zero delegation +* Test effective stake with 0% as max pool stake +* Test effective stake with 100% as max pool stake */ @@ -85,15 +87,15 @@ var _ = Describe("keeper_suite_effective_stake_test.go", Ordered, func() { }) // ACT - effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) // ASSERT - Expect(len(effectiveStakes)).To(Equal(3)) - Expect(effectiveStakes[i.STAKER_0]).To(Equal(100 * i.KYVE)) - Expect(effectiveStakes[i.STAKER_1]).To(Equal(100 * i.KYVE)) - Expect(effectiveStakes[i.STAKER_2]).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) - Expect(s.App().StakersKeeper.GetPoolTotalStake(s.Ctx(), 0)).To(Equal(300 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_2, 0)).To(Equal(100 * i.KYVE)) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(300 * i.KYVE)) }) It("Test effective stake with one validator above the max pool voting power", func() { @@ -128,16 +130,14 @@ var _ = Describe("keeper_suite_effective_stake_test.go", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - // ACT - effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) - // ASSERT - Expect(len(effectiveStakes)).To(Equal(3)) - Expect(effectiveStakes[i.STAKER_0]).To(Equal(100 * i.KYVE)) - Expect(effectiveStakes[i.STAKER_1]).To(Equal(200 * i.KYVE)) - Expect(effectiveStakes[i.STAKER_2]).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) - Expect(s.App().StakersKeeper.GetPoolTotalStake(s.Ctx(), 0)).To(Equal(400 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_2, 0)).To(Equal(100 * i.KYVE)) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(400 * i.KYVE)) }) It("Test effective stake with multiple validators above the max pool voting power", func() { @@ -176,16 +176,14 @@ var _ = Describe("keeper_suite_effective_stake_test.go", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - // ACT - effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) - // ASSERT - Expect(len(effectiveStakes)).To(Equal(3)) - Expect(effectiveStakes[i.STAKER_0]).To(Equal(140 * i.KYVE)) - Expect(effectiveStakes[i.STAKER_1]).To(Equal(140 * i.KYVE)) - Expect(effectiveStakes[i.STAKER_2]).To(Equal(120 * i.KYVE)) + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) + + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(140 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(140 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_2, 0)).To(Equal(120 * i.KYVE)) - Expect(s.App().StakersKeeper.GetPoolTotalStake(s.Ctx(), 0)).To(Equal(400 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(400 * i.KYVE)) }) It("Test effective stake with fewer validators than required to undercut the max pool voting power", func() { @@ -224,12 +222,10 @@ var _ = Describe("keeper_suite_effective_stake_test.go", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - // ACT - effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) - // ASSERT - Expect(len(effectiveStakes)).To(BeZero()) - Expect(s.App().StakersKeeper.GetPoolTotalStake(s.Ctx(), 0)).To(BeZero()) + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeTrue()) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(BeZero()) }) It("Test effective stake with some validators having zero delegation", func() { @@ -264,16 +260,14 @@ var _ = Describe("keeper_suite_effective_stake_test.go", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - // ACT - effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) - // ASSERT - Expect(len(effectiveStakes)).To(Equal(3)) - Expect(effectiveStakes[i.STAKER_0]).To(Equal(100 * i.KYVE)) - Expect(effectiveStakes[i.STAKER_1]).To(Equal(0 * i.KYVE)) - Expect(effectiveStakes[i.STAKER_2]).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) - Expect(s.App().StakersKeeper.GetPoolTotalStake(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(0 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_2, 0)).To(Equal(100 * i.KYVE)) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) }) It("Test effective stake with all validators having zero delegation", func() { @@ -308,11 +302,75 @@ var _ = Describe("keeper_suite_effective_stake_test.go", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - // ACT - effectiveStakes := s.App().StakersKeeper.GetEffectiveValidatorStakes(s.Ctx(), 0) + // ASSERT + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(BeZero()) + }) + + It("Test effective stake with 0% as max pool stake", func() { + // ARRANGE + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("0") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) // ASSERT - Expect(len(effectiveStakes)).To(BeZero()) - Expect(s.App().StakersKeeper.GetPoolTotalStake(s.Ctx(), 0)).To(BeZero()) + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeTrue()) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(BeZero()) + }) + + It("Test effective stake with 100% as max pool stake", func() { + // ARRANGE + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("1") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // ASSERT + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) + + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(100 * i.KYVE)) }) }) diff --git a/x/stakers/keeper/logic_stakers.go b/x/stakers/keeper/logic_stakers.go index 22009d1f..2cff35ee 100644 --- a/x/stakers/keeper/logic_stakers.go +++ b/x/stakers/keeper/logic_stakers.go @@ -2,6 +2,7 @@ package keeper import ( m "math" + "sort" "cosmossdk.io/math" @@ -15,6 +16,85 @@ import ( errorsTypes "github.com/cosmos/cosmos-sdk/types/errors" ) +// getEffectiveValidatorStakes returns a map for all pool stakers their effective stake. Effective stake +// is the actual stake at risk for a validator, it can be lower than the provided stake because +// of the max voting power per pool parameter, but it can never be higher. Thus, if the effective +// stake is lower than the provided one the slash +// TODO: explain or link to formula +func (k Keeper) getEffectiveValidatorStakes(ctx sdk.Context, poolId uint64, mustIncludeStakers ...string) (effectiveStakes map[string]uint64) { + type ValidatorStake struct { + Address string + Stake uint64 + } + + addresses := util.RemoveDuplicateStrings(append(k.GetAllStakerAddressesOfPool(ctx, poolId), mustIncludeStakers...)) + maxVotingPower := k.poolKeeper.GetMaxVotingPowerPerPool(ctx) + effectiveStakes = make(map[string]uint64) + validators := make([]ValidatorStake, 0) + totalStake := int64(0) + + for _, address := range addresses { + validator, _ := k.GetValidator(ctx, address) + valaccount, _ := k.GetValaccount(ctx, poolId, address) + stake := uint64(valaccount.StakeFraction.MulInt(validator.GetBondedTokens()).TruncateInt64()) + + effectiveStakes[address] = stake + validators = append(validators, ValidatorStake{ + Address: address, + Stake: stake, + }) + totalStake += int64(stake) + } + + totalStakeRemainder := totalStake + + // sort descending based on stake + sort.Slice(validators, func(i, j int) bool { + return validators[i].Stake > validators[j].Stake + }) + + if totalStake == 0 || maxVotingPower.IsZero() { + return make(map[string]uint64) + } + + if math.LegacyOneDec().Quo(maxVotingPower).GT(math.LegacyNewDec(int64(len(addresses)))) { + return make(map[string]uint64) + } + + for i, validator := range validators { + if math.LegacyNewDec(int64(effectiveStakes[validator.Address])).GT(maxVotingPower.MulInt64(totalStake)) { + amount := math.LegacyNewDec(int64(effectiveStakes[validator.Address])).Sub(maxVotingPower.MulInt64(totalStake)).TruncateInt64() + + totalStakeRemainder -= int64(validator.Stake) + effectiveStakes[validator.Address] -= uint64(amount) + + if totalStakeRemainder > 0 { + for _, v := range validators[i+1:] { + effectiveStakes[v.Address] += uint64(math.LegacyNewDec(int64(v.Stake)).QuoInt64(totalStakeRemainder).MulInt64(amount).TruncateInt64()) + } + } + } + } + + scaleFactor := math.LegacyZeroDec() + + // get lowest validator with effective stake still bigger than zero + for i := len(validators) - 1; i >= 0; i-- { + if effectiveStakes[validators[i].Address] > 0 { + scaleFactor = math.LegacyNewDec(int64(validators[i].Stake)).QuoInt64(int64(effectiveStakes[validators[i].Address])) + break + } + } + + // scale all effective stakes down to scale factor + for _, validator := range validators { + // TODO: is rounding here fine? + effectiveStakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(effectiveStakes[validator.Address])).RoundInt64()) + } + + return +} + // getLowestStaker returns the staker with the lowest total stake // (self-delegation + delegation) of a given pool. // If all pool slots are taken, this is the staker who then @@ -23,9 +103,9 @@ func (k Keeper) getLowestStaker(ctx sdk.Context, poolId uint64) (val stakingType var minAmount uint64 = m.MaxUint64 for _, staker := range k.getAllStakersOfPool(ctx, poolId) { - delegationAmount := k.GetValidatorPoolStake(ctx, util.MustAccountAddressFromValAddress(staker.OperatorAddress), poolId) - if delegationAmount < minAmount { - minAmount = delegationAmount + stake := k.GetValidatorPoolStake(ctx, util.MustAccountAddressFromValAddress(staker.OperatorAddress), poolId) + if stake < minAmount { + minAmount = stake val = staker } } diff --git a/x/stakers/keeper/msg_server_join_pool_test.go b/x/stakers/keeper/msg_server_join_pool_test.go index 85d7f519..92f7ffbd 100644 --- a/x/stakers/keeper/msg_server_join_pool_test.go +++ b/x/stakers/keeper/msg_server_join_pool_test.go @@ -71,6 +71,10 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { } s.RunTxPoolSuccess(msg) + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("1") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) @@ -124,7 +128,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(HaveLen(1)) - totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + totalStakeOfPool := s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) @@ -178,7 +182,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(HaveLen(0)) - totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 1) + totalStakeOfPool := s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 1) Expect(totalStakeOfPool).To(Equal(0 * i.KYVE)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 1)).To(Equal(0 * i.KYVE)) @@ -234,7 +238,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(HaveLen(2)) - totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + totalStakeOfPool := s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(200 * i.KYVE)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) @@ -252,7 +256,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + totalStakeOfPool := s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) // ACT @@ -281,7 +285,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(HaveLen(1)) - totalStakeOfPool = s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + totalStakeOfPool = s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(150 * i.KYVE)) @@ -576,7 +580,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(HaveLen(1)) - totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + totalStakeOfPool := s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) @@ -619,7 +623,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(HaveLen(1)) - totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + totalStakeOfPool := s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) @@ -686,7 +690,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { } // STAKER_0 is lowest staker and all stakers are full now. - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) s.CreateValidator(i.STAKER_1, "Staker-1", int64(150*i.KYVE)) @@ -701,7 +705,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { }) // Assert - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal((150*49 + 150) * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal((150*49 + 150) * i.KYVE)) Expect(s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0)).ToNot(ContainElement(i.STAKER_0)) }) @@ -731,7 +735,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { } // STAKER_0 is lowest staker and all stakers are full now. - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) s.CreateValidator(i.STAKER_1, "Staker-1", int64(50*i.KYVE)) @@ -746,7 +750,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { }) // Assert - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) Expect(s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0)).To(ContainElement(i.STAKER_0)) Expect(s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0)).ToNot(ContainElement(i.STAKER_1)) }) @@ -777,7 +781,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { } // Alice is lowest staker and all stakers are full now. - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) s.CreateValidator(i.STAKER_1, "Staker-1", int64(150*i.KYVE)) @@ -798,7 +802,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { }) // ASSERT - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal((150*49 + 250) * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal((150*49 + 250) * i.KYVE)) Expect(s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0)).To(ContainElement(i.STAKER_0)) Expect(s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0)).NotTo(ContainElement(i.STAKER_1)) }) @@ -829,7 +833,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { } // STAKER_0 is lowest staker and all stakers are full now. - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) s.CreateValidator(i.STAKER_1, "Staker-1", int64(50*i.KYVE)) @@ -844,7 +848,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { }) // Assert - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) Expect(s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0)).To(ContainElement(i.STAKER_0)) Expect(s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0)).ToNot(ContainElement(i.STAKER_1)) }) @@ -875,7 +879,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { } // Alice is lowest staker and all stakers are full now. - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) s.CreateValidator(i.STAKER_1, "Staker-1", int64(50*i.KYVE)) @@ -896,7 +900,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { }) // ASSERT - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal((150*49 + 100) * i.KYVE)) Expect(s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0)).To(ContainElement(i.STAKER_0)) Expect(s.App().StakersKeeper.GetAllStakerAddressesOfPool(s.Ctx(), 0)).NotTo(ContainElement(i.STAKER_1)) }) @@ -961,7 +965,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(HaveLen(1)) - totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + totalStakeOfPool := s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) @@ -1031,7 +1035,7 @@ var _ = Describe("msg_server_join_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(HaveLen(1)) - totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + totalStakeOfPool := s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) diff --git a/x/stakers/keeper/msg_server_leave_pool_test.go b/x/stakers/keeper/msg_server_leave_pool_test.go index 80e5bfad..ca33d3e5 100644 --- a/x/stakers/keeper/msg_server_leave_pool_test.go +++ b/x/stakers/keeper/msg_server_leave_pool_test.go @@ -43,6 +43,10 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { // create staker s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("1") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + // join pool s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ Creator: i.STAKER_0, @@ -86,7 +90,7 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(HaveLen(1)) - totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + totalStakeOfPool := s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) @@ -110,7 +114,7 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(BeEmpty()) - totalStakeOfPool = s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + totalStakeOfPool = s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(BeZero()) // check if commission and stake fraction is still available @@ -159,7 +163,7 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(HaveLen(2)) - totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + totalStakeOfPool := s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(200 * i.KYVE)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) @@ -183,7 +187,7 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(HaveLen(1)) - totalStakeOfPool = s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0) + totalStakeOfPool = s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) // check if commission and stake fraction is still available @@ -264,7 +268,7 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(HaveLen(1)) - totalStakeOfPool := s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 1) + totalStakeOfPool := s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 1) Expect(totalStakeOfPool).To(Equal(100 * i.KYVE)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(totalStakeOfPool)) @@ -286,7 +290,7 @@ var _ = Describe("msg_server_leave_pool.go", Ordered, func() { Expect(valaccountsOfPool).To(BeEmpty()) - totalStakeOfPool = s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 1) + totalStakeOfPool = s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 1) Expect(totalStakeOfPool).To(BeZero()) // check if commission and stake fraction is still available diff --git a/x/stakers/keeper/msg_server_update_stake_fraction_test.go b/x/stakers/keeper/msg_server_update_stake_fraction_test.go index e406f7a9..afb76ea5 100644 --- a/x/stakers/keeper/msg_server_update_stake_fraction_test.go +++ b/x/stakers/keeper/msg_server_update_stake_fraction_test.go @@ -50,6 +50,10 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { } s.RunTxPoolSuccess(msg) + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("1") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ @@ -71,7 +75,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) }) It("Increase stake fraction to 50% from previous stake fraction", func() { @@ -87,7 +91,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(50 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) }) It("Decrease stake fraction to 0% from previous stake fraction", func() { @@ -111,7 +115,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(BeZero()) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(BeZero()) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(BeZero()) }) It("Decrease stake fraction to 1% from previous stake fraction", func() { @@ -127,7 +131,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) // wait for update s.CommitAfterSeconds(s.App().StakersKeeper.GetStakeFractionChangeTime(s.Ctx())) @@ -136,7 +140,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.01"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(1 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(1 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(1 * i.KYVE)) }) It("Increase stake fraction to 100% from previous stake fraction", func() { @@ -152,7 +156,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("1"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(100 * i.KYVE)) }) It("Update stake fraction to same value from previous stake fraction", func() { @@ -168,7 +172,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) }) It("Update stake fraction with a negative number from previous stake fraction", func() { @@ -184,7 +188,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) }) It("Update stake fraction with a too high number from previous stake fraction during change time", func() { @@ -200,7 +204,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) }) It("Increase stake fraction after stake fraction has been decreased before during change time", func() { @@ -223,7 +227,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.2"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(20 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(20 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(20 * i.KYVE)) // wait for update s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) @@ -232,7 +236,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.2"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(20 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(20 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(20 * i.KYVE)) }) It("Decrease stake fraction after stake fraction has been decreased before during change time", func() { @@ -255,7 +259,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) // wait for update s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) @@ -264,7 +268,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.01"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(1 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(1 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(1 * i.KYVE)) }) It("Decrease stake fraction after stake fraction has been increased before", func() { @@ -278,7 +282,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(50 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) s.PerformValidityChecks() @@ -293,7 +297,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(50 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) // wait for update s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) @@ -302,7 +306,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.02"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(2 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(2 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(2 * i.KYVE)) }) It("Update stake fraction with multiple pools", func() { @@ -344,12 +348,12 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount0, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount0.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(50 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) valaccount1, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) Expect(valaccount1.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 1)).To(Equal(10 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 1)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 1)).To(Equal(10 * i.KYVE)) // wait for update s.CommitAfterSeconds(s.App().StakersKeeper.GetCommissionChangeTime(s.Ctx())) @@ -358,12 +362,12 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount0, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount0.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.5"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(50 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(50 * i.KYVE)) valaccount1, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 1, i.STAKER_0) Expect(valaccount1.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.03"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 1)).To(Equal(3 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 1)).To(Equal(3 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 1)).To(Equal(3 * i.KYVE)) }) It("Validator stake increases while stake fraction stays the same", func() { @@ -371,7 +375,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) // ACT s.SelfDelegateValidator(i.STAKER_0, 50*i.KYVE) @@ -380,7 +384,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(15 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(15 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(15 * i.KYVE)) }) It("Validator stake decreases while stake fraction stays the same", func() { @@ -388,7 +392,7 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(10 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(10 * i.KYVE)) // ACT s.SelfUndelegateValidator(i.STAKER_0, 50*i.KYVE) @@ -402,6 +406,6 @@ var _ = Describe("msg_server_update_stake_fraction.go", Ordered, func() { valaccount, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccount.StakeFraction).To(Equal(math.LegacyMustNewDecFromStr("0.1"))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(5 * i.KYVE)) - Expect(s.App().StakersKeeper.GetDelegationOfPool(s.Ctx(), 0)).To(Equal(5 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(5 * i.KYVE)) }) }) From dd4b9622273771137eda8c2d0cf0961263e4f6b3 Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Tue, 17 Dec 2024 16:44:30 +0100 Subject: [PATCH 09/15] chore: export effective stake method --- x/bundles/keeper/logic_bundles.go | 10 +- x/bundles/types/expected_keepers.go | 1 + x/stakers/keeper/exported_functions.go | 135 ++++++++++- .../keeper_suite_effective_stake_test.go | 217 ++++++++++++++++++ x/stakers/keeper/logic_stakers.go | 80 ------- x/stakers/keeper/msg_server_join_pool.go | 2 - 6 files changed, 354 insertions(+), 91 deletions(-) diff --git a/x/bundles/keeper/logic_bundles.go b/x/bundles/keeper/logic_bundles.go index cfa4a035..e2a18130 100644 --- a/x/bundles/keeper/logic_bundles.go +++ b/x/bundles/keeper/logic_bundles.go @@ -497,24 +497,26 @@ func (k Keeper) GetVoteDistribution(ctx sdk.Context, poolId uint64) (voteDistrib return } + stakes := k.stakerKeeper.GetValidatorPoolStakes(ctx, poolId) + // get voting power for valid for _, voter := range bundleProposal.VotersValid { - voteDistribution.Valid += k.stakerKeeper.GetValidatorPoolStake(ctx, voter, poolId) + voteDistribution.Valid += stakes[voter] } // get voting power for invalid for _, voter := range bundleProposal.VotersInvalid { - voteDistribution.Invalid += k.stakerKeeper.GetValidatorPoolStake(ctx, voter, poolId) + voteDistribution.Invalid += stakes[voter] } // get voting power for abstain for _, voter := range bundleProposal.VotersAbstain { - voteDistribution.Abstain += k.stakerKeeper.GetValidatorPoolStake(ctx, voter, poolId) + voteDistribution.Abstain += stakes[voter] } // get total voting power for _, staker := range k.stakerKeeper.GetAllStakerAddressesOfPool(ctx, poolId) { - voteDistribution.Total += k.stakerKeeper.GetValidatorPoolStake(ctx, staker, poolId) + voteDistribution.Total += stakes[staker] } if voteDistribution.Total == 0 { diff --git a/x/bundles/types/expected_keepers.go b/x/bundles/types/expected_keepers.go index 7a667f46..e4d64802 100644 --- a/x/bundles/types/expected_keepers.go +++ b/x/bundles/types/expected_keepers.go @@ -42,6 +42,7 @@ type StakerKeeper interface { GetValidatorPoolCommission(ctx sdk.Context, staker string, poolId uint64) math.LegacyDec GetValidatorPoolStake(ctx sdk.Context, staker string, poolId uint64) uint64 GetTotalStakeOfPool(ctx sdk.Context, poolId uint64) (totalStake uint64) + GetValidatorPoolStakes(ctx sdk.Context, poolId uint64, mustIncludeStakers ...string) map[string]uint64 IsVotingPowerTooHigh(ctx sdk.Context, poolId uint64) bool Slash(ctx sdk.Context, poolId uint64, staker string, slashType stakersTypes.SlashType) PayoutRewards(ctx sdk.Context, staker string, amount sdk.Coins, payerModuleName string) error diff --git a/x/stakers/keeper/exported_functions.go b/x/stakers/keeper/exported_functions.go index 0d31c2e7..0a8e02f0 100644 --- a/x/stakers/keeper/exported_functions.go +++ b/x/stakers/keeper/exported_functions.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "sort" "cosmossdk.io/errors" "cosmossdk.io/math" @@ -83,7 +84,7 @@ func (k Keeper) GetActiveStakers(ctx sdk.Context) []string { // GetTotalStakeOfPool returns the amount in uykve which actively secures // the given pool func (k Keeper) GetTotalStakeOfPool(ctx sdk.Context, poolId uint64) (totalStake uint64) { - effectiveStakes := k.getEffectiveValidatorStakes(ctx, poolId) + effectiveStakes := k.GetValidatorPoolStakes(ctx, poolId) for _, stake := range effectiveStakes { totalStake += stake } @@ -125,7 +126,129 @@ func (k Keeper) GetValidatorPoolCommission(ctx sdk.Context, staker string, poolI // GetValidatorPoolStake returns stake a validator has actively and at risk inside the pool func (k Keeper) GetValidatorPoolStake(ctx sdk.Context, staker string, poolId uint64) uint64 { - return k.getEffectiveValidatorStakes(ctx, poolId, staker)[staker] + return k.GetValidatorPoolStakes(ctx, poolId, staker)[staker] +} + +// GetValidatorPoolStakes returns a map for all pool validators with their effective stake. Effective stake +// is the actual amount which determines the validator's voting power and is the actual amount at risk for +// slashing. The effective stake can be lower (never higher) than the specified stake by the validators by +// his stake fraction because of the maximum voting power which limits the voting power a validator can have +// in a pool. +// +// We limit the voting power by first sorting all validators based on their stake and start at the highest. From +// there we check if this validator exceeds the voting power with his stake, if he does we cut off an amount +// from his stake and redistribute it to all the validators below him based on their stakes. Because we are simply +// redistributing exact amounts we do not need to worry about changing the total stake which would mess up voting +// powers of other validators again. After this has been repeated for every validator that exceeds the max voting +// power we finally scale down all stakes to the lowest validator's stake. This is because the top validators lost +// stake and the lowest validators gained stake, but because it is not allowed to risk more than specified so we scale +// everything down accordingly. This results in a stake distribution where every validator who was below the max +// voting power has the same effective stake as his dedicated stake and those validators who where above it have +// less effective stake. +func (k Keeper) GetValidatorPoolStakes(ctx sdk.Context, poolId uint64, mustIncludeStakers ...string) map[string]uint64 { + type ValidatorStake struct { + Address string + Stake uint64 + } + + validators := make([]ValidatorStake, 0) + stakes := make(map[string]uint64) + + // we include given stakers since in some instances the staker we are looking for has been already kicked + // out of a pool, but we still need to payout rewards or slash him afterward depending on his last action + // right before leaving the pool + addresses := util.RemoveDuplicateStrings(append(k.GetAllStakerAddressesOfPool(ctx, poolId), mustIncludeStakers...)) + maxVotingPower := k.poolKeeper.GetMaxVotingPowerPerPool(ctx) + + // it is impossible regardless how many validators are in a pool to have a max voting power of 0%, + // therefore we return here + if maxVotingPower.IsZero() { + return stakes + } + + // if there are not enough validators in a pool so that the max voting power is always + // exceeded by at least one validator we return + if math.LegacyOneDec().Quo(maxVotingPower).GT(math.LegacyNewDec(int64(len(addresses)))) { + return stakes + } + + totalStake := int64(0) + + for _, address := range addresses { + validator, _ := k.GetValidator(ctx, address) + valaccount, _ := k.GetValaccount(ctx, poolId, address) + + // calculate the stake the validator has specifically chosen for this pool + // with his stake fraction + stake := uint64(valaccount.StakeFraction.MulInt(validator.GetBondedTokens()).TruncateInt64()) + + stakes[address] = stake + validators = append(validators, ValidatorStake{ + Address: address, + Stake: stake, + }) + totalStake += int64(stake) + } + + totalStakeRemainder := totalStake + + // sort descending based on stake + sort.Slice(validators, func(i, j int) bool { + return validators[i].Stake > validators[j].Stake + }) + + // if the total stake of the pool is zero we return + if totalStake == 0 { + return stakes + } + + for i, validator := range validators { + // check if the validator has a higher stake than allowed by the max voting power + if math.LegacyNewDec(int64(stakes[validator.Address])).GT(maxVotingPower.MulInt64(totalStake)) { + // if the validator got a stake which would give him a higher voting power than the maximum allowed + // one we cut off the exact amount from his stake so that he is just below the max voting power + cutoffAmount := math.LegacyNewDec(int64(stakes[validator.Address])).Sub(maxVotingPower.MulInt64(totalStake)).TruncateInt64() + + totalStakeRemainder -= int64(validator.Stake) + stakes[validator.Address] -= uint64(cutoffAmount) + + // we take the cutoff amount and distribute it on the remaining validators down the list + // who all have less voting power than the current one. We distribute the cutoff amount + // based on the validator's stake + if totalStakeRemainder > 0 { + for _, v := range validators[i+1:] { + stakes[v.Address] += uint64(math.LegacyNewDec(int64(v.Stake)).QuoInt64(totalStakeRemainder).MulInt64(cutoffAmount).TruncateInt64()) + } + } + } + } + + // after we have redistributed all cutoff amounts so that no validator exceeds the maximum voting power + // based on their remaining effective stake we now scale the stakes to get the true effective staking amount. + // This is because while the top validators who got their voting power reduced the lower validators have actually + // gained voting power relatively. But because their effective stake is now bigger than their allocated stake + // we have to scale it down again, because we are not allowed to slash more than the validator has allocated in + // this particular pool. Therefore, we take the stake of the lowest validator (with a bigger stake than 0) and scale + // down all stakes of all other validators to that accordingly + scaleFactor := math.LegacyZeroDec() + + // get the lowest validator with effective stake still bigger than zero and determine the scale factor + for i := len(validators) - 1; i >= 0; i-- { + if stakes[validators[i].Address] > 0 { + scaleFactor = math.LegacyNewDec(int64(validators[i].Stake)).QuoInt64(int64(stakes[validators[i].Address])) + break + } + } + + // scale all effective stakes down to scale factor + for _, validator := range validators { + stakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(stakes[validator.Address])).RoundInt64()) + } + + // the result is a map which contains the effective stake for every validator in a pool. The effective stake + // can not be higher than the dedicated stake specified by the validator by his stake fraction, therefore it + // represents the true amount of $KYVE which is at risk for slashing + return stakes } // GetOutstandingCommissionRewards returns the outstanding commission rewards for a given validator @@ -189,12 +312,14 @@ func (k Keeper) Slash(ctx sdk.Context, poolId uint64, staker string, slashType s consAddrBytes, _ := validator.GetConsAddr() - // get real stake fraction from the effective stake which is truly at risk for getting slashed - // by dividing it with the total bonded stake from the validator + // here the stake fraction can be actually different from the stake fraction the validator has specified + // for this pool because with the max voting power in place his effective stake in a pool could have been + // reduced because his original stake was too high. Therefore, we determine the true stake fraction + // by dividing his effective stake with his bonded amount. stakeFraction := math.LegacyZeroDec() if !validator.GetBondedTokens().IsZero() { - stakeFraction = math.LegacyNewDec(int64(k.getEffectiveValidatorStakes(ctx, poolId, staker)[staker])).QuoInt(validator.GetBondedTokens()) + stakeFraction = math.LegacyNewDec(int64(k.GetValidatorPoolStake(ctx, staker, poolId))).QuoInt(validator.GetBondedTokens()) } // the validator can only be slashed for his effective stake fraction in a pool, therefore we diff --git a/x/stakers/keeper/keeper_suite_effective_stake_test.go b/x/stakers/keeper/keeper_suite_effective_stake_test.go index 8697929b..991b7d41 100644 --- a/x/stakers/keeper/keeper_suite_effective_stake_test.go +++ b/x/stakers/keeper/keeper_suite_effective_stake_test.go @@ -23,6 +23,11 @@ TEST CASES - keeper_suite_effective_stake_test.go * Test effective stake with all validators having zero delegation * Test effective stake with 0% as max pool stake * Test effective stake with 100% as max pool stake +* Test effective stake with all validators below the max pool voting power due to stake fractions +* Test effective stake with one validator above the max pool voting power due to stake fractions +* Test effective stake with multiple validators above the max pool voting power due to stake fractions +* Test effective stake with some validators having zero delegation due to stake fractions +* Test effective stake with all validators having zero delegation due to stake fractions */ @@ -373,4 +378,216 @@ var _ = Describe("keeper_suite_effective_stake_test.go", Ordered, func() { Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(100 * i.KYVE)) }) + + It("Test effective stake with all validators below the max pool voting power due to stake fractions", func() { + // ARRANGE + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(200*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.5"), + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(500*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.2"), + }) + + // ACT + + // ASSERT + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) + + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_2, 0)).To(Equal(100 * i.KYVE)) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(300 * i.KYVE)) + }) + + It("Test effective stake with one validator above the max pool voting power due to stake fractions", func() { + // ARRANGE + s.CreateValidator(i.STAKER_0, "Staker-0", int64(200*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.5"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(300*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.9"), + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(500*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.2"), + }) + + // ASSERT + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) + + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_2, 0)).To(Equal(100 * i.KYVE)) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(400 * i.KYVE)) + }) + + It("Test effective stake with multiple validators above the max pool voting power due to stake fractions", func() { + // ARRANGE + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("0.35") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.8"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.7"), + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.2"), + }) + + // ASSERT + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) + + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(uint64(23333333334))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(uint64(23333333334))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_2, 0)).To(Equal(20 * i.KYVE)) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(uint64(66666666668))) + }) + + It("Test effective stake with some validators having zero delegation due to stake fractions", func() { + // ARRANGE + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0"), + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(200*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.5"), + }) + + // ASSERT + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) + + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(0 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_2, 0)).To(Equal(100 * i.KYVE)) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + }) + + It("Test effective stake with all validators having zero delegation due to stake fractions", func() { + // ARRANGE + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0"), + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) + s.RunTxStakersSuccess(&stakerstypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Amount: 100 * i.KYVE, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0"), + }) + + // ASSERT + Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(BeZero()) + }) }) diff --git a/x/stakers/keeper/logic_stakers.go b/x/stakers/keeper/logic_stakers.go index 2cff35ee..1d888b25 100644 --- a/x/stakers/keeper/logic_stakers.go +++ b/x/stakers/keeper/logic_stakers.go @@ -2,7 +2,6 @@ package keeper import ( m "math" - "sort" "cosmossdk.io/math" @@ -16,85 +15,6 @@ import ( errorsTypes "github.com/cosmos/cosmos-sdk/types/errors" ) -// getEffectiveValidatorStakes returns a map for all pool stakers their effective stake. Effective stake -// is the actual stake at risk for a validator, it can be lower than the provided stake because -// of the max voting power per pool parameter, but it can never be higher. Thus, if the effective -// stake is lower than the provided one the slash -// TODO: explain or link to formula -func (k Keeper) getEffectiveValidatorStakes(ctx sdk.Context, poolId uint64, mustIncludeStakers ...string) (effectiveStakes map[string]uint64) { - type ValidatorStake struct { - Address string - Stake uint64 - } - - addresses := util.RemoveDuplicateStrings(append(k.GetAllStakerAddressesOfPool(ctx, poolId), mustIncludeStakers...)) - maxVotingPower := k.poolKeeper.GetMaxVotingPowerPerPool(ctx) - effectiveStakes = make(map[string]uint64) - validators := make([]ValidatorStake, 0) - totalStake := int64(0) - - for _, address := range addresses { - validator, _ := k.GetValidator(ctx, address) - valaccount, _ := k.GetValaccount(ctx, poolId, address) - stake := uint64(valaccount.StakeFraction.MulInt(validator.GetBondedTokens()).TruncateInt64()) - - effectiveStakes[address] = stake - validators = append(validators, ValidatorStake{ - Address: address, - Stake: stake, - }) - totalStake += int64(stake) - } - - totalStakeRemainder := totalStake - - // sort descending based on stake - sort.Slice(validators, func(i, j int) bool { - return validators[i].Stake > validators[j].Stake - }) - - if totalStake == 0 || maxVotingPower.IsZero() { - return make(map[string]uint64) - } - - if math.LegacyOneDec().Quo(maxVotingPower).GT(math.LegacyNewDec(int64(len(addresses)))) { - return make(map[string]uint64) - } - - for i, validator := range validators { - if math.LegacyNewDec(int64(effectiveStakes[validator.Address])).GT(maxVotingPower.MulInt64(totalStake)) { - amount := math.LegacyNewDec(int64(effectiveStakes[validator.Address])).Sub(maxVotingPower.MulInt64(totalStake)).TruncateInt64() - - totalStakeRemainder -= int64(validator.Stake) - effectiveStakes[validator.Address] -= uint64(amount) - - if totalStakeRemainder > 0 { - for _, v := range validators[i+1:] { - effectiveStakes[v.Address] += uint64(math.LegacyNewDec(int64(v.Stake)).QuoInt64(totalStakeRemainder).MulInt64(amount).TruncateInt64()) - } - } - } - } - - scaleFactor := math.LegacyZeroDec() - - // get lowest validator with effective stake still bigger than zero - for i := len(validators) - 1; i >= 0; i-- { - if effectiveStakes[validators[i].Address] > 0 { - scaleFactor = math.LegacyNewDec(int64(validators[i].Stake)).QuoInt64(int64(effectiveStakes[validators[i].Address])) - break - } - } - - // scale all effective stakes down to scale factor - for _, validator := range validators { - // TODO: is rounding here fine? - effectiveStakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(effectiveStakes[validator.Address])).RoundInt64()) - } - - return -} - // getLowestStaker returns the staker with the lowest total stake // (self-delegation + delegation) of a given pool. // If all pool slots are taken, this is the staker who then diff --git a/x/stakers/keeper/msg_server_join_pool.go b/x/stakers/keeper/msg_server_join_pool.go index c745550d..0764430b 100644 --- a/x/stakers/keeper/msg_server_join_pool.go +++ b/x/stakers/keeper/msg_server_join_pool.go @@ -76,8 +76,6 @@ func (k msgServer) JoinPool(goCtx context.Context, msg *types.MsgJoinPool) (*typ } } - // TODO: check here if validator with his stake fraction is over the maximum join limit - k.AddValaccountToPool(ctx, msg.PoolId, msg.Creator, msg.Valaddress, msg.Commission, msg.StakeFraction) if err := util.TransferFromAddressToAddress(k.bankKeeper, ctx, msg.Creator, msg.Valaddress, msg.Amount); err != nil { From 28de85bac596335c562e0b5b1417d2578a503889 Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Tue, 17 Dec 2024 16:56:34 +0100 Subject: [PATCH 10/15] test: round robin with stake fractions and max voting power --- x/bundles/keeper/logic_round_robin_test.go | 94 +++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/x/bundles/keeper/logic_round_robin_test.go b/x/bundles/keeper/logic_round_robin_test.go index 040005b4..bd5229c8 100644 --- a/x/bundles/keeper/logic_round_robin_test.go +++ b/x/bundles/keeper/logic_round_robin_test.go @@ -22,6 +22,8 @@ TEST CASES - logic_bundles.go * Empty round-robin set * Partially filled round-robin set (one staker with 0 delegation) * Frequency analysis +* Frequency analysis with stake fractions +* Frequency analysis with maximum voting power cap * Frequency analysis (rounding) * Frequency analysis (excluded) * Exclude everybody @@ -32,6 +34,10 @@ TEST CASES - logic_bundles.go */ func joinDummy(s *i.KeeperTestSuite, index, kyveAmount uint64) { + joinDummyWithStakeFraction(s, index, kyveAmount, math.LegacyOneDec()) +} + +func joinDummyWithStakeFraction(s *i.KeeperTestSuite, index, kyveAmount uint64, stakeFraction math.LegacyDec) { s.CreateValidator(i.DUMMY[index], fmt.Sprintf("dummy-%d", index), int64(kyveAmount*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ @@ -40,7 +46,7 @@ func joinDummy(s *i.KeeperTestSuite, index, kyveAmount uint64) { Valaddress: i.VALDUMMY[index], Amount: 0, Commission: math.LegacyMustNewDecFromStr("0.1"), - StakeFraction: math.LegacyMustNewDecFromStr("1"), + StakeFraction: stakeFraction, }) } @@ -94,6 +100,10 @@ var _ = Describe("logic_round_robin.go", Ordered, func() { Duration: 60, } s.App().PoolKeeper.SetPool(s.Ctx(), pool) + + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("1") + s.App().PoolKeeper.SetParams(s.Ctx(), params) }) AfterEach(func() { @@ -182,6 +192,87 @@ var _ = Describe("logic_round_robin.go", Ordered, func() { It("Frequency analysis", func() { // ARRANGE + joinDummy(s, 0, 2) + joinDummy(s, 1, 31) + joinDummy(s, 2, 67) + + // ACT + rrvs := s.App().BundlesKeeper.LoadRoundRobinValidatorSet(s.Ctx(), 0) + + frequency1 := make(map[string]int, 0) + for i := 0; i < 10; i++ { + frequency1[rrvs.NextProposer()] += 1 + } + + frequency2 := make(map[string]int, 0) + for i := 0; i < 100; i++ { + frequency2[rrvs.NextProposer()] += 1 + } + + frequency3 := make(map[string]int, 0) + for i := 0; i < 100000; i++ { + frequency3[rrvs.NextProposer()] += 1 + } + + // ASSERT + + Expect(frequency1[i.DUMMY[0]]).To(Equal(0)) + Expect(frequency1[i.DUMMY[1]]).To(Equal(3)) + Expect(frequency1[i.DUMMY[2]]).To(Equal(7)) + + Expect(frequency2[i.DUMMY[0]]).To(Equal(2)) + Expect(frequency2[i.DUMMY[1]]).To(Equal(31)) + Expect(frequency2[i.DUMMY[2]]).To(Equal(67)) + + Expect(frequency3[i.DUMMY[0]]).To(Equal(2000)) + Expect(frequency3[i.DUMMY[1]]).To(Equal(31000)) + Expect(frequency3[i.DUMMY[2]]).To(Equal(67000)) + }) + + It("Frequency analysis with stake fractions", func() { + // ARRANGE + joinDummyWithStakeFraction(s, 0, 100, math.LegacyMustNewDecFromStr("0")) + joinDummyWithStakeFraction(s, 1, 100, math.LegacyMustNewDecFromStr("0.5")) + joinDummyWithStakeFraction(s, 2, 100, math.LegacyMustNewDecFromStr("1")) + + // ACT + rrvs := s.App().BundlesKeeper.LoadRoundRobinValidatorSet(s.Ctx(), 0) + + frequency1 := make(map[string]int, 0) + for i := 0; i < 10; i++ { + frequency1[rrvs.NextProposer()] += 1 + } + + frequency2 := make(map[string]int, 0) + for i := 0; i < 100; i++ { + frequency2[rrvs.NextProposer()] += 1 + } + + frequency3 := make(map[string]int, 0) + for i := 0; i < 100000; i++ { + frequency3[rrvs.NextProposer()] += 1 + } + + // ASSERT + Expect(frequency1[i.DUMMY[0]]).To(Equal(0)) + Expect(frequency1[i.DUMMY[1]]).To(Equal(3)) + Expect(frequency1[i.DUMMY[2]]).To(Equal(7)) + + Expect(frequency2[i.DUMMY[0]]).To(Equal(0)) + Expect(frequency2[i.DUMMY[1]]).To(Equal(34)) + Expect(frequency2[i.DUMMY[2]]).To(Equal(66)) + + Expect(frequency3[i.DUMMY[0]]).To(Equal(0)) + Expect(frequency3[i.DUMMY[1]]).To(Equal(33333)) + Expect(frequency3[i.DUMMY[2]]).To(Equal(66667)) + }) + + It("Frequency analysis with maximum voting power cap", func() { + // ARRANGE + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("0.5") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + // NOTE that dummy with index 2 has more than 50% voting power, so his effective stake // will be lower joinDummy(s, 0, 2) @@ -207,7 +298,6 @@ var _ = Describe("logic_round_robin.go", Ordered, func() { } // ASSERT - Expect(frequency1[i.DUMMY[0]]).To(Equal(0)) Expect(frequency1[i.DUMMY[1]]).To(Equal(5)) Expect(frequency1[i.DUMMY[2]]).To(Equal(5)) From cdb78fe979e885f6a186a49742ddcfe06fee5ce7 Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Wed, 18 Dec 2024 10:30:05 +0100 Subject: [PATCH 11/15] test: added more unit tests --- .../keeper_suite_invalid_bundles_test.go | 462 +++++++++++++++++- .../keeper/keeper_suite_valid_bundles_test.go | 202 ++++++++ 2 files changed, 647 insertions(+), 17 deletions(-) diff --git a/x/bundles/keeper/keeper_suite_invalid_bundles_test.go b/x/bundles/keeper/keeper_suite_invalid_bundles_test.go index 3208c8e2..d6b270d0 100644 --- a/x/bundles/keeper/keeper_suite_invalid_bundles_test.go +++ b/x/bundles/keeper/keeper_suite_invalid_bundles_test.go @@ -23,6 +23,8 @@ TEST CASES - invalid bundles * Produce an invalid bundle with multiple validators and no foreign delegations * Produce an invalid bundle with multiple validators and foreign delegations * Produce an invalid bundle with multiple validators although some voted valid +* Produce an invalid bundle with multiple validators and stake fractions +* Produce an invalid bundle with multiple validators and stake fractions and foreign delegations */ @@ -78,6 +80,22 @@ var _ = Describe("invalid bundles", Ordered, func() { AmountsPerBundle: i.KYVECoins(1 * i.T_KYVE), }) + initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) + initialBalanceValaddress0 = s.GetBalanceFromAddress(i.VALADDRESS_0_A) + + initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + + initialBalanceStaker2 = s.GetBalanceFromAddress(i.STAKER_2) + initialBalanceValaddress2 = s.GetBalanceFromAddress(i.VALADDRESS_2_A) + }) + + AfterEach(func() { + s.PerformValidityChecks() + }) + + It("Produce an invalid bundle with multiple validators and no foreign delegations", func() { + // ARRANGE s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ @@ -98,24 +116,8 @@ var _ = Describe("invalid bundles", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) - initialBalanceValaddress0 = s.GetBalanceFromAddress(i.VALADDRESS_0_A) - - initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) - initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) - - initialBalanceStaker2 = s.GetBalanceFromAddress(i.STAKER_2) - initialBalanceValaddress2 = s.GetBalanceFromAddress(i.VALADDRESS_2_A) - s.CommitAfterSeconds(60) - }) - AfterEach(func() { - s.PerformValidityChecks() - }) - - It("Produce an invalid bundle with multiple validators and no foreign delegations", func() { - // ARRANGE s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ Creator: i.VALADDRESS_0_A, Staker: i.STAKER_0, @@ -140,7 +142,14 @@ var _ = Describe("invalid bundles", Ordered, func() { StakeFraction: math.LegacyMustNewDecFromStr("1"), }) - initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_2) + initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) + initialBalanceValaddress0 = s.GetBalanceFromAddress(i.VALADDRESS_0_A) + + initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + + initialBalanceStaker2 = s.GetBalanceFromAddress(i.STAKER_2) + initialBalanceValaddress2 = s.GetBalanceFromAddress(i.VALADDRESS_2_A) // ACT s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ @@ -264,6 +273,26 @@ var _ = Describe("invalid bundles", Ordered, func() { It("Produce an invalid bundle with multiple validators and foreign delegations", func() { // ARRANGE + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) + + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + s.RunTxSuccess(stakingTypes.NewMsgDelegate( i.ALICE, util.MustValaddressFromOperatorAddress(i.STAKER_0), @@ -292,6 +321,8 @@ var _ = Describe("invalid bundles", Ordered, func() { sdk.NewInt64Coin(globalTypes.Denom, int64(100*i.KYVE)), )) + s.CommitAfterSeconds(60) + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ Creator: i.VALADDRESS_0_A, Staker: i.STAKER_0, @@ -306,7 +337,14 @@ var _ = Describe("invalid bundles", Ordered, func() { BundleSummary: "test_value", }) + initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) + initialBalanceValaddress0 = s.GetBalanceFromAddress(i.VALADDRESS_0_A) + initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + + initialBalanceStaker2 = s.GetBalanceFromAddress(i.STAKER_2) + initialBalanceValaddress2 = s.GetBalanceFromAddress(i.VALADDRESS_2_A) // ACT s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ @@ -434,6 +472,26 @@ var _ = Describe("invalid bundles", Ordered, func() { It("Produce an invalid bundle with multiple validators although some voted valid", func() { // ARRANGE + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) + + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + s.RunTxSuccess(stakingTypes.NewMsgDelegate( i.ALICE, util.MustValaddressFromOperatorAddress(i.STAKER_0), @@ -479,6 +537,8 @@ var _ = Describe("invalid bundles", Ordered, func() { sdk.NewInt64Coin(globalTypes.Denom, int64(150*i.KYVE)), )) + s.CommitAfterSeconds(60) + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ Creator: i.VALADDRESS_0_A, Staker: i.STAKER_0, @@ -493,8 +553,14 @@ var _ = Describe("invalid bundles", Ordered, func() { BundleSummary: "test_value", }) + initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) + initialBalanceValaddress0 = s.GetBalanceFromAddress(i.VALADDRESS_0_A) + initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + initialBalanceStaker2 = s.GetBalanceFromAddress(i.STAKER_2) + initialBalanceValaddress2 = s.GetBalanceFromAddress(i.VALADDRESS_2_A) // ACT s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ @@ -647,4 +713,366 @@ var _ = Describe("invalid bundles", Ordered, func() { Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100 * i.KYVE)) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) }) + + It("Produce an invalid bundle with multiple validators and stake fractions", func() { + // ARRANGE + s.CreateValidator(i.STAKER_0, "Staker-0", int64(200*i.KYVE)) + + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.5"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) + + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CommitAfterSeconds(60) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + DataSize: 100, + DataHash: "test_hash", + FromIndex: 0, + BundleSize: 100, + FromKey: "0", + ToKey: "99", + BundleSummary: "test_value", + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) + + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) + initialBalanceValaddress0 = s.GetBalanceFromAddress(i.VALADDRESS_0_A) + + initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + + initialBalanceStaker2 = s.GetBalanceFromAddress(i.STAKER_2) + initialBalanceValaddress2 = s.GetBalanceFromAddress(i.VALADDRESS_2_A) + + // ACT + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: bundletypes.VOTE_TYPE_INVALID, + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_2_A, + Staker: i.STAKER_2, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: bundletypes.VOTE_TYPE_INVALID, + }) + + s.CommitAfterSeconds(60) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", + DataSize: 100, + DataHash: "test_hash2", + FromIndex: 100, + BundleSize: 100, + FromKey: "100", + ToKey: "199", + BundleSummary: "test_value2", + }) + + // ASSERT + // check if bundle got not finalized on pool + pool, poolFound := s.App().PoolKeeper.GetPool(s.Ctx(), 0) + Expect(poolFound).To(BeTrue()) + + Expect(pool.CurrentKey).To(Equal("")) + Expect(pool.CurrentSummary).To(BeEmpty()) + Expect(pool.CurrentIndex).To(BeZero()) + Expect(pool.TotalBundles).To(BeZero()) + + // check if finalized bundle exists + _, finalizedBundleFound := s.App().BundlesKeeper.GetFinalizedBundle(s.Ctx(), 0, 0) + Expect(finalizedBundleFound).To(BeFalse()) + + // check if bundle proposal got dropped + bundleProposal, bundleProposalFound := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) + Expect(bundleProposalFound).To(BeTrue()) + + Expect(bundleProposal.PoolId).To(Equal(uint64(0))) + Expect(bundleProposal.StorageId).To(BeEmpty()) + Expect(bundleProposal.Uploader).To(BeEmpty()) + Expect(bundleProposal.NextUploader).NotTo(BeEmpty()) + Expect(bundleProposal.DataSize).To(BeZero()) + Expect(bundleProposal.DataHash).To(BeEmpty()) + Expect(bundleProposal.BundleSize).To(BeZero()) + Expect(bundleProposal.FromKey).To(BeEmpty()) + Expect(bundleProposal.ToKey).To(BeEmpty()) + Expect(bundleProposal.BundleSummary).To(BeEmpty()) + Expect(bundleProposal.UpdatedAt).NotTo(BeZero()) + Expect(bundleProposal.VotersValid).To(BeEmpty()) + Expect(bundleProposal.VotersInvalid).To(BeEmpty()) + Expect(bundleProposal.VotersAbstain).To(BeEmpty()) + + // check uploader status + _, uploaderActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(uploaderActive).To(BeFalse()) + + balanceValaddress := s.GetBalanceFromAddress(i.VALADDRESS_0_A) + Expect(balanceValaddress).To(Equal(initialBalanceValaddress0)) + + balanceUploader := s.GetBalanceFromAddress(i.STAKER_0) + + _, uploaderFound := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) + Expect(uploaderFound).To(BeTrue()) + + Expect(balanceUploader).To(Equal(initialBalanceStaker0)) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(BeEmpty()) + + // calculate uploader slashes + fraction := s.App().StakersKeeper.GetUploadSlash(s.Ctx()) + slashAmount := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) + + Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(200*i.KYVE - slashAmount)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + + // check voter status + valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) + Expect(valaccountVoter.Points).To(BeZero()) + + balanceVoterValaddress := s.GetBalanceFromAddress(valaccountVoter.Valaddress) + Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) + + balanceVoter := s.GetBalanceFromAddress(valaccountVoter.Staker) + + Expect(balanceVoter).To(Equal(initialBalanceStaker1)) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_1, i.STAKER_1)).To(BeEmpty()) + + // check voter 2 status + valaccountVoter, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_2) + Expect(valaccountVoter.Points).To(BeZero()) + + balanceVoterValaddress = s.GetBalanceFromAddress(valaccountVoter.Valaddress) + Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) + + balanceVoter = s.GetBalanceFromAddress(valaccountVoter.Staker) + + Expect(balanceVoter).To(Equal(initialBalanceStaker1)) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_2, i.STAKER_2)).To(BeEmpty()) + + // check pool funds + fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + + // assert total pool funds + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100 * i.KYVE)) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) + }) + + It("Produce an invalid bundle with multiple validators and stake fractions and foreign delegations", func() { + // ARRANGE + s.CreateValidator(i.STAKER_0, "Staker-0", int64(100*i.KYVE)) + + s.RunTxSuccess(stakingTypes.NewMsgDelegate( + i.CHARLIE, + util.MustValaddressFromOperatorAddress(i.STAKER_0), + sdk.NewInt64Coin(globalTypes.Denom, int64(100*i.KYVE)), + )) + + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ + Creator: i.STAKER_0, + PoolId: 0, + Valaddress: i.VALADDRESS_0_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("0.5"), + }) + + s.CreateValidator(i.STAKER_1, "Staker-1", int64(100*i.KYVE)) + + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ + Creator: i.STAKER_1, + PoolId: 0, + Valaddress: i.VALADDRESS_1_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.CommitAfterSeconds(60) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + DataSize: 100, + DataHash: "test_hash", + FromIndex: 0, + BundleSize: 100, + FromKey: "0", + ToKey: "99", + BundleSummary: "test_value", + }) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) + + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) + initialBalanceValaddress0 = s.GetBalanceFromAddress(i.VALADDRESS_0_A) + + initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + + initialBalanceStaker2 = s.GetBalanceFromAddress(i.STAKER_2) + initialBalanceValaddress2 = s.GetBalanceFromAddress(i.VALADDRESS_2_A) + + // ACT + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: bundletypes.VOTE_TYPE_INVALID, + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_2_A, + Staker: i.STAKER_2, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: bundletypes.VOTE_TYPE_INVALID, + }) + + s.CommitAfterSeconds(60) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", + DataSize: 100, + DataHash: "test_hash2", + FromIndex: 100, + BundleSize: 100, + FromKey: "100", + ToKey: "199", + BundleSummary: "test_value2", + }) + + // ASSERT + // check if bundle got not finalized on pool + pool, poolFound := s.App().PoolKeeper.GetPool(s.Ctx(), 0) + Expect(poolFound).To(BeTrue()) + + Expect(pool.CurrentKey).To(Equal("")) + Expect(pool.CurrentSummary).To(BeEmpty()) + Expect(pool.CurrentIndex).To(BeZero()) + Expect(pool.TotalBundles).To(BeZero()) + + // check if finalized bundle exists + _, finalizedBundleFound := s.App().BundlesKeeper.GetFinalizedBundle(s.Ctx(), 0, 0) + Expect(finalizedBundleFound).To(BeFalse()) + + // check if bundle proposal got dropped + bundleProposal, bundleProposalFound := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) + Expect(bundleProposalFound).To(BeTrue()) + + Expect(bundleProposal.PoolId).To(Equal(uint64(0))) + Expect(bundleProposal.StorageId).To(BeEmpty()) + Expect(bundleProposal.Uploader).To(BeEmpty()) + Expect(bundleProposal.NextUploader).NotTo(BeEmpty()) + Expect(bundleProposal.DataSize).To(BeZero()) + Expect(bundleProposal.DataHash).To(BeEmpty()) + Expect(bundleProposal.BundleSize).To(BeZero()) + Expect(bundleProposal.FromKey).To(BeEmpty()) + Expect(bundleProposal.ToKey).To(BeEmpty()) + Expect(bundleProposal.BundleSummary).To(BeEmpty()) + Expect(bundleProposal.UpdatedAt).NotTo(BeZero()) + Expect(bundleProposal.VotersValid).To(BeEmpty()) + Expect(bundleProposal.VotersInvalid).To(BeEmpty()) + Expect(bundleProposal.VotersAbstain).To(BeEmpty()) + + // check uploader status + _, uploaderActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(uploaderActive).To(BeFalse()) + + balanceValaddress := s.GetBalanceFromAddress(i.VALADDRESS_0_A) + Expect(balanceValaddress).To(Equal(initialBalanceValaddress0)) + + balanceUploader := s.GetBalanceFromAddress(i.STAKER_0) + + _, uploaderFound := s.App().StakersKeeper.GetValidator(s.Ctx(), i.STAKER_0) + Expect(uploaderFound).To(BeTrue()) + + Expect(balanceUploader).To(Equal(initialBalanceStaker0)) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(BeEmpty()) + + // calculate uploader slashes (stake fraction is 0.5 because only 100 kyve out of 200 are at risk) + fraction := s.App().StakersKeeper.GetUploadSlash(s.Ctx()).Mul(math.LegacyMustNewDecFromStr("0.5")) + slashAmount := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) + slashAmountDelegator := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) + + Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(100*i.KYVE - slashAmount)) + Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_0, i.CHARLIE)).To(Equal(100*i.KYVE - slashAmountDelegator)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + + // check voter status + valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) + Expect(valaccountVoter.Points).To(BeZero()) + + balanceVoterValaddress := s.GetBalanceFromAddress(valaccountVoter.Valaddress) + Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) + + balanceVoter := s.GetBalanceFromAddress(valaccountVoter.Staker) + + Expect(balanceVoter).To(Equal(initialBalanceStaker1)) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_1, i.STAKER_1)).To(BeEmpty()) + + // check voter 2 status + valaccountVoter, _ = s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_2) + Expect(valaccountVoter.Points).To(BeZero()) + + balanceVoterValaddress = s.GetBalanceFromAddress(valaccountVoter.Valaddress) + Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) + + balanceVoter = s.GetBalanceFromAddress(valaccountVoter.Staker) + + Expect(balanceVoter).To(Equal(initialBalanceStaker1)) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_2, i.STAKER_2)).To(BeEmpty()) + + // check pool funds + fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + + // assert total pool funds + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100 * i.KYVE)) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) + }) }) diff --git a/x/bundles/keeper/keeper_suite_valid_bundles_test.go b/x/bundles/keeper/keeper_suite_valid_bundles_test.go index 17e5b636..addc5630 100644 --- a/x/bundles/keeper/keeper_suite_valid_bundles_test.go +++ b/x/bundles/keeper/keeper_suite_valid_bundles_test.go @@ -25,6 +25,7 @@ TEST CASES - valid bundles * Produce a valid bundle with multiple validators and foreign delegation although some did not vote at all * Produce a valid bundle with multiple validators and foreign delegation although some voted abstain * Produce a valid bundle with multiple validators and foreign delegation although some voted invalid +* Produce a valid bundle with multiple validators and foreign delegation although some voted invalid with maximum voting power * Produce a valid bundle with multiple validators and no foreign delegations and another storage provider * Produce a valid bundle with multiple validators, multiple coins and no foreign delegations * Produce a valid bundle with multiple validators, multiple coins which are not enough for the storage reward and no foreign delegations @@ -963,6 +964,207 @@ var _ = Describe("valid bundles", Ordered, func() { Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) }) + It("Produce a valid bundle with multiple validators and foreign delegation although some voted invalid with maximum voting power", func() { + // ARRANGE + params := s.App().PoolKeeper.GetParams(s.Ctx()) + params.MaxVotingPowerPerPool = math.LegacyMustNewDecFromStr("0.4") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + + s.CreateValidator(i.STAKER_2, "Staker-2", int64(100*i.KYVE)) + + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ + Creator: i.STAKER_2, + PoolId: 0, + Valaddress: i.VALADDRESS_2_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + // delegate to staker 2 so he runs into the max voting power limit + s.RunTxSuccess(stakingTypes.NewMsgDelegate( + i.CHARLIE, + util.MustValaddressFromOperatorAddress(i.STAKER_2), + sdk.NewInt64Coin(globalTypes.Denom, int64(300*i.KYVE)), + )) + + s.CreateValidator(i.STAKER_3, "Staker-3", int64(100*i.KYVE)) + + s.RunTxStakersSuccess(&stakertypes.MsgJoinPool{ + Creator: i.STAKER_3, + PoolId: 0, + Valaddress: i.VALADDRESS_3_A, + Commission: math.LegacyMustNewDecFromStr("0.1"), + StakeFraction: math.LegacyMustNewDecFromStr("1"), + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgClaimUploaderRole{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + }) + + s.CommitAfterSeconds(60) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + DataSize: 100, + DataHash: "test_hash", + FromIndex: 0, + BundleSize: 100, + FromKey: "0", + ToKey: "99", + BundleSummary: "test_value", + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: bundletypes.VOTE_TYPE_VALID, + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_2_A, + Staker: i.STAKER_2, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: bundletypes.VOTE_TYPE_INVALID, + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_3_A, + Staker: i.STAKER_3, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: bundletypes.VOTE_TYPE_VALID, + }) + + initialBalanceStaker2 = s.GetCoinsFromAddress(i.STAKER_2) + initialBalanceValaddress2 = s.GetCoinsFromAddress(i.VALADDRESS_2_A) + + c1 := s.GetCoinsFromCommunityPool() + + s.CommitAfterSeconds(60) + + // ACT + // TODO: why is staker 2 selected as next uploader? + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_2_A, + Staker: i.STAKER_2, + PoolId: 0, + StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", + DataSize: 100, + DataHash: "test_hash2", + FromIndex: 100, + BundleSize: 100, + FromKey: "100", + ToKey: "199", + BundleSummary: "test_value2", + }) + + // ASSERT + // check if bundle got finalized on pool + pool, poolFound := s.App().PoolKeeper.GetPool(s.Ctx(), 0) + Expect(poolFound).To(BeTrue()) + + Expect(pool.CurrentKey).To(Equal("99")) + Expect(pool.CurrentSummary).To(Equal("test_value")) + Expect(pool.CurrentIndex).To(Equal(uint64(100))) + Expect(pool.TotalBundles).To(Equal(uint64(1))) + + // check if finalized bundle got saved + finalizedBundle, finalizedBundleFound := s.App().BundlesKeeper.GetFinalizedBundle(s.Ctx(), 0, 0) + Expect(finalizedBundleFound).To(BeTrue()) + + Expect(finalizedBundle.PoolId).To(Equal(uint64(0))) + Expect(finalizedBundle.StorageId).To(Equal("y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI")) + Expect(finalizedBundle.Uploader).To(Equal(i.STAKER_0)) + Expect(finalizedBundle.FromIndex).To(Equal(uint64(0))) + Expect(finalizedBundle.ToIndex).To(Equal(uint64(100))) + Expect(finalizedBundle.FromKey).To(Equal("0")) + Expect(finalizedBundle.ToKey).To(Equal("99")) + Expect(finalizedBundle.BundleSummary).To(Equal("test_value")) + Expect(finalizedBundle.DataHash).To(Equal("test_hash")) + Expect(finalizedBundle.FinalizedAt).NotTo(BeZero()) + Expect(finalizedBundle.StakeSecurity.ValidVotePower).To(Equal(300 * i.KYVE)) + Expect(finalizedBundle.StakeSecurity.TotalVotePower).To(Equal(500*i.KYVE + 1)) + + // check if next bundle proposal got registered + bundleProposal, bundleProposalFound := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) + Expect(bundleProposalFound).To(BeTrue()) + + Expect(bundleProposal.PoolId).To(Equal(uint64(0))) + Expect(bundleProposal.StorageId).To(Equal("P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg")) + Expect(bundleProposal.Uploader).To(Equal(i.STAKER_2)) + Expect(bundleProposal.NextUploader).To(Equal(i.STAKER_3)) + Expect(bundleProposal.DataSize).To(Equal(uint64(100))) + Expect(bundleProposal.DataHash).To(Equal("test_hash2")) + Expect(bundleProposal.BundleSize).To(Equal(uint64(100))) + Expect(bundleProposal.FromKey).To(Equal("100")) + Expect(bundleProposal.ToKey).To(Equal("199")) + Expect(bundleProposal.BundleSummary).To(Equal("test_value2")) + Expect(bundleProposal.UpdatedAt).NotTo(BeZero()) + Expect(bundleProposal.VotersValid).To(ContainElement(i.STAKER_2)) + Expect(bundleProposal.VotersInvalid).To(BeEmpty()) + Expect(bundleProposal.VotersAbstain).To(BeEmpty()) + + // check uploader status + valaccountUploader, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccountUploader.Points).To(BeZero()) + + balanceUploaderValaddress := s.GetCoinsFromAddress(valaccountUploader.Valaddress) + Expect(balanceUploaderValaddress).To(Equal(initialBalanceValaddress0)) + + // calculate voter slashes (due to maximum vote power only 200 kyve out of 400 where at risk for slashing) + fraction := s.App().StakersKeeper.GetVoteSlash(s.Ctx()).Mul(math.LegacyMustNewDecFromStr("0.5")) // 200 / 400 + slashAmountVoter := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) + slashAmountDelegator := uint64(math.LegacyNewDec(int64(300 * i.KYVE)).Mul(fraction).TruncateInt64()) + + Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_2, i.STAKER_2)).To(Equal(100*i.KYVE - slashAmountVoter)) + Expect(s.App().StakersKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.STAKER_2, i.CHARLIE)).To(Equal(300*i.KYVE - slashAmountDelegator)) + + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(300 * i.KYVE)) + + // check voter status + _, voterActive := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_2) + Expect(voterActive).To(BeFalse()) + + balanceVoterValaddress := s.GetCoinsFromAddress(i.VALADDRESS_2_A) + Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress2)) + + balanceVoter := s.GetCoinsFromAddress(i.STAKER_2) + Expect(balanceVoter).To(Equal(initialBalanceStaker2)) + + // check uploader rewards + balanceUploader := s.GetCoinsFromAddress(valaccountUploader.Staker) + + // assert payout transfer + Expect(balanceUploader.String()).To(Equal(initialBalanceStaker0.String())) + // assert commission rewards + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * 0.1 + (100 * 0.5) + Expect(s.App().StakersKeeper.GetOutstandingCommissionRewards(s.Ctx(), valaccountUploader.Staker).String()).To(Equal(i.ACoins(1035).String())) + // assert uploader self delegation rewards + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * (1 - 0.1) + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.ACoins(8865).String())) + + // check voter rewards + Expect(s.App().StakersKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_2, i.CHARLIE)).To(BeEmpty()) + + fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + + // assert total pool funds + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(i.ACoins(100*i.T_KYVE - amountPerBundle).String())) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) + }) + It("Produce a valid bundle with multiple validators and no foreign delegations and another storage provider", func() { // ARRANGE storageProviderId := uint32(2) From ef69783fe19ccc171f2d7b5fa7e48458f49491ec Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Wed, 18 Dec 2024 11:22:59 +0100 Subject: [PATCH 12/15] chore: remove unused code --- x/stakers/keeper/getters_valaccount.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/x/stakers/keeper/getters_valaccount.go b/x/stakers/keeper/getters_valaccount.go index aa307a41..0535efb7 100644 --- a/x/stakers/keeper/getters_valaccount.go +++ b/x/stakers/keeper/getters_valaccount.go @@ -96,14 +96,6 @@ func (k Keeper) GetPoolCount(ctx sdk.Context, stakerAddress string) (poolCount u // # Raw KV-Store operations # // ############################# -// DoesValaccountExist only checks if the key is present in the KV-Store -// without loading and unmarshalling to full entry -//func (k Keeper) DoesValaccountExist(ctx sdk.Context, poolId uint64, stakerAddress string) bool { -// storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) -// store := prefix.NewStore(storeAdapter, types.ValaccountPrefix) -// return store.Has(types.ValaccountKey(poolId, stakerAddress)) -//} - // SetValaccount set a specific Valaccount in the store from its index func (k Keeper) SetValaccount(ctx sdk.Context, valaccount types.Valaccount) { storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) From 9037988440fe1587fc13c4059be0f15951b0d221 Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Wed, 18 Dec 2024 11:42:51 +0100 Subject: [PATCH 13/15] chore: add missing changes --- CHANGELOG.md | 1 + x/stakers/keeper/getters_params.go | 2 ++ x/stakers/keeper/getters_stake_fraction.go | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 741872bc..fedf109d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ An '!' indicates a state machine breaking change. - ! (`x/stakers`) [#209](https://github.com/KYVENetwork/chain/pull/209) Shared Staking: Consensus-validator stake is now used for the protocol. - ! (`x/stakers`) [#210](https://github.com/KYVENetwork/chain/pull/210) Shared Staking: Pool specific commission and stake fraction. +- ! (`x/stakers`) [#211](https://github.com/KYVENetwork/chain/pull/211) Shared Staking: Maximum voting power per pool. ### Bug Fixes diff --git a/x/stakers/keeper/getters_params.go b/x/stakers/keeper/getters_params.go index 8a2864f2..aade9b04 100644 --- a/x/stakers/keeper/getters_params.go +++ b/x/stakers/keeper/getters_params.go @@ -59,6 +59,8 @@ func (k Keeper) getSlashFraction(ctx sdk.Context, slashType types.SlashType) (sl slashAmountRatio = k.GetVoteSlash(ctx) case types.SLASH_TYPE_UPLOAD: slashAmountRatio = k.GetUploadSlash(ctx) + default: + slashAmountRatio = math.LegacyZeroDec() } return } diff --git a/x/stakers/keeper/getters_stake_fraction.go b/x/stakers/keeper/getters_stake_fraction.go index cab95cb3..e1100bad 100644 --- a/x/stakers/keeper/getters_stake_fraction.go +++ b/x/stakers/keeper/getters_stake_fraction.go @@ -65,7 +65,7 @@ func (k Keeper) RemoveStakeFractionEntry(ctx sdk.Context, stakeFractionChangeEnt store := prefix.NewStore(storeAdapter, types.StakeFractionChangeEntryKeyPrefix) store.Delete(types.StakeFractionChangeEntryKey(stakeFractionChangeEntry.Index)) - indexStore := prefix.NewStore(storeAdapter, types.StakeFractionChangeEntryKeyPrefix) + indexStore := prefix.NewStore(storeAdapter, types.StakeFractionChangeKeyPrefixIndex2) indexStore.Delete(types.StakeFractionChangeEntryKeyIndex2( stakeFractionChangeEntry.Staker, stakeFractionChangeEntry.PoolId, From 6976d20fb9e79e5bb2aaa145f4ac7b6551d4ef81 Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Thu, 19 Dec 2024 17:16:51 +0100 Subject: [PATCH 14/15] chore: round down to stay below max voting power --- x/stakers/keeper/exported_functions.go | 25 ++++++++++++++++--- .../keeper_suite_effective_stake_test.go | 18 ++++++------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/x/stakers/keeper/exported_functions.go b/x/stakers/keeper/exported_functions.go index 0a8e02f0..0e74ad19 100644 --- a/x/stakers/keeper/exported_functions.go +++ b/x/stakers/keeper/exported_functions.go @@ -193,7 +193,7 @@ func (k Keeper) GetValidatorPoolStakes(ctx sdk.Context, poolId uint64, mustInclu totalStakeRemainder := totalStake // sort descending based on stake - sort.Slice(validators, func(i, j int) bool { + sort.SliceStable(validators, func(i, j int) bool { return validators[i].Stake > validators[j].Stake }) @@ -202,6 +202,8 @@ func (k Keeper) GetValidatorPoolStakes(ctx sdk.Context, poolId uint64, mustInclu return stakes } + var lastCutoffIndex int + for i, validator := range validators { // check if the validator has a higher stake than allowed by the max voting power if math.LegacyNewDec(int64(stakes[validator.Address])).GT(maxVotingPower.MulInt64(totalStake)) { @@ -220,9 +222,20 @@ func (k Keeper) GetValidatorPoolStakes(ctx sdk.Context, poolId uint64, mustInclu stakes[v.Address] += uint64(math.LegacyNewDec(int64(v.Stake)).QuoInt64(totalStakeRemainder).MulInt64(cutoffAmount).TruncateInt64()) } } + + lastCutoffIndex = i + } else { + // if we reach the first validator who is below the max voting power we know that the remaining + // ones will be also below it + break } } + // if no amounts got cut off we can return already + if totalStakeRemainder == totalStake { + return stakes + } + // after we have redistributed all cutoff amounts so that no validator exceeds the maximum voting power // based on their remaining effective stake we now scale the stakes to get the true effective staking amount. // This is because while the top validators who got their voting power reduced the lower validators have actually @@ -241,8 +254,14 @@ func (k Keeper) GetValidatorPoolStakes(ctx sdk.Context, poolId uint64, mustInclu } // scale all effective stakes down to scale factor - for _, validator := range validators { - stakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(stakes[validator.Address])).RoundInt64()) + for i, validator := range validators { + // for all validators who got cut off we always round down to ensure that their voting power actually + // stays below the max voting power + if i <= lastCutoffIndex { + stakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(stakes[validator.Address])).TruncateInt64()) + } else { + stakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(stakes[validator.Address])).RoundInt64()) + } } // the result is a map which contains the effective stake for every validator in a pool. The effective stake diff --git a/x/stakers/keeper/keeper_suite_effective_stake_test.go b/x/stakers/keeper/keeper_suite_effective_stake_test.go index 991b7d41..e68ea9a4 100644 --- a/x/stakers/keeper/keeper_suite_effective_stake_test.go +++ b/x/stakers/keeper/keeper_suite_effective_stake_test.go @@ -139,10 +139,10 @@ var _ = Describe("keeper_suite_effective_stake_test.go", Ordered, func() { Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(200*i.KYVE - 1)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_2, 0)).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(400 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(400*i.KYVE - 1)) }) It("Test effective stake with multiple validators above the max pool voting power", func() { @@ -268,11 +268,11 @@ var _ = Describe("keeper_suite_effective_stake_test.go", Ordered, func() { // ASSERT Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) - Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100*i.KYVE - 1)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(0 * i.KYVE)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_2, 0)).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(200*i.KYVE - 1)) }) It("Test effective stake with all validators having zero delegation", func() { @@ -459,10 +459,10 @@ var _ = Describe("keeper_suite_effective_stake_test.go", Ordered, func() { Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(200 * i.KYVE)) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(200*i.KYVE - 1)) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_2, 0)).To(Equal(100 * i.KYVE)) - Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(400 * i.KYVE)) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(400*i.KYVE - 1)) }) It("Test effective stake with multiple validators above the max pool voting power due to stake fractions", func() { @@ -504,11 +504,11 @@ var _ = Describe("keeper_suite_effective_stake_test.go", Ordered, func() { // ASSERT Expect(s.App().StakersKeeper.IsVotingPowerTooHigh(s.Ctx(), 0)).To(BeFalse()) - Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(uint64(23333333334))) - Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(uint64(23333333334))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_0, 0)).To(Equal(uint64(23333333333))) + Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_1, 0)).To(Equal(uint64(23333333333))) Expect(s.App().StakersKeeper.GetValidatorPoolStake(s.Ctx(), i.STAKER_2, 0)).To(Equal(20 * i.KYVE)) - Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(uint64(66666666668))) + Expect(s.App().StakersKeeper.GetTotalStakeOfPool(s.Ctx(), 0)).To(Equal(uint64(66666666666))) }) It("Test effective stake with some validators having zero delegation due to stake fractions", func() { From 0c53e7abef8046fb1fc2f56829a371ad21c3e17c Mon Sep 17 00:00:00 2001 From: Troy Kessler Date: Fri, 20 Dec 2024 09:59:33 +0100 Subject: [PATCH 15/15] chore: round up --- x/stakers/keeper/exported_functions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/stakers/keeper/exported_functions.go b/x/stakers/keeper/exported_functions.go index 0e74ad19..8b2286f1 100644 --- a/x/stakers/keeper/exported_functions.go +++ b/x/stakers/keeper/exported_functions.go @@ -260,7 +260,7 @@ func (k Keeper) GetValidatorPoolStakes(ctx sdk.Context, poolId uint64, mustInclu if i <= lastCutoffIndex { stakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(stakes[validator.Address])).TruncateInt64()) } else { - stakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(stakes[validator.Address])).RoundInt64()) + stakes[validator.Address] = uint64(scaleFactor.MulInt64(int64(stakes[validator.Address])).Ceil().TruncateInt64()) } }