Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: LSM changes to distribution #4

Merged
merged 10 commits into from
Nov 28, 2023
Merged
209 changes: 109 additions & 100 deletions api/cosmos/distribution/v1beta1/tx.pulsar.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion codec/amino_codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func TestAminoCodecUnpackAnyFails(t *testing.T) {

func TestAminoCodecFullDecodeAndEncode(t *testing.T) {
// This tx comes from https://github.com/cosmos/cosmos-sdk/issues/8117.
txSigned := `{"type":"cosmos-sdk/StdTx","value":{"msg":[{"type":"cosmos-sdk/MsgCreateValidator","value":{"description":{"moniker":"fulltest","identity":"satoshi","website":"example.com","details":"example inc"},"commission":{"rate":"0.500000000000000000","max_rate":"1.000000000000000000","max_change_rate":"0.200000000000000000"},"min_self_delegation":"1000000","delegator_address":"cosmos14pt0q5cwf38zt08uu0n6yrstf3rndzr5057jys","validator_address":"cosmosvaloper14pt0q5cwf38zt08uu0n6yrstf3rndzr52q28gr","pubkey":{"type":"tendermint/PubKeyEd25519","value":"CYrOiM3HtS7uv1B1OAkknZnFYSRpQYSYII8AtMMtev0="},"value":{"denom":"umuon","amount":"700000000"}}}],"fee":{"amount":[{"denom":"umuon","amount":"6000"}],"gas":"160000"},"signatures":[{"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"AwAOXeWgNf1FjMaayrSnrOOKz+Fivr6DiI/i0x0sZCHw"},"signature":"RcnfS/u2yl7uIShTrSUlDWvsXo2p2dYu6WJC8VDVHMBLEQZWc8bsINSCjOnlsIVkUNNe1q/WCA9n3Gy1+0zhYA=="}],"memo":"","timeout_height":"0"}}`
txSigned := `{"type":"cosmos-sdk/StdTx","value":{"msg":[{"type":"cosmos-sdk/MsgCreateValidator","value":{"description":{"moniker":"fulltest","identity":"satoshi","website":"example.com","details":"example inc"},"commission":{"rate":"0.500000000000000000","max_rate":"1.000000000000000000","max_change_rate":"0.200000000000000000"},"min_self_delegation":"0","delegator_address":"cosmos14pt0q5cwf38zt08uu0n6yrstf3rndzr5057jys","validator_address":"cosmosvaloper14pt0q5cwf38zt08uu0n6yrstf3rndzr52q28gr","pubkey":{"type":"tendermint/PubKeyEd25519","value":"CYrOiM3HtS7uv1B1OAkknZnFYSRpQYSYII8AtMMtev0="},"value":{"denom":"umuon","amount":"700000000"}}}],"fee":{"amount":[{"denom":"umuon","amount":"6000"}],"gas":"160000"},"signatures":[{"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"AwAOXeWgNf1FjMaayrSnrOOKz+Fivr6DiI/i0x0sZCHw"},"signature":"RcnfS/u2yl7uIShTrSUlDWvsXo2p2dYu6WJC8VDVHMBLEQZWc8bsINSCjOnlsIVkUNNe1q/WCA9n3Gy1+0zhYA=="}],"memo":"","timeout_height":"0"}}`
legacyCdc := testutil.MakeTestEncodingConfig(staking.AppModuleBasic{}, auth.AppModuleBasic{}).Amino
var tx legacytx.StdTx
err := legacyCdc.UnmarshalJSON([]byte(txSigned), &tx)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ require (
github.com/cosmos/gogoproto v1.4.10
github.com/cosmos/iavl v0.20.1
github.com/cosmos/ledger-cosmos-go v0.12.4
github.com/gogo/protobuf v1.3.2
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.3
github.com/google/gofuzz v1.2.0
Expand Down Expand Up @@ -104,7 +105,6 @@ require (
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.1.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.4 // indirect
Expand Down
6 changes: 6 additions & 0 deletions proto/cosmos/distribution/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ message MsgCommunityPoolSpend {

// MsgWithdrawTokenizeShareRecordReward withdraws tokenize share rewards for a specific record
message MsgWithdrawTokenizeShareRecordReward {
option (cosmos.msg.v1.signer) = "owner_address";
option (amino.name) = "cosmos-sdk/distr/MsgWithdrawTokenizeShareRecordReward";

option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

Expand All @@ -194,6 +197,9 @@ message MsgWithdrawTokenizeShareRecordRewardResponse {}
// MsgWithdrawAllTokenizeShareRecordReward withdraws tokenize share rewards or all
// records owned by the designated owner
message MsgWithdrawAllTokenizeShareRecordReward {
option (cosmos.msg.v1.signer) = "owner_address";
option (amino.name) = "cosmos-sdk/distr/MsgWithdrawAllTokenizeShareRecordReward";

option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

Expand Down
82 changes: 82 additions & 0 deletions tests/integration/distribution/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"github.com/cosmos/cosmos-sdk/x/distribution/keeper"
"github.com/cosmos/cosmos-sdk/x/distribution/testutil"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtestutil "github.com/cosmos/cosmos-sdk/x/staking/testutil"
Expand All @@ -35,6 +37,7 @@ type KeeperTestSuite struct {

interfaceRegistry codectypes.InterfaceRegistry
bankKeeper bankkeeper.Keeper
mintKeeper mintkeeper.Keeper
distrKeeper keeper.Keeper
stakingKeeper *stakingkeeper.Keeper
msgServer types.MsgServer
Expand All @@ -44,6 +47,7 @@ func (suite *KeeperTestSuite) SetupTest() {
app, err := simtestutil.Setup(testutil.AppConfig,
&suite.interfaceRegistry,
&suite.bankKeeper,
&suite.mintKeeper,
&suite.distrKeeper,
&suite.stakingKeeper,
)
Expand Down Expand Up @@ -673,6 +677,84 @@ func (suite *KeeperTestSuite) TestGRPCCommunityPool() {
}
}

func (suite *KeeperTestSuite) TestGRPCTokenizeShareRecordReward() {
ctx, queryClient := suite.ctx, suite.queryClient

addr := simtestutil.AddTestAddrs(suite.bankKeeper, suite.stakingKeeper, ctx, 2, sdk.NewInt(100000000))
valAddrs := simtestutil.ConvertAddrsToValAddrs(addr)
tstaking := stakingtestutil.NewHelper(suite.T(), ctx, suite.stakingKeeper)

// create validator with 50% commission
tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
valPower := int64(100)
tstaking.CreateValidatorWithValPower(valAddrs[0], valConsPk1, valPower, true)

// end block to bond validator
staking.EndBlocker(ctx, suite.stakingKeeper)

// next block
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)

// fetch validator and delegation
val := suite.stakingKeeper.Validator(ctx, valAddrs[0])
del := suite.stakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0])

// end period
endingPeriod := suite.distrKeeper.IncrementValidatorPeriod(ctx, val)

// calculate delegation rewards
suite.distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod)

// start out block height
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
val = suite.stakingKeeper.Validator(ctx, valAddrs[0])
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)

// allocate some rewards
initial := suite.stakingKeeper.TokensFromConsensusPower(ctx, 10)
tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecFromInt(initial)}}
suite.distrKeeper.AllocateTokensToValidator(ctx, val, tokens)

// end period
suite.distrKeeper.IncrementValidatorPeriod(ctx, val)

coins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, initial)}
err := suite.mintKeeper.MintCoins(ctx, coins)
suite.Require().NoError(err)

