Skip to content

Commit

Permalink
Merge pull request #509 from CosmWasm/490-update-cosmwasm
Browse files Browse the repository at this point in the history
Update cosmwasm
  • Loading branch information
chipshort authored Feb 1, 2024
2 parents f1f537a + 0009ee3 commit 719d794
Show file tree
Hide file tree
Showing 14 changed files with 156 additions and 77 deletions.
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

0 comments on commit 719d794

Please sign in to comment.