mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-23 03:41:34 +00:00
*: return errors.ErrUnsupported where appropriate
Signed-off-by: Roman Khimov <roman@nspcc.ru>
This commit is contained in:
parent
97506fb48d
commit
6d4ebdcef3
9 changed files with 43 additions and 36 deletions
|
@ -21,10 +21,6 @@ type TrieStore struct {
|
||||||
trie *Trie
|
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.
|
// NewTrieStore returns a new ready to use MPT-backed storage.
|
||||||
func NewTrieStore(root util.Uint256, mode TrieMode, backed storage.Store) *TrieStore {
|
func NewTrieStore(root util.Uint256, mode TrieMode, backed storage.Store) *TrieStore {
|
||||||
cache, ok := backed.(*storage.MemCachedStore)
|
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) {
|
func (m *TrieStore) Get(key []byte) ([]byte, error) {
|
||||||
if len(key) == 0 {
|
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]) {
|
switch storage.KeyPrefix(key[0]) {
|
||||||
case storage.STStorage, storage.STTempStorage:
|
case storage.STStorage, storage.STTempStorage:
|
||||||
|
@ -51,22 +48,23 @@ func (m *TrieStore) Get(key []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
return res, err
|
return res, err
|
||||||
default:
|
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 {
|
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
|
// 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).
|
// 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.
|
// Seek implements the Store interface.
|
||||||
func (m *TrieStore) Seek(rng storage.SeekRange, f func(k, v []byte) bool) {
|
func (m *TrieStore) Seek(rng storage.SeekRange, f func(k, v []byte) bool) {
|
||||||
prefix := storage.KeyPrefix(rng.Prefix[0])
|
prefix := storage.KeyPrefix(rng.Prefix[0])
|
||||||
if prefix != storage.STStorage && prefix != storage.STTempStorage { // Prefix is always non-empty.
|
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:])
|
prefixP := toNibbles(rng.Prefix[1:])
|
||||||
fromP := []byte{}
|
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 {
|
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.
|
// Close implements the Store interface.
|
||||||
|
|
|
@ -2,6 +2,7 @@ package mpt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
"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)
|
st := NewTrieStore(source.root.Hash(), ModeAll, backed)
|
||||||
|
|
||||||
t.Run("forbidden operations", func(t *testing.T) {
|
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)})
|
_, err := st.Get([]byte{byte(storage.STTokenTransferInfo)})
|
||||||
require.ErrorIs(t, err, ErrForbiddenTrieStoreOperation)
|
require.ErrorIs(t, err, errors.ErrUnsupported)
|
||||||
require.ErrorIs(t, st.PutChangeSet(nil, nil), ErrForbiddenTrieStoreOperation)
|
require.ErrorIs(t, st.PutChangeSet(nil, nil), errors.ErrUnsupported)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Get", func(t *testing.T) {
|
t.Run("Get", func(t *testing.T) {
|
||||||
|
|
|
@ -201,16 +201,16 @@ func curveHasherFromStackitem(si stackitem.Item, allowKeccak bool) (elliptic.Cur
|
||||||
return elliptic.P256(), hash.Sha256, nil
|
return elliptic.P256(), hash.Sha256, nil
|
||||||
case int64(Secp256k1Keccak256):
|
case int64(Secp256k1Keccak256):
|
||||||
if !allowKeccak {
|
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
|
return secp256k1.S256(), Keccak256, nil
|
||||||
case int64(Secp256r1Keccak256):
|
case int64(Secp256r1Keccak256):
|
||||||
if !allowKeccak {
|
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
|
return elliptic.P256(), Keccak256, nil
|
||||||
default:
|
default:
|
||||||
return nil, nil, errors.New("unsupported curve/hash type")
|
return nil, nil, fmt.Errorf("%w: unknown curve/hash", errors.ErrUnsupported)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,8 @@ var (
|
||||||
// of transaction awaiting process and no result was received yet.
|
// of transaction awaiting process and no result was received yet.
|
||||||
ErrContextDone = errors.New("waiter context done")
|
ErrContextDone = errors.New("waiter context done")
|
||||||
// ErrAwaitingNotSupported is returned from Wait method if Waiter instance
|
// ErrAwaitingNotSupported is returned from Wait method if Waiter instance
|
||||||
// doesn't support transaction awaiting.
|
// doesn't support transaction awaiting. It's compatible with [errors.ErrUnsupported].
|
||||||
ErrAwaitingNotSupported = errors.New("awaiting not supported")
|
ErrAwaitingNotSupported = fmt.Errorf("%w: awaiting", errors.ErrUnsupported)
|
||||||
// ErrMissedEvent is returned when RPCEventBased closes receiver channel
|
// ErrMissedEvent is returned when RPCEventBased closes receiver channel
|
||||||
// which happens if missed event was received from the RPC server.
|
// which happens if missed event was received from the RPC server.
|
||||||
ErrMissedEvent = errors.New("some event was missed")
|
ErrMissedEvent = errors.New("some event was missed")
|
||||||
|
|
|
@ -14,7 +14,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExpandFuncParameterIntoScript pushes provided FuncParam parameter
|
// 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 {
|
func ExpandFuncParameterIntoScript(script *io.BinWriter, fp FuncParam) error {
|
||||||
switch fp.Type {
|
switch fp.Type {
|
||||||
case smartcontract.ByteArrayType:
|
case smartcontract.ByteArrayType:
|
||||||
|
@ -92,7 +93,7 @@ func ExpandFuncParameterIntoScript(script *io.BinWriter, fp FuncParam) error {
|
||||||
emit.Opcodes(script, opcode.PUSHNULL)
|
emit.Opcodes(script, opcode.PUSHNULL)
|
||||||
}
|
}
|
||||||
default:
|
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
|
return script.Err
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,7 +200,8 @@ func (p *Parameter) UnmarshalJSON(data []byte) (err error) {
|
||||||
// NewParameterFromString returns a new Parameter initialized from the given
|
// NewParameterFromString returns a new Parameter initialized from the given
|
||||||
// string in neo-go-specific format. It is intended to be used in user-facing
|
// 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
|
// 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) {
|
func NewParameterFromString(in string) (*Parameter, error) {
|
||||||
var (
|
var (
|
||||||
char rune
|
char rune
|
||||||
|
@ -227,7 +228,7 @@ func NewParameterFromString(in string) (*Parameter, error) {
|
||||||
}
|
}
|
||||||
// We currently do not support following types:
|
// We currently do not support following types:
|
||||||
if res.Type == ArrayType || res.Type == MapType || res.Type == InteropInterfaceType || res.Type == VoidType {
|
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()
|
buf.Reset()
|
||||||
hadType = true
|
hadType = true
|
||||||
|
@ -264,7 +265,8 @@ func NewParameterFromString(in string) (*Parameter, error) {
|
||||||
// NewParameterFromValue infers Parameter type from the value given and adjusts
|
// 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
|
// 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,
|
// 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) {
|
func NewParameterFromValue(value any) (Parameter, error) {
|
||||||
var result = Parameter{
|
var result = Parameter{
|
||||||
Value: value,
|
Value: value,
|
||||||
|
@ -373,7 +375,7 @@ func NewParameterFromValue(value any) (Parameter, error) {
|
||||||
case nil:
|
case nil:
|
||||||
result.Type = AnyType
|
result.Type = AnyType
|
||||||
default:
|
default:
|
||||||
return result, fmt.Errorf("unsupported parameter %T", value)
|
return result, fmt.Errorf("%w: %T type", errors.ErrUnsupported, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
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
|
// 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
|
// an array item by emit.Array. It correlates with the way an RPC server handles
|
||||||
// FuncParams for invoke* calls inside the request.ExpandArrayIntoScript function.
|
// FuncParams for invoke* calls inside the request.ExpandArrayIntoScript function.
|
||||||
|
// [errors.ErrUnsupported] is returned for unsupported types.
|
||||||
func ExpandParameterToEmitable(param Parameter) (any, error) {
|
func ExpandParameterToEmitable(param Parameter) (any, error) {
|
||||||
var err error
|
var err error
|
||||||
switch t := param.Type; t {
|
switch t := param.Type; t {
|
||||||
|
@ -410,7 +413,7 @@ func ExpandParameterToEmitable(param Parameter) (any, error) {
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
case MapType, InteropInterfaceType, UnknownType, VoidType:
|
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:
|
default:
|
||||||
return param.Value, nil
|
return param.Value, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -787,11 +787,11 @@ func TestParameterFromValue(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: make(map[string]int),
|
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)},
|
value: []any{1, 2, make(map[string]int)},
|
||||||
err: "unsupported parameter map[string]int",
|
err: "unsupported operation: map[string]int type",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,8 @@ func Array(w *io.BinWriter, es ...any) {
|
||||||
// - stackitem.Convertible, stackitem.Item
|
// - stackitem.Convertible, stackitem.Item
|
||||||
// - nil
|
// - nil
|
||||||
// - []any
|
// - []any
|
||||||
|
//
|
||||||
|
// [errors.ErrUnsupported] is returned for unsupported types.
|
||||||
func Any(w *io.BinWriter, something any) {
|
func Any(w *io.BinWriter, something any) {
|
||||||
switch e := something.(type) {
|
switch e := something.(type) {
|
||||||
case []any:
|
case []any:
|
||||||
|
@ -181,7 +183,7 @@ func Any(w *io.BinWriter, something any) {
|
||||||
StackItem(w, e)
|
StackItem(w, e)
|
||||||
default:
|
default:
|
||||||
if something != nil {
|
if something != nil {
|
||||||
w.Err = fmt.Errorf("unsupported type: %T", e)
|
w.Err = fmt.Errorf("%w: %T type", errors.ErrUnsupported, e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Opcodes(w, opcode.PUSHNULL)
|
Opcodes(w, opcode.PUSHNULL)
|
||||||
|
@ -199,14 +201,15 @@ func Convertible(w *io.BinWriter, c stackitem.Convertible) {
|
||||||
StackItem(w, si)
|
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) {
|
func StackItem(w *io.BinWriter, si stackitem.Item) {
|
||||||
switch t := si.Type(); t {
|
switch t := si.Type(); t {
|
||||||
case stackitem.AnyT:
|
case stackitem.AnyT:
|
||||||
if si.Value() == nil {
|
if si.Value() == nil {
|
||||||
Opcodes(w, opcode.PUSHNULL)
|
Opcodes(w, opcode.PUSHNULL)
|
||||||
} else {
|
} 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
|
return
|
||||||
}
|
}
|
||||||
case stackitem.BooleanT:
|
case stackitem.BooleanT:
|
||||||
|
@ -240,7 +243,7 @@ func StackItem(w *io.BinWriter, si stackitem.Item) {
|
||||||
Int(w, int64(len(arr)))
|
Int(w, int64(len(arr)))
|
||||||
Opcodes(w, opcode.PACKMAP)
|
Opcodes(w, opcode.PACKMAP)
|
||||||
default:
|
default:
|
||||||
w.Err = fmt.Errorf("%s is unsuppoted", t)
|
w.Err = fmt.Errorf("%w: %s type", errors.ErrUnsupported, t)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -547,7 +547,7 @@ func TestEmitStackitem(t *testing.T) {
|
||||||
for _, si := range itms {
|
for _, si := range itms {
|
||||||
buf := io.NewBufBinWriter()
|
buf := io.NewBufBinWriter()
|
||||||
StackItem(buf.BinWriter, si)
|
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()
|
buf := io.NewBufBinWriter()
|
||||||
StackItem(buf.BinWriter, StrangeStackItem{})
|
StackItem(buf.BinWriter, StrangeStackItem{})
|
||||||
actualErr := buf.Err
|
actualErr := buf.Err
|
||||||
require.Error(t, actualErr)
|
require.ErrorIs(t, actualErr, errors.ErrUnsupported)
|
||||||
require.True(t, strings.Contains(actualErr.Error(), "only nil value supported"), actualErr.Error())
|
require.True(t, strings.Contains(actualErr.Error(), "Any can only be nil"), actualErr.Error())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue