Proper systemerror follow-up (#715)

* Add custom NoSuchContract error

* Return custom NoSuchContract error from WasmQuerier

* Add custom NoSuchContract error

* Use custom ErrNoSuchContract error

Map to corresponding wasmvmtypes error

* Handle wrapped errors

Co-authored-by: Alex Peters <alpe@users.noreply.github.com>
This commit is contained in:
Mauro Lacy
2022-01-20 17:05:10 +01:00
committed by GitHub
parent b8319aa334
commit bf84b199a8
3 changed files with 60 additions and 2 deletions

View File

@@ -2,6 +2,7 @@ package keeper
import (
"encoding/json"
"errors"
"fmt"
"github.com/cosmos/cosmos-sdk/baseapp"
@@ -52,7 +53,14 @@ func (q QueryHandler) Query(request wasmvmtypes.QueryRequest, gasLimit uint64) (
defer func() {
q.Ctx.GasMeter().ConsumeGas(subCtx.GasMeter().GasConsumed(), "contract sub-query")
}()
return q.Plugins.HandleQuery(subCtx, q.Caller, request)
res, err := q.Plugins.HandleQuery(subCtx, q.Caller, request)
// Error mapping
var noSuchContract *types.ErrNoSuchContract
if ok := errors.As(err, &noSuchContract); ok {
return res, wasmvmtypes.NoSuchContract{Addr: noSuchContract.Addr}
}
return res, err
}
func (q QueryHandler) GasConsumed() uint64 {
@@ -483,7 +491,7 @@ func WasmQuerier(k wasmQueryKeeper) func(ctx sdk.Context, request *wasmvmtypes.W
}
info := k.GetContractInfo(ctx, addr)
if info == nil {
return nil, wasmvmtypes.NoSuchContract{Addr: request.ContractInfo.ContractAddr}
return nil, &types.ErrNoSuchContract{Addr: request.ContractInfo.ContractAddr}
}
res := wasmvmtypes.ContractInfoResponse{

View File

@@ -4,6 +4,9 @@ import (
"encoding/json"
"testing"
"github.com/cosmos/cosmos-sdk/store"
dbm "github.com/tendermint/tm-db"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -442,6 +445,34 @@ func TestContractInfoWasmQuerier(t *testing.T) {
}
}
func TestQueryErrors(t *testing.T) {
specs := map[string]struct {
src error
expErr error
}{
"no error": {},
"no such contract": {
src: &types.ErrNoSuchContract{Addr: "contract-addr"},
expErr: wasmvmtypes.NoSuchContract{Addr: "contract-addr"},
},
"no such contract - wrapped": {
src: sdkerrors.Wrap(&types.ErrNoSuchContract{Addr: "contract-addr"}, "my additional data"),
expErr: wasmvmtypes.NoSuchContract{Addr: "contract-addr"},
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
mock := WasmVMQueryHandlerFn(func(ctx sdk.Context, caller sdk.AccAddress, request wasmvmtypes.QueryRequest) ([]byte, error) {
return nil, spec.src
})
ctx := sdk.Context{}.WithGasMeter(sdk.NewInfiniteGasMeter()).WithMultiStore(store.NewCommitMultiStore(dbm.NewMemDB()))
q := NewQueryHandler(ctx, mock, sdk.AccAddress{}, NewDefaultWasmGasRegister())
_, gotErr := q.Query(wasmvmtypes.QueryRequest{}, 1)
assert.Equal(t, spec.expErr, gotErr)
})
}
}
type mockWasmQueryKeeper struct {
GetContractInfoFn func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo
QueryRawFn func(ctx sdk.Context, contractAddress sdk.AccAddress, key []byte) []byte

View File

@@ -69,4 +69,23 @@ var (
// ErrInvalidEvent error if an attribute/event from the contract is invalid
ErrInvalidEvent = sdkErrors.Register(DefaultCodespace, 21, "invalid event")
// error if an address does not belong to a contract (just for registration)
_ = sdkErrors.Register(DefaultCodespace, 22, "no such contract")
)
type ErrNoSuchContract struct {
Addr string
}
func (m *ErrNoSuchContract) Error() string {
return "no such contract: " + m.Addr
}
func (m *ErrNoSuchContract) ABCICode() uint32 {
return 22
}
func (m *ErrNoSuchContract) Codespace() string {
return DefaultCodespace
}