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 }