-
Notifications
You must be signed in to change notification settings - Fork 193
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(wasmbinding)!: whitelisted stargate queries for QueryRequest::St…
…argate: auth, bank, gov, tokenfactory, epochs, inflation, oracle, sudo, devgas (#1646) * fix(tokenfactory)!: Fix bug in MsgBurn on total supply tracking * chore: rm stablecoin. How does this keep getting merged lol * test: add export statements for the gRPC query service descriptions in each module * feat(wasmbinding): whitelisted stargate queries for QueryRequest::Stargate * changelog * fix changelog * refactor!: make the epoch infos name consistent * docs,test(stargate_query): leave an in-depth explainer above the function * refactor: pR comments: earlier return + remove duplicate hardcoded paths * test: proto package may have more than 3 'parts'. Use len - 1 instead * docs: fix small documentation typos
- Loading branch information
1 parent
ac000f2
commit 2ae0475
Showing
28 changed files
with
450 additions
and
8,058 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
package wasmbinding | ||
|
||
import ( | ||
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" | ||
|
||
devgas "github.com/NibiruChain/nibiru/x/devgas/v1/types" | ||
epochs "github.com/NibiruChain/nibiru/x/epochs/types" | ||
inflation "github.com/NibiruChain/nibiru/x/inflation/types" | ||
oracle "github.com/NibiruChain/nibiru/x/oracle/types" | ||
sudotypes "github.com/NibiruChain/nibiru/x/sudo/types" | ||
tokenfactory "github.com/NibiruChain/nibiru/x/tokenfactory/types" | ||
|
||
auth "github.com/cosmos/cosmos-sdk/x/auth/types" | ||
bank "github.com/cosmos/cosmos-sdk/x/bank/types" | ||
gov "github.com/cosmos/cosmos-sdk/x/gov/types/v1" | ||
|
||
ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" | ||
ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" | ||
ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" | ||
) | ||
|
||
/* | ||
WasmAcceptedStargateQueries: Specifies which `QueryRequest::Stargate` types | ||
can be sent to the application. | ||
### On Stargate Queries: | ||
A Stargate query is encoded the same way as abci_query, with path and protobuf | ||
encoded request data. The format is defined in | ||
[ADR-21](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-021-protobuf-query-encoding.md). | ||
- The response is protobuf encoded data directly without a JSON response wrapper. | ||
The caller is responsible for compiling the proper protobuf definitions for both | ||
requests and responses. | ||
```rust | ||
enum QueryRequest { | ||
Stargate { | ||
/// this is the fully qualified service path used for routing, | ||
/// eg. custom/cosmos_sdk.x.bank.v1.Query/QueryBalance | ||
path: String, | ||
/// this is the expected protobuf message type (not any), binary encoded | ||
data: Binary, | ||
}, | ||
// ... | ||
} | ||
``` | ||
### Relationship with Protobuf Message: | ||
A protobuf message with type URL "/cosmos.bank.v1beta1.QueryBalanceResponse" | ||
communicates a lot of information. From this type URL, we know: | ||
- The protobuf message has package "cosmos.bank.v1beta1" | ||
- The protobuf message has name "QueryBalanceResponse" | ||
That is, a type URL is of the form "/[PB_MSG.PACKAGE]/[PB_MSG.NAME]" | ||
The `QueryRequest::Stargate.path` is defined based on method name of the gRPC | ||
service description, not the type URL. In this example: | ||
- The service name is "cosmos.bank.v1beta1.Query" | ||
- The method name for this request on that service is "Balance" | ||
This results in the expected `Stargate.path` of "/[SERVICE_NAME]/[METHOD]". | ||
By convention, the gRPC query service corresponding to a package is always | ||
"[PB_MSG.PACKAGE].Query". | ||
Given only the `PB_MSG.PACKAGE` and the `PB_MSG.NAME` of either the query | ||
request or response, we should know the `QueryRequest::Stargate.path` | ||
deterministically. | ||
*/ | ||
func WasmAcceptedStargateQueries() wasmkeeper.AcceptedStargateQueries { | ||
return wasmkeeper.AcceptedStargateQueries{ | ||
// ibc | ||
"/ibc.core.client.v1.Query/ClientState": &ibcclienttypes.QueryClientStateResponse{}, | ||
"/ibc.core.client.v1.Query/ConsensusState": &ibcclienttypes.QueryConsensusStateResponse{}, | ||
"/ibc.core.connection.v1.Query/Connection": &ibcconnectiontypes.QueryConnectionResponse{}, | ||
"/ibc.core.connection.v1.Query/Connections": &ibcconnectiontypes.QueryConnectionsResponse{}, | ||
"/ibc.core.connection.v1.Query/ClientConnections": &ibcconnectiontypes.QueryClientConnectionsResponse{}, | ||
"/ibc.core.connection.v1.Query/ConnectionConsensusState": &ibcconnectiontypes.QueryConnectionConsensusStateResponse{}, | ||
"/ibc.core.connection.v1.Query/ConnectionParams": &ibcconnectiontypes.QueryConnectionParamsResponse{}, | ||
|
||
// ibc transfer | ||
"/ibc.applications.transfer.v1.Query/DenomTrace": &ibctransfertypes.QueryDenomTraceResponse{}, | ||
"/ibc.applications.transfer.v1.Query/Params": &ibctransfertypes.QueryParamsResponse{}, | ||
"/ibc.applications.transfer.v1.Query/DenomHash": &ibctransfertypes.QueryDenomHashResponse{}, | ||
"/ibc.applications.transfer.v1.Query/EscrowAddress": &ibctransfertypes.QueryEscrowAddressResponse{}, | ||
"/ibc.applications.transfer.v1.Query/TotalEscrowForDenom": &ibctransfertypes.QueryTotalEscrowForDenomResponse{}, | ||
|
||
// cosmos auth | ||
"/cosmos.auth.v1beta1.Query/Account": new(auth.QueryAccountResponse), | ||
"/cosmos.auth.v1beta1.Query/Params": new(auth.QueryParamsResponse), | ||
|
||
// cosmos bank | ||
"/cosmos.bank.v1beta1.Query/Balance": new(bank.QueryBalanceResponse), | ||
"/cosmos.bank.v1beta1.Query/DenomMetadata": new(bank.QueryDenomMetadataResponse), | ||
"/cosmos.bank.v1beta1.Query/Params": new(bank.QueryParamsResponse), | ||
"/cosmos.bank.v1beta1.Query/SupplyOf": new(bank.QuerySupplyOfResponse), | ||
"/cosmos.bank.v1beta1.Query/AllBalances": new(bank.QueryAllBalancesResponse), | ||
|
||
// cosmos gov | ||
"/cosmos.gov.v1.Query/Proposal": new(gov.QueryProposalResponse), | ||
"/cosmos.gov.v1.Query/Params": new(gov.QueryParamsResponse), | ||
"/cosmos.gov.v1.Query/Vote": new(gov.QueryVoteResponse), | ||
|
||
// nibiru tokenfactory | ||
"/nibiru.tokenfactory.v1.Query/Denoms": new(tokenfactory.QueryDenomsResponse), | ||
"/nibiru.tokenfactory.v1.Query/Params": new(tokenfactory.QueryParamsResponse), | ||
"/nibiru.tokenfactory.v1.Query/DenomInfo": new(tokenfactory.QueryDenomInfoResponse), | ||
|
||
// nibiru epochs | ||
"/nibiru.epochs.v1.Query/EpochInfos": new(epochs.QueryEpochInfosResponse), | ||
"/nibiru.epochs.v1.Query/CurrentEpoch": new(epochs.QueryCurrentEpochResponse), | ||
|
||
// nibiru inflation | ||
"/nibiru.inflation.v1.Query/Period": new(inflation.QueryPeriodResponse), | ||
"/nibiru.inflation.v1.Query/EpochMintProvision": new(inflation.QueryEpochMintProvisionResponse), | ||
"/nibiru.inflation.v1.Query/SkippedEpochs": new(inflation.QuerySkippedEpochsResponse), | ||
"/nibiru.inflation.v1.Query/CirculatingSupply": new(inflation.QueryCirculatingSupplyResponse), | ||
"/nibiru.inflation.v1.Query/InflationRate": new(inflation.QueryInflationRateResponse), | ||
"/nibiru.inflation.v1.Query/Params": new(inflation.QueryParamsResponse), | ||
|
||
// nibiru oracle | ||
"/nibiru.oracle.v1.Query/ExchangeRate": new(oracle.QueryExchangeRateResponse), | ||
"/nibiru.oracle.v1.Query/ExchangeRateTwap": new(oracle.QueryExchangeRateResponse), | ||
"/nibiru.oracle.v1.Query/ExchangeRates": new(oracle.QueryExchangeRatesResponse), | ||
"/nibiru.oracle.v1.Query/Actives": new(oracle.QueryActivesResponse), | ||
"/nibiru.oracle.v1.Query/VoteTargets": new(oracle.QueryVoteTargetsResponse), | ||
"/nibiru.oracle.v1.Query/FeederDelegation": new(oracle.QueryFeederDelegationResponse), | ||
"/nibiru.oracle.v1.Query/MissCounter": new(oracle.QueryMissCounterResponse), | ||
"/nibiru.oracle.v1.Query/AggregatePrevote": new(oracle.QueryAggregatePrevoteResponse), | ||
"/nibiru.oracle.v1.Query/AggregatePrevotes": new(oracle.QueryAggregatePrevotesResponse), | ||
"/nibiru.oracle.v1.Query/AggregateVote": new(oracle.QueryAggregateVoteResponse), | ||
"/nibiru.oracle.v1.Query/AggregateVotes": new(oracle.QueryAggregateVotesResponse), | ||
"/nibiru.oracle.v1.Query/Params": new(oracle.QueryParamsResponse), | ||
|
||
// nibiru sudo | ||
"/nibiru.sudo.v1.Query/QuerySudoers": new(sudotypes.QuerySudoersResponse), | ||
|
||
// nibiru devgas | ||
"/nibiru.devgas.v1.Query/FeeShares": new(devgas.QueryFeeSharesResponse), | ||
"/nibiru.devgas.v1.Query/FeeShare": new(devgas.QueryFeeShareResponse), | ||
"/nibiru.devgas.v1.Query/Params": new(devgas.QueryParamsResponse), | ||
"/nibiru.devgas.v1.Query/FeeSharesByWithdrawer": new(devgas.QueryFeeSharesByWithdrawerResponse), | ||
|
||
// TODO: for post v1 | ||
// nibiru.perp | ||
|
||
// TODO: for post v1 | ||
// nibiru.spot | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package wasmbinding_test | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/cosmos/gogoproto/proto" | ||
"github.com/stretchr/testify/assert" | ||
"google.golang.org/grpc" | ||
|
||
"github.com/NibiruChain/nibiru/wasmbinding" | ||
|
||
"github.com/NibiruChain/nibiru/x/common/set" | ||
|
||
devgas "github.com/NibiruChain/nibiru/x/devgas/v1/types" | ||
epochs "github.com/NibiruChain/nibiru/x/epochs/types" | ||
inflation "github.com/NibiruChain/nibiru/x/inflation/types" | ||
oracle "github.com/NibiruChain/nibiru/x/oracle/types" | ||
sudotypes "github.com/NibiruChain/nibiru/x/sudo/types" | ||
tokenfactory "github.com/NibiruChain/nibiru/x/tokenfactory/types" | ||
) | ||
|
||
/* | ||
TestWasmAcceptedStargateQueries: Verifies that the query paths registered in | ||
the Wasm keeper's StargateQuerier are the official method names in the gRPC | ||
query service of each path's respective module. | ||
> ℹ️ "All stargate query paths must be actual GRPC query service methods" | ||
Please see the function doc comment for WasmAcceptedStargateQueries in | ||
stargate_query.go to understand in detail what invariants this test checks | ||
for. | ||
Given only the `PB_MSG.PACKAGE` and the `PB_MSG.NAME` of either the query | ||
request or response, we should know the `QueryRequest::Stargate.path` | ||
deterministically. | ||
*/ | ||
func TestWasmAcceptedStargateQueries(t *testing.T) { | ||
t.Log("stargateQueryPaths: Add nibiru query paths from GRPC service descriptions") | ||
queryServiceDescriptions := []grpc.ServiceDesc{ | ||
epochs.GrpcQueryServiceDesc(), | ||
devgas.GrpcQueryServiceDesc(), | ||
inflation.GrpcQueryServiceDesc(), | ||
oracle.GrpcQueryServiceDesc(), | ||
sudotypes.GrpcQueryServiceDesc(), | ||
tokenfactory.GrpcQueryServiceDesc(), | ||
} | ||
stargateQueryPaths := set.New[string]() | ||
for _, serviceDesc := range queryServiceDescriptions { | ||
for _, queryMethod := range serviceDesc.Methods { | ||
stargateQueryPaths.Add( | ||
fmt.Sprintf("/%v/%v", serviceDesc.ServiceName, queryMethod.MethodName), | ||
) | ||
} | ||
} | ||
|
||
t.Log("stargateQueryPaths: Add cosmos and ibc query paths") | ||
// The GRPC service descriptions aren't exported as copies from the | ||
// Cosmos-SDK and remain private vars. Maybe we could ask the maintainers to | ||
// export them in the future. | ||
for queryPath := range wasmbinding.WasmAcceptedStargateQueries() { | ||
stargateQueryPaths.Add(queryPath) | ||
} | ||
|
||
// It's not required for the response type and the method description of the | ||
// stargate query's gRPC path to match up exactly as expected. The exception | ||
// to this convention is when our response type isn't stripped of its | ||
// "Response" suffix and "Query" prefix is not the same as the method name. | ||
// This happens when "QueryAAARequest" does not return a "QueryAAAResponse". | ||
exceptionPaths := set.New[string]("/nibiru.oracle.v1.QueryExchangeRateResponse") | ||
|
||
gotQueryPaths := []string{} | ||
for queryPath, protobufResponse := range wasmbinding.WasmAcceptedStargateQueries() { | ||
gotQueryPaths = append(gotQueryPaths, queryPath) | ||
|
||
// Show that the underlying protobuf name and query paths coincide. | ||
pbQueryResponseTypeUrl := "/" + proto.MessageName(protobufResponse) | ||
isExceptionPath := exceptionPaths.Has(pbQueryResponseTypeUrl) | ||
splitResponse := strings.Split(pbQueryResponseTypeUrl, "Response") | ||
assert.Lenf(t, splitResponse, 2, "typeUrl: %v", | ||
splitResponse, pbQueryResponseTypeUrl) | ||
|
||
// Get proto message "package" from the response type | ||
typeUrlMinusSuffix := splitResponse[0] | ||
typeUrlPartsFromProtoMsg := strings.Split(typeUrlMinusSuffix, ".") | ||
lenOfParts := len(typeUrlPartsFromProtoMsg) | ||
assert.GreaterOrEqual(t, lenOfParts, 4, typeUrlPartsFromProtoMsg) | ||
protoMessagePackage := typeUrlPartsFromProtoMsg[:lenOfParts-1] | ||
|
||
// Get proto message "package" from the query path | ||
typeUrlPartsFromQueryPath := strings.Split(queryPath, ".") | ||
assert.GreaterOrEqual(t, len(typeUrlPartsFromQueryPath), 4, typeUrlPartsFromQueryPath) | ||
queryPathProtoPackage := typeUrlPartsFromQueryPath[:lenOfParts-1] | ||
|
||
// Verify that the packages match | ||
assert.Equalf(t, queryPathProtoPackage, protoMessagePackage, | ||
"package names inconsistent:\nfrom query path: %v\nfrom protobuf object: %v", | ||
queryPath, pbQueryResponseTypeUrl, | ||
) | ||
|
||
// Verify that the method names match too. | ||
if isExceptionPath { | ||
continue | ||
} | ||
methodNameFromPb := strings.TrimLeft(typeUrlPartsFromProtoMsg[3], "Query") | ||
methodNameFromPath := strings.TrimLeft(typeUrlPartsFromQueryPath[3], "Query/") | ||
assert.Equalf(t, methodNameFromPb, methodNameFromPath, | ||
"method names inconsistent:\nfrom query path: %v\nfrom protobuf object: %v", | ||
queryPath, pbQueryResponseTypeUrl, | ||
) | ||
} | ||
|
||
t.Log("All stargate query paths must be actual GRPC query service methods") | ||
assert.ElementsMatch(t, stargateQueryPaths.ToSlice(), gotQueryPaths) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.