*: return errors.ErrUnsupported where appropriate

Signed-off-by: Roman Khimov <roman@nspcc.ru>
This commit is contained in:
Roman Khimov 2024-08-26 21:27:09 +03:00
parent 97506fb48d
commit 6d4ebdcef3
9 changed files with 43 additions and 36 deletions

View file

@ -21,10 +21,6 @@ type TrieStore struct {
trie *Trie
}
// ErrForbiddenTrieStoreOperation is returned when operation is not supposed to
// be performed over MPT-based Store.
var ErrForbiddenTrieStoreOperation = errors.New("operation is not allowed to be performed over TrieStore")
// NewTrieStore returns a new ready to use MPT-backed storage.
func NewTrieStore(root util.Uint256, mode TrieMode, backed storage.Store) *TrieStore {
cache, ok := backed.(*storage.MemCachedStore)
@ -37,10 +33,11 @@ func NewTrieStore(root util.Uint256, mode TrieMode, backed storage.Store) *TrieS
}
}
// Get implements the Store interface.
// Get implements the Store interface. It can return [errors.ErrUnsupported]
// for unsupported operations.
func (m *TrieStore) Get(key []byte) ([]byte, error) {
if len(key) == 0 {
return nil, fmt.Errorf("%w: Get is supported only for contract storage items", ErrForbiddenTrieStoreOperation)
return nil, fmt.Errorf("%w: Get is supported only for contract storage items", errors.ErrUnsupported)
}
switch storage.KeyPrefix(key[0]) {
case storage.STStorage, storage.STTempStorage:
@ -51,22 +48,23 @@ func (m *TrieStore) Get(key []byte) ([]byte, error) {
}
return res, err
default:
return nil, fmt.Errorf("%w: Get is supported only for contract storage items", ErrForbiddenTrieStoreOperation)
return nil, fmt.Errorf("%w: Get is supported only for contract storage items", errors.ErrUnsupported)
}
}
// PutChangeSet implements the Store interface.
// PutChangeSet implements the Store interface. It's not supported, so it
// always returns [errors.ErrUnsupported].
func (m *TrieStore) PutChangeSet(puts map[string][]byte, stor map[string][]byte) error {
// Only Get and Seek should be supported, as TrieStore is read-only and is always
// should be wrapped by MemCachedStore to properly support put operations (if any).
return fmt.Errorf("%w: PutChangeSet is not supported", ErrForbiddenTrieStoreOperation)
return fmt.Errorf("%w: PutChangeSet is not supported", errors.ErrUnsupported)
}
// Seek implements the Store interface.
func (m *TrieStore) Seek(rng storage.SeekRange, f func(k, v []byte) bool) {
prefix := storage.KeyPrefix(rng.Prefix[0])
if prefix != storage.STStorage && prefix != storage.STTempStorage { // Prefix is always non-empty.
panic(fmt.Errorf("%w: Seek is supported only for contract storage items", ErrForbiddenTrieStoreOperation))
panic(fmt.Errorf("%w: Seek is supported only for contract storage items", errors.ErrUnsupported))
}
prefixP := toNibbles(rng.Prefix[1:])
fromP := []byte{}
@ -113,9 +111,10 @@ func (m *TrieStore) Seek(rng storage.SeekRange, f func(k, v []byte) bool) {
}
}
// SeekGC implements the Store interface.
// SeekGC implements the Store interface. It's not supported, so it always
// returns [errors.ErrUnsupported].
func (m *TrieStore) SeekGC(rng storage.SeekRange, keep func(k, v []byte) bool) error {
return fmt.Errorf("%w: SeekGC is not supported", ErrForbiddenTrieStoreOperation)
return fmt.Errorf("%w: SeekGC is not supported", errors.ErrUnsupported)
}
// Close implements the Store interface.

View file

