From 22cd77870a373090b25576db0ce7938c2efabb77 Mon Sep 17 00:00:00 2001 From: MD Aleem <72057206+aleem1314@users.noreply.github.com> Date: Thu, 16 Sep 2021 02:48:01 +0530 Subject: [PATCH 1/5] feat(tests): add simapp setup helpers (#10020) --- simapp/app_test.go | 44 +++++++++----------- simapp/test_helpers.go | 90 +++++++++++++++++++++++++++++++++++----- testutil/mock/privval.go | 50 ++++++++++++++++++++++ x/bank/app_test.go | 10 ++--- x/bank/bench_test.go | 4 +- x/slashing/app_test.go | 2 +- x/staking/app_test.go | 2 +- x/upgrade/abci_test.go | 53 +++++++++++------------ 8 files changed, 182 insertions(+), 73 deletions(-) create mode 100644 testutil/mock/privval.go diff --git a/simapp/app_test.go b/simapp/app_test.go index 249775349b84..0598609de3be 100644 --- a/simapp/app_test.go +++ b/simapp/app_test.go @@ -39,7 +39,15 @@ import ( func TestSimAppExportAndBlockedAddrs(t *testing.T) { encCfg := MakeTestEncodingConfig() db := dbm.NewMemDB() - app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{}) + app := NewSimappWithCustomOptions(t, false, SetupOptions{ + Logger: log.NewTMLogger(log.NewSyncWriter(os.Stdout)), + DB: db, + InvCheckPeriod: 0, + EncConfig: encCfg, + HomePath: DefaultNodeHome, + SkipUpgradeHeights: map[int64]bool{}, + AppOpts: EmptyAppOptions{}, + }) for acc := range maccPerms { require.True( @@ -49,22 +57,11 @@ func TestSimAppExportAndBlockedAddrs(t *testing.T) { ) } - genesisState := NewDefaultGenesisState(encCfg.Codec) - stateBytes, err := json.MarshalIndent(genesisState, "", " ") - require.NoError(t, err) - - // Initialize the chain - app.InitChain( - abci.RequestInitChain{ - Validators: []abci.ValidatorUpdate{}, - AppStateBytes: stateBytes, - }, - ) app.Commit() // Making a new app object with the db, so that initchain hasn't been called app2 := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{}) - _, err = app2.ExportAppStateAndValidators(false, []string{}) + _, err := app2.ExportAppStateAndValidators(false, []string{}) require.NoError(t, err, "ExportAppStateAndValidators should not have an error") } @@ -249,18 +246,15 @@ func TestInitGenesisOnMigration(t *testing.T) { func TestUpgradeStateOnGenesis(t *testing.T) { encCfg := MakeTestEncodingConfig() db := dbm.NewMemDB() - app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{}) - genesisState := NewDefaultGenesisState(encCfg.Codec) - stateBytes, err := json.MarshalIndent(genesisState, "", " ") - require.NoError(t, err) - - // Initialize the chain - app.InitChain( - abci.RequestInitChain{ - Validators: []abci.ValidatorUpdate{}, - AppStateBytes: stateBytes, - }, - ) + app := NewSimappWithCustomOptions(t, false, SetupOptions{ + Logger: log.NewTMLogger(log.NewSyncWriter(os.Stdout)), + DB: db, + InvCheckPeriod: 0, + EncConfig: encCfg, + HomePath: DefaultNodeHome, + SkipUpgradeHeights: map[int64]bool{}, + AppOpts: EmptyAppOptions{}, + }) // make sure the upgrade keeper has version map in state ctx := app.NewContext(false, tmproto.Header{}) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index df8f6a5794ce..58e365aed655 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + tmjson "github.com/tendermint/tendermint/libs/json" "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" @@ -21,8 +22,12 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/simapp/helpers" + "github.com/cosmos/cosmos-sdk/simapp/params" + "github.com/cosmos/cosmos-sdk/testutil/mock" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -50,6 +55,17 @@ var DefaultConsensusParams = &abci.ConsensusParams{ }, } +// SetupOptions defines arguments that are passed into `Simapp` constructor. +type SetupOptions struct { + Logger log.Logger + DB *dbm.MemDB + InvCheckPeriod uint + HomePath string + SkipUpgradeHeights map[int64]bool + EncConfig params.EncodingConfig + AppOpts types.AppOptions +} + func setup(withGenesis bool, invCheckPeriod uint) (*SimApp, GenesisState) { db := dbm.NewMemDB() encCdc := MakeTestEncodingConfig() @@ -60,6 +76,47 @@ func setup(withGenesis bool, invCheckPeriod uint) (*SimApp, GenesisState) { return app, GenesisState{} } +// NewSimappWithCustomOptions initializes a new SimApp with custom options. +func NewSimappWithCustomOptions(t *testing.T, isCheckTx bool, options SetupOptions) *SimApp { + t.Helper() + + privVal := mock.NewPV() + pubKey, err := privVal.GetPubKey() + require.NoError(t, err) + // create validator set with single validator + validator := tmtypes.NewValidator(pubKey, 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + + // generate genesis account + senderPrivKey := secp256k1.GenPrivKey() + acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) + balance := banktypes.Balance{ + Address: acc.GetAddress().String(), + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))), + } + + app := NewSimApp(options.Logger, options.DB, nil, true, options.SkipUpgradeHeights, options.HomePath, options.InvCheckPeriod, options.EncConfig, options.AppOpts) + genesisState := NewDefaultGenesisState(app.appCodec) + genesisState = genesisStateWithValSet(t, app, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance) + + if !isCheckTx { + // init chain must be called to stop deliverState from being nil + stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ") + require.NoError(t, err) + + // Initialize the chain + app.InitChain( + abci.RequestInitChain{ + Validators: []abci.ValidatorUpdate{}, + ConsensusParams: DefaultConsensusParams, + AppStateBytes: stateBytes, + }, + ) + } + + return app +} + // Setup initializes a new SimApp. A Nop logger is set in SimApp. func Setup(t *testing.T, isCheckTx bool) *SimApp { t.Helper() @@ -83,12 +140,10 @@ func Setup(t *testing.T, isCheckTx bool) *SimApp { return app } -// SetupWithGenesisValSet initializes a new SimApp with a validator set and genesis accounts -// that also act as delegators. For simplicity, each validator is bonded with a delegation -// of one consensus engine unit (10^6) in the default token of the simapp from first genesis -// account. A Nop logger is set in SimApp. -func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp { - app, genesisState := setup(true, 5) +func genesisStateWithValSet(t *testing.T, + app *SimApp, genesisState GenesisState, + valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, + balances ...banktypes.Balance) GenesisState { // set genesis accounts authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis) @@ -96,7 +151,7 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) - bondAmt := sdk.NewInt(1000000) + bondAmt := sdk.DefaultPowerReduction for _, val := range valSet.Validators { pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey) @@ -140,6 +195,19 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{}) genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) + return genesisState +} + +// SetupWithGenesisValSet initializes a new SimApp with a validator set and genesis accounts +// that also act as delegators. For simplicity, each validator is bonded with a delegation +// of one consensus engine unit in the default token of the simapp from first genesis +// account. A Nop logger is set in SimApp. +func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp { + t.Helper() + + app, genesisState := setup(true, 5) + genesisState = genesisStateWithValSet(t, app, genesisState, valSet, genAccs, balances...) + stateBytes, err := json.MarshalIndent(genesisState, "", " ") require.NoError(t, err) @@ -166,7 +234,9 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs // SetupWithGenesisAccounts initializes a new SimApp with the provided genesis // accounts and possible balances. -func SetupWithGenesisAccounts(genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp { +func SetupWithGenesisAccounts(t *testing.T, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp { + t.Helper() + app, genesisState := setup(true, 0) authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis) @@ -180,9 +250,7 @@ func SetupWithGenesisAccounts(genAccs []authtypes.GenesisAccount, balances ...ba genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) stateBytes, err := json.MarshalIndent(genesisState, "", " ") - if err != nil { - panic(err) - } + require.NoError(t, err) app.InitChain( abci.RequestInitChain{ diff --git a/testutil/mock/privval.go b/testutil/mock/privval.go new file mode 100644 index 000000000000..fe46659b3df9 --- /dev/null +++ b/testutil/mock/privval.go @@ -0,0 +1,50 @@ +package mock + +import ( + "github.com/tendermint/tendermint/crypto" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmtypes "github.com/tendermint/tendermint/types" + + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +var _ tmtypes.PrivValidator = PV{} + +// MockPV implements PrivValidator without any safety or persistence. +// Only use it for testing. +type PV struct { + PrivKey cryptotypes.PrivKey +} + +func NewPV() PV { + return PV{ed25519.GenPrivKey()} +} + +// GetPubKey implements PrivValidator interface +func (pv PV) GetPubKey() (crypto.PubKey, error) { + return cryptocodec.ToTmPubKeyInterface(pv.PrivKey.PubKey()) +} + +// SignVote implements PrivValidator interface +func (pv PV) SignVote(chainID string, vote *tmproto.Vote) error { + signBytes := tmtypes.VoteSignBytes(chainID, vote) + sig, err := pv.PrivKey.Sign(signBytes) + if err != nil { + return err + } + vote.Signature = sig + return nil +} + +// SignProposal implements PrivValidator interface +func (pv PV) SignProposal(chainID string, proposal *tmproto.Proposal) error { + signBytes := tmtypes.ProposalSignBytes(chainID, proposal) + sig, err := pv.PrivKey.Sign(signBytes) + if err != nil { + return err + } + proposal.Signature = sig + return nil +} diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 5e134010e483..d1e810277edd 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -92,7 +92,7 @@ func TestSendNotEnoughBalance(t *testing.T) { } genAccs := []authtypes.GenesisAccount{acc} - app := simapp.SetupWithGenesisAccounts(genAccs) + app := simapp.SetupWithGenesisAccounts(t, genAccs) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67)))) @@ -127,7 +127,7 @@ func TestMsgMultiSendWithAccounts(t *testing.T) { } genAccs := []authtypes.GenesisAccount{acc} - app := simapp.SetupWithGenesisAccounts(genAccs) + app := simapp.SetupWithGenesisAccounts(t, genAccs) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67)))) @@ -197,7 +197,7 @@ func TestMsgMultiSendMultipleOut(t *testing.T) { } genAccs := []authtypes.GenesisAccount{acc1, acc2} - app := simapp.SetupWithGenesisAccounts(genAccs) + app := simapp.SetupWithGenesisAccounts(t, genAccs) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) @@ -246,7 +246,7 @@ func TestMsgMultiSendMultipleInOut(t *testing.T) { } genAccs := []authtypes.GenesisAccount{acc1, acc2, acc4} - app := simapp.SetupWithGenesisAccounts(genAccs) + app := simapp.SetupWithGenesisAccounts(t, genAccs) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) @@ -293,7 +293,7 @@ func TestMsgMultiSendDependent(t *testing.T) { require.NoError(t, err) genAccs := []authtypes.GenesisAccount{acc1, acc2} - app := simapp.SetupWithGenesisAccounts(genAccs) + app := simapp.SetupWithGenesisAccounts(t, genAccs) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index 0755e2cabb7f..7503ee671565 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -29,7 +29,7 @@ func BenchmarkOneBankSendTxPerBlock(b *testing.B) { // construct genesis state genAccs := []types.GenesisAccount{&acc} - benchmarkApp := simapp.SetupWithGenesisAccounts(genAccs) + benchmarkApp := simapp.SetupWithGenesisAccounts(&testing.T{}, genAccs) ctx := benchmarkApp.BaseApp.NewContext(false, tmproto.Header{}) // some value conceivably higher than the benchmarks would ever go @@ -73,7 +73,7 @@ func BenchmarkOneBankMultiSendTxPerBlock(b *testing.B) { // Construct genesis state genAccs := []authtypes.GenesisAccount{&acc} - benchmarkApp := simapp.SetupWithGenesisAccounts(genAccs) + benchmarkApp := simapp.SetupWithGenesisAccounts(&testing.T{}, genAccs) ctx := benchmarkApp.BaseApp.NewContext(false, tmproto.Header{}) // some value conceivably higher than the benchmarks would ever go diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 028d41755607..e9ece2c690a1 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -57,7 +57,7 @@ func TestSlashingMsgs(t *testing.T) { }, } - app := simapp.SetupWithGenesisAccounts(accs, balances...) + app := simapp.SetupWithGenesisAccounts(t, accs, balances...) simapp.CheckBalance(t, app, addr1, sdk.Coins{genCoin}) description := stakingtypes.NewDescription("foo_moniker", "", "", "", "") diff --git a/x/staking/app_test.go b/x/staking/app_test.go index 65a6e4524ebf..a97954254826 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -59,7 +59,7 @@ func TestStakingMsgs(t *testing.T) { }, } - app := simapp.SetupWithGenesisAccounts(accs, balances...) + app := simapp.SetupWithGenesisAccounts(t, accs, balances...) simapp.CheckBalance(t, app, addr1, sdk.Coins{genCoin}) simapp.CheckBalance(t, app, addr2, sdk.Coins{genCoin}) diff --git a/x/upgrade/abci_test.go b/x/upgrade/abci_test.go index 5e0d1fd79242..16206447ac53 100644 --- a/x/upgrade/abci_test.go +++ b/x/upgrade/abci_test.go @@ -1,7 +1,6 @@ package upgrade_test import ( - "encoding/json" "errors" "fmt" "os" @@ -34,20 +33,18 @@ type TestSuite struct { var s TestSuite -func setupTest(height int64, skip map[int64]bool) TestSuite { +func setupTest(t *testing.T, height int64, skip map[int64]bool) TestSuite { + db := dbm.NewMemDB() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, skip, simapp.DefaultNodeHome, 0, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{}) - genesisState := simapp.NewDefaultGenesisState(app.AppCodec()) - stateBytes, err := json.MarshalIndent(genesisState, "", " ") - if err != nil { - panic(err) - } - app.InitChain( - abci.RequestInitChain{ - Validators: []abci.ValidatorUpdate{}, - AppStateBytes: stateBytes, - }, - ) + app := simapp.NewSimappWithCustomOptions(t, false, simapp.SetupOptions{ + Logger: log.NewNopLogger(), + SkipUpgradeHeights: skip, + DB: db, + InvCheckPeriod: 0, + HomePath: simapp.DefaultNodeHome, + EncConfig: simapp.MakeTestEncodingConfig(), + AppOpts: simapp.EmptyAppOptions{}, + }) s.keeper = app.UpgradeKeeper s.ctx = app.BaseApp.NewContext(false, tmproto.Header{Height: height, Time: time.Now()}) @@ -59,7 +56,7 @@ func setupTest(height int64, skip map[int64]bool) TestSuite { } func TestRequireName(t *testing.T) { - s := setupTest(10, map[int64]bool{}) + s := setupTest(t, 10, map[int64]bool{}) err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{}}) require.NotNil(t, err) @@ -67,14 +64,14 @@ func TestRequireName(t *testing.T) { } func TestRequireFutureBlock(t *testing.T) { - s := setupTest(10, map[int64]bool{}) + s := setupTest(t, 10, map[int64]bool{}) err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: s.ctx.BlockHeight()}}) require.NotNil(t, err) require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) } func TestDoHeightUpgrade(t *testing.T) { - s := setupTest(10, map[int64]bool{}) + s := setupTest(t, 10, map[int64]bool{}) t.Log("Verify can schedule an upgrade") err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: s.ctx.BlockHeight() + 1}}) require.Nil(t, err) @@ -83,7 +80,7 @@ func TestDoHeightUpgrade(t *testing.T) { } func TestCanOverwriteScheduleUpgrade(t *testing.T) { - s := setupTest(10, map[int64]bool{}) + s := setupTest(t, 10, map[int64]bool{}) t.Log("Can overwrite plan") err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "bad_test", Height: s.ctx.BlockHeight() + 10}}) require.Nil(t, err) @@ -132,7 +129,7 @@ func VerifyDoUpgradeWithCtx(t *testing.T, newCtx sdk.Context, proposalName strin } func TestHaltIfTooNew(t *testing.T) { - s := setupTest(10, map[int64]bool{}) + s := setupTest(t, 10, map[int64]bool{}) t.Log("Verify that we don't panic with registered plan not in database at all") var called int s.keeper.SetUpgradeHandler("future", func(ctx sdk.Context, plan types.Plan, vm module.VersionMap) (module.VersionMap, error) { @@ -175,7 +172,7 @@ func VerifyCleared(t *testing.T, newCtx sdk.Context) { } func TestCanClear(t *testing.T) { - s := setupTest(10, map[int64]bool{}) + s := setupTest(t, 10, map[int64]bool{}) t.Log("Verify upgrade is scheduled") err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: s.ctx.BlockHeight() + 100}}) require.Nil(t, err) @@ -187,7 +184,7 @@ func TestCanClear(t *testing.T) { } func TestCantApplySameUpgradeTwice(t *testing.T) { - s := setupTest(10, map[int64]bool{}) + s := setupTest(t, 10, map[int64]bool{}) height := s.ctx.BlockHeader().Height + 1 err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: height}}) require.Nil(t, err) @@ -199,7 +196,7 @@ func TestCantApplySameUpgradeTwice(t *testing.T) { } func TestNoSpuriousUpgrades(t *testing.T) { - s := setupTest(10, map[int64]bool{}) + s := setupTest(t, 10, map[int64]bool{}) t.Log("Verify that no upgrade panic is triggered in the BeginBlocker when we haven't scheduled an upgrade") req := abci.RequestBeginBlock{Header: s.ctx.BlockHeader()} require.NotPanics(t, func() { @@ -243,7 +240,7 @@ func TestContains(t *testing.T) { var ( skipOne int64 = 11 ) - s := setupTest(10, map[int64]bool{skipOne: true}) + s := setupTest(t, 10, map[int64]bool{skipOne: true}) VerifySet(t, map[int64]bool{skipOne: true}) t.Log("case where array contains the element") @@ -258,7 +255,7 @@ func TestSkipUpgradeSkippingAll(t *testing.T) { skipOne int64 = 11 skipTwo int64 = 20 ) - s := setupTest(10, map[int64]bool{skipOne: true, skipTwo: true}) + s := setupTest(t, 10, map[int64]bool{skipOne: true, skipTwo: true}) newCtx := s.ctx @@ -295,7 +292,7 @@ func TestUpgradeSkippingOne(t *testing.T) { skipOne int64 = 11 skipTwo int64 = 20 ) - s := setupTest(10, map[int64]bool{skipOne: true}) + s := setupTest(t, 10, map[int64]bool{skipOne: true}) newCtx := s.ctx @@ -330,7 +327,7 @@ func TestUpgradeSkippingOnlyTwo(t *testing.T) { skipTwo int64 = 20 skipThree int64 = 25 ) - s := setupTest(10, map[int64]bool{skipOne: true, skipTwo: true}) + s := setupTest(t, 10, map[int64]bool{skipOne: true, skipTwo: true}) newCtx := s.ctx @@ -369,7 +366,7 @@ func TestUpgradeSkippingOnlyTwo(t *testing.T) { } func TestUpgradeWithoutSkip(t *testing.T) { - s := setupTest(10, map[int64]bool{}) + s := setupTest(t, 10, map[int64]bool{}) newCtx := s.ctx.WithBlockHeight(s.ctx.BlockHeight() + 1).WithBlockTime(time.Now()) req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: s.ctx.BlockHeight() + 1}}) @@ -384,7 +381,7 @@ func TestUpgradeWithoutSkip(t *testing.T) { } func TestDumpUpgradeInfoToFile(t *testing.T) { - s := setupTest(10, map[int64]bool{}) + s := setupTest(t, 10, map[int64]bool{}) require := require.New(t) // require no error when the upgrade info file does not exist From 9c916a87bb807fe5a520639a177de86b9866c5f0 Mon Sep 17 00:00:00 2001 From: Ryan Christoffersen <12519942+ryanchristo@users.noreply.github.com> Date: Thu, 16 Sep 2021 02:39:42 -0700 Subject: [PATCH 2/5] docs: feegrant client spec (#10160) * docs: feegrant client spec * fix cli statement Co-authored-by: Aleksandr Bezobchuk --- x/feegrant/spec/05_client.md | 184 +++++++++++++++++++++++++++++++++++ x/feegrant/spec/README.md | 3 + 2 files changed, 187 insertions(+) create mode 100644 x/feegrant/spec/05_client.md diff --git a/x/feegrant/spec/05_client.md b/x/feegrant/spec/05_client.md new file mode 100644 index 000000000000..dbb5005bca64 --- /dev/null +++ b/x/feegrant/spec/05_client.md @@ -0,0 +1,184 @@ + + +# Client + +## CLI + +A user can query and interact with the `feegrant` module using the CLI. + +### Query + +The `query` commands allow users to query `feegrant` state. + +``` +simd query feegrant --help +``` + +#### grant + +The `grant` command allows users to query a grant for a given granter-grantee pair. + +``` +simd query feegrant grant [granter] [grantee] [flags] +``` + +Example: + +``` +simd query feegrant grant cosmos1.. cosmos1.. +``` + +Example Output: + +``` +allowance: + '@type': /cosmos.feegrant.v1beta1.BasicAllowance + expiration: null + spend_limit: + - amount: "100" + denom: stake +grantee: cosmos1.. +granter: cosmos1.. +``` + +#### grants + +The `grants` command allows users to query all grants for a given grantee. + +``` +simd query feegrant grants [grantee] [flags] +``` + +Example: + +``` +simd query feegrant grants cosmos1.. +``` + +Example Output: + +``` +allowances: +- allowance: + '@type': /cosmos.feegrant.v1beta1.BasicAllowance + expiration: null + spend_limit: + - amount: "100" + denom: stake + grantee: cosmos1.. + granter: cosmos1.. +pagination: + next_key: null + total: "0" +``` + +### Transactions + +The `tx` commands allow users to interact with the `feegrant` module. + +``` +simd tx feegrant --help +``` + +#### grant + +The `grant` command allows users to grant fee allowances to another account. The fee allowance can have an expiration date, a total spend limit, and/or a periodic spend limit. + +``` +simd tx feegrant grant [granter] [grantee] [flags] +``` + +Example (one-time spend limit): + +``` +simd tx feegrant grant cosmos1.. cosmos1.. --spend-limit 100stake +``` + +Example (periodic spend limit): + +``` +simd tx feegrant grant cosmos1.. cosmos1.. --period 3600 --period-limit 10stake +``` + +#### revoke + +The `revoke` command allows users to revoke a granted fee allowance. + +``` +simd tx feegrant revoke [granter] [grantee] [flags] +``` + +Example: + +``` +simd tx feegrant revoke cosmos1.. cosmos1.. +``` + +## gRPC + +A user can query the `feegrant` module using gRPC endpoints. + +### Allowance + +The `Allowance` endpoint allows users to query a granted fee allowance. + +``` +cosmos.feegrant.v1beta1.Query/Allowance +``` + +Example: + +``` +grpcurl -plaintext \ + -d '{"grantee":"cosmos1..","granter":"cosmos1.."}' \ + localhost:9090 \ + cosmos.feegrant.v1beta1.Query/Allowance +``` + +Example Output: + +``` +{ + "allowance": { + "granter": "cosmos1..", + "grantee": "cosmos1..", + "allowance": {"@type":"/cosmos.feegrant.v1beta1.BasicAllowance","spendLimit":[{"denom":"stake","amount":"100"}]} + } +} +``` + +### Allowances + +The `Allowances` endpoint allows users to query all granted fee allowances for a given grantee. + +``` +cosmos.feegrant.v1beta1.Query/Allowances +``` + +Example: + +``` +grpcurl -plaintext \ + -d '{"address":"cosmos1.."}' \ + localhost:9090 \ + cosmos.feegrant.v1beta1.Query/Allowances +``` + +Example Output: + +``` +{ + "allowances": [ + { + "granter": "cosmos1..", + "grantee": "cosmos1..", + "allowance": {"@type":"/cosmos.feegrant.v1beta1.BasicAllowance","spendLimit":[{"denom":"stake","amount":"100"}]} + } + ], + "pagination": { + "total": "1" + } +} +``` diff --git a/x/feegrant/spec/README.md b/x/feegrant/spec/README.md index b1bd7febfd61..d59854b665e6 100644 --- a/x/feegrant/spec/README.md +++ b/x/feegrant/spec/README.md @@ -30,3 +30,6 @@ This module allows accounts to grant fee allowances and to use fees from their a - [MsgGrantAllowance](04_events.md#msggrantallowance) - [MsgRevokeAllowance](04_events.md#msgrevokeallowance) - [Exec fee allowance](04_events.md#exec-fee-allowance) +5. **[Client](05_client.md)** + - [CLI](05_client.md#cli) + - [gRPC](05_client.md#grpc) \ No newline at end of file From 8a3d7dddea7b08b5e293a4ad896b877c93d42a40 Mon Sep 17 00:00:00 2001 From: Ryan Christoffersen <12519942+ryanchristo@users.noreply.github.com> Date: Thu, 16 Sep 2021 02:44:10 -0700 Subject: [PATCH 3/5] docs: distribution client spec (#10159) ## Description Ref: #9707 Add `client.md` page to `distribution` module spec. --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct `docs:` prefix in the PR title - [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] provided a link to the relevant issue or specification - [x] followed the [documentation writing guidelines](https://github.com/cosmos/cosmos-sdk/blob/master/docs/DOC_WRITING_GUIDELINES.md) - [x] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct `docs:` prefix in the PR title - [ ] confirmed all author checklist items have been addressed - [ ] confirmed that this PR only changes documentation - [ ] reviewed content for consistency - [ ] reviewed content for thoroughness - [ ] reviewed content for spelling and grammar - [ ] tested instructions (if applicable) --- x/distribution/spec/08_client.md | 469 +++++++++++++++++++++++++++++++ x/distribution/spec/README.md | 3 + 2 files changed, 472 insertions(+) create mode 100644 x/distribution/spec/08_client.md diff --git a/x/distribution/spec/08_client.md b/x/distribution/spec/08_client.md new file mode 100644 index 000000000000..0e80a2f2d431 --- /dev/null +++ b/x/distribution/spec/08_client.md @@ -0,0 +1,469 @@ + + +# Client + +## CLI + +A user can query and interact with the `distribution` module using the CLI. + +### Query + +The `query` commands allow users to query `distribution` state. + +``` +simd query distribution --help +``` + +#### commission + +The `commission` command allows users to query validator commission rewards by address. + +``` +simd query distribution commission [address] [flags] +``` + +Example: + +``` +simd query distribution commission cosmosvaloper1.. +``` + +Example Output: + +``` +commission: +- amount: "1000000.000000000000000000" + denom: stake +``` + +#### community-pool + +The `community-pool` command allows users to query all coin balances within the community pool. + +``` +simd query distribution community-pool [flags] +``` + +Example: + +``` +simd query distribution community-pool +``` + +Example Output: + +``` +pool: +- amount: "1000000.000000000000000000" + denom: stake +``` + +#### params + +The `params` command allows users to query the parameters of the `distribution` module. + +``` +simd query distribution params [flags] +``` + +Example: + +``` +simd query distribution params +``` + +Example Output: + +``` +base_proposer_reward: "0.010000000000000000" +bonus_proposer_reward: "0.040000000000000000" +community_tax: "0.020000000000000000" +withdraw_addr_enabled: true +``` + +#### rewards + +The `rewards` command allows users to query delegator rewards. Users can optionally include the validator address to query rewards earned from a specific validator. + +``` +simd query distribution rewards [delegator-addr] [validator-addr] [flags] +``` + +Example: + +``` +simd query distribution rewards cosmos1.. +``` + +Example Output: + +``` +rewards: +- reward: + - amount: "1000000.000000000000000000" + denom: stake + validator_address: cosmosvaloper1.. +total: +- amount: "1000000.000000000000000000" + denom: stake +``` + +#### slashes + +The `slashes` command allows users to query all slashes for a given block range. + +``` +simd query distribution slashes [validator] [start-height] [end-height] [flags] +``` + +Example: + +``` +simd query distribution slashes cosmosvaloper1.. 1 1000 +``` + +Example Output: + +``` +pagination: + next_key: null + total: "0" +slashes: +- validator_period: 20, + fraction: "0.009999999999999999" +``` + +#### validator-outstanding-rewards + +The `validator-outstanding-rewards` command allows users to query all outstanding (un-withdrawn) rewards for a validator and all their delegations. + +``` +simd query distribution validator-outstanding-rewards [validator] [flags] +``` + +Example: + +``` +simd query distribution validator-outstanding-rewards cosmosvaloper1.. +``` + +Example Output: + +``` +rewards: +- amount: "1000000.000000000000000000" + denom: stake +``` + +### Transactions + +The `tx` commands allow users to interact with the `distribution` module. + +``` +simd tx distribution --help +``` + +#### fund-community-pool + +The `fund-community-pool` command allows users to send funds to the community pool. + +``` +simd tx distribution fund-community-pool [amount] [flags] +``` + +Example: + +``` +simd tx distribution fund-community-pool 100stake --from cosmos1.. +``` + +#### set-withdraw-addr + +The `set-withdraw-addr` command allows users to set the withdraw address for rewards associated with a delegator address. + +``` +simd tx distribution set-withdraw-addr [withdraw-addr] [flags] +``` + +Example: + +``` +simd tx distribution set-withdraw-addr cosmos1.. --from cosmos1.. +``` + +#### withdraw-all-rewards + +The `withdraw-all-rewards` command allows users to withdraw all rewards for a delegator. + +``` +simd tx distribution withdraw-all-rewards [flags] +``` + +Example: + +``` +simd tx distribution withdraw-all-rewards --from cosmos1.. +``` + +#### withdraw-rewards + +The `withdraw-rewards` command allows users to withdraw all rewards from a given delegation address, +and optionally withdraw validator commission if the delegation address given is a validator operator and the user proves the `--commision` flag. + +``` +simd tx distribution withdraw-rewards [validator-addr] [flags] +``` + +Example: + +``` +simd tx distribution withdraw-rewards cosmosvaloper1.. --from cosmos1.. --commision +``` + +## gRPC + +A user can query the `distribution` module using gRPC endpoints. + +### Params + +The `Params` endpoint allows users to query parameters of the `distribution` module. + +Example: + +``` +grpcurl -plaintext \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/Params +``` + +Example Output: + +``` +{ + "params": { + "communityTax": "20000000000000000", + "baseProposerReward": "10000000000000000", + "bonusProposerReward": "40000000000000000", + "withdrawAddrEnabled": true + } +} +``` + +### ValidatorOutstandingRewards + +The `ValidatorOutstandingRewards` endpoint allows users to query rewards of a validator address. + +Example: + +``` +grpcurl -plaintext \ + -d '{"validator_address":"cosmosvalop1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/ValidatorOutstandingRewards +``` + +Example Output: + +``` +{ + "rewards": { + "rewards": [ + { + "denom": "stake", + "amount": "1000000000000000" + } + ] + } +} +``` + +### ValidatorCommission + +The `ValidatorCommission` endpoint allows users to query accumulated commission for a validator. + +Example: + +``` +grpcurl -plaintext \ + -d '{"validator_address":"cosmosvalop1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/ValidatorCommission +``` + +Example Output: + +``` +{ + "commission": { + "commission": [ + { + "denom": "stake", + "amount": "1000000000000000" + } + ] + } +} +``` + +### ValidatorSlashes + +The `ValidatorSlashes` endpoint allows users to query slash events of a validator. + +Example: + +``` +grpcurl -plaintext \ + -d '{"validator_address":"cosmosvalop1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/ValidatorSlashes +``` + +Example Output: + +``` +{ + "slashes": [ + { + "validator_period": "20", + "fraction": "0.009999999999999999" + } + ], + "pagination": { + "total": "1" + } +} +``` + +### DelegationRewards + +The `DelegationRewards` endpoint allows users to query the total rewards accrued by a delegation. + +Example: + +``` +grpcurl -plaintext \ + -d '{"delegator_address":"cosmos1..","validator_address":"cosmosvalop1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/DelegationRewards +``` + +Example Output: + +``` +{ + "rewards": [ + { + "denom": "stake", + "amount": "1000000000000000" + } + ] +} +``` + +### DelegationTotalRewards + +The `DelegationTotalRewards` endpoint allows users to query the total rewards accrued by each validator. + +Example: + +``` +grpcurl -plaintext \ + -d '{"delegator_address":"cosmos1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/DelegationTotalRewards +``` + +Example Output: + +``` +{ + "rewards": [ + { + "validatorAddress": "cosmosvaloper1..", + "reward": [ + { + "denom": "stake", + "amount": "1000000000000000" + } + ] + } + ], + "total": [ + { + "denom": "stake", + "amount": "1000000000000000" + } + ] +} +``` + +### DelegatorValidators + +The `DelegatorValidators` endpoint allows users to query all validators for given delegator. + +Example: + +``` +grpcurl -plaintext \ + -d '{"delegator_address":"cosmos1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/DelegatorValidators +``` + +Example Output: + +``` +{ + "validators": [ + "cosmosvaloper1.." + ] +} +``` + +### DelegatorWithdrawAddress + +The `DelegatorWithdrawAddress` endpoint allows users to query the withdraw address of a delegator. + +Example: + +``` +grpcurl -plaintext \ + -d '{"delegator_address":"cosmos1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/DelegatorWithdrawAddress +``` + +Example Output: + +``` +{ + "withdrawAddress": "cosmos1.." +} +``` + +### CommunityPool + +The `CommunityPool` endpoint allows users to query the community pool coins. + +Example: + +``` +grpcurl -plaintext \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/CommunityPool +``` + +Example Output: + +``` +{ + "pool": [ + { + "denom": "stake", + "amount": "1000000000000000000" + } + ] +} +``` diff --git a/x/distribution/spec/README.md b/x/distribution/spec/README.md index 868b425901b1..992c87821628 100644 --- a/x/distribution/spec/README.md +++ b/x/distribution/spec/README.md @@ -101,3 +101,6 @@ to set up a script to periodically withdraw and rebond rewards. - [BeginBlocker](06_events.md#beginblocker) - [Handlers](06_events.md#handlers) 7. **[Parameters](07_params.md)** +8. **[Parameters](07_params.md)** + - [CLI](08_client.md#cli) + - [gRPC](08_client.md#grpc) \ No newline at end of file From 5a72b5e02b3339eca0d4b750dffd47583a879ded Mon Sep 17 00:00:00 2001 From: Geoff Lee Date: Thu, 16 Sep 2021 19:14:03 +0900 Subject: [PATCH 4/5] fix: rosetta server boot and add burn event type to pass check:data (#10150) ## Description closes: #10121 closes: #10088 rosetta server fails to run with genesis.json has initial_heights 2 or larger rosetta-cli check:data fails to parse EventTypeCoinBurn --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) --- server/rosetta/client_online.go | 25 ++++++++++++++++++- .../rosetta/lib/internal/service/offline.go | 2 +- server/rosetta/lib/internal/service/online.go | 11 +++++--- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/server/rosetta/client_online.go b/server/rosetta/client_online.go index e78d9a6f045d..0a34b8b1a878 100644 --- a/server/rosetta/client_online.go +++ b/server/rosetta/client_online.go @@ -76,7 +76,9 @@ func NewClient(cfg *Config) (*Client, error) { supportedOperations = append( supportedOperations, - bank.EventTypeCoinSpent, bank.EventTypeCoinReceived, + bank.EventTypeCoinSpent, + bank.EventTypeCoinReceived, + bank.EventTypeCoinBurn, ) return &Client{ @@ -185,6 +187,10 @@ func (c *Client) BlockByHash(ctx context.Context, hash string) (crgtypes.BlockRe } func (c *Client) BlockByHeight(ctx context.Context, height *int64) (crgtypes.BlockResponse, error) { + height, err := c.getHeight(ctx, height) + if err != nil { + return crgtypes.BlockResponse{}, crgerrs.WrapError(crgerrs.ErrBadGateway, err.Error()) + } block, err := c.tmRPC.Block(ctx, height) if err != nil { return crgtypes.BlockResponse{}, crgerrs.WrapError(crgerrs.ErrBadGateway, err.Error()) @@ -204,6 +210,10 @@ func (c *Client) BlockTransactionsByHash(ctx context.Context, hash string) (crgt } func (c *Client) BlockTransactionsByHeight(ctx context.Context, height *int64) (crgtypes.BlockTransactionsResponse, error) { + height, err := c.getHeight(ctx, height) + if err != nil { + return crgtypes.BlockTransactionsResponse{}, crgerrs.WrapError(crgerrs.ErrBadGateway, err.Error()) + } blockTxResp, err := c.blockTxs(ctx, height) if err != nil { return crgtypes.BlockTransactionsResponse{}, err @@ -468,3 +478,16 @@ func (c *Client) blockTxs(ctx context.Context, height *int64) (crgtypes.BlockTra Transactions: finalTxs, }, nil } + +func (c *Client) getHeight(ctx context.Context, height *int64) (realHeight *int64, err error) { + if height != nil && *height == -1 { + genesis, err := c.tmRPC.Genesis(ctx) + if err != nil { + return nil, err + } + realHeight = &(genesis.Genesis.InitialHeight) + } else { + realHeight = height + } + return +} diff --git a/server/rosetta/lib/internal/service/offline.go b/server/rosetta/lib/internal/service/offline.go index cc420cc431eb..0d0f4eb1b4c0 100644 --- a/server/rosetta/lib/internal/service/offline.go +++ b/server/rosetta/lib/internal/service/offline.go @@ -17,7 +17,7 @@ func NewOffline(network *types.NetworkIdentifier, client crgtypes.Client) (crgty OnlineNetwork{ client: client, network: network, - networkOptions: networkOptionsFromClient(client), + networkOptions: networkOptionsFromClient(client, nil), }, }, nil } diff --git a/server/rosetta/lib/internal/service/online.go b/server/rosetta/lib/internal/service/online.go index 4853a0fcd29c..c4315417267b 100644 --- a/server/rosetta/lib/internal/service/online.go +++ b/server/rosetta/lib/internal/service/online.go @@ -19,7 +19,7 @@ func NewOnlineNetwork(network *types.NetworkIdentifier, client crgtypes.Client) ctx, cancel := context.WithTimeout(context.Background(), genesisBlockFetchTimeout) defer cancel() - var genesisHeight int64 = 1 + var genesisHeight int64 = -1 // to use initial_height in genesis.json block, err := client.BlockByHeight(ctx, &genesisHeight) if err != nil { return OnlineNetwork{}, err @@ -28,7 +28,7 @@ func NewOnlineNetwork(network *types.NetworkIdentifier, client crgtypes.Client) return OnlineNetwork{ client: client, network: network, - networkOptions: networkOptionsFromClient(client), + networkOptions: networkOptionsFromClient(client, block.Block), genesisBlockIdentifier: block.Block, }, nil } @@ -50,7 +50,11 @@ func (o OnlineNetwork) AccountCoins(_ context.Context, _ *types.AccountCoinsRequ } // networkOptionsFromClient builds network options given the client -func networkOptionsFromClient(client crgtypes.Client) *types.NetworkOptionsResponse { +func networkOptionsFromClient(client crgtypes.Client, genesisBlock *types.BlockIdentifier) *types.NetworkOptionsResponse { + var tsi *int64 = nil + if genesisBlock != nil { + tsi = &(genesisBlock.Index) + } return &types.NetworkOptionsResponse{ Version: &types.Version{ RosettaVersion: crgtypes.SpecVersion, @@ -61,6 +65,7 @@ func networkOptionsFromClient(client crgtypes.Client) *types.NetworkOptionsRespo OperationTypes: client.SupportedOperations(), Errors: crgerrs.SealAndListErrors(), HistoricalBalanceLookup: true, + TimestampStartIndex: tsi, }, } } From 5e98404654ab4b30016aed913fa346e4bc27bc26 Mon Sep 17 00:00:00 2001 From: Ryan Christoffersen <12519942+ryanchristo@users.noreply.github.com> Date: Thu, 16 Sep 2021 04:08:28 -0700 Subject: [PATCH 5/5] docs: bank client spec (#10147) ## Description Ref: #9707 Add `client.md` page to `bank` module spec. --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct `docs:` prefix in the PR title - [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] provided a link to the relevant issue or specification - [x] followed the [documentation writing guidelines](https://github.com/cosmos/cosmos-sdk/blob/master/docs/DOC_WRITING_GUIDELINES.md) - [x] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct `docs:` prefix in the PR title - [ ] confirmed all author checklist items have been addressed - [ ] confirmed that this PR only changes documentation - [ ] reviewed content for consistency - [ ] reviewed content for thoroughness - [ ] reviewed content for spelling and grammar - [ ] tested instructions (if applicable) --- x/bank/spec/06_client.md | 390 +++++++++++++++++++++++++++++++++++++++ x/bank/spec/README.md | 3 + 2 files changed, 393 insertions(+) create mode 100644 x/bank/spec/06_client.md diff --git a/x/bank/spec/06_client.md b/x/bank/spec/06_client.md new file mode 100644 index 000000000000..077e950e8baf --- /dev/null +++ b/x/bank/spec/06_client.md @@ -0,0 +1,390 @@ + + +# Client + +## CLI + +A user can query and interact with the `bank` module using the CLI. + +### Query + +The `query` commands allow users to query `bank` state. + +``` +simd query bank --help +``` + +#### balances + +The `balances` command allows users to query account balances by address. + +``` +simd query bank balances [address] [flags] +``` + +Example: + +``` +simd query bank balances cosmos1.. +``` + +Example Output: + +``` +balances: +- amount: "1000000000" + denom: stake +pagination: + next_key: null + total: "0" +``` + +#### denom-metadata + +The `denom-metadata` command allows users to query metadata for coin denominations. A user can query metadata for a single denomination using the `--denom` flag or all denominations without it. + +``` +simd query bank denom-metadata [flags] +``` + +Example: + +``` +simd query bank denom-metadata --denom stake +``` + +Example Output: + +``` +metadata: + base: stake + denom_units: + - aliases: + - STAKE + denom: stake + description: native staking token of simulation app + display: stake + name: SimApp Token + symbol: STK +``` + +#### total + +The `total` command allows users to query the total supply of coins. A user can query the total supply for a single coin using the `--denom` flag or all coins without it. + +``` +simd query bank total [flags] +``` + +Example: + +``` +simd query bank total --denom stake +``` + +Example Output: + +``` +amount: "10000000000" +denom: stake +``` + +### Transactions + +The `tx` commands allow users to interact with the `bank` module. + +``` +simd tx bank --help +``` + +#### send + +The `send` command allows users to send funds from one account to another. + +``` +simd tx bank send [from_key_or_address] [to_address] [amount] [flags] +``` + +Example: + +``` +simd tx bank send cosmos1.. cosmos1.. 100stake +``` + +## gRPC + +A user can query the `bank` module using gRPC endpoints. + +### Balance + +The `Balance` endpoint allows users to query account balance by address for a given denomination. + +``` +cosmos.bank.v1beta1.Query/Balance +``` + +Example: + +``` +grpcurl -plaintext \ + -d '{"address":"cosmos1..","denom":"stake"}' \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/Balance +``` + +Example Output: + +``` +{ + "balance": { + "denom": "stake", + "amount": "1000000000" + } +} +``` + +### AllBalances + +The `AllBalances` endpoint allows users to query account balance by address for all denominations. + +``` +cosmos.bank.v1beta1.Query/AllBalances +``` + +Example: + +``` +grpcurl -plaintext \ + -d '{"address":"cosmos1.."}' \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/AllBalances +``` + +Example Output: + +``` +{ + "balances": [ + { + "denom": "stake", + "amount": "1000000000" + } + ], + "pagination": { + "total": "1" + } +} +``` + +### DenomMetadata + +The `DenomMetadata` endpoint allows users to query metadata for a single coin denomination. + +``` +cosmos.bank.v1beta1.Query/DenomMetadata +``` + +Example: + +``` +grpcurl -plaintext \ + -d '{"denom":"stake"}' \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/DenomMetadata +``` + +Example Output: + +``` +{ + "metadata": { + "description": "native staking token of simulation app", + "denomUnits": [ + { + "denom": "stake", + "aliases": [ + "STAKE" + ] + } + ], + "base": "stake", + "display": "stake", + "name": "SimApp Token", + "symbol": "STK" + } +} +``` + +### DenomsMetadata + +The `DenomsMetadata` endpoint allows users to query metadata for all coin denominations. + +``` +cosmos.bank.v1beta1.Query/DenomsMetadata +``` + +Example: + +``` +grpcurl -plaintext \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/DenomsMetadata +``` + +Example Output: + +``` +{ + "metadatas": [ + { + "description": "native staking token of simulation app", + "denomUnits": [ + { + "denom": "stake", + "aliases": [ + "STAKE" + ] + } + ], + "base": "stake", + "display": "stake", + "name": "SimApp Token", + "symbol": "STK" + } + ], + "pagination": { + "total": "1" + } +} +``` + +### DenomOwners + +The `DenomOwners` endpoint allows users to query metadata for a single coin denomination. + +``` +cosmos.bank.v1beta1.Query/DenomOwners +``` + +Example: + +``` +grpcurl -plaintext \ + -d '{"denom":"stake"}' \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/DenomOwners +``` + +Example Output: + +``` +{ + "denomOwners": [ + { + "address": "cosmos1..", + "balance": { + "denom": "stake", + "amount": "5000000000" + } + }, + { + "address": "cosmos1..", + "balance": { + "denom": "stake", + "amount": "5000000000" + } + }, + ], + "pagination": { + "total": "2" + } +} +``` + +### TotalSupply + +The `TotalSupply` endpoint allows users to query the total supply of all coins. + +``` +cosmos.bank.v1beta1.Query/TotalSupply +``` + +Example: + +``` +grpcurl -plaintext \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/TotalSupply +``` + +Example Output: + +``` +{ + "supply": [ + { + "denom": "stake", + "amount": "10000000000" + } + ], + "pagination": { + "total": "1" + } +} +``` + +### SupplyOf + +The `SupplyOf` endpoint allows users to query the total supply of a single coin. + +``` +cosmos.bank.v1beta1.Query/SupplyOf +``` + +Example: + +``` +grpcurl -plaintext \ + -d '{"denom":"stake"}' \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/SupplyOf +``` + +Example Output: + +``` +{ + "amount": { + "denom": "stake", + "amount": "10000000000" + } +} +``` + +### Params + +The `Params` endpoint allows users to query the parameters of the `bank` module. + +``` +cosmos.bank.v1beta1.Query/Params +``` + +Example: + +``` +grpcurl -plaintext \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/Params +``` + +Example Output: + +``` +{ + "params": { + "defaultSendEnabled": true + } +} +``` diff --git a/x/bank/spec/README.md b/x/bank/spec/README.md index 9a1a0afb6edc..53b68c7d7b57 100644 --- a/x/bank/spec/README.md +++ b/x/bank/spec/README.md @@ -100,3 +100,6 @@ The available permissions are: 4. **[Events](04_events.md)** - [Handlers](04_events.md#handlers) 5. **[Parameters](05_params.md)** +6. **[Client](06_client.md)** + - [CLI](06_client.md#cli) + - [gRPC](06_client.md#grpc) \ No newline at end of file