Skip to content
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 @@ -324,7 +324,7 @@ func (k Keeper) instantiate(
return nil, nil, errorsmod.Wrap(types.ErrVMError, err.Error())
}
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 Down Expand Up @@ -408,7 +408,7 @@ func (k Keeper) execute(ctx context.Context, contractAddress, caller sdk.AccAddr
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 @@ -485,7 +485,7 @@ func (k Keeper) migrate(
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 @@ -550,7 +550,7 @@ func (k Keeper) Sudo(ctx context.Context, contractAddress sdk.AccAddress, msg []
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 @@ -590,7 +590,7 @@ func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply was
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))
}

ctx.EventManager().EmitEvent(sdk.NewEvent(
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 @@ -209,18 +209,19 @@ func redactError(err error) error {
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
}

// 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 @@ func (k Keeper) OnConnectChannel(
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))
}

return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok)
Expand Down Expand Up @@ -110,7 +110,7 @@ func (k Keeper) OnCloseChannel(
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))
}

return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok)
Expand Down Expand Up @@ -201,7 +201,7 @@ func (k Keeper) OnAckPacket(
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))
}

return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok)
Expand Down Expand Up @@ -232,7 +232,7 @@ func (k Keeper) OnTimeoutPacket(
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))
}

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
// By returning the wrapped error here, we ensure
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())
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)
}