@ -2,6 +2,7 @@ package mpt
import (
"bytes"
"errors"
"testing"
"github.com/nspcc-dev/neo-go/pkg/core/storage"
@ -15,10 +16,10 @@ func TestTrieStore_TestTrieOperations(t *testing.T) {
st := NewTrieStore(source.root.Hash(), ModeAll, backed)
t.Run("forbidden operations", func(t *testing.T) {
require.ErrorIs(t, st.SeekGC(storage.SeekRange{}, nil), ErrForbiddenTrieStoreOperation)
require.ErrorIs(t, st.SeekGC(storage.SeekRange{}, nil), errors.ErrUnsupported)
_, err := st.Get([]byte{byte(storage.STTokenTransferInfo)})
require.ErrorIs(t, err, ErrForbiddenTrieStoreOperation)
require.ErrorIs(t, st.PutChangeSet(nil, nil), ErrForbiddenTrieStoreOperation)
require.ErrorIs(t, err, errors.ErrUnsupported)
require.ErrorIs(t, st.PutChangeSet(nil, nil), errors.ErrUnsupported)
})
t.Run("Get", func(t *testing.T) {

View file

@ -201,16 +201,16 @@ func curveHasherFromStackitem(si stackitem.Item, allowKeccak bool) (elliptic.Cur
return elliptic.P256(), hash.Sha256, nil
case int64(Secp256k1Keccak256):
if !allowKeccak {
return nil, nil, errors.New("unsupported hash type")
return nil, nil, fmt.Errorf("%w: keccak hash", errors.ErrUnsupported)
}
return secp256k1.S256(), Keccak256, nil
case int64(Secp256r1Keccak256):
if !allowKeccak {
return nil, nil, errors.New("unsupported hash type")
return nil, nil, fmt.Errorf("%w: keccak hash", errors.ErrUnsupported)
}
return elliptic.P256(), Keccak256, nil
default:
return nil, nil, errors.New("unsupported curve/hash type")
return nil, nil, fmt.Errorf("%w: unknown curve/hash", errors.ErrUnsupported)
}
}

View file

@ -29,8 +29,8 @@ var (
// of transaction awaiting process and no result was received yet.
ErrContextDone = errors.New("waiter context done")
// ErrAwaitingNotSupported is returned from Wait method if Waiter instance
// doesn't support transaction awaiting.
ErrAwaitingNotSupported = errors.New("awaiting not supported")
// doesn't support transaction awaiting. It's compatible with [errors.ErrUnsupported].
ErrAwaitingNotSupported = fmt.Errorf("%w: awaiting", errors.ErrUnsupported)
// ErrMissedEvent is returned when RPCEventBased closes receiver channel
// which happens if missed event was received from the RPC server.
ErrMissedEvent = errors.New("some event was missed")

View file

@ -14,7 +14,8 @@ import (
)
// ExpandFuncParameterIntoScript pushes provided FuncParam parameter
// into the given buffer.
// into the given buffer. Returns [errors.ErrUnsupported] for types it can't
// process.
func ExpandFuncParameterIntoScript(script *io.BinWriter, fp FuncParam) error {
switch fp.Type {
case smartcontract.ByteArrayType:
@ -92,7 +93,7 @@ func ExpandFuncParameterIntoScript(script *io.BinWriter, fp FuncParam) error {
emit.Opcodes(script, opcode.PUSHNULL)
}
default:
return fmt.Errorf("parameter type %v is not supported", fp.Type)
return fmt.Errorf("%w: parameter type %v", errors.ErrUnsupported, fp.Type)
}
return script.Err
}

View file

@ -200,7 +200,8 @@ func (p *Parameter) UnmarshalJSON(data []byte) (err error) {
// NewParameterFromString returns a new Parameter initialized from the given
// string in neo-go-specific format. It is intended to be used in user-facing
// interfaces and has some heuristics in it to simplify parameter passing. The exact
// syntax is documented in the cli documentation.
// syntax is documented in the cli documentation. [errors.ErrUnsupported] will be
// returned in case of unsupported parameter types.
func NewParameterFromString(in string) (*Parameter, error) {
var (
char rune
@ -227,7 +228,7 @@ func NewParameterFromString(in string) (*Parameter, error) {
}
// We currently do not support following types:
if res.Type == ArrayType || res.Type == MapType || res.Type == InteropInterfaceType || res.Type == VoidType {
return nil, fmt.Errorf("unsupported parameter type %s", res.Type)
return nil, fmt.Errorf("%w: type %s", errors.ErrUnsupported, res.Type)
}
buf.Reset()
hadType = true
@ -264,7 +265,8 @@ func NewParameterFromString(in string) (*Parameter, error) {
// NewParameterFromValue infers Parameter type from the value given and adjusts
// the value if needed. It does not copy the value if it can avoid doing so. All
// regular integers, util.*, keys.PublicKey*, string and bool types are supported,
// slice of byte slices is accepted and converted as well.
// slice of byte slices is accepted and converted as well. [errors.ErrUnsupported]
// will be returned for types that can't be used now.
func NewParameterFromValue(value any) (Parameter, error) {
var result = Parameter{
Value: value,
@ -373,7 +375,7 @@ func NewParameterFromValue(value any) (Parameter, error) {
case nil:
result.Type = AnyType
default:
return result, fmt.Errorf("unsupported parameter %T", value)
return result, fmt.Errorf("%w: %T type", errors.ErrUnsupported, value)
}
return result, nil
@ -396,6 +398,7 @@ func NewParametersFromValues(values ...any) ([]Parameter, error) {
// ExpandParameterToEmitable converts a parameter to a type which can be handled as
// an array item by emit.Array. It correlates with the way an RPC server handles
// FuncParams for invoke* calls inside the request.ExpandArrayIntoScript function.
// [errors.ErrUnsupported] is returned for unsupported types.
func ExpandParameterToEmitable(param Parameter) (any, error) {
var err error
switch t := param.Type; t {
@ -410,7 +413,7 @@ func ExpandParameterToEmitable(param Parameter) (any, error) {
}
return res, nil
case MapType, InteropInterfaceType, UnknownType, VoidType:
return nil, fmt.Errorf("unsupported parameter type: %s", t.String())
return nil, fmt.Errorf("%w: %s type", errors.ErrUnsupported, t.String())
default:
return param.Value, nil
}

View file

@ -787,11 +787,11 @@ func TestParameterFromValue(t *testing.T) {
},
{
value: make(map[string]int),
err: "unsupported parameter map[string]int",
err: "unsupported operation: map[string]int type",
},
{
value: []any{1, 2, make(map[string]int)},
err: "unsupported parameter map[string]int",
err: "unsupported operation: map[string]int type",
},
}

View file

@ -127,6 +127,8 @@ func Array(w *io.BinWriter, es ...any) {
// - stackitem.Convertible, stackitem.Item
// - nil
// - []any
//
// [errors.ErrUnsupported] is returned for unsupported types.
func Any(w *io.BinWriter, something any) {
switch e := something.(type) {
case []any:
@ -181,7 +183,7 @@ func Any(w *io.BinWriter, something any) {
StackItem(w, e)
default:
if something != nil {
w.Err = fmt.Errorf("unsupported type: %T", e)
w.Err = fmt.Errorf("%w: %T type", errors.ErrUnsupported, e)
return
}
Opcodes(w, opcode.PUSHNULL)
@ -199,14 +201,15 @@ func Convertible(w *io.BinWriter, c stackitem.Convertible) {
StackItem(w, si)
}
// StackItem emits provided stackitem.Item to the given buffer.
// StackItem emits provided stackitem.Item to the given buffer. If it can't
// be emitted [errors.ErrUnsupported] is returned.
func StackItem(w *io.BinWriter, si stackitem.Item) {
switch t := si.Type(); t {
case stackitem.AnyT:
if si.Value() == nil {
Opcodes(w, opcode.PUSHNULL)
} else {
w.Err = fmt.Errorf("only nil value supported for %s", t)
w.Err = fmt.Errorf("%w: %s can only be nil", errors.ErrUnsupported, t)
return
}
case stackitem.BooleanT:
@ -240,7 +243,7 @@ func StackItem(w *io.BinWriter, si stackitem.Item) {
Int(w, int64(len(arr)))
Opcodes(w, opcode.PACKMAP)
default:
w.Err = fmt.Errorf("%s is unsuppoted", t)
w.Err = fmt.Errorf("%w: %s type", errors.ErrUnsupported, t)
return
}
}

View file

@ -547,7 +547,7 @@ func TestEmitStackitem(t *testing.T) {
for _, si := range itms {
buf := io.NewBufBinWriter()
StackItem(buf.BinWriter, si)
require.Error(t, buf.Err)
require.ErrorIs(t, buf.Err, errors.ErrUnsupported)
}
})
@ -555,8 +555,8 @@ func TestEmitStackitem(t *testing.T) {
buf := io.NewBufBinWriter()
StackItem(buf.BinWriter, StrangeStackItem{})
actualErr := buf.Err
require.Error(t, actualErr)
require.True(t, strings.Contains(actualErr.Error(), "only nil value supported"), actualErr.Error())
require.ErrorIs(t, actualErr, errors.ErrUnsupported)
require.True(t, strings.Contains(actualErr.Error(), "Any can only be nil"), actualErr.Error())
})
}