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

Update cosmwasm #509

Merged
merged 8 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions docs/MIGRATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,30 @@
- `VM.StoreCode` now returns a `uint64` containing the gas cost in CosmWasm gas
and takes a gas limit as argument. This was previously calculated in wasmd.
The change brings consistency with the other functions that cause gas usage.
- `GoAPI` now requires an additional `ValidateAddress` function that validates
whether the given string is a valid address. This was previously done
internally using separate calls to `CanonicalizeAddress` and `HumanizeAddress`
but can be done more efficiently using a single call.

## Renamings

This section contains renamed symbols that do not require any further
explanation. Some of the new names may be available in 1.x already in cases
where the old name was deprecated.

| Old name | New name | Note |
| ------------------------ | --------------------------- | ----------------------------------------------------------- |
| `VM.Create` | `VM.StoreCode` | StoreCode brings consistency with wasmd naming |
| `SubcallResult` | `SubMsgResult` | Contracts do not "call" each other but send messages around |
| `SubcallResponse` | `SubMsgResponse` | Contracts do not "call" each other but send messages around |
| `HumanizeAddress` | `HumanizeAddressFunc` | Follow [best practice for naming function types][ft] |
| `CanonicalizeAddress` | `CanonicalizeAddressFunc` | Follow [best practice for naming function types][ft] |
| `GoAPI.HumanAddress` | `GoAPI.HumanizeAddress` | Perfer verbs for converters |
| `GoAPI.CanonicalAddress` | `GoAPI.CanonicalizeAddress` | Perfer verbs for converters |
| `CosmosMsg.Stargate` | `CosmosMsg.Any` | The message has nothing to do with Stargate |
| `StargateMsg` | `AnyMsg` | The message has nothing to do with Stargate |
| `QueryResponse` | `QueryResult` | Brings consistency with the naming of the other results |
| `VoteMsg.Vote` | `VoteMsg.Option` | Brings consistency with Cosmos SDK naming |
| Old name | New name | Note |
| --------------------------------- | ------------------------------------- | ------------------------------------------------------------ |
| `VM.Create` | `VM.StoreCode` | StoreCode brings consistency with wasmd naming |
| `AnalysisReport.RequiredFeatures` | `AnalysisReport.RequiredCapabilities` | Renamed for a long time, but now the old version was removed |
| `SubcallResult` | `SubMsgResult` | Contracts do not "call" each other but send messages around |
| `SubcallResponse` | `SubMsgResponse` | Contracts do not "call" each other but send messages around |
| `HumanizeAddress` | `HumanizeAddressFunc` | Follow [best practice for naming function types][ft] |
| `CanonicalizeAddress` | `CanonicalizeAddressFunc` | Follow [best practice for naming function types][ft] |
| `GoAPI.HumanAddress` | `GoAPI.HumanizeAddress` | Perfer verbs for converters |
| `GoAPI.CanonicalAddress` | `GoAPI.CanonicalizeAddress` | Perfer verbs for converters |
| `CosmosMsg.Stargate` | `CosmosMsg.Any` | The message has nothing to do with Stargate |
| `StargateMsg` | `AnyMsg` | The message has nothing to do with Stargate |
| `QueryResponse` | `QueryResult` | Brings consistency with the naming of the other results |
| `VoteMsg.Vote` | `VoteMsg.Option` | Brings consistency with Cosmos SDK naming |

[ft]: https://stackoverflow.com/a/60073310
2 changes: 0 additions & 2 deletions ibc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,6 @@ func TestAnalyzeCode(t *testing.T) {
report, err := vm.AnalyzeCode(checksum)
require.NoError(t, err)
require.False(t, report.HasIBCEntryPoints)
require.Equal(t, "", report.RequiredFeatures)
require.Equal(t, "", report.RequiredCapabilities)

// Store IBC contract
Expand All @@ -313,7 +312,6 @@ func TestAnalyzeCode(t *testing.T) {
report2, err := vm.AnalyzeCode(checksum2)
require.NoError(t, err)
require.True(t, report2.HasIBCEntryPoints)
require.Equal(t, "iterator,stargate", report2.RequiredFeatures)
require.Equal(t, "iterator,stargate", report2.RequiredCapabilities)
}

Expand Down
4 changes: 4 additions & 0 deletions internal/api/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,10 @@ typedef struct GoApiVtable {
struct UnmanagedVector *canonicalized_address_out,
struct UnmanagedVector *err_msg_out,
uint64_t *gas_used);
int32_t (*validate_address)(const struct api_t *api,
struct U8SliceView input,
struct UnmanagedVector *err_msg_out,
uint64_t *gas_used);
} GoApiVtable;

typedef struct GoApi {
Expand Down
26 changes: 26 additions & 0 deletions internal/api/callbacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ GoError cNextValue_cgo(iterator_t *ptr, gas_meter_t *gas_meter, uint64_t *used_g
// api
GoError cHumanizeAddress_cgo(api_t *ptr, U8SliceView src, UnmanagedVector *dest, UnmanagedVector *errOut, uint64_t *used_gas);
GoError cCanonicalizeAddress_cgo(api_t *ptr, U8SliceView src, UnmanagedVector *dest, UnmanagedVector *errOut, uint64_t *used_gas);
GoError cValidateAddress_cgo(api_t *ptr, U8SliceView src, UnmanagedVector *errOut, uint64_t *used_gas);
// and querier
GoError cQueryExternal_cgo(querier_t *ptr, uint64_t gas_limit, uint64_t *used_gas, U8SliceView request, UnmanagedVector *result, UnmanagedVector *errOut);

Expand Down Expand Up @@ -365,6 +366,7 @@ func nextPart(ref C.iterator_t, gasMeter *C.gas_meter_t, usedGas *cu64, output *
var api_vtable = C.GoApiVtable{
humanize_address: C.any_function_t(C.cHumanizeAddress_cgo),
canonicalize_address: C.any_function_t(C.cCanonicalizeAddress_cgo),
validate_address: C.any_function_t(C.cValidateAddress_cgo),
}

// contract: original pointer/struct referenced must live longer than C.GoApi struct
Expand Down Expand Up @@ -431,6 +433,30 @@ func cCanonicalizeAddress(ptr *C.api_t, src C.U8SliceView, dest *C.UnmanagedVect
return C.GoError_None
}

//export cValidateAddress
func cValidateAddress(ptr *C.api_t, src C.U8SliceView, errOut *C.UnmanagedVector, used_gas *cu64) (ret C.GoError) {
defer recoverPanic(&ret)

if errOut == nil {
return C.GoError_BadArgument
}
if !(*errOut).is_none {
panic("Got a non-none UnmanagedVector we're about to override. This is a bug because someone has to drop the old one.")
}

api := (*types.GoAPI)(unsafe.Pointer(ptr))
s := string(copyU8Slice(src))
cost, err := api.ValidateAddress(s)

*used_gas = cu64(cost)
if err != nil {
// store the actual error message in the return buffer
*errOut = newUnmanagedVector([]byte(err.Error()))
return C.GoError_User
}
return C.GoError_None
}

/****** Go Querier ********/

var querier_vtable = C.QuerierVtable{
Expand Down
4 changes: 4 additions & 0 deletions internal/api/callbacks_cgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ GoError cNextValue(iterator_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas,
// imports (api)
GoError cHumanizeAddress(api_t *ptr, U8SliceView src, UnmanagedVector *dest, UnmanagedVector *errOut, uint64_t *used_gas);
GoError cCanonicalizeAddress(api_t *ptr, U8SliceView src, UnmanagedVector *dest, UnmanagedVector *errOut, uint64_t *used_gas);
GoError cValidateAddress(api_t *ptr, U8SliceView src, UnmanagedVector *errOut, uint64_t *used_gas);
// imports (querier)
GoError cQueryExternal(querier_t *ptr, uint64_t gas_limit, uint64_t *used_gas, U8SliceView request, UnmanagedVector *result, UnmanagedVector *errOut);

Expand Down Expand Up @@ -51,6 +52,9 @@ GoError cCanonicalizeAddress_cgo(api_t *ptr, U8SliceView src, UnmanagedVector *d
GoError cHumanizeAddress_cgo(api_t *ptr, U8SliceView src, UnmanagedVector *dest, UnmanagedVector *errOut, uint64_t *used_gas) {
return cHumanizeAddress(ptr, src, dest, errOut, used_gas);
}
GoError cValidateAddress_cgo(api_t *ptr, U8SliceView src, UnmanagedVector *errOut, uint64_t *used_gas) {
return cValidateAddress(ptr, src, errOut, used_gas);
}

// Gateway functions (querier)
GoError cQueryExternal_cgo(querier_t *ptr, uint64_t gas_limit, uint64_t *used_gas, U8SliceView request, UnmanagedVector *result, UnmanagedVector *errOut) {
Expand Down
14 changes: 10 additions & 4 deletions internal/api/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,11 @@ func AnalyzeCode(cache Cache, checksum []byte) (*types.AnalysisReport, error) {
return nil, errorWithMessage(err, errmsg)
}
requiredCapabilities := string(copyAndDestroyUnmanagedVector(report.required_capabilities))
entrypoints := string(copyAndDestroyUnmanagedVector(report.entrypoints))
res := types.AnalysisReport{
HasIBCEntryPoints: bool(report.has_ibc_entry_points),
RequiredFeatures: requiredCapabilities,
RequiredCapabilities: requiredCapabilities,
Entrypoints: strings.Split(entrypoints, ","),
}
return &res, nil
}
Expand Down Expand Up @@ -725,17 +726,22 @@ func errorWithMessage(err error, b C.UnmanagedVector) error {
// to be caused by user data.
func checkAndPinAPI(api *types.GoAPI, pinner runtime.Pinner) {
if api == nil {
panic("API must not be nil. If you don't want to provide API functionality, please create an instance that returns an error on every call to HumanizeAddress() and CanonicalizeAddress().")
panic("API must not be nil. If you don't want to provide API functionality, please create an instance that returns an error on every call to HumanizeAddress(), CanonicalizeAddress() and ValidateAddress().")
}

// func cHumanizeAddress assumes this is set
if api.HumanizeAddress == nil {
panic("HumanizeAddress in API must not be nil. If you don't want to provide API functionality, please create an instance that returns an error on every call to HumanizeAddress() and CanonicalizeAddress().")
panic("HumanizeAddress in API must not be nil. If you don't want to provide API functionality, please create an instance that returns an error on every call to HumanizeAddress(), CanonicalizeAddress() and ValidateAddress().")
}

// func cCanonicalizeAddress assumes this is set
if api.CanonicalizeAddress == nil {
panic("CanonicalizeAddress in API must not be nil. If you don't want to provide API functionality, please create an instance that returns an error on every call to HumanizeAddress() and CanonicalizeAddress().")
panic("CanonicalizeAddress in API must not be nil. If you don't want to provide API functionality, please create an instance that returns an error on every call to HumanizeAddress(), CanonicalizeAddress() and ValidateAddress().")
}

// func cValidateAddress assumes this is set
if api.ValidateAddress == nil {
panic("ValidateAddress in API must not be nil. If you don't want to provide API functionality, please create an instance that returns an error on every call to HumanizeAddress(), CanonicalizeAddress() and ValidateAddress().")
}

pinner.Pin(api) // this pointer is used in Rust (`state` in `C.GoApi`) and must not change
Expand Down
5 changes: 5 additions & 0 deletions internal/api/mock_failure.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@ func MockFailureHumanizeAddress(canon []byte) (string, uint64, error) {
return "", 0, fmt.Errorf("mock failure - human_address")
}

func MockFailureValidateAddress(human string) (uint64, error) {
return 0, fmt.Errorf("mock failure - validate_address")
}

func NewMockFailureAPI() *types.GoAPI {
return &types.GoAPI{
HumanizeAddress: MockFailureHumanizeAddress,
CanonicalizeAddress: MockFailureCanonicalizeAddress,
ValidateAddress: MockFailureValidateAddress,
}
}
19 changes: 19 additions & 0 deletions internal/api/mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,10 +361,29 @@ func MockHumanizeAddress(canon []byte) (string, uint64, error) {
return human, CostHuman, nil
}

func MockValidateAddress(input string) (gasCost uint64, _ error) {
canonicalized, gasCostCanonicalize, err := MockCanonicalizeAddress(input)
gasCost += gasCostCanonicalize
if err != nil {
return gasCost, err
}
humanized, gasCostHumanize, err := MockHumanizeAddress(canonicalized)
gasCost += gasCostHumanize
if err != nil {
return gasCost, err
}
if humanized != strings.ToLower(input) {
return gasCost, fmt.Errorf("address validation failed")
}

return gasCost, nil
}

func NewMockAPI() *types.GoAPI {
return &types.GoAPI{
HumanizeAddress: MockHumanizeAddress,
CanonicalizeAddress: MockCanonicalizeAddress,
ValidateAddress: MockValidateAddress,
}
}

Expand Down
Loading
Loading