Merge PR #2730: add tx search pagination related CLI/REST API parameter
This commit is contained in:
parent
11738de624
commit
916ea85630
|
@ -43,6 +43,7 @@ FEATURES
|
||||||
|
|
||||||
* Gaia CLI (`gaiacli`)
|
* Gaia CLI (`gaiacli`)
|
||||||
* \#2399 Implement `params` command to query slashing parameters.
|
* \#2399 Implement `params` command to query slashing parameters.
|
||||||
|
* [\#2730](https://github.com/cosmos/cosmos-sdk/issues/2730) Add tx search pagination parameter
|
||||||
* [\#3027](https://github.com/cosmos/cosmos-sdk/issues/3027) Implement
|
* [\#3027](https://github.com/cosmos/cosmos-sdk/issues/3027) Implement
|
||||||
`query gov proposer [proposal-id]` to query for a proposal's proposer.
|
`query gov proposer [proposal-id]` to query for a proposal's proposer.
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
@ -17,11 +18,16 @@ import (
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
|
"github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
flagTags = "tags"
|
flagTags = "tags"
|
||||||
flagAny = "any"
|
flagAny = "any"
|
||||||
|
flagPage = "page"
|
||||||
|
flagLimit = "limit"
|
||||||
|
defaultPage = 1
|
||||||
|
defaultLimit = 30 // should be consistent with tendermint/tendermint/rpc/core/pipe.go:19
|
||||||
)
|
)
|
||||||
|
|
||||||
// default client command to search through tagged transactions
|
// default client command to search through tagged transactions
|
||||||
|
@ -32,7 +38,7 @@ func SearchTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||||
Long: strings.TrimSpace(`
|
Long: strings.TrimSpace(`
|
||||||
Search for transactions that match exactly the given tags. For example:
|
Search for transactions that match exactly the given tags. For example:
|
||||||
|
|
||||||
$ gaiacli query txs --tags '<tag1>:<value1>&<tag2>:<value2>'
|
$ gaiacli query txs --tags '<tag1>:<value1>&<tag2>:<value2>' --page 1 --limit 30
|
||||||
`),
|
`),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
tagsStr := viper.GetString(flagTags)
|
tagsStr := viper.GetString(flagTags)
|
||||||
|
@ -53,12 +59,18 @@ $ gaiacli query txs --tags '<tag1>:<value1>&<tag2>:<value2>'
|
||||||
}
|
}
|
||||||
|
|
||||||
keyValue := strings.Split(tag, ":")
|
keyValue := strings.Split(tag, ":")
|
||||||
tag = fmt.Sprintf("%s='%s'", keyValue[0], keyValue[1])
|
if keyValue[0] == types.TxHeightKey {
|
||||||
|
tag = fmt.Sprintf("%s=%s", keyValue[0], keyValue[1])
|
||||||
|
} else {
|
||||||
|
tag = fmt.Sprintf("%s='%s'", keyValue[0], keyValue[1])
|
||||||
|
}
|
||||||
tmTags = append(tmTags, tag)
|
tmTags = append(tmTags, tag)
|
||||||
}
|
}
|
||||||
|
page := viper.GetInt(flagPage)
|
||||||
|
limit := viper.GetInt(flagLimit)
|
||||||
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
txs, err := SearchTxs(cliCtx, cdc, tmTags)
|
txs, err := SearchTxs(cliCtx, cdc, tmTags, page, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -86,17 +98,27 @@ $ gaiacli query txs --tags '<tag1>:<value1>&<tag2>:<value2>'
|
||||||
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
||||||
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
|
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
|
||||||
cmd.Flags().String(flagTags, "", "tag:value list of tags that must match")
|
cmd.Flags().String(flagTags, "", "tag:value list of tags that must match")
|
||||||
|
cmd.Flags().Int32(flagPage, defaultPage, "Query a specific page of paginated results")
|
||||||
|
cmd.Flags().Int32(flagLimit, defaultLimit, "Query number of transactions results per page returned")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchTxs performs a search for transactions for a given set of tags via
|
// SearchTxs performs a search for transactions for a given set of tags via
|
||||||
// Tendermint RPC. It returns a slice of Info object containing txs and metadata.
|
// Tendermint RPC. It returns a slice of Info object containing txs and metadata.
|
||||||
// An error is returned if the query fails.
|
// An error is returned if the query fails.
|
||||||
func SearchTxs(cliCtx context.CLIContext, cdc *codec.Codec, tags []string) ([]Info, error) {
|
func SearchTxs(cliCtx context.CLIContext, cdc *codec.Codec, tags []string, page, limit int) ([]Info, error) {
|
||||||
if len(tags) == 0 {
|
if len(tags) == 0 {
|
||||||
return nil, errors.New("must declare at least one tag to search")
|
return nil, errors.New("must declare at least one tag to search")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if page <= 0 {
|
||||||
|
return nil, errors.New("page must greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
if limit <= 0 {
|
||||||
|
return nil, errors.New("limit must greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
// XXX: implement ANY
|
// XXX: implement ANY
|
||||||
query := strings.Join(tags, " AND ")
|
query := strings.Join(tags, " AND ")
|
||||||
|
|
||||||
|
@ -108,10 +130,7 @@ func SearchTxs(cliCtx context.CLIContext, cdc *codec.Codec, tags []string) ([]In
|
||||||
|
|
||||||
prove := !cliCtx.TrustNode
|
prove := !cliCtx.TrustNode
|
||||||
|
|
||||||
// TODO: take these as args
|
res, err := node.TxSearch(query, prove, page, limit)
|
||||||
page := 0
|
|
||||||
perPage := 100
|
|
||||||
res, err := node.TxSearch(query, prove, page, perPage)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -153,6 +172,7 @@ func FormatTxResults(cdc *codec.Codec, res []*ctypes.ResultTx) ([]Info, error) {
|
||||||
func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
|
func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
var tags []string
|
var tags []string
|
||||||
|
var page, limit int
|
||||||
var txs []Info
|
var txs []Info
|
||||||
err := r.ParseForm()
|
err := r.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -164,18 +184,14 @@ func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, values := range r.Form {
|
tags, page, limit, err = parseHTTPArgs(r)
|
||||||
value, err := url.QueryUnescape(values[0])
|
|
||||||
if err != nil {
|
|
||||||
utils.WriteErrorResponse(w, http.StatusBadRequest, sdk.AppendMsgToErr("could not decode query value", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tag := fmt.Sprintf("%s='%s'", key, value)
|
if err != nil {
|
||||||
tags = append(tags, tag)
|
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
txs, err = SearchTxs(cliCtx, cdc, tags)
|
txs, err = SearchTxs(cliCtx, cdc, tags, page, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
|
@ -184,3 +200,51 @@ func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.
|
||||||
utils.PostProcessResponse(w, cdc, txs, cliCtx.Indent)
|
utils.PostProcessResponse(w, cdc, txs, cliCtx.Indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseHTTPArgs(r *http.Request) (tags []string, page, limit int, err error) {
|
||||||
|
tags = make([]string, 0, len(r.Form))
|
||||||
|
for key, values := range r.Form {
|
||||||
|
if key == "page" || key == "limit" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var value string
|
||||||
|
value, err = url.QueryUnescape(values[0])
|
||||||
|
if err != nil {
|
||||||
|
return tags, page, limit, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tag string
|
||||||
|
if key == types.TxHeightKey {
|
||||||
|
tag = fmt.Sprintf("%s=%s", key, value)
|
||||||
|
} else {
|
||||||
|
tag = fmt.Sprintf("%s='%s'", key, value)
|
||||||
|
}
|
||||||
|
tags = append(tags, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
pageStr := r.FormValue("page")
|
||||||
|
if pageStr == "" {
|
||||||
|
page = defaultPage
|
||||||
|
} else {
|
||||||
|
page, err = strconv.Atoi(pageStr)
|
||||||
|
if err != nil {
|
||||||
|
return tags, page, limit, err
|
||||||
|
} else if page <= 0 {
|
||||||
|
return tags, page, limit, errors.New("page must greater than 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
limitStr := r.FormValue("limit")
|
||||||
|
if limitStr == "" {
|
||||||
|
limit = defaultLimit
|
||||||
|
} else {
|
||||||
|
limit, err = strconv.Atoi(limitStr)
|
||||||
|
if err != nil {
|
||||||
|
return tags, page, limit, err
|
||||||
|
} else if limit <= 0 {
|
||||||
|
return tags, page, limit, errors.New("limit must greater than 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags, page, limit, nil
|
||||||
|
}
|
||||||
|
|
|
@ -44,8 +44,8 @@ type GaiaApp struct {
|
||||||
// keys to access the substores
|
// keys to access the substores
|
||||||
keyMain *sdk.KVStoreKey
|
keyMain *sdk.KVStoreKey
|
||||||
keyAccount *sdk.KVStoreKey
|
keyAccount *sdk.KVStoreKey
|
||||||
keyStaking *sdk.KVStoreKey
|
keyStaking *sdk.KVStoreKey
|
||||||
tkeyStaking *sdk.TransientStoreKey
|
tkeyStaking *sdk.TransientStoreKey
|
||||||
keySlashing *sdk.KVStoreKey
|
keySlashing *sdk.KVStoreKey
|
||||||
keyMint *sdk.KVStoreKey
|
keyMint *sdk.KVStoreKey
|
||||||
keyDistr *sdk.KVStoreKey
|
keyDistr *sdk.KVStoreKey
|
||||||
|
@ -59,7 +59,7 @@ type GaiaApp struct {
|
||||||
accountKeeper auth.AccountKeeper
|
accountKeeper auth.AccountKeeper
|
||||||
feeCollectionKeeper auth.FeeCollectionKeeper
|
feeCollectionKeeper auth.FeeCollectionKeeper
|
||||||
bankKeeper bank.Keeper
|
bankKeeper bank.Keeper
|
||||||
stakingKeeper staking.Keeper
|
stakingKeeper staking.Keeper
|
||||||
slashingKeeper slashing.Keeper
|
slashingKeeper slashing.Keeper
|
||||||
mintKeeper mint.Keeper
|
mintKeeper mint.Keeper
|
||||||
distrKeeper distr.Keeper
|
distrKeeper distr.Keeper
|
||||||
|
@ -79,8 +79,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
|
||||||
cdc: cdc,
|
cdc: cdc,
|
||||||
keyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
|
keyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
|
||||||
keyAccount: sdk.NewKVStoreKey(auth.StoreKey),
|
keyAccount: sdk.NewKVStoreKey(auth.StoreKey),
|
||||||
keyStaking: sdk.NewKVStoreKey(staking.StoreKey),
|
keyStaking: sdk.NewKVStoreKey(staking.StoreKey),
|
||||||
tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey),
|
tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey),
|
||||||
keyMint: sdk.NewKVStoreKey(mint.StoreKey),
|
keyMint: sdk.NewKVStoreKey(mint.StoreKey),
|
||||||
keyDistr: sdk.NewKVStoreKey(distr.StoreKey),
|
keyDistr: sdk.NewKVStoreKey(distr.StoreKey),
|
||||||
tkeyDistr: sdk.NewTransientStoreKey(distr.TStoreKey),
|
tkeyDistr: sdk.NewTransientStoreKey(distr.TStoreKey),
|
||||||
|
|
|
@ -34,7 +34,7 @@ var (
|
||||||
type GenesisState struct {
|
type GenesisState struct {
|
||||||
Accounts []GenesisAccount `json:"accounts"`
|
Accounts []GenesisAccount `json:"accounts"`
|
||||||
AuthData auth.GenesisState `json:"auth"`
|
AuthData auth.GenesisState `json:"auth"`
|
||||||
StakingData staking.GenesisState `json:"staking"`
|
StakingData staking.GenesisState `json:"staking"`
|
||||||
MintData mint.GenesisState `json:"mint"`
|
MintData mint.GenesisState `json:"mint"`
|
||||||
DistrData distr.GenesisState `json:"distr"`
|
DistrData distr.GenesisState `json:"distr"`
|
||||||
GovData gov.GenesisState `json:"gov"`
|
GovData gov.GenesisState `json:"gov"`
|
||||||
|
@ -50,7 +50,7 @@ func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
|
||||||
return GenesisState{
|
return GenesisState{
|
||||||
Accounts: accounts,
|
Accounts: accounts,
|
||||||
AuthData: authData,
|
AuthData: authData,
|
||||||
StakingData: stakingData,
|
StakingData: stakingData,
|
||||||
MintData: mintData,
|
MintData: mintData,
|
||||||
DistrData: distrData,
|
DistrData: distrData,
|
||||||
GovData: govData,
|
GovData: govData,
|
||||||
|
@ -144,7 +144,7 @@ func NewDefaultGenesisState() GenesisState {
|
||||||
return GenesisState{
|
return GenesisState{
|
||||||
Accounts: nil,
|
Accounts: nil,
|
||||||
AuthData: auth.DefaultGenesisState(),
|
AuthData: auth.DefaultGenesisState(),
|
||||||
StakingData: staking.DefaultGenesisState(),
|
StakingData: staking.DefaultGenesisState(),
|
||||||
MintData: mint.DefaultGenesisState(),
|
MintData: mint.DefaultGenesisState(),
|
||||||
DistrData: distr.DefaultGenesisState(),
|
DistrData: distr.DefaultGenesisState(),
|
||||||
GovData: gov.DefaultGenesisState(),
|
GovData: gov.DefaultGenesisState(),
|
||||||
|
|
|
@ -163,7 +163,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||||
genesis := GenesisState{
|
genesis := GenesisState{
|
||||||
Accounts: genesisAccounts,
|
Accounts: genesisAccounts,
|
||||||
AuthData: authGenesis,
|
AuthData: authGenesis,
|
||||||
StakingData: stakingGenesis,
|
StakingData: stakingGenesis,
|
||||||
MintData: mintGenesis,
|
MintData: mintGenesis,
|
||||||
DistrData: distr.DefaultGenesisWithValidators(valAddrs),
|
DistrData: distr.DefaultGenesisWithValidators(valAddrs),
|
||||||
SlashingData: slashingGenesis,
|
SlashingData: slashingGenesis,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package clitest
|
package clitest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
@ -354,7 +355,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
tests.WaitForNextNBlocksTM(1, f.Port)
|
tests.WaitForNextNBlocksTM(1, f.Port)
|
||||||
|
|
||||||
// Ensure transaction tags can be queried
|
// Ensure transaction tags can be queried
|
||||||
txs := f.QueryTxs("action:submit_proposal", fmt.Sprintf("proposer:%s", fooAddr))
|
txs := f.QueryTxs(1, 50, "action:submit_proposal", fmt.Sprintf("proposer:%s", fooAddr))
|
||||||
require.Len(t, txs, 1)
|
require.Len(t, txs, 1)
|
||||||
|
|
||||||
// Ensure deposit was deducted
|
// Ensure deposit was deducted
|
||||||
|
@ -397,7 +398,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
require.Equal(t, int64(15), deposit.Amount.AmountOf(denom).Int64())
|
require.Equal(t, int64(15), deposit.Amount.AmountOf(denom).Int64())
|
||||||
|
|
||||||
// Ensure tags are set on the transaction
|
// Ensure tags are set on the transaction
|
||||||
txs = f.QueryTxs("action:deposit", fmt.Sprintf("depositor:%s", fooAddr))
|
txs = f.QueryTxs(1, 50, "action:deposit", fmt.Sprintf("depositor:%s", fooAddr))
|
||||||
require.Len(t, txs, 1)
|
require.Len(t, txs, 1)
|
||||||
|
|
||||||
// Ensure account has expected amount of funds
|
// Ensure account has expected amount of funds
|
||||||
|
@ -434,7 +435,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
require.Equal(t, gov.OptionYes, votes[0].Option)
|
require.Equal(t, gov.OptionYes, votes[0].Option)
|
||||||
|
|
||||||
// Ensure tags are applied to voting transaction properly
|
// Ensure tags are applied to voting transaction properly
|
||||||
txs = f.QueryTxs("action:vote", fmt.Sprintf("voter:%s", fooAddr))
|
txs = f.QueryTxs(1, 50, "action:vote", fmt.Sprintf("voter:%s", fooAddr))
|
||||||
require.Len(t, txs, 1)
|
require.Len(t, txs, 1)
|
||||||
|
|
||||||
// Ensure no proposals in deposit period
|
// Ensure no proposals in deposit period
|
||||||
|
@ -456,6 +457,54 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
f.Cleanup()
|
f.Cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGaiaCLIQueryTxPagination(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
f := InitFixtures(t)
|
||||||
|
|
||||||
|
// start gaiad server
|
||||||
|
proc := f.GDStart()
|
||||||
|
defer proc.Stop(false)
|
||||||
|
|
||||||
|
fooAddr := f.KeyAddress(keyFoo)
|
||||||
|
barAddr := f.KeyAddress(keyBar)
|
||||||
|
|
||||||
|
for i := 1; i <= 30; i++ {
|
||||||
|
success := executeWrite(t, fmt.Sprintf(
|
||||||
|
"gaiacli tx send %s --amount=%dfootoken --to=%s --from=foo",
|
||||||
|
f.Flags(), i, barAddr), app.DefaultKeyPass)
|
||||||
|
require.True(t, success)
|
||||||
|
tests.WaitForNextNBlocksTM(1, f.Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
// perPage = 15, 2 pages
|
||||||
|
txsPage1 := f.QueryTxs(1, 15, fmt.Sprintf("sender:%s", fooAddr))
|
||||||
|
require.Len(t, txsPage1, 15)
|
||||||
|
txsPage2 := f.QueryTxs(2, 15, fmt.Sprintf("sender:%s", fooAddr))
|
||||||
|
require.Len(t, txsPage2, 15)
|
||||||
|
require.NotEqual(t, txsPage1, txsPage2)
|
||||||
|
txsPage3 := f.QueryTxs(3, 15, fmt.Sprintf("sender:%s", fooAddr))
|
||||||
|
require.Len(t, txsPage3, 15)
|
||||||
|
require.Equal(t, txsPage2, txsPage3)
|
||||||
|
|
||||||
|
// perPage = 16, 2 pages
|
||||||
|
txsPage1 = f.QueryTxs(1, 16, fmt.Sprintf("sender:%s", fooAddr))
|
||||||
|
require.Len(t, txsPage1, 16)
|
||||||
|
txsPage2 = f.QueryTxs(2, 16, fmt.Sprintf("sender:%s", fooAddr))
|
||||||
|
require.Len(t, txsPage2, 14)
|
||||||
|
require.NotEqual(t, txsPage1, txsPage2)
|
||||||
|
|
||||||
|
// perPage = 50
|
||||||
|
txsPageFull := f.QueryTxs(1, 50, fmt.Sprintf("sender:%s", fooAddr))
|
||||||
|
require.Len(t, txsPageFull, 30)
|
||||||
|
require.Equal(t, txsPageFull, append(txsPage1, txsPage2...))
|
||||||
|
|
||||||
|
// perPage = 0
|
||||||
|
f.QueryTxsInvalid(errors.New("ERROR: page must greater than 0"), 0, 50, fmt.Sprintf("sender:%s", fooAddr))
|
||||||
|
|
||||||
|
// limit = 0
|
||||||
|
f.QueryTxsInvalid(errors.New("ERROR: limit must greater than 0"), 1, 0, fmt.Sprintf("sender:%s", fooAddr))
|
||||||
|
}
|
||||||
|
|
||||||
func TestGaiaCLIValidateSignatures(t *testing.T) {
|
func TestGaiaCLIValidateSignatures(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
f := InitFixtures(t)
|
f := InitFixtures(t)
|
||||||
|
|
|
@ -294,8 +294,8 @@ func (f *Fixtures) QueryAccount(address sdk.AccAddress, flags ...string) auth.Ba
|
||||||
// gaiacli query txs
|
// gaiacli query txs
|
||||||
|
|
||||||
// QueryTxs is gaiacli query txs
|
// QueryTxs is gaiacli query txs
|
||||||
func (f *Fixtures) QueryTxs(tags ...string) []tx.Info {
|
func (f *Fixtures) QueryTxs(page, limit int, tags ...string) []tx.Info {
|
||||||
cmd := fmt.Sprintf("gaiacli query txs --tags='%s' %v", queryTags(tags), f.Flags())
|
cmd := fmt.Sprintf("gaiacli query txs --page=%d --limit=%d --tags='%s' %v", page, limit, queryTags(tags), f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, cmd, "")
|
out, _ := tests.ExecuteT(f.T, cmd, "")
|
||||||
var txs []tx.Info
|
var txs []tx.Info
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -304,6 +304,13 @@ func (f *Fixtures) QueryTxs(tags ...string) []tx.Info {
|
||||||
return txs
|
return txs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryTxsInvalid query txs with wrong parameters and compare expected error
|
||||||
|
func (f *Fixtures) QueryTxsInvalid(expectedErr error, page, limit int, tags ...string) {
|
||||||
|
cmd := fmt.Sprintf("gaiacli query txs --page=%d --limit=%d --tags='%s' %v", page, limit, queryTags(tags), f.Flags())
|
||||||
|
_, err := tests.ExecuteT(f.T, cmd, "")
|
||||||
|
require.EqualError(f.T, expectedErr, err)
|
||||||
|
}
|
||||||
|
|
||||||
//___________________________________________________________________________________
|
//___________________________________________________________________________________
|
||||||
// gaiacli query staking
|
// gaiacli query staking
|
||||||
|
|
||||||
|
|
|
@ -133,8 +133,8 @@ type GaiaApp struct {
|
||||||
// keys to access the substores
|
// keys to access the substores
|
||||||
keyMain *sdk.KVStoreKey
|
keyMain *sdk.KVStoreKey
|
||||||
keyAccount *sdk.KVStoreKey
|
keyAccount *sdk.KVStoreKey
|
||||||
keyStaking *sdk.KVStoreKey
|
keyStaking *sdk.KVStoreKey
|
||||||
tkeyStaking *sdk.TransientStoreKey
|
tkeyStaking *sdk.TransientStoreKey
|
||||||
keySlashing *sdk.KVStoreKey
|
keySlashing *sdk.KVStoreKey
|
||||||
keyParams *sdk.KVStoreKey
|
keyParams *sdk.KVStoreKey
|
||||||
tkeyParams *sdk.TransientStoreKey
|
tkeyParams *sdk.TransientStoreKey
|
||||||
|
@ -160,8 +160,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
|
||||||
cdc: cdc,
|
cdc: cdc,
|
||||||
keyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
|
keyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
|
||||||
keyAccount: sdk.NewKVStoreKey(auth.StoreKey),
|
keyAccount: sdk.NewKVStoreKey(auth.StoreKey),
|
||||||
keyStaking: sdk.NewKVStoreKey(staking.StoreKey),
|
keyStaking: sdk.NewKVStoreKey(staking.StoreKey),
|
||||||
tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey),
|
tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey),
|
||||||
keySlashing: sdk.NewKVStoreKey(slashing.StoreKey),
|
keySlashing: sdk.NewKVStoreKey(slashing.StoreKey),
|
||||||
keyParams: sdk.NewKVStoreKey(params.StoreKey),
|
keyParams: sdk.NewKVStoreKey(params.StoreKey),
|
||||||
tkeyParams: sdk.NewTransientStoreKey(params.TStoreKey),
|
tkeyParams: sdk.NewTransientStoreKey(params.TStoreKey),
|
||||||
|
|
|
@ -57,7 +57,7 @@ type DemocoinApp struct {
|
||||||
coolKeeper cool.Keeper
|
coolKeeper cool.Keeper
|
||||||
powKeeper pow.Keeper
|
powKeeper pow.Keeper
|
||||||
ibcMapper ibc.Mapper
|
ibcMapper ibc.Mapper
|
||||||
stakingKeeper simplestaking.Keeper
|
stakingKeeper simplestaking.Keeper
|
||||||
|
|
||||||
// Manage getting and setting accounts
|
// Manage getting and setting accounts
|
||||||
accountKeeper auth.AccountKeeper
|
accountKeeper auth.AccountKeeper
|
||||||
|
|
|
@ -214,6 +214,11 @@ And for using multiple `tags`:
|
||||||
gaiacli query txs --tags='<tag1>:<value1>&<tag2>:<value2>'
|
gaiacli query txs --tags='<tag1>:<value1>&<tag2>:<value2>'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The pagination is supported as well via `page` and `limit`:
|
||||||
|
```bash
|
||||||
|
gaiacli query txs --tags='<tag>:<value>' --page=1 --limit=20
|
||||||
|
```
|
||||||
|
|
||||||
::: tip Note
|
::: tip Note
|
||||||
|
|
||||||
The action tag always equals the message type returned by the `Type()` function of the relevant message.
|
The action tag always equals the message type returned by the `Type()` function of the relevant message.
|
||||||
|
|
|
@ -116,7 +116,7 @@ type DelegationSet interface {
|
||||||
// event hooks for staking validator object
|
// event hooks for staking validator object
|
||||||
type StakingHooks interface {
|
type StakingHooks interface {
|
||||||
AfterValidatorCreated(ctx Context, valAddr ValAddress) // Must be called when a validator is created
|
AfterValidatorCreated(ctx Context, valAddr ValAddress) // Must be called when a validator is created
|
||||||
BeforeValidatorModified(ctx Context, valAddr ValAddress) // Must be called when a validator's state changes
|
BeforeValidatorModified(ctx Context, valAddr ValAddress) // Must be called when a validator's state changes
|
||||||
AfterValidatorRemoved(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is deleted
|
AfterValidatorRemoved(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is deleted
|
||||||
|
|
||||||
AfterValidatorBonded(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is bonded
|
AfterValidatorBonded(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is bonded
|
||||||
|
|
|
@ -27,7 +27,7 @@ type (
|
||||||
GenesisState = types.GenesisState
|
GenesisState = types.GenesisState
|
||||||
|
|
||||||
// expected keepers
|
// expected keepers
|
||||||
StakingKeeper = types.StakingKeeper
|
StakingKeeper = types.StakingKeeper
|
||||||
BankKeeper = types.BankKeeper
|
BankKeeper = types.BankKeeper
|
||||||
FeeCollectionKeeper = types.FeeCollectionKeeper
|
FeeCollectionKeeper = types.FeeCollectionKeeper
|
||||||
)
|
)
|
||||||
|
@ -71,7 +71,7 @@ const (
|
||||||
StoreKey = types.StoreKey
|
StoreKey = types.StoreKey
|
||||||
TStoreKey = types.TStoreKey
|
TStoreKey = types.TStoreKey
|
||||||
RouterKey = types.RouterKey
|
RouterKey = types.RouterKey
|
||||||
QuerierRoute = types.QuerierRoute
|
QuerierRoute = types.QuerierRoute
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -2,7 +2,6 @@ package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
@ -10,6 +9,11 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov/tags"
|
"github.com/cosmos/cosmos-sdk/x/gov/tags"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultPage = 1
|
||||||
|
defaultLimit = 30 // should be consistent with tendermint/tendermint/rpc/core/pipe.go:19
|
||||||
|
)
|
||||||
|
|
||||||
// Proposer contains metadata of a governance proposal used for querying a
|
// Proposer contains metadata of a governance proposal used for querying a
|
||||||
// proposer.
|
// proposer.
|
||||||
type Proposer struct {
|
type Proposer struct {
|
||||||
|
@ -32,7 +36,9 @@ func QueryDepositsByTxQuery(
|
||||||
fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
|
fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
|
||||||
}
|
}
|
||||||
|
|
||||||
infos, err := tx.SearchTxs(cliCtx, cdc, tags)
|
// NOTE: SearchTxs is used to facilitate the txs query which does not currently
|
||||||
|
// support configurable pagination.
|
||||||
|
infos, err := tx.SearchTxs(cliCtx, cdc, tags, defaultPage, defaultLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -75,7 +81,9 @@ func QueryVotesByTxQuery(
|
||||||
fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
|
fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
|
||||||
}
|
}
|
||||||
|
|
||||||
infos, err := tx.SearchTxs(cliCtx, cdc, tags)
|
// NOTE: SearchTxs is used to facilitate the txs query which does not currently
|
||||||
|
// support configurable pagination.
|
||||||
|
infos, err := tx.SearchTxs(cliCtx, cdc, tags, defaultPage, defaultLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -114,7 +122,9 @@ func QueryVoteByTxQuery(
|
||||||
fmt.Sprintf("%s='%s'", tags.Voter, []byte(params.Voter.String())),
|
fmt.Sprintf("%s='%s'", tags.Voter, []byte(params.Voter.String())),
|
||||||
}
|
}
|
||||||
|
|
||||||
infos, err := tx.SearchTxs(cliCtx, cdc, tags)
|
// NOTE: SearchTxs is used to facilitate the txs query which does not currently
|
||||||
|
// support configurable pagination.
|
||||||
|
infos, err := tx.SearchTxs(cliCtx, cdc, tags, defaultPage, defaultLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -155,7 +165,9 @@ func QueryDepositByTxQuery(
|
||||||
fmt.Sprintf("%s='%s'", tags.Depositor, []byte(params.Depositor.String())),
|
fmt.Sprintf("%s='%s'", tags.Depositor, []byte(params.Depositor.String())),
|
||||||
}
|
}
|
||||||
|
|
||||||
infos, err := tx.SearchTxs(cliCtx, cdc, tags)
|
// NOTE: SearchTxs is used to facilitate the txs query which does not currently
|
||||||
|
// support configurable pagination.
|
||||||
|
infos, err := tx.SearchTxs(cliCtx, cdc, tags, defaultPage, defaultLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -195,7 +207,9 @@ func QueryProposerByTxQuery(
|
||||||
fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", proposalID))),
|
fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", proposalID))),
|
||||||
}
|
}
|
||||||
|
|
||||||
infos, err := tx.SearchTxs(cliCtx, cdc, tags)
|
// NOTE: SearchTxs is used to facilitate the txs query which does not currently
|
||||||
|
// support configurable pagination.
|
||||||
|
infos, err := tx.SearchTxs(cliCtx, cdc, tags, defaultPage, defaultLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ type ValidatorSigningInfo struct {
|
||||||
StartHeight int64 `json:"start_height"` // height at which validator was first a candidate OR was unjailed
|
StartHeight int64 `json:"start_height"` // height at which validator was first a candidate OR was unjailed
|
||||||
IndexOffset int64 `json:"index_offset"` // index offset into signed block bit array
|
IndexOffset int64 `json:"index_offset"` // index offset into signed block bit array
|
||||||
JailedUntil time.Time `json:"jailed_until"` // timestamp validator cannot be unjailed until
|
JailedUntil time.Time `json:"jailed_until"` // timestamp validator cannot be unjailed until
|
||||||
Tombstoned bool `json:"tombstoned"` // whether or not a validator has been tombstoned (killed out of validator set)
|
Tombstoned bool `json:"tombstoned"` // whether or not a validator has been tombstoned (killed out of validator set)
|
||||||
MissedBlocksCounter int64 `json:"missed_blocks_counter"` // missed blocks counter (to avoid scanning the array every time)
|
MissedBlocksCounter int64 `json:"missed_blocks_counter"` // missed blocks counter (to avoid scanning the array every time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue