vm: add TryBytes() to StackItem interface

Conversion should be done in a StackItem, not in an Element.
This commit is contained in:
Evgenii Stratonikov 2020-03-11 16:04:28 +03:00
parent aab7dd515f
commit 5da82e8cf0
3 changed files with 57 additions and 14 deletions

View file

@ -170,6 +170,11 @@ func (c *Context) Dup() StackItem {
return c 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. // ToContractParameter implements StackItem interface.
func (c *Context) ToContractParameter(map[StackItem]bool) smartcontract.Parameter { func (c *Context) ToContractParameter(map[StackItem]bool) smartcontract.Parameter {
return smartcontract.Parameter{ return smartcontract.Parameter{

View file

@ -125,21 +125,11 @@ func (e *Element) Bool() bool {
// Bytes attempts to get the underlying value of the element as a byte array. // 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. // Will panic if the assertion failed which will be caught by the VM.
func (e *Element) Bytes() []byte { func (e *Element) Bytes() []byte {
switch t := e.value.(type) { bs, err := e.value.TryBytes()
case *ByteArrayItem: if err != nil {
return t.value panic(err)
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())
} }
return bs
} }
// Array attempts to get the underlying value of the element as an array of // Array attempts to get the underlying value of the element as an array of

View file

@ -4,6 +4,7 @@ import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"math/big" "math/big"
"reflect" "reflect"
@ -18,6 +19,8 @@ type StackItem interface {
Value() interface{} Value() interface{}
// Dup duplicates current StackItem. // Dup duplicates current StackItem.
Dup() StackItem Dup() StackItem
// TryBytes converts StackItem to a byte slice.
TryBytes() ([]byte, error)
// ToContractParameter converts StackItem to smartcontract.Parameter // ToContractParameter converts StackItem to smartcontract.Parameter
ToContractParameter(map[StackItem]bool) smartcontract.Parameter ToContractParameter(map[StackItem]bool) smartcontract.Parameter
} }
@ -118,6 +121,11 @@ func (i *StructItem) Dup() StackItem {
return i 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. // ToContractParameter implements StackItem interface.
func (i *StructItem) ToContractParameter(seen map[StackItem]bool) smartcontract.Parameter { func (i *StructItem) ToContractParameter(seen map[StackItem]bool) smartcontract.Parameter {
var value []smartcontract.Parameter var value []smartcontract.Parameter
@ -167,6 +175,11 @@ func (i *BigIntegerItem) Bytes() []byte {
return emit.IntToBytes(i.value) return emit.IntToBytes(i.value)
} }
// TryBytes implements StackItem interface.
func (i *BigIntegerItem) TryBytes() ([]byte, error) {
return i.Bytes(), nil
}
// Value implements StackItem interface. // Value implements StackItem interface.
func (i *BigIntegerItem) Value() interface{} { func (i *BigIntegerItem) Value() interface{} {
return i.value return i.value
@ -226,6 +239,21 @@ func (i *BoolItem) Dup() StackItem {
return &BoolItem{i.value} 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. // ToContractParameter implements StackItem interface.
func (i *BoolItem) ToContractParameter(map[StackItem]bool) smartcontract.Parameter { func (i *BoolItem) ToContractParameter(map[StackItem]bool) smartcontract.Parameter {
return smartcontract.Parameter{ return smartcontract.Parameter{
@ -260,6 +288,11 @@ func (i *ByteArrayItem) String() string {
return "ByteArray" return "ByteArray"
} }
// TryBytes implements StackItem interface.
func (i *ByteArrayItem) TryBytes() ([]byte, error) {
return i.value, nil
}
// Dup implements StackItem interface. // Dup implements StackItem interface.
func (i *ByteArrayItem) Dup() StackItem { func (i *ByteArrayItem) Dup() StackItem {
a := make([]byte, len(i.value)) a := make([]byte, len(i.value))
@ -301,6 +334,11 @@ func (i *ArrayItem) String() string {
return "Array" 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. // Dup implements StackItem interface.
func (i *ArrayItem) Dup() StackItem { func (i *ArrayItem) Dup() StackItem {
// reference type // reference type
@ -341,6 +379,11 @@ func (i *MapItem) Value() interface{} {
return i.value 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 { func (i *MapItem) String() string {
return "Map" return "Map"
} }
@ -438,6 +481,11 @@ func (i *InteropItem) Dup() StackItem {
return i 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. // ToContractParameter implements StackItem interface.
func (i *InteropItem) ToContractParameter(map[StackItem]bool) smartcontract.Parameter { func (i *InteropItem) ToContractParameter(map[StackItem]bool) smartcontract.Parameter {
return smartcontract.Parameter{ return smartcontract.Parameter{