diff --git a/pkg/vm/context.go b/pkg/vm/context.go index 43ea9c6ae..b934b2ba3 100644 --- a/pkg/vm/context.go +++ b/pkg/vm/context.go @@ -170,6 +170,11 @@ func (c *Context) Dup() StackItem { return c } +// TryBytes implements StackItem interface. +func (c *Context) TryBytes() ([]byte, error) { + return nil, errors.New("can't convert Context to ByteArray") +} + // ToContractParameter implements StackItem interface. func (c *Context) ToContractParameter(map[StackItem]bool) smartcontract.Parameter { return smartcontract.Parameter{ diff --git a/pkg/vm/stack.go b/pkg/vm/stack.go index b9b417212..361b81854 100644 --- a/pkg/vm/stack.go +++ b/pkg/vm/stack.go @@ -125,21 +125,11 @@ func (e *Element) Bool() bool { // Bytes attempts to get the underlying value of the element as a byte array. // Will panic if the assertion failed which will be caught by the VM. func (e *Element) Bytes() []byte { - switch t := e.value.(type) { - case *ByteArrayItem: - return t.value - case *BigIntegerItem: - return t.Bytes() // neoVM returns in LE - case *BoolItem: - if t.value { - return []byte{1} - } - // return []byte{0} - // FIXME revert when NEO 3.0 https://github.com/nspcc-dev/neo-go/issues/477 - return []byte{} - default: - panic("can't convert to []byte: " + t.String()) + bs, err := e.value.TryBytes() + if err != nil { + panic(err) } + return bs } // Array attempts to get the underlying value of the element as an array of diff --git a/pkg/vm/stack_item.go b/pkg/vm/stack_item.go index 9ab19f835..188b11de6 100644 --- a/pkg/vm/stack_item.go +++ b/pkg/vm/stack_item.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "encoding/hex" "encoding/json" + "errors" "fmt" "math/big" "reflect" @@ -18,6 +19,8 @@ type StackItem interface { Value() interface{} // Dup duplicates current StackItem. Dup() StackItem + // TryBytes converts StackItem to a byte slice. + TryBytes() ([]byte, error) // ToContractParameter converts StackItem to smartcontract.Parameter ToContractParameter(map[StackItem]bool) smartcontract.Parameter } @@ -118,6 +121,11 @@ func (i *StructItem) Dup() StackItem { return i } +// TryBytes implements StackItem interface. +func (i *StructItem) TryBytes() ([]byte, error) { + return nil, errors.New("can't convert Struct to ByteArray") +} + // ToContractParameter implements StackItem interface. func (i *StructItem) ToContractParameter(seen map[StackItem]bool) smartcontract.Parameter { var value []smartcontract.Parameter @@ -167,6 +175,11 @@ func (i *BigIntegerItem) Bytes() []byte { return emit.IntToBytes(i.value) } +// TryBytes implements StackItem interface. +func (i *BigIntegerItem) TryBytes() ([]byte, error) { + return i.Bytes(), nil +} + // Value implements StackItem interface. func (i *BigIntegerItem) Value() interface{} { return i.value @@ -226,6 +239,21 @@ func (i *BoolItem) Dup() StackItem { return &BoolItem{i.value} } +// Bytes converts BoolItem to bytes. +func (i *BoolItem) Bytes() []byte { + if i.value { + return []byte{1} + } + // return []byte{0} + // FIXME revert when NEO 3.0 https://github.com/nspcc-dev/neo-go/issues/477 + return []byte{} +} + +// TryBytes implements StackItem interface. +func (i *BoolItem) TryBytes() ([]byte, error) { + return i.Bytes(), nil +} + // ToContractParameter implements StackItem interface. func (i *BoolItem) ToContractParameter(map[StackItem]bool) smartcontract.Parameter { return smartcontract.Parameter{ @@ -260,6 +288,11 @@ func (i *ByteArrayItem) String() string { return "ByteArray" } +// TryBytes implements StackItem interface. +func (i *ByteArrayItem) TryBytes() ([]byte, error) { + return i.value, nil +} + // Dup implements StackItem interface. func (i *ByteArrayItem) Dup() StackItem { a := make([]byte, len(i.value)) @@ -301,6 +334,11 @@ func (i *ArrayItem) String() string { return "Array" } +// TryBytes implements StackItem interface. +func (i *ArrayItem) TryBytes() ([]byte, error) { + return nil, errors.New("can't convert Array to ByteArray") +} + // Dup implements StackItem interface. func (i *ArrayItem) Dup() StackItem { // reference type @@ -341,6 +379,11 @@ func (i *MapItem) Value() interface{} { return i.value } +// TryBytes implements StackItem interface. +func (i *MapItem) TryBytes() ([]byte, error) { + return nil, errors.New("can't convert Map to ByteArray") +} + func (i *MapItem) String() string { return "Map" } @@ -438,6 +481,11 @@ func (i *InteropItem) Dup() StackItem { return i } +// TryBytes implements StackItem interface. +func (i *InteropItem) TryBytes() ([]byte, error) { + return nil, errors.New("can't convert Interop to ByteArray") +} + // ToContractParameter implements StackItem interface. func (i *InteropItem) ToContractParameter(map[StackItem]bool) smartcontract.Parameter { return smartcontract.Parameter{