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 to wasmvm 2.0.0-rc.1 #1804

Merged
merged 45 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
b1c5bfb
Update to wasmvm 2.0.0-rc.1
chipshort Feb 6, 2024
c7ba88f
Adjust to type changes and renamings
chipshort Feb 6, 2024
d4e6417
Adjust to nested results
chipshort Feb 6, 2024
e4d95c2
Fix StoreCode gas usage
chipshort Feb 7, 2024
54670c4
Add ValidateAddress impl
chipshort Feb 7, 2024
73e7ebb
go mod tidy
chipshort Feb 7, 2024
cca0005
Fix lint
chipshort Feb 7, 2024
244c55a
Reduce gas factor
chipshort Feb 7, 2024
c8f84ff
Fix wasmvm path in CI
chipshort Feb 7, 2024
ec2c70b
Fix address validation
chipshort Feb 8, 2024
ffe6aaa
Fix dockerfile
chipshort Feb 8, 2024
db25a82
Add cosmwasm_2_0 capability
chipshort Feb 8, 2024
dd992b0
Use different tempdir for each test run
chipshort Feb 14, 2024
5984896
Add cosmwasm_2_0 capability to README
chipshort Feb 15, 2024
6d7c91c
Remove unnecessary conversion
chipshort Feb 15, 2024
2ec0628
Fix TestAppStateDeterminism
chipshort Feb 15, 2024
137cb26
Fix TestAppImportExport
chipshort Feb 15, 2024
1d77a66
Fix errors
chipshort Feb 15, 2024
1037fc8
Use updated reflect contract
chipshort Feb 15, 2024
5e2d766
Update to wasmvm rc.2
chipshort Feb 16, 2024
3539fe9
Fix gas numbers
chipshort Feb 16, 2024
b88f84a
Fix Dockerfile
chipshort Feb 16, 2024
2887105
Handle TransferMsg.Memo field
chipshort Feb 16, 2024
a30e083
Add flattened msgResponses to SubMsgResponse
webmaster128 Jan 31, 2024
d6ec8d4
Fix MockMessageHandler
chipshort Feb 16, 2024
219da83
Run gofumpt
chipshort Feb 19, 2024
7f88c95
Format imports
chipshort Feb 19, 2024
0ca56bd
Pass Payload from submsg to reply
chipshort Feb 19, 2024
97694f1
Add extra error for wasmvm errors
chipshort Feb 20, 2024
d94360c
Do not redact contract errors
chipshort Feb 21, 2024
9cc1a5a
Implement grpc query
chipshort Feb 21, 2024
4f8d513
Fix spelling
chipshort Feb 21, 2024
4c2d28a
Remove unnecessary comments
chipshort Feb 26, 2024
5dc97d5
Rename reflect.wasm to stargate_reflect.wasm
chipshort Feb 26, 2024
77504d8
Cleanup
chipshort Feb 26, 2024
8663a85
Add msgResponses in IBCRawPacketHandler
chipshort Feb 26, 2024
e982aab
Apply suggestions from code review
chipshort Feb 26, 2024
f41bb6f
Fix costValidate
chipshort Feb 26, 2024
8607164
Add validateAddress test
chipshort Feb 26, 2024
044caab
Update capability table
chipshort Feb 27, 2024
1ee2c49
Use reflect contract from 1.5
chipshort Feb 27, 2024
4e7e534
Add DeterministicError type for redactError
chipshort Feb 28, 2024
3e960ee
Fix DeterministicError docs
chipshort Feb 29, 2024
ad93ad3
Add contract error integration test
chipshort Mar 4, 2024
62eaa6e
Add nil checks
chipshort Mar 6, 2024
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
10 changes: 5 additions & 5 deletions x/wasm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,10 +321,10 @@
res, gasUsed, err := k.wasmVM.Instantiate(codeInfo.CodeHash, env, info, initMsg, vmStore, cosmwasmAPI, querier, k.gasMeter(sdkCtx), gas, costJSONDeserialization)
k.consumeRuntimeGas(sdkCtx, gasUsed)
if err != nil {
return nil, nil, errorsmod.Wrap(types.ErrVMError, err.Error())

Check warning on line 324 in x/wasm/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/keeper.go#L324

Added line #L324 was not covered by tests
}
if res.Err != "" {
return nil, nil, errorsmod.Wrap(types.ErrInstantiateFailed, res.Err)
return nil, nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrInstantiateFailed, res.Err))
}

// persist instance first
Expand All @@ -334,7 +334,7 @@
// check for IBC flag
report, err := k.wasmVM.AnalyzeCode(codeInfo.CodeHash)
if err != nil {
return nil, nil, errorsmod.Wrap(types.ErrVMError, err.Error())

Check warning on line 337 in x/wasm/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/keeper.go#L337

Added line #L337 was not covered by tests
}
if report.HasIBCEntryPoints {
// register IBC port
Expand Down Expand Up @@ -408,7 +408,7 @@
return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error())
}
if res.Err != "" {
return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err)
return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err))
}

sdkCtx.EventManager().EmitEvent(sdk.NewEvent(
Expand Down Expand Up @@ -458,7 +458,7 @@
// check for IBC flag
switch report, err := k.wasmVM.AnalyzeCode(newCodeInfo.CodeHash); {
case err != nil:
return nil, errorsmod.Wrap(types.ErrVMError, err.Error())

Check warning on line 461 in x/wasm/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/keeper.go#L461

Added line #L461 was not covered by tests
case !report.HasIBCEntryPoints && contractInfo.IBCPortID != "":
// prevent update to non ibc contract
return nil, errorsmod.Wrap(types.ErrMigrationFailed, "requires ibc callbacks")
Expand All @@ -485,7 +485,7 @@
return nil, errorsmod.Wrap(types.ErrVMError, err.Error())
}
if res.Err != "" {
return nil, errorsmod.Wrap(types.ErrMigrationFailed, res.Err)
return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrMigrationFailed, res.Err))
}
// delete old secondary index entry
err = k.removeFromContractCodeSecondaryIndex(ctx, contractAddress, k.mustGetLastContractHistoryEntry(sdkCtx, contractAddress))
Expand Down Expand Up @@ -547,10 +547,10 @@
res, gasUsed, execErr := k.wasmVM.Sudo(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, k.gasMeter(sdkCtx), gas, costJSONDeserialization)
k.consumeRuntimeGas(sdkCtx, gasUsed)
if execErr != nil {
return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error())

Check warning on line 550 in x/wasm/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/keeper.go#L550

Added line #L550 was not covered by tests
}
if res.Err != "" {
return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err)
return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err))

Check warning on line 553 in x/wasm/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/keeper.go#L553

Added line #L553 was not covered by tests
}

sdkCtx.EventManager().EmitEvent(sdk.NewEvent(
Expand Down Expand Up @@ -590,7 +590,7 @@
return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error())
}
if res.Err != "" {
return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err)
return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err))

Check warning on line 593 in x/wasm/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/keeper.go#L593

Added line #L593 was not covered by tests
}

