Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Build Address gRPC Query #1753

Merged
merged 11 commits into from
Jan 9, 2024
38 changes: 38 additions & 0 deletions docs/proto/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
- [CodeInfoResponse](#cosmwasm.wasm.v1.CodeInfoResponse)
- [QueryAllContractStateRequest](#cosmwasm.wasm.v1.QueryAllContractStateRequest)
- [QueryAllContractStateResponse](#cosmwasm.wasm.v1.QueryAllContractStateResponse)
- [QueryBuildAddressRequest](#cosmwasm.wasm.v1.QueryBuildAddressRequest)
- [QueryBuildAddressResponse](#cosmwasm.wasm.v1.QueryBuildAddressResponse)
- [QueryCodeRequest](#cosmwasm.wasm.v1.QueryCodeRequest)
- [QueryCodeResponse](#cosmwasm.wasm.v1.QueryCodeResponse)
- [QueryCodesRequest](#cosmwasm.wasm.v1.QueryCodesRequest)
Expand Down Expand Up @@ -1018,6 +1020,41 @@ Query/AllContractState RPC method



<a name="cosmwasm.wasm.v1.QueryBuildAddressRequest"></a>

### QueryBuildAddressRequest
QueryBuildAddressRequest is the request type for the Query/BuildAddress RPC
method.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `code_hash` | [string](#string) | | CodeHash is the hash of the code |
| `creator_address` | [string](#string) | | CreatorAddress is the address of the contract instantiator |
| `salt` | [string](#string) | | Salt is a hex encoded salt |
| `init_args` | [bytes](#bytes) | | InitArgs are optional json encoded init args to be used in contract address building if provided |






<a name="cosmwasm.wasm.v1.QueryBuildAddressResponse"></a>

### QueryBuildAddressResponse
QueryBuildAddressResponse is the response type for the Query/BuildAddress RPC
method.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `address` | [string](#string) | | Address is the contract address |






<a name="cosmwasm.wasm.v1.QueryCodeRequest"></a>

### QueryCodeRequest
Expand Down Expand Up @@ -1363,6 +1400,7 @@ Query provides defines the gRPC querier service
| `PinnedCodes` | [QueryPinnedCodesRequest](#cosmwasm.wasm.v1.QueryPinnedCodesRequest) | [QueryPinnedCodesResponse](#cosmwasm.wasm.v1.QueryPinnedCodesResponse) | PinnedCodes gets the pinned code ids | GET|/cosmwasm/wasm/v1/codes/pinned|
| `Params` | [QueryParamsRequest](#cosmwasm.wasm.v1.QueryParamsRequest) | [QueryParamsResponse](#cosmwasm.wasm.v1.QueryParamsResponse) | Params gets the module params | GET|/cosmwasm/wasm/v1/codes/params|
| `ContractsByCreator` | [QueryContractsByCreatorRequest](#cosmwasm.wasm.v1.QueryContractsByCreatorRequest) | [QueryContractsByCreatorResponse](#cosmwasm.wasm.v1.QueryContractsByCreatorResponse) | ContractsByCreator gets the contracts by creator | GET|/cosmwasm/wasm/v1/contracts/creator/{creator_address}|
| `BuildAddress` | [QueryBuildAddressRequest](#cosmwasm.wasm.v1.QueryBuildAddressRequest) | [QueryBuildAddressResponse](#cosmwasm.wasm.v1.QueryBuildAddressResponse) | BuildAddress builds a contract address | GET|/cosmwasm/wasm/v1/contract/build_address|

<!-- end services -->

Expand Down
27 changes: 27 additions & 0 deletions proto/cosmwasm/wasm/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ service Query {
option (google.api.http).get =
"/cosmwasm/wasm/v1/contracts/creator/{creator_address}";
}

// BuildAddress builds a contract address
rpc BuildAddress(QueryBuildAddressRequest)
returns (QueryBuildAddressResponse) {
option (google.api.http).get = "/cosmwasm/wasm/v1/contract/build_address";
}
}

// QueryContractInfoRequest is the request type for the Query/ContractInfo RPC
Expand Down Expand Up @@ -268,4 +274,25 @@ message QueryContractsByCreatorResponse {
[ (cosmos_proto.scalar) = "cosmos.AddressString" ];
// Pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

// QueryBuildAddressRequest is the request type for the Query/BuildAddress RPC
// method.
message QueryBuildAddressRequest {
// CodeHash is the hash of the code
string code_hash = 1;
// CreatorAddress is the address of the contract instantiator
string creator_address = 2 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
// Salt is a hex encoded salt
string salt = 3;
// InitArgs are optional json encoded init args to be used in contract address
// building if provided
bytes init_args = 4;
}

// QueryBuildAddressResponse is the response type for the Query/BuildAddress RPC
// method.
message QueryBuildAddressResponse {
// Address is the contract address
string address = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
}
34 changes: 34 additions & 0 deletions x/wasm/keeper/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import (
"context"
"encoding/binary"
"encoding/hex"
"runtime/debug"

"google.golang.org/grpc/codes"
Expand Down Expand Up @@ -406,3 +407,36 @@
}
return req, nil
}

func (q GrpcQuerier) BuildAddress(c context.Context, req *types.QueryBuildAddressRequest) (*types.QueryBuildAddressResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
codeHash, err := hex.DecodeString(req.CodeHash)
if err != nil {
return nil, err

Check warning on line 417 in x/wasm/keeper/querier.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/querier.go#L417

Added line #L417 was not covered by tests
}
creator, err := sdk.AccAddressFromBech32(req.CreatorAddress)
if err != nil {
return nil, err

Check warning on line 421 in x/wasm/keeper/querier.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/querier.go#L421

Added line #L421 was not covered by tests
}
salt, err := hex.DecodeString(req.Salt)
if err != nil {
return nil, err

Check warning on line 425 in x/wasm/keeper/querier.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/querier.go#L425

Added line #L425 was not covered by tests
}
if len(salt) == 0 {
return nil, status.Error(codes.InvalidArgument, "empty salt")

Check warning on line 428 in x/wasm/keeper/querier.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/querier.go#L428

Added line #L428 was not covered by tests
}
if req.InitArgs == nil {
return &types.QueryBuildAddressResponse{
Address: BuildContractAddressPredictable(codeHash, creator, salt, []byte{}).String(),
}, nil
}
initMsg := types.RawContractMessage(req.InitArgs)
if err := initMsg.ValidateBasic(); err != nil {
return nil, err

Check warning on line 437 in x/wasm/keeper/querier.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/querier.go#L437

Added line #L437 was not covered by tests
}
return &types.QueryBuildAddressResponse{
Address: BuildContractAddressPredictable(codeHash, creator, salt, initMsg).String(),
}, nil
}
57 changes: 57 additions & 0 deletions x/wasm/keeper/querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1047,3 +1047,60 @@ func TestEnsurePaginationParams(t *testing.T) {
})
}
}

func TestQueryBuildAddress(t *testing.T) {
specs := map[string]struct {
srcQuery *types.QueryBuildAddressRequest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
srcQuery *types.QueryBuildAddressRequest
src *types.QueryBuildAddressRequest

personal preference, just to keep consistent with all the others

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done here: e405904

exp *types.QueryBuildAddressResponse
expErr error
}{
"empty request": {
srcQuery: nil,
expErr: status.Error(codes.InvalidArgument, "empty request"),
},
"valid - without init args": {
srcQuery: &types.QueryBuildAddressRequest{
CodeHash: "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
CreatorAddress: "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
Salt: "61",
InitArgs: nil,
},
exp: &types.QueryBuildAddressResponse{
Address: "cosmos165fz7lnnt6e08knjqsz6fnz9drs7gewezyq3pl5uspc3zgt5lldq4ge3pl",
},
expErr: nil,
},
"valid - with init args": {
srcQuery: &types.QueryBuildAddressRequest{
CodeHash: "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
CreatorAddress: "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
Salt: "61",
InitArgs: []byte(`{"verifier":"cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz"}`),
},
exp: &types.QueryBuildAddressResponse{
Address: "cosmos150kq3ggdvc9lftcv6ns75t3v6lcpxdmvuwtqr6e9fc029z6h4maqepgss6",
},
expErr: nil,
},
}

ctx, keepers := CreateTestInput(t, false, AvailableCapabilities)
keeper := keepers.WasmKeeper

q := Querier(keeper)
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
got, gotErr := q.BuildAddress(ctx, spec.srcQuery)
if spec.expErr != nil {
fmt.Println("here")
fmt.Println("err: ", gotErr)
NotJeremyLiu marked this conversation as resolved.
Show resolved Hide resolved
require.Error(t, gotErr)
assert.ErrorContains(t, gotErr, spec.expErr.Error())
return
}
require.NoError(t, gotErr)
require.NotNil(t, got)
assert.Equal(t, spec.exp.Address, got.Address)
})
}
}
Loading