Skip to content

Commit

Permalink
Do not redact contract errors
Browse files Browse the repository at this point in the history
  • Loading branch information
chipshort committed Feb 21, 2024
1 parent 97694f1 commit d94360c
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 4 deletions.
26 changes: 26 additions & 0 deletions x/wasm/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,32 @@ func TestInstantiateWithNonExistingCodeID(t *testing.T) {
require.Nil(t, addr)
}

func TestContractErrorRedacting(t *testing.T) {
ctx, keepers := CreateTestInput(t, false, AvailableCapabilities)

deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len))
keepers.Faucet.Fund(ctx, creator, deposit...)
example := StoreHackatomExampleContract(t, ctx, keepers)

initMsg := HackatomExampleInitMsg{
Verifier: []byte{1, 2, 3}, // invalid length
Beneficiary: RandomAccountAddress(t),
}
initMsgBz, err := json.Marshal(initMsg)
require.NoError(t, err)

em := sdk.NewEventManager()

_, _, err = keepers.ContractKeeper.Instantiate(ctx.WithEventManager(em), example.CodeID, creator, nil, initMsgBz, "demo contract 1", nil)
require.Error(t, err)
require.Contains(t, err.Error(), "addr_validate errored: invalid address")

err = redactError(err)
// contract error should not be redacted
require.Contains(t, err.Error(), "addr_validate errored: invalid address")
}

func TestInstantiateWithContractDataResponse(t *testing.T) {
ctx, keepers := CreateTestInput(t, false, AvailableCapabilities)

Expand Down
6 changes: 6 additions & 0 deletions x/wasm/keeper/msg_dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@ func redactError(err error) error {
// 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
20 changes: 16 additions & 4 deletions x/wasm/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ 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 @@ -19,10 +23,10 @@ var (
ErrAccountExists = errorsmod.Register(DefaultCodespace, 3, "contract account already exists")

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

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

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

// ErrQueryFailed error for rust smart query contract failure
ErrQueryFailed = errorsmod.Register(DefaultCodespace, 9, "query wasm contract failed")
ErrQueryFailed = errorsmod.Register(DefaultCodespace, QueryErrorCode, "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, 11, "migrate wasm contract failed")
ErrMigrationFailed = errorsmod.Register(DefaultCodespace, MigrateErrorCode, "migrate wasm contract failed")

// ErrEmpty error for empty content
ErrEmpty = errorsmod.Register(DefaultCodespace, 12, "empty")
Expand Down Expand Up @@ -91,6 +95,14 @@ 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

0 comments on commit d94360c

Please sign in to comment.