ctx.EventManager().EmitEvent(sdk.NewEvent(
Expand Down Expand Up @@ -773,7 +773,7 @@
queryResult, gasUsed, qErr := k.wasmVM.Query(codeInfo.CodeHash, env, req, prefixStore, cosmwasmAPI, querier, k.gasMeter(sdkCtx), k.runtimeGasForContract(sdkCtx), costJSONDeserialization)
k.consumeRuntimeGas(sdkCtx, gasUsed)
if qErr != nil {
return nil, errorsmod.Wrap(types.ErrVMError, qErr.Error())

Check warning on line 776 in x/wasm/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/keeper.go#L776

Added line #L776 was not covered by tests
}
if queryResult.Err != "" {
return nil, errorsmod.Wrap(types.ErrQueryFailed, queryResult.Err)
Expand Down
13 changes: 7 additions & 6 deletions x/wasm/keeper/msg_dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
// DispatchMessages sends all messages.
func (d MessageDispatcher) DispatchMessages(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.CosmosMsg) error {
for _, msg := range msgs {
events, _, _, err := d.messenger.DispatchMsg(ctx, contractAddr, ibcPort, msg)

Check warning on line 53 in x/wasm/keeper/msg_dispatcher.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/msg_dispatcher.go#L53

Added line #L53 was not covered by tests
if err != nil {
return err
}
Expand Down Expand Up @@ -209,18 +209,19 @@
return err
}

// If it is a DeterministicError, we can safely return it without redaction.
// We only check the top level error to avoid changes in the error chain becoming
// consensus-breaking.
if _, ok := err.(types.DeterministicError); ok {
return err
webmaster128 marked this conversation as resolved.
Show resolved Hide resolved
}

// FIXME: do we want to hardcode some constant string mappings here as well?
// Or better document them? (SDK error string may change on a patch release to fix wording)
// sdk/11 is out of gas
// sdk/5 is insufficient funds (on bank send)
// (we can theoretically redact less in the future, but this is a first step to safety)
codespace, code, _ := errorsmod.ABCIInfo(err, false)

// Also do not redact any errors that are coming from the contract,
// as they are always deterministic
if codespace == types.DefaultCodespace && contains(types.ContractErrorCodes, code) {
return err
}
return fmt.Errorf("codespace: %s, code: %d", codespace, code)
}

Expand Down
2 changes: 1 addition & 1 deletion x/wasm/keeper/recurse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ func TestLimitRecursiveQueryGas(t *testing.T) {
expectQueriesFromContract: 10,
expectOutOfGas: false,
expectError: "query wasm contract failed", // Error we get from the contract instance doing the failing query, not wasmd
expectedGas: 10*(GasWork2k+GasReturnHashed) + 3124,
expectedGas: 10*(GasWork2k+GasReturnHashed) - 249,
},
}

Expand Down
8 changes: 4 additions & 4 deletions x/wasm/keeper/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error())
}
if res.Err != "" {
return errorsmod.Wrap(types.ErrExecuteFailed, res.Err)
return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err))

Check warning on line 79 in x/wasm/keeper/relay.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/relay.go#L79

Added line #L79 was not covered by tests
}

return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok)
Expand Down Expand Up @@ -110,7 +110,7 @@
return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error())
}
if res.Err != "" {
return errorsmod.Wrap(types.ErrExecuteFailed, res.Err)
return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err))

Check warning on line 113 in x/wasm/keeper/relay.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/relay.go#L113

Added line #L113 was not covered by tests
}

return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok)
Expand Down Expand Up @@ -201,7 +201,7 @@
return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error())
}
if res.Err != "" {
chipshort marked this conversation as resolved.
Show resolved Hide resolved
return errorsmod.Wrap(types.ErrExecuteFailed, res.Err)
return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err))

Check warning on line 204 in x/wasm/keeper/relay.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/relay.go#L204

Added line #L204 was not covered by tests
}

return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok)
Expand Down Expand Up @@ -232,7 +232,7 @@
return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error())
}
if res.Err != "" {
chipshort marked this conversation as resolved.
Show resolved Hide resolved
return errorsmod.Wrap(types.ErrExecuteFailed, res.Err)
return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err))

Check warning on line 235 in x/wasm/keeper/relay.go

View check run for this annotation

Codecov / codecov/patch

x/wasm/keeper/relay.go#L235

Added line #L235 was not covered by tests
}

return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok)
Expand Down
49 changes: 33 additions & 16 deletions x/wasm/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ import (
var (
DefaultCodespace = ModuleName

// ContractErrorCodes are the error codes for errors returned by the contract
// Since contract execution is deterministic, the errors are also deterministic
ContractErrorCodes = []uint32{InstantiateErrorCode, ExecuteErrorCode, QueryErrorCode, MigrateErrorCode}

// Note: never use code 1 for any errors - that is reserved for ErrInternal in the core cosmos sdk

// ErrCreateFailed error for wasm code that has already been uploaded or failed
Expand All @@ -23,10 +19,10 @@ var (
ErrAccountExists = errorsmod.Register(DefaultCodespace, 3, "contract account already exists")

// ErrInstantiateFailed error for rust instantiate contract failure
ErrInstantiateFailed = errorsmod.Register(DefaultCodespace, InstantiateErrorCode, "instantiate wasm contract failed")
ErrInstantiateFailed = errorsmod.Register(DefaultCodespace, 4, "instantiate wasm contract failed")

// ErrExecuteFailed error for rust execution contract failure
ErrExecuteFailed = errorsmod.Register(DefaultCodespace, ExecuteErrorCode, "execute wasm contract failed")
ErrExecuteFailed = errorsmod.Register(DefaultCodespace, 5, "execute wasm contract failed")

// ErrGasLimit error for out of gas
ErrGasLimit = errorsmod.Register(DefaultCodespace, 6, "insufficient gas")
Expand All @@ -38,13 +34,13 @@ var (
ErrNotFound = errorsmod.Register(DefaultCodespace, 8, "not found")

// ErrQueryFailed error for rust smart query contract failure
ErrQueryFailed = errorsmod.Register(DefaultCodespace, QueryErrorCode, "query wasm contract failed")
ErrQueryFailed = errorsmod.Register(DefaultCodespace, 9, "query wasm contract failed")

// ErrInvalidMsg error when we cannot process the error returned from the contract
ErrInvalidMsg = errorsmod.Register(DefaultCodespace, 10, "invalid CosmosMsg from the contract")

// ErrMigrationFailed error for rust execution contract failure
ErrMigrationFailed = errorsmod.Register(DefaultCodespace, MigrateErrorCode, "migrate wasm contract failed")
ErrMigrationFailed = errorsmod.Register(DefaultCodespace, 11, "migrate wasm contract failed")

// ErrEmpty error for empty content
ErrEmpty = errorsmod.Register(DefaultCodespace, 12, "empty")
Expand Down Expand Up @@ -95,14 +91,6 @@ var (
ErrVMError = errorsmod.Register(DefaultCodespace, 29, "wasmvm error")
)

// Error codes for wasm contract errors
const (
InstantiateErrorCode = 4
ExecuteErrorCode = 5
QueryErrorCode = 9
MigrateErrorCode = 11
)

// WasmVMErrorable mapped error type in wasmvm and are not redacted
type WasmVMErrorable interface {
// ToWasmVMError convert instance to wasmvm friendly error if possible otherwise root cause. never nil
Expand Down Expand Up @@ -164,3 +152,32 @@ func (e WasmVMFlavouredError) Wrap(desc string) error { return errorsmod.Wrap(e,
func (e WasmVMFlavouredError) Wrapf(desc string, args ...interface{}) error {
return errorsmod.Wrapf(e, desc, args...)
}

// DeterministicError is a wrapper type around an error that the creator guarantees to have
// a deterministic error message.
// This means that the `Error()` function must always return the same string on all nodes.
// DeterministicErrors are not redacted when returned to a contract,
// so not upholding this guarantee can lead to consensus failures.
type DeterministicError struct {
error
}

var _ error = DeterministicError{}

// MarkErrorDeterministic marks an error as deterministic.
// Make sure to only do that if the error message is deterministic between systems.
// See [DeterministicError] for more details.
func MarkErrorDeterministic(e error) DeterministicError {
return DeterministicError{error: e}
}

// Unwrap implements the built-in errors.Unwrap
func (e DeterministicError) Unwrap() error {
return e.error
}

// Cause is the same as unwrap but used by ABCIInfo
webmaster128 marked this conversation as resolved.
Show resolved Hide resolved
// By returning the wrapped error here, we ensure
chipshort marked this conversation as resolved.
Show resolved Hide resolved
func (e DeterministicError) Cause() error {
return e.Unwrap()
}
16 changes: 16 additions & 0 deletions x/wasm/types/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,19 @@ func TestWasmVMFlavouredError(t *testing.T) {
t.Run(name, spec.exec)
}
}

func TestDeterministicError(t *testing.T) {
inner := ErrInstantiateFailed
err := MarkErrorDeterministic(inner)

// behaves like a wrapper around inner error
assert.Equal(t, inner.Error(), err.Error())
chipshort marked this conversation as resolved.
Show resolved Hide resolved
assert.Equal(t, inner, err.Cause())
assert.Equal(t, inner, err.Unwrap())

// also works with ABCIInfo
codespace, code, _ := errorsmod.ABCIInfo(err, false)
innerCodeSpace, innerCode, _ := errorsmod.ABCIInfo(inner, false)
assert.Equal(t, innerCodeSpace, codespace)
assert.Equal(t, innerCode, code)
}
Loading