err = suite.bankKeeper.SendCoinsFromModuleToModule(ctx, minttypes.ModuleName, types.ModuleName, coins)
suite.Require().NoError(err)
// tokenize share amount
delTokens := sdk.NewInt(1000000)
msgServer := stakingkeeper.NewMsgServerImpl(suite.stakingKeeper)
_, err = msgServer.TokenizeShares(sdk.WrapSDKContext(ctx), &stakingtypes.MsgTokenizeShares{
DelegatorAddress: sdk.AccAddress(valAddrs[0]).String(),
ValidatorAddress: valAddrs[0].String(),
TokenizedShareOwner: sdk.AccAddress(valAddrs[0]).String(),
Amount: sdk.NewCoin(sdk.DefaultBondDenom, delTokens),
})
suite.Require().NoError(err)

staking.EndBlocker(ctx, suite.stakingKeeper)
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
suite.distrKeeper.AllocateTokensToValidator(ctx, val, tokens)
suite.distrKeeper.IncrementValidatorPeriod(ctx, val)

rewards, err := queryClient.TokenizeShareRecordReward(gocontext.Background(), &types.QueryTokenizeShareRecordRewardRequest{
OwnerAddress: sdk.AccAddress(valAddrs[0]).String(),
})
suite.Require().NoError(err)
suite.Require().Equal(&types.QueryTokenizeShareRecordRewardResponse{
Rewards: []types.TokenizeShareRecordReward{
{
RecordId: 1,
Reward: sdk.DecCoins{sdk.NewInt64DecCoin("stake", 50000)},
},
},
Total: sdk.DecCoins{sdk.NewInt64DecCoin("stake", 50000)},
}, rewards)
}

func TestDistributionTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}
46 changes: 46 additions & 0 deletions x/distribution/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func GetQueryCmd() *cobra.Command {
GetCmdQueryValidatorSlashes(),
GetCmdQueryDelegatorRewards(),
GetCmdQueryCommunityPool(),
GetCmdQueryTokenizeShareRecordReward(),
)

