github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/gov/client/utils/query.go (about)

     1  package utils
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client"
     7  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context"
     8  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     9  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/client/utils"
    10  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/gov/types"
    11  )
    12  
    13  const (
    14  	defaultPage  = 1
    15  	defaultLimit = 30 // should be consistent with tendermint/tendermint/rpc/core/pipe.go:19
    16  )
    17  
    18  // Proposer contains metadata of a governance proposal used for querying a
    19  // proposer.
    20  type Proposer struct {
    21  	ProposalID uint64 `json:"proposal_id" yaml:"proposal_id"`
    22  	Proposer   string `json:"proposer" yaml:"proposer"`
    23  }
    24  
    25  // NewProposer returns a new Proposer given id and proposer
    26  func NewProposer(proposalID uint64, proposer string) Proposer {
    27  	return Proposer{proposalID, proposer}
    28  }
    29  
    30  func (p Proposer) String() string {
    31  	return fmt.Sprintf("Proposal with ID %d was proposed by %s", p.ProposalID, p.Proposer)
    32  }
    33  
    34  // QueryDepositsByTxQuery will query for deposits via a direct txs tags query. It
    35  // will fetch and build deposits directly from the returned txs and return a
    36  // JSON marshalled result or any error that occurred.
    37  //
    38  // NOTE: SearchTxs is used to facilitate the txs query which does not currently
    39  // support configurable pagination.
    40  func QueryDepositsByTxQuery(cliCtx context.CLIContext, params types.QueryProposalParams) ([]byte, error) {
    41  	events := []string{
    42  		fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgDeposit),
    43  		fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
    44  	}
    45  
    46  	// NOTE: SearchTxs is used to facilitate the txs query which does not currently
    47  	// support configurable pagination.
    48  	searchResult, err := utils.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	var deposits []types.Deposit
    54  
    55  	for _, info := range searchResult.Txs {
    56  		for _, msg := range info.Tx.GetMsgs() {
    57  			if msg.Type() == types.TypeMsgDeposit {
    58  				depMsg := msg.(types.MsgDeposit)
    59  
    60  				deposits = append(deposits, types.Deposit{
    61  					Depositor:  depMsg.Depositor,
    62  					ProposalID: params.ProposalID,
    63  					Amount:     depMsg.Amount,
    64  				})
    65  			}
    66  		}
    67  	}
    68  
    69  	if cliCtx.Indent {
    70  		return cliCtx.Codec.MarshalJSONIndent(deposits, "", "  ")
    71  	}
    72  
    73  	return cliCtx.Codec.MarshalJSON(deposits)
    74  }
    75  
    76  // QueryVotesByTxQuery will query for votes via a direct txs tags query. It
    77  // will fetch and build votes directly from the returned txs and return a JSON
    78  // marshalled result or any error that occurred.
    79  func QueryVotesByTxQuery(cliCtx context.CLIContext, params types.QueryProposalVotesParams) ([]byte, error) {
    80  	var (
    81  		events = []string{
    82  			fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgVote),
    83  			fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
    84  		}
    85  		votes      []types.Vote
    86  		nextTxPage = defaultPage
    87  		totalLimit = params.Limit * params.Page
    88  	)
    89  	// query interrupted either if we collected enough votes or tx indexer run out of relevant txs
    90  	for len(votes) < totalLimit {
    91  		searchResult, err := utils.QueryTxsByEvents(cliCtx, events, nextTxPage, defaultLimit)
    92  		if err != nil {
    93  			return nil, err
    94  		}
    95  		nextTxPage++
    96  		for _, info := range searchResult.Txs {
    97  			for _, msg := range info.Tx.GetMsgs() {
    98  				if msg.Type() == types.TypeMsgVote {
    99  					voteMsg := msg.(types.MsgVote)
   100  
   101  					votes = append(votes, types.Vote{
   102  						Voter:      voteMsg.Voter,
   103  						ProposalID: params.ProposalID,
   104  						Option:     voteMsg.Option,
   105  					})
   106  				}
   107  			}
   108  		}
   109  		if len(searchResult.Txs) != defaultLimit {
   110  			break
   111  		}
   112  	}
   113  	start, end := client.Paginate(len(votes), params.Page, params.Limit, 100)
   114  	if start < 0 || end < 0 {
   115  		votes = []types.Vote{}
   116  	} else {
   117  		votes = votes[start:end]
   118  	}
   119  	if cliCtx.Indent {
   120  		return cliCtx.Codec.MarshalJSONIndent(votes, "", "  ")
   121  	}
   122  	return cliCtx.Codec.MarshalJSON(votes)
   123  }
   124  
   125  // QueryVoteByTxQuery will query for a single vote via a direct txs tags query.
   126  func QueryVoteByTxQuery(cliCtx context.CLIContext, params types.QueryVoteParams) ([]byte, error) {
   127  	events := []string{
   128  		fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgVote),
   129  		fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
   130  		fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Voter.String())),
   131  	}
   132  
   133  	// NOTE: SearchTxs is used to facilitate the txs query which does not currently
   134  	// support configurable pagination.
   135  	searchResult, err := utils.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	for _, info := range searchResult.Txs {
   140  		for _, msg := range info.Tx.GetMsgs() {
   141  			// there should only be a single vote under the given conditions
   142  			if msg.Type() == types.TypeMsgVote {
   143  				voteMsg := msg.(types.MsgVote)
   144  
   145  				vote := types.Vote{
   146  					Voter:      voteMsg.Voter,
   147  					ProposalID: params.ProposalID,
   148  					Option:     voteMsg.Option,
   149  				}
   150  
   151  				if cliCtx.Indent {
   152  					return cliCtx.Codec.MarshalJSONIndent(vote, "", "  ")
   153  				}
   154  
   155  				return cliCtx.Codec.MarshalJSON(vote)
   156  			}
   157  		}
   158  	}
   159  
   160  	return nil, fmt.Errorf("address '%s' did not vote on proposalID %d", params.Voter, params.ProposalID)
   161  }
   162  
   163  // QueryDepositByTxQuery will query for a single deposit via a direct txs tags
   164  // query.
   165  func QueryDepositByTxQuery(cliCtx context.CLIContext, params types.QueryDepositParams) ([]byte, error) {
   166  	events := []string{
   167  		fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgDeposit),
   168  		fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
   169  		fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Depositor.String())),
   170  	}
   171  
   172  	// NOTE: SearchTxs is used to facilitate the txs query which does not currently
   173  	// support configurable pagination.
   174  	searchResult, err := utils.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  
   179  	for _, info := range searchResult.Txs {
   180  		for _, msg := range info.Tx.GetMsgs() {
   181  			// there should only be a single deposit under the given conditions
   182  			if msg.Type() == types.TypeMsgDeposit {
   183  				depMsg := msg.(types.MsgDeposit)
   184  
   185  				deposit := types.Deposit{
   186  					Depositor:  depMsg.Depositor,
   187  					ProposalID: params.ProposalID,
   188  					Amount:     depMsg.Amount,
   189  				}
   190  
   191  				if cliCtx.Indent {
   192  					return cliCtx.Codec.MarshalJSONIndent(deposit, "", "  ")
   193  				}
   194  
   195  				return cliCtx.Codec.MarshalJSON(deposit)
   196  			}
   197  		}
   198  	}
   199  
   200  	return nil, fmt.Errorf("address '%s' did not deposit to proposalID %d", params.Depositor, params.ProposalID)
   201  }
   202  
   203  // QueryProposerByTxQuery will query for a proposer of a governance proposal by
   204  // ID.
   205  func QueryProposerByTxQuery(cliCtx context.CLIContext, proposalID uint64) (Proposer, error) {
   206  	events := []string{
   207  		fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgSubmitProposal),
   208  		fmt.Sprintf("%s.%s='%s'", types.EventTypeSubmitProposal, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", proposalID))),
   209  	}
   210  
   211  	// NOTE: SearchTxs is used to facilitate the txs query which does not currently
   212  	// support configurable pagination.
   213  	searchResult, err := utils.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit)
   214  	if err != nil {
   215  		return Proposer{}, err
   216  	}
   217  
   218  	for _, info := range searchResult.Txs {
   219  		for _, msg := range info.Tx.GetMsgs() {
   220  			// there should only be a single proposal under the given conditions
   221  			if msg.Type() == types.TypeMsgSubmitProposal {
   222  				subMsg := msg.(types.MsgSubmitProposal)
   223  				return NewProposer(proposalID, subMsg.Proposer.String()), nil
   224  			}
   225  		}
   226  	}
   227  
   228  	return Proposer{}, fmt.Errorf("failed to find the proposer for proposalID %d", proposalID)
   229  }
   230  
   231  // QueryProposalByID takes a proposalID and returns a proposal
   232  func QueryProposalByID(proposalID uint64, cliCtx context.CLIContext, queryRoute string) ([]byte, error) {
   233  	params := types.NewQueryProposalParams(proposalID)
   234  	bz, err := cliCtx.Codec.MarshalJSON(params)
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  
   239  	res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/proposal", queryRoute), bz)
   240  	if err != nil {
   241  		return nil, err
   242  	}
   243  
   244  	return res, err
   245  }