return distQueryCmd
Expand Down Expand Up @@ -364,3 +365,48 @@ $ %s query distribution community-pool
flags.AddQueryFlagsToCmd(cmd)
return cmd
}

// GetCmdQueryTokenizeShareRecordReward implements the query tokenize share record rewards
func GetCmdQueryTokenizeShareRecordReward() *cobra.Command {
bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix()

cmd := &cobra.Command{
Use: "tokenize-share-record-rewards [owner]",
Args: cobra.ExactArgs(1),
Short: "Query distribution tokenize share record rewards",
Long: strings.TrimSpace(
fmt.Sprintf(`Query the query tokenize share record rewards.

Example:
$ %s query distribution tokenize-share-record-rewards %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj
`,
version.AppName, bech32PrefixAccAddr,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

ownerAddr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
}

res, err := queryClient.TokenizeShareRecordReward(
cmd.Context(),
&types.QueryTokenizeShareRecordRewardRequest{OwnerAddress: ownerAddr.String()},
)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)
return cmd
}
48 changes: 48 additions & 0 deletions x/distribution/client/cli/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -678,3 +678,51 @@ func (s *CLITestSuite) TestNewFundCommunityPoolCmd() {
})
}
}

func (s *CLITestSuite) TestNewWithdrawAllTokenizeShareRecordRewardCmd() {
val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)

testCases := []struct {
name string
args []string
expectErr bool
expectedCode uint32
respType proto.Message
}{
{
"valid transaction of withdraw tokenize share record reward",
[]string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, val[0].Address.String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(10))).String()),
},
false, 0, &sdk.TxResponse{},
},
}

for _, tc := range testCases {
tc := tc

s.Run(tc.name, func() {
cmd := cli.NewWithdrawAllTokenizeShareRecordRewardCmd()

out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err, out.String())
s.Require().NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String())

txResp := tc.respType.(*sdk.TxResponse)
s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
}
})
}
}

// This test requires multiple validators, if I add this test to `IntegrationTestSuite` by increasing
// `NumValidators` the existing tests are leading to non-determnism so created new suite for this test.
func (s *CLITestSuite) TestNewWithdrawAllRewardsGenerateOnly() {
// TODO add LSM test
}
72 changes: 72 additions & 0 deletions x/distribution/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cli

import (
"fmt"
"strconv"
"strings"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -40,6 +41,8 @@ func NewTxCmd() *cobra.Command {
NewWithdrawAllRewardsCmd(),
NewSetWithdrawAddrCmd(),
NewFundCommunityPoolCmd(),
NewWithdrawTokenizeShareRecordRewardCmd(),
NewWithdrawAllTokenizeShareRecordRewardCmd(),
)

return distTxCmd
Expand Down Expand Up @@ -254,3 +257,72 @@ $ %s tx distribution fund-community-pool 100uatom --from mykey

return cmd
}

// WithdrawAllTokenizeShareRecordReward defines a method to withdraw reward for all owning TokenizeShareRecord
func NewWithdrawAllTokenizeShareRecordRewardCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw-all-tokenize-share-rewards",
Args: cobra.ExactArgs(0),
Short: "Withdraw reward for all owning TokenizeShareRecord",
Long: strings.TrimSpace(
fmt.Sprintf(`Withdraw reward for all owned TokenizeShareRecord

Example:
$ %s tx distribution withdraw-tokenize-share-rewards --from mykey
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

msg := types.NewMsgWithdrawAllTokenizeShareRecordReward(clientCtx.GetFromAddress())

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

// WithdrawTokenizeShareRecordReward defines a method to withdraw reward for an owning TokenizeShareRecord
func NewWithdrawTokenizeShareRecordRewardCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw-tokenize-share-rewards",
Args: cobra.ExactArgs(1),
Short: "Withdraw reward for an owning TokenizeShareRecord",
Long: strings.TrimSpace(
fmt.Sprintf(`Withdraw reward for an owned TokenizeShareRecord

Example:
$ %s tx distribution withdraw-tokenize-share-rewards 1 --from mykey
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

recordID, err := strconv.Atoi(args[0])
if err != nil {
return err
}

msg := types.NewMsgWithdrawTokenizeShareRecordReward(clientCtx.GetFromAddress(), uint64(recordID))

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}
4 changes: 4 additions & 0 deletions x/distribution/keeper/delegation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ func TestCalculateRewardsBasic(t *testing.T) {
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 2)}}, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddr).Commission)
}

func TestWithdrawTokenizeShareRecordReward(t *testing.T) {
// TODO add LSM test

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's merge without this test as I will add it a little later.

}

func TestCalculateRewardsAfterSlash(t *testing.T) {
ctrl := gomock.NewController(t)
key := sdk.NewKVStoreKey(disttypes.StoreKey)
Expand Down
Loading
Loading