mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-29 23:33:37 +00:00
Merge pull request #2128 from nspcc-dev/vm-update-int
Some VM optimizations
This commit is contained in:
commit
5b12dd2025
13 changed files with 222 additions and 219 deletions
|
@ -2097,20 +2097,17 @@ func (c *codegen) resolveFuncDecls(f *ast.File, pkg *types.Package) {
|
||||||
func (c *codegen) writeJumps(b []byte) ([]byte, error) {
|
func (c *codegen) writeJumps(b []byte) ([]byte, error) {
|
||||||
ctx := vm.NewContext(b)
|
ctx := vm.NewContext(b)
|
||||||
var offsets []int
|
var offsets []int
|
||||||
for op, _, err := ctx.Next(); err == nil && ctx.IP() < len(b); op, _, err = ctx.Next() {
|
for op, param, err := ctx.Next(); err == nil && ctx.IP() < len(b); op, param, err = ctx.Next() {
|
||||||
switch op {
|
switch op {
|
||||||
case opcode.JMP, opcode.JMPIFNOT, opcode.JMPIF, opcode.CALL,
|
case opcode.JMP, opcode.JMPIFNOT, opcode.JMPIF, opcode.CALL,
|
||||||
opcode.JMPEQ, opcode.JMPNE,
|
opcode.JMPEQ, opcode.JMPNE,
|
||||||
opcode.JMPGT, opcode.JMPGE, opcode.JMPLE, opcode.JMPLT:
|
opcode.JMPGT, opcode.JMPGE, opcode.JMPLE, opcode.JMPLT:
|
||||||
case opcode.TRYL:
|
case opcode.TRYL:
|
||||||
nextIP := ctx.NextIP()
|
_, err := c.replaceLabelWithOffset(ctx.IP(), param)
|
||||||
catchArg := b[nextIP-8:]
|
|
||||||
_, err := c.replaceLabelWithOffset(ctx.IP(), catchArg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
finallyArg := b[nextIP-4:]
|
_, err = c.replaceLabelWithOffset(ctx.IP(), param[4:])
|
||||||
_, err = c.replaceLabelWithOffset(ctx.IP(), finallyArg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -2118,10 +2115,7 @@ func (c *codegen) writeJumps(b []byte) ([]byte, error) {
|
||||||
opcode.JMPEQL, opcode.JMPNEL,
|
opcode.JMPEQL, opcode.JMPNEL,
|
||||||
opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLEL, opcode.JMPLTL,
|
opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLEL, opcode.JMPLTL,
|
||||||
opcode.CALLL, opcode.PUSHA, opcode.ENDTRYL:
|
opcode.CALLL, opcode.PUSHA, opcode.ENDTRYL:
|
||||||
// we can't use arg returned by ctx.Next() because it is copied
|
offset, err := c.replaceLabelWithOffset(ctx.IP(), param)
|
||||||
nextIP := ctx.NextIP()
|
|
||||||
arg := b[nextIP-4:]
|
|
||||||
offset, err := c.replaceLabelWithOffset(ctx.IP(), arg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ func ParameterFromStackItem(i stackitem.Item, seen map[stackitem.Item]bool) Para
|
||||||
Type: IntegerType,
|
Type: IntegerType,
|
||||||
Value: i.Value().(*big.Int).Int64(),
|
Value: i.Value().(*big.Int).Int64(),
|
||||||
}
|
}
|
||||||
case *stackitem.Bool:
|
case stackitem.Bool:
|
||||||
return Parameter{
|
return Parameter{
|
||||||
Type: BoolType,
|
Type: BoolType,
|
||||||
Value: i.Value().(bool),
|
Value: i.Value().(bool),
|
||||||
|
|
|
@ -97,9 +97,9 @@ func (c *Context) NextIP() int {
|
||||||
return c.nextip
|
return c.nextip
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next returns the next instruction to execute with its parameter if any. After
|
// Next returns the next instruction to execute with its parameter if any.
|
||||||
// its invocation the instruction pointer points to the instruction being
|
// The parameter is not copied and shouldn't be written to. After its invocation
|
||||||
// returned.
|
// the instruction pointer points to the instruction being returned.
|
||||||
func (c *Context) Next() (opcode.Opcode, []byte, error) {
|
func (c *Context) Next() (opcode.Opcode, []byte, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -171,8 +171,7 @@ func (c *Context) Next() (opcode.Opcode, []byte, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return instr, nil, err
|
return instr, nil, err
|
||||||
}
|
}
|
||||||
parameter := make([]byte, numtoread)
|
parameter := c.prog[c.nextip : c.nextip+numtoread]
|
||||||
copy(parameter, c.prog[c.nextip:c.nextip+numtoread])
|
|
||||||
c.nextip += numtoread
|
c.nextip += numtoread
|
||||||
return instr, parameter, nil
|
return instr, parameter, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,7 +195,7 @@ func compareItems(t *testing.T, a, b stackitem.Item) {
|
||||||
require.Equal(t, val, ac.Value().(*big.Int).Int64())
|
require.Equal(t, val, ac.Value().(*big.Int).Int64())
|
||||||
case *stackitem.ByteArray:
|
case *stackitem.ByteArray:
|
||||||
require.Equal(t, val, bigint.FromBytes(ac.Value().([]byte)).Int64())
|
require.Equal(t, val, bigint.FromBytes(ac.Value().([]byte)).Int64())
|
||||||
case *stackitem.Bool:
|
case stackitem.Bool:
|
||||||
if ac.Value().(bool) {
|
if ac.Value().(bool) {
|
||||||
require.Equal(t, val, int64(1))
|
require.Equal(t, val, int64(1))
|
||||||
} else {
|
} else {
|
||||||
|
@ -208,6 +208,28 @@ func compareItems(t *testing.T, a, b stackitem.Item) {
|
||||||
p, ok := b.(*stackitem.Pointer)
|
p, ok := b.(*stackitem.Pointer)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.Equal(t, si.Position(), p.Position()) // there no script in test files
|
require.Equal(t, si.Position(), p.Position()) // there no script in test files
|
||||||
|
case *stackitem.Array, *stackitem.Struct:
|
||||||
|
require.Equal(t, a.Type(), b.Type())
|
||||||
|
|
||||||
|
as := a.Value().([]stackitem.Item)
|
||||||
|
bs := a.Value().([]stackitem.Item)
|
||||||
|
require.Equal(t, len(as), len(bs))
|
||||||
|
|
||||||
|
for i := range as {
|
||||||
|
compareItems(t, as[i], bs[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
case *stackitem.Map:
|
||||||
|
require.Equal(t, a.Type(), b.Type())
|
||||||
|
|
||||||
|
as := a.Value().([]stackitem.MapElement)
|
||||||
|
bs := a.Value().([]stackitem.MapElement)
|
||||||
|
require.Equal(t, len(as), len(bs))
|
||||||
|
|
||||||
|
for i := range as {
|
||||||
|
compareItems(t, as[i].Key, bs[i].Key)
|
||||||
|
compareItems(t, as[i].Value, bs[i].Value)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
require.Equal(t, a, b)
|
require.Equal(t, a, b)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,19 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// refCounter represents reference counter for the VM.
|
// refCounter represents reference counter for the VM.
|
||||||
type refCounter struct {
|
type refCounter int
|
||||||
items map[stackitem.Item]int
|
|
||||||
size int
|
type (
|
||||||
}
|
rcInc interface {
|
||||||
|
IncRC() int
|
||||||
|
}
|
||||||
|
rcDec interface {
|
||||||
|
DecRC() int
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func newRefCounter() *refCounter {
|
func newRefCounter() *refCounter {
|
||||||
return &refCounter{
|
return new(refCounter)
|
||||||
items: make(map[stackitem.Item]int),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add adds an item to the reference counter.
|
// Add adds an item to the reference counter.
|
||||||
|
@ -21,23 +25,20 @@ func (r *refCounter) Add(item stackitem.Item) {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.size++
|
*r++
|
||||||
|
|
||||||
switch item.(type) {
|
irc, ok := item.(rcInc)
|
||||||
case *stackitem.Array, *stackitem.Struct, *stackitem.Map:
|
if !ok || irc.IncRC() > 1 {
|
||||||
if r.items[item]++; r.items[item] > 1 {
|
return
|
||||||
return
|
}
|
||||||
|
switch t := item.(type) {
|
||||||
|
case *stackitem.Array, *stackitem.Struct:
|
||||||
|
for _, it := range item.Value().([]stackitem.Item) {
|
||||||
|
r.Add(it)
|
||||||
}
|
}
|
||||||
|
case *stackitem.Map:
|
||||||
switch t := item.(type) {
|
for i := range t.Value().([]stackitem.MapElement) {
|
||||||
case *stackitem.Array, *stackitem.Struct:
|
r.Add(t.Value().([]stackitem.MapElement)[i].Value)
|
||||||
for _, it := range item.Value().([]stackitem.Item) {
|
|
||||||
r.Add(it)
|
|
||||||
}
|
|
||||||
case *stackitem.Map:
|
|
||||||
for i := range t.Value().([]stackitem.MapElement) {
|
|
||||||
r.Add(t.Value().([]stackitem.MapElement)[i].Value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,26 +48,20 @@ func (r *refCounter) Remove(item stackitem.Item) {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.size--
|
*r--
|
||||||
|
|
||||||
switch item.(type) {
|
irc, ok := item.(rcDec)
|
||||||
case *stackitem.Array, *stackitem.Struct, *stackitem.Map:
|
if !ok || irc.DecRC() > 0 {
|
||||||
if r.items[item] > 1 {
|
return
|
||||||
r.items[item]--
|
}
|
||||||
return
|
switch t := item.(type) {
|
||||||
|
case *stackitem.Array, *stackitem.Struct:
|
||||||
|
for _, it := range item.Value().([]stackitem.Item) {
|
||||||
|
r.Remove(it)
|
||||||
}
|
}
|
||||||
|
case *stackitem.Map:
|
||||||
delete(r.items, item)
|
for i := range t.Value().([]stackitem.MapElement) {
|
||||||
|
r.Remove(t.Value().([]stackitem.MapElement)[i].Value)
|
||||||
switch t := item.(type) {
|
|
||||||
case *stackitem.Array, *stackitem.Struct:
|
|
||||||
for _, it := range item.Value().([]stackitem.Item) {
|
|
||||||
r.Remove(it)
|
|
||||||
}
|
|
||||||
case *stackitem.Map:
|
|
||||||
for i := range t.Value().([]stackitem.MapElement) {
|
|
||||||
r.Remove(t.Value().([]stackitem.MapElement)[i].Value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,24 +10,34 @@ import (
|
||||||
func TestRefCounter_Add(t *testing.T) {
|
func TestRefCounter_Add(t *testing.T) {
|
||||||
r := newRefCounter()
|
r := newRefCounter()
|
||||||
|
|
||||||
require.Equal(t, 0, r.size)
|
require.Equal(t, 0, int(*r))
|
||||||
|
|
||||||
r.Add(stackitem.Null{})
|
r.Add(stackitem.Null{})
|
||||||
require.Equal(t, 1, r.size)
|
require.Equal(t, 1, int(*r))
|
||||||
|
|
||||||
r.Add(stackitem.Null{})
|
r.Add(stackitem.Null{})
|
||||||
require.Equal(t, 2, r.size) // count scalar items twice
|
require.Equal(t, 2, int(*r)) // count scalar items twice
|
||||||
|
|
||||||
arr := stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte{1}), stackitem.NewBool(false)})
|
arr := stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte{1}), stackitem.NewBool(false)})
|
||||||
r.Add(arr)
|
r.Add(arr)
|
||||||
require.Equal(t, 5, r.size) // array + 2 elements
|
require.Equal(t, 5, int(*r)) // array + 2 elements
|
||||||
|
|
||||||
r.Add(arr)
|
r.Add(arr)
|
||||||
require.Equal(t, 6, r.size) // count only array
|
require.Equal(t, 6, int(*r)) // count only array
|
||||||
|
|
||||||
r.Remove(arr)
|
r.Remove(arr)
|
||||||
require.Equal(t, 5, r.size)
|
require.Equal(t, 5, int(*r))
|
||||||
|
|
||||||
r.Remove(arr)
|
r.Remove(arr)
|
||||||
require.Equal(t, 2, r.size)
|
require.Equal(t, 2, int(*r))
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRefCounter_Add(b *testing.B) {
|
||||||
|
a := stackitem.NewArray(nil)
|
||||||
|
rc := newRefCounter()
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
rc.Add(a)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package stackitem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -90,45 +89,23 @@ func mkInvConversion(from Item, to Type) error {
|
||||||
func Make(v interface{}) Item {
|
func Make(v interface{}) Item {
|
||||||
switch val := v.(type) {
|
switch val := v.(type) {
|
||||||
case int:
|
case int:
|
||||||
return &BigInteger{
|
return (*BigInteger)(big.NewInt(int64(val)))
|
||||||
value: big.NewInt(int64(val)),
|
|
||||||
}
|
|
||||||
case int64:
|
case int64:
|
||||||
return &BigInteger{
|
return (*BigInteger)(big.NewInt(val))
|
||||||
value: big.NewInt(val),
|
|
||||||
}
|
|
||||||
case uint8:
|
case uint8:
|
||||||
return &BigInteger{
|
return (*BigInteger)(big.NewInt(int64(val)))
|
||||||
value: big.NewInt(int64(val)),
|
|
||||||
}
|
|
||||||
case uint16:
|
case uint16:
|
||||||
return &BigInteger{
|
return (*BigInteger)(big.NewInt(int64(val)))
|
||||||
value: big.NewInt(int64(val)),
|
|
||||||
}
|
|
||||||
case uint32:
|
case uint32:
|
||||||
return &BigInteger{
|
return (*BigInteger)(big.NewInt(int64(val)))
|
||||||
value: big.NewInt(int64(val)),
|
|
||||||
}
|
|
||||||
case uint64:
|
case uint64:
|
||||||
b := make([]byte, 8)
|
return (*BigInteger)(new(big.Int).SetUint64(val))
|
||||||
binary.BigEndian.PutUint64(b, val)
|
|
||||||
bigInt := big.NewInt(0)
|
|
||||||
bigInt.SetBytes(b)
|
|
||||||
return &BigInteger{
|
|
||||||
value: bigInt,
|
|
||||||
}
|
|
||||||
case []byte:
|
case []byte:
|
||||||
return &ByteArray{
|
return NewByteArray(val)
|
||||||
value: val,
|
|
||||||
}
|
|
||||||
case string:
|
case string:
|
||||||
return &ByteArray{
|
return NewByteArray([]byte(val))
|
||||||
value: []byte(val),
|
|
||||||
}
|
|
||||||
case bool:
|
case bool:
|
||||||
return &Bool{
|
return Bool(val)
|
||||||
value: val,
|
|
||||||
}
|
|
||||||
case []Item:
|
case []Item:
|
||||||
return &Array{
|
return &Array{
|
||||||
value: val,
|
value: val,
|
||||||
|
@ -207,6 +184,7 @@ func convertPrimitive(item Item, typ Type) (Item, error) {
|
||||||
// Struct represents a struct on the stack.
|
// Struct represents a struct on the stack.
|
||||||
type Struct struct {
|
type Struct struct {
|
||||||
value []Item
|
value []Item
|
||||||
|
rc
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStruct returns an new Struct object.
|
// NewStruct returns an new Struct object.
|
||||||
|
@ -330,7 +308,7 @@ func (i *Struct) Clone() (*Struct, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Struct) clone(limit *int) (*Struct, error) {
|
func (i *Struct) clone(limit *int) (*Struct, error) {
|
||||||
ret := &Struct{make([]Item, len(i.value))}
|
ret := &Struct{value: make([]Item, len(i.value))}
|
||||||
for j := range i.value {
|
for j := range i.value {
|
||||||
*limit--
|
*limit--
|
||||||
if *limit < 0 {
|
if *limit < 0 {
|
||||||
|
@ -402,9 +380,7 @@ func (i Null) Convert(typ Type) (Item, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// BigInteger represents a big integer on the stack.
|
// BigInteger represents a big integer on the stack.
|
||||||
type BigInteger struct {
|
type BigInteger big.Int
|
||||||
value *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBigInteger returns an new BigInteger object.
|
// NewBigInteger returns an new BigInteger object.
|
||||||
func NewBigInteger(value *big.Int) *BigInteger {
|
func NewBigInteger(value *big.Int) *BigInteger {
|
||||||
|
@ -420,19 +396,22 @@ func NewBigInteger(value *big.Int) *BigInteger {
|
||||||
panic(errTooBigInteger)
|
panic(errTooBigInteger)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &BigInteger{
|
return (*BigInteger)(value)
|
||||||
value: value,
|
}
|
||||||
}
|
|
||||||
|
// Big casts i to the big.Int type.
|
||||||
|
func (i *BigInteger) Big() *big.Int {
|
||||||
|
return (*big.Int)(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bytes converts i to a slice of bytes.
|
// Bytes converts i to a slice of bytes.
|
||||||
func (i *BigInteger) Bytes() []byte {
|
func (i *BigInteger) Bytes() []byte {
|
||||||
return bigint.ToBytes(i.value)
|
return bigint.ToBytes(i.Big())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryBool implements Item interface.
|
// TryBool implements Item interface.
|
||||||
func (i *BigInteger) TryBool() (bool, error) {
|
func (i *BigInteger) TryBool() (bool, error) {
|
||||||
return i.value.Sign() != 0, nil
|
return i.Big().Sign() != 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryBytes implements Item interface.
|
// TryBytes implements Item interface.
|
||||||
|
@ -442,7 +421,7 @@ func (i *BigInteger) TryBytes() ([]byte, error) {
|
||||||
|
|
||||||
// TryInteger implements Item interface.
|
// TryInteger implements Item interface.
|
||||||
func (i *BigInteger) TryInteger() (*big.Int, error) {
|
func (i *BigInteger) TryInteger() (*big.Int, error) {
|
||||||
return i.value, nil
|
return i.Big(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equals implements Item interface.
|
// Equals implements Item interface.
|
||||||
|
@ -453,12 +432,12 @@ func (i *BigInteger) Equals(s Item) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
val, ok := s.(*BigInteger)
|
val, ok := s.(*BigInteger)
|
||||||
return ok && i.value.Cmp(val.value) == 0
|
return ok && i.Big().Cmp(val.Big()) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value implements Item interface.
|
// Value implements Item interface.
|
||||||
func (i *BigInteger) Value() interface{} {
|
func (i *BigInteger) Value() interface{} {
|
||||||
return i.value
|
return i.Big()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *BigInteger) String() string {
|
func (i *BigInteger) String() string {
|
||||||
|
@ -468,7 +447,7 @@ func (i *BigInteger) String() string {
|
||||||
// Dup implements Item interface.
|
// Dup implements Item interface.
|
||||||
func (i *BigInteger) Dup() Item {
|
func (i *BigInteger) Dup() Item {
|
||||||
n := new(big.Int)
|
n := new(big.Int)
|
||||||
return &BigInteger{n.Set(i.value)}
|
return (*BigInteger)(n.Set(i.Big()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type implements Item interface.
|
// Type implements Item interface.
|
||||||
|
@ -481,103 +460,95 @@ func (i *BigInteger) Convert(typ Type) (Item, error) {
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
func (i *BigInteger) MarshalJSON() ([]byte, error) {
|
func (i *BigInteger) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(i.value)
|
return json.Marshal(i.Big())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bool represents a boolean Item.
|
// Bool represents a boolean Item.
|
||||||
type Bool struct {
|
type Bool bool
|
||||||
value bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBool returns an new Bool object.
|
// NewBool returns an new Bool object.
|
||||||
func NewBool(val bool) *Bool {
|
func NewBool(val bool) Bool {
|
||||||
return &Bool{
|
return Bool(val)
|
||||||
value: val,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value implements Item interface.
|
// Value implements Item interface.
|
||||||
func (i *Bool) Value() interface{} {
|
func (i Bool) Value() interface{} {
|
||||||
return i.value
|
return bool(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
func (i *Bool) MarshalJSON() ([]byte, error) {
|
func (i Bool) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(i.value)
|
return json.Marshal(bool(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Bool) String() string {
|
func (i Bool) String() string {
|
||||||
return "Boolean"
|
return "Boolean"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dup implements Item interface.
|
// Dup implements Item interface.
|
||||||
func (i *Bool) Dup() Item {
|
func (i Bool) Dup() Item {
|
||||||
return &Bool{i.value}
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryBool implements Item interface.
|
// TryBool implements Item interface.
|
||||||
func (i *Bool) TryBool() (bool, error) { return i.value, nil }
|
func (i Bool) TryBool() (bool, error) { return bool(i), nil }
|
||||||
|
|
||||||
// Bytes converts Bool to bytes.
|
// Bytes converts Bool to bytes.
|
||||||
func (i *Bool) Bytes() []byte {
|
func (i Bool) Bytes() []byte {
|
||||||
if i.value {
|
if i {
|
||||||
return []byte{1}
|
return []byte{1}
|
||||||
}
|
}
|
||||||
return []byte{0}
|
return []byte{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryBytes implements Item interface.
|
// TryBytes implements Item interface.
|
||||||
func (i *Bool) TryBytes() ([]byte, error) {
|
func (i Bool) TryBytes() ([]byte, error) {
|
||||||
return i.Bytes(), nil
|
return i.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryInteger implements Item interface.
|
// TryInteger implements Item interface.
|
||||||
func (i *Bool) TryInteger() (*big.Int, error) {
|
func (i Bool) TryInteger() (*big.Int, error) {
|
||||||
if i.value {
|
if i {
|
||||||
return big.NewInt(1), nil
|
return big.NewInt(1), nil
|
||||||
}
|
}
|
||||||
return big.NewInt(0), nil
|
return big.NewInt(0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equals implements Item interface.
|
// Equals implements Item interface.
|
||||||
func (i *Bool) Equals(s Item) bool {
|
func (i Bool) Equals(s Item) bool {
|
||||||
if i == s {
|
if i == s {
|
||||||
return true
|
return true
|
||||||
} else if s == nil {
|
} else if s == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
val, ok := s.(*Bool)
|
val, ok := s.(Bool)
|
||||||
return ok && i.value == val.value
|
return ok && i == val
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type implements Item interface.
|
// Type implements Item interface.
|
||||||
func (i *Bool) Type() Type { return BooleanT }
|
func (i Bool) Type() Type { return BooleanT }
|
||||||
|
|
||||||
// Convert implements Item interface.
|
// Convert implements Item interface.
|
||||||
func (i *Bool) Convert(typ Type) (Item, error) {
|
func (i Bool) Convert(typ Type) (Item, error) {
|
||||||
return convertPrimitive(i, typ)
|
return convertPrimitive(i, typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByteArray represents a byte array on the stack.
|
// ByteArray represents a byte array on the stack.
|
||||||
type ByteArray struct {
|
type ByteArray []byte
|
||||||
value []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewByteArray returns an new ByteArray object.
|
// NewByteArray returns an new ByteArray object.
|
||||||
func NewByteArray(b []byte) *ByteArray {
|
func NewByteArray(b []byte) *ByteArray {
|
||||||
return &ByteArray{
|
return (*ByteArray)(&b)
|
||||||
value: b,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value implements Item interface.
|
// Value implements Item interface.
|
||||||
func (i *ByteArray) Value() interface{} {
|
func (i *ByteArray) Value() interface{} {
|
||||||
return i.value
|
return []byte(*i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
func (i *ByteArray) MarshalJSON() ([]byte, error) {
|
func (i *ByteArray) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(hex.EncodeToString(i.value))
|
return json.Marshal(hex.EncodeToString(*i))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ByteArray) String() string {
|
func (i *ByteArray) String() string {
|
||||||
|
@ -586,10 +557,10 @@ func (i *ByteArray) String() string {
|
||||||
|
|
||||||
// TryBool implements Item interface.
|
// TryBool implements Item interface.
|
||||||
func (i *ByteArray) TryBool() (bool, error) {
|
func (i *ByteArray) TryBool() (bool, error) {
|
||||||
if len(i.value) > MaxBigIntegerSizeBits/8 {
|
if len(*i) > MaxBigIntegerSizeBits/8 {
|
||||||
return false, errTooBigInteger
|
return false, errTooBigInteger
|
||||||
}
|
}
|
||||||
for _, b := range i.value {
|
for _, b := range *i {
|
||||||
if b != 0 {
|
if b != 0 {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
@ -598,21 +569,21 @@ func (i *ByteArray) TryBool() (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryBytes implements Item interface.
|
// TryBytes implements Item interface.
|
||||||
func (i *ByteArray) TryBytes() ([]byte, error) {
|
func (i ByteArray) TryBytes() ([]byte, error) {
|
||||||
return i.value, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryInteger implements Item interface.
|
// TryInteger implements Item interface.
|
||||||
func (i *ByteArray) TryInteger() (*big.Int, error) {
|
func (i ByteArray) TryInteger() (*big.Int, error) {
|
||||||
if len(i.value) > MaxBigIntegerSizeBits/8 {
|
if len(i) > MaxBigIntegerSizeBits/8 {
|
||||||
return nil, errTooBigInteger
|
return nil, errTooBigInteger
|
||||||
}
|
}
|
||||||
return bigint.FromBytes(i.value), nil
|
return bigint.FromBytes(i), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equals implements Item interface.
|
// Equals implements Item interface.
|
||||||
func (i *ByteArray) Equals(s Item) bool {
|
func (i *ByteArray) Equals(s Item) bool {
|
||||||
if len(i.value) > MaxByteArrayComparableSize {
|
if len(*i) > MaxByteArrayComparableSize {
|
||||||
panic(errTooBigComparable)
|
panic(errTooBigComparable)
|
||||||
}
|
}
|
||||||
if i == s {
|
if i == s {
|
||||||
|
@ -624,15 +595,16 @@ func (i *ByteArray) Equals(s Item) bool {
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if len(val.value) > MaxByteArrayComparableSize {
|
if len(*val) > MaxByteArrayComparableSize {
|
||||||
panic(errTooBigComparable)
|
panic(errTooBigComparable)
|
||||||
}
|
}
|
||||||
return bytes.Equal(i.value, val.value)
|
return bytes.Equal(*i, *val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dup implements Item interface.
|
// Dup implements Item interface.
|
||||||
func (i *ByteArray) Dup() Item {
|
func (i *ByteArray) Dup() Item {
|
||||||
return &ByteArray{slice.Copy(i.value)}
|
ba := slice.Copy(*i)
|
||||||
|
return (*ByteArray)(&ba)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type implements Item interface.
|
// Type implements Item interface.
|
||||||
|
@ -646,6 +618,7 @@ func (i *ByteArray) Convert(typ Type) (Item, error) {
|
||||||
// Array represents a new Array object.
|
// Array represents a new Array object.
|
||||||
type Array struct {
|
type Array struct {
|
||||||
value []Item
|
value []Item
|
||||||
|
rc
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewArray returns a new Array object.
|
// NewArray returns a new Array object.
|
||||||
|
@ -746,6 +719,7 @@ type MapElement struct {
|
||||||
// if need be.
|
// if need be.
|
||||||
type Map struct {
|
type Map struct {
|
||||||
value []MapElement
|
value []MapElement
|
||||||
|
rc
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMap returns new Map object.
|
// NewMap returns new Map object.
|
||||||
|
@ -861,7 +835,7 @@ func (i *Map) Drop(index int) {
|
||||||
// key.
|
// key.
|
||||||
func IsValidMapKey(key Item) error {
|
func IsValidMapKey(key Item) error {
|
||||||
switch key.(type) {
|
switch key.(type) {
|
||||||
case *Bool, *BigInteger:
|
case Bool, *BigInteger:
|
||||||
return nil
|
return nil
|
||||||
case *ByteArray:
|
case *ByteArray:
|
||||||
size := len(key.Value().([]byte))
|
size := len(key.Value().([]byte))
|
||||||
|
@ -1045,20 +1019,16 @@ func (p *Pointer) Position() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer represents represents Buffer stack item.
|
// Buffer represents represents Buffer stack item.
|
||||||
type Buffer struct {
|
type Buffer []byte
|
||||||
value []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBuffer returns a new Buffer object.
|
// NewBuffer returns a new Buffer object.
|
||||||
func NewBuffer(b []byte) *Buffer {
|
func NewBuffer(b []byte) *Buffer {
|
||||||
return &Buffer{
|
return (*Buffer)(&b)
|
||||||
value: b,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value implements Item interface.
|
// Value implements Item interface.
|
||||||
func (i *Buffer) Value() interface{} {
|
func (i *Buffer) Value() interface{} {
|
||||||
return i.value
|
return []byte(*i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements fmt.Stringer interface.
|
// String implements fmt.Stringer interface.
|
||||||
|
@ -1073,7 +1043,7 @@ func (i *Buffer) TryBool() (bool, error) {
|
||||||
|
|
||||||
// TryBytes implements Item interface.
|
// TryBytes implements Item interface.
|
||||||
func (i *Buffer) TryBytes() ([]byte, error) {
|
func (i *Buffer) TryBytes() ([]byte, error) {
|
||||||
return i.value, nil
|
return *i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryInteger implements Item interface.
|
// TryInteger implements Item interface.
|
||||||
|
@ -1093,7 +1063,7 @@ func (i *Buffer) Dup() Item {
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
func (i *Buffer) MarshalJSON() ([]byte, error) {
|
func (i *Buffer) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(hex.EncodeToString(i.value))
|
return json.Marshal(hex.EncodeToString(*i))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type implements Item interface.
|
// Type implements Item interface.
|
||||||
|
@ -1107,12 +1077,12 @@ func (i *Buffer) Convert(typ Type) (Item, error) {
|
||||||
case BufferT:
|
case BufferT:
|
||||||
return i, nil
|
return i, nil
|
||||||
case ByteArrayT:
|
case ByteArrayT:
|
||||||
return NewByteArray(slice.Copy(i.value)), nil
|
return NewByteArray(slice.Copy(*i)), nil
|
||||||
case IntegerT:
|
case IntegerT:
|
||||||
if len(i.value) > MaxBigIntegerSizeBits/8 {
|
if len(*i) > MaxBigIntegerSizeBits/8 {
|
||||||
return nil, errTooBigInteger
|
return nil, errTooBigInteger
|
||||||
}
|
}
|
||||||
return NewBigInteger(bigint.FromBytes(i.value)), nil
|
return NewBigInteger(bigint.FromBytes(*i)), nil
|
||||||
default:
|
default:
|
||||||
return nil, mkInvConversion(i, typ)
|
return nil, mkInvConversion(i, typ)
|
||||||
}
|
}
|
||||||
|
@ -1120,7 +1090,7 @@ func (i *Buffer) Convert(typ Type) (Item, error) {
|
||||||
|
|
||||||
// Len returns length of Buffer value.
|
// Len returns length of Buffer value.
|
||||||
func (i *Buffer) Len() int {
|
func (i *Buffer) Len() int {
|
||||||
return len(i.value)
|
return len(*i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy returns new deep copy of the provided item.
|
// DeepCopy returns new deep copy of the provided item.
|
||||||
|
@ -1162,17 +1132,14 @@ func deepCopy(item Item, seen map[Item]Item) Item {
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
case *BigInteger:
|
case *BigInteger:
|
||||||
bi := new(big.Int).SetBytes(it.value.Bytes())
|
bi := new(big.Int).Set(it.Big())
|
||||||
if it.value.Sign() == -1 {
|
return (*BigInteger)(bi)
|
||||||
bi.Neg(bi)
|
|
||||||
}
|
|
||||||
return NewBigInteger(bi)
|
|
||||||
case *ByteArray:
|
case *ByteArray:
|
||||||
return NewByteArray(slice.Copy(it.value))
|
return NewByteArray(slice.Copy(*it))
|
||||||
case *Buffer:
|
case *Buffer:
|
||||||
return NewBuffer(slice.Copy(it.value))
|
return NewBuffer(slice.Copy(*it))
|
||||||
case *Bool:
|
case Bool:
|
||||||
return NewBool(it.value)
|
return it
|
||||||
case *Pointer:
|
case *Pointer:
|
||||||
return NewPointerWithHash(it.pos, it.script, it.hash)
|
return NewPointerWithHash(it.pos, it.script, it.hash)
|
||||||
case *Interop:
|
case *Interop:
|
||||||
|
|
|
@ -15,67 +15,67 @@ var makeStackItemTestCases = []struct {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
input: int64(3),
|
input: int64(3),
|
||||||
result: &BigInteger{value: big.NewInt(3)},
|
result: (*BigInteger)(big.NewInt(3)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: int16(3),
|
input: int16(3),
|
||||||
result: &BigInteger{value: big.NewInt(3)},
|
result: (*BigInteger)(big.NewInt(3)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: 3,
|
input: 3,
|
||||||
result: &BigInteger{value: big.NewInt(3)},
|
result: (*BigInteger)(big.NewInt(3)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: uint8(3),
|
input: uint8(3),
|
||||||
result: &BigInteger{value: big.NewInt(3)},
|
result: (*BigInteger)(big.NewInt(3)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: uint16(3),
|
input: uint16(3),
|
||||||
result: &BigInteger{value: big.NewInt(3)},
|
result: (*BigInteger)(big.NewInt(3)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: uint32(3),
|
input: uint32(3),
|
||||||
result: &BigInteger{value: big.NewInt(3)},
|
result: (*BigInteger)(big.NewInt(3)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: uint64(3),
|
input: uint64(3),
|
||||||
result: &BigInteger{value: big.NewInt(3)},
|
result: (*BigInteger)(big.NewInt(3)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: big.NewInt(3),
|
input: big.NewInt(3),
|
||||||
result: &BigInteger{value: big.NewInt(3)},
|
result: (*BigInteger)(big.NewInt(3)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: []byte{1, 2, 3, 4},
|
input: []byte{1, 2, 3, 4},
|
||||||
result: &ByteArray{value: []byte{1, 2, 3, 4}},
|
result: NewByteArray([]byte{1, 2, 3, 4}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: []byte{},
|
input: []byte{},
|
||||||
result: &ByteArray{value: []byte{}},
|
result: NewByteArray([]byte{}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "bla",
|
input: "bla",
|
||||||
result: &ByteArray{value: []byte("bla")},
|
result: NewByteArray([]byte("bla")),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "",
|
input: "",
|
||||||
result: &ByteArray{value: []byte{}},
|
result: NewByteArray([]byte{}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: true,
|
input: true,
|
||||||
result: &Bool{value: true},
|
result: Bool(true),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: false,
|
input: false,
|
||||||
result: &Bool{value: false},
|
result: Bool(false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: []Item{&BigInteger{value: big.NewInt(3)}, &ByteArray{value: []byte{1, 2, 3}}},
|
input: []Item{(*BigInteger)(big.NewInt(3)), NewByteArray([]byte{1, 2, 3})},
|
||||||
result: &Array{value: []Item{&BigInteger{value: big.NewInt(3)}, &ByteArray{value: []byte{1, 2, 3}}}},
|
result: &Array{value: []Item{(*BigInteger)(big.NewInt(3)), NewByteArray([]byte{1, 2, 3})}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: []int{1, 2, 3},
|
input: []int{1, 2, 3},
|
||||||
result: &Array{value: []Item{&BigInteger{value: big.NewInt(1)}, &BigInteger{value: big.NewInt(2)}, &BigInteger{value: big.NewInt(3)}}},
|
result: &Array{value: []Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,18 +281,18 @@ var equalsTestCases = map[string][]struct {
|
||||||
result: false,
|
result: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item1: NewArray([]Item{&BigInteger{big.NewInt(1)}, &BigInteger{big.NewInt(2)}, &BigInteger{big.NewInt(3)}}),
|
item1: NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}),
|
||||||
item2: NewArray([]Item{&BigInteger{big.NewInt(1)}, &BigInteger{big.NewInt(2)}, &BigInteger{big.NewInt(3)}}),
|
item2: NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}),
|
||||||
result: false,
|
result: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item1: NewArray([]Item{&BigInteger{big.NewInt(1)}}),
|
item1: NewArray([]Item{(*BigInteger)(big.NewInt(1))}),
|
||||||
item2: NewBigInteger(big.NewInt(1)),
|
item2: NewBigInteger(big.NewInt(1)),
|
||||||
result: false,
|
result: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item1: NewArray([]Item{&BigInteger{big.NewInt(1)}, &BigInteger{big.NewInt(2)}, &BigInteger{big.NewInt(3)}}),
|
item1: NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}),
|
||||||
item2: NewArray([]Item{&BigInteger{big.NewInt(1)}, &BigInteger{big.NewInt(2)}, &BigInteger{big.NewInt(4)}}),
|
item2: NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(4))}),
|
||||||
result: false,
|
result: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -441,7 +441,7 @@ var marshalJSONTestCases = []struct {
|
||||||
result: []byte(`"010203"`),
|
result: []byte(`"010203"`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: &Array{value: []Item{&BigInteger{value: big.NewInt(3)}, &ByteArray{value: []byte{1, 2, 3}}}},
|
input: &Array{value: []Item{(*BigInteger)(big.NewInt(3)), NewByteArray([]byte{1, 2, 3})}},
|
||||||
result: []byte(`[3,"010203"]`),
|
result: []byte(`[3,"010203"]`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -459,8 +459,8 @@ func TestMarshalJSON(t *testing.T) {
|
||||||
switch testCase.input.(type) {
|
switch testCase.input.(type) {
|
||||||
case *BigInteger:
|
case *BigInteger:
|
||||||
actual, err = testCase.input.(*BigInteger).MarshalJSON()
|
actual, err = testCase.input.(*BigInteger).MarshalJSON()
|
||||||
case *Bool:
|
case Bool:
|
||||||
actual, err = testCase.input.(*Bool).MarshalJSON()
|
actual, err = testCase.input.(Bool).MarshalJSON()
|
||||||
case *ByteArray:
|
case *ByteArray:
|
||||||
actual, err = testCase.input.(*ByteArray).MarshalJSON()
|
actual, err = testCase.input.(*ByteArray).MarshalJSON()
|
||||||
case *Array:
|
case *Array:
|
||||||
|
@ -532,7 +532,9 @@ func TestDeepCopy(t *testing.T) {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
actual := DeepCopy(tc.item)
|
actual := DeepCopy(tc.item)
|
||||||
require.Equal(t, tc.item, actual)
|
require.Equal(t, tc.item, actual)
|
||||||
require.False(t, actual == tc.item)
|
if tc.item.Type() != BooleanT {
|
||||||
|
require.False(t, actual == tc.item)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,18 +110,18 @@ func toJSON(data []byte, seen map[Item]sliceNoPointer, item Item) ([]byte, error
|
||||||
data = append(data, '}')
|
data = append(data, '}')
|
||||||
seen[item] = sliceNoPointer{start, len(data)}
|
seen[item] = sliceNoPointer{start, len(data)}
|
||||||
case *BigInteger:
|
case *BigInteger:
|
||||||
if it.value.CmpAbs(big.NewInt(MaxAllowedInteger)) == 1 {
|
if it.Big().CmpAbs(big.NewInt(MaxAllowedInteger)) == 1 {
|
||||||
return nil, fmt.Errorf("%w (MaxAllowedInteger)", ErrInvalidValue)
|
return nil, fmt.Errorf("%w (MaxAllowedInteger)", ErrInvalidValue)
|
||||||
}
|
}
|
||||||
data = append(data, it.value.String()...)
|
data = append(data, it.Big().String()...)
|
||||||
case *ByteArray, *Buffer:
|
case *ByteArray, *Buffer:
|
||||||
raw, err := itemToJSONString(it)
|
raw, err := itemToJSONString(it)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
data = append(data, raw...)
|
data = append(data, raw...)
|
||||||
case *Bool:
|
case Bool:
|
||||||
if it.value {
|
if it {
|
||||||
data = append(data, "true"...)
|
data = append(data, "true"...)
|
||||||
} else {
|
} else {
|
||||||
data = append(data, "false"...)
|
data = append(data, "false"...)
|
||||||
|
@ -288,12 +288,12 @@ func toJSONWithTypes(item Item, seen map[Item]bool) (interface{}, error) {
|
||||||
}
|
}
|
||||||
value = arr
|
value = arr
|
||||||
delete(seen, item)
|
delete(seen, item)
|
||||||
case *Bool:
|
case Bool:
|
||||||
value = it.value
|
value = bool(it)
|
||||||
case *Buffer, *ByteArray:
|
case *Buffer, *ByteArray:
|
||||||
value = base64.StdEncoding.EncodeToString(it.Value().([]byte))
|
value = base64.StdEncoding.EncodeToString(it.Value().([]byte))
|
||||||
case *BigInteger:
|
case *BigInteger:
|
||||||
value = it.value.String()
|
value = it.Big().String()
|
||||||
case *Map:
|
case *Map:
|
||||||
if seen[item] {
|
if seen[item] {
|
||||||
return "", ErrRecursive
|
return "", ErrRecursive
|
||||||
|
|
15
pkg/vm/stackitem/reference.go
Normal file
15
pkg/vm/stackitem/reference.go
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package stackitem
|
||||||
|
|
||||||
|
type rc struct {
|
||||||
|
count int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rc) IncRC() int {
|
||||||
|
r.count++
|
||||||
|
return r.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rc) DecRC() int {
|
||||||
|
r.count--
|
||||||
|
return r.count
|
||||||
|
}
|
|
@ -103,9 +103,9 @@ func (w *serContext) serialize(item Item) error {
|
||||||
data := t.Value().([]byte)
|
data := t.Value().([]byte)
|
||||||
w.appendVarUint(uint64(len(data)))
|
w.appendVarUint(uint64(len(data)))
|
||||||
w.data = append(w.data, data...)
|
w.data = append(w.data, data...)
|
||||||
case *Bool:
|
case Bool:
|
||||||
w.data = append(w.data, byte(BooleanT))
|
w.data = append(w.data, byte(BooleanT))
|
||||||
if t.Value().(bool) {
|
if t {
|
||||||
w.data = append(w.data, 1)
|
w.data = append(w.data, 1)
|
||||||
} else {
|
} else {
|
||||||
w.data = append(w.data, 0)
|
w.data = append(w.data, 0)
|
||||||
|
|
|
@ -105,7 +105,6 @@ func NewWithTrigger(t trigger.Type) *VM {
|
||||||
Invocations: make(map[util.Uint160]int),
|
Invocations: make(map[util.Uint160]int),
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.refs.items = make(map[stackitem.Item]int)
|
|
||||||
initStack(&vm.istack, "invocation", nil)
|
initStack(&vm.istack, "invocation", nil)
|
||||||
vm.estack = newStack("evaluation", &vm.refs)
|
vm.estack = newStack("evaluation", &vm.refs)
|
||||||
return vm
|
return vm
|
||||||
|
@ -520,7 +519,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
if errRecover := recover(); errRecover != nil {
|
if errRecover := recover(); errRecover != nil {
|
||||||
v.state = FaultState
|
v.state = FaultState
|
||||||
err = newError(ctx.ip, op, errRecover)
|
err = newError(ctx.ip, op, errRecover)
|
||||||
} else if v.refs.size > MaxStackSize {
|
} else if v.refs > MaxStackSize {
|
||||||
v.state = FaultState
|
v.state = FaultState
|
||||||
err = newError(ctx.ip, op, "stack is too big")
|
err = newError(ctx.ip, op, "stack is too big")
|
||||||
}
|
}
|
||||||
|
|
|
@ -415,7 +415,7 @@ func TestStackLimit(t *testing.T) {
|
||||||
require.NoError(t, vm.Step(), "failed to initialize static slot")
|
require.NoError(t, vm.Step(), "failed to initialize static slot")
|
||||||
for i := range expected {
|
for i := range expected {
|
||||||
require.NoError(t, vm.Step())
|
require.NoError(t, vm.Step())
|
||||||
require.Equal(t, expected[i].size, vm.refs.size, "i: %d", i)
|
require.Equal(t, expected[i].size, int(vm.refs), "i: %d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -829,7 +829,7 @@ func getTestFuncForVM(prog []byte, result interface{}, args ...interface{}) func
|
||||||
if result != nil {
|
if result != nil {
|
||||||
f = func(t *testing.T, v *VM) {
|
f = func(t *testing.T, v *VM) {
|
||||||
require.Equal(t, 1, v.estack.Len())
|
require.Equal(t, 1, v.estack.Len())
|
||||||
require.Equal(t, stackitem.Make(result), v.estack.Pop().value)
|
require.Equal(t, stackitem.Make(result).Value(), v.estack.Pop().Value())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getCustomTestFuncForVM(prog, f, args...)
|
return getCustomTestFuncForVM(prog, f, args...)
|
||||||
|
@ -1761,7 +1761,7 @@ func TestPACK_UNPACK_MaxSize(t *testing.T) {
|
||||||
vm.estack.PushVal(len(elements))
|
vm.estack.PushVal(len(elements))
|
||||||
runVM(t, vm)
|
runVM(t, vm)
|
||||||
// check reference counter = 1+1+1024
|
// check reference counter = 1+1+1024
|
||||||
assert.Equal(t, 1+1+len(elements), vm.refs.size)
|
assert.Equal(t, 1+1+len(elements), int(vm.refs))
|
||||||
assert.Equal(t, 1+1+len(elements), vm.estack.Len()) // canary + length + elements
|
assert.Equal(t, 1+1+len(elements), vm.estack.Len()) // canary + length + elements
|
||||||
assert.Equal(t, int64(len(elements)), vm.estack.Peek(0).Value().(*big.Int).Int64())
|
assert.Equal(t, int64(len(elements)), vm.estack.Peek(0).Value().(*big.Int).Int64())
|
||||||
for i := 0; i < len(elements); i++ {
|
for i := 0; i < len(elements); i++ {
|
||||||
|
@ -1784,7 +1784,7 @@ func TestPACK_UNPACK_PACK_MaxSize(t *testing.T) {
|
||||||
vm.estack.PushVal(len(elements))
|
vm.estack.PushVal(len(elements))
|
||||||
runVM(t, vm)
|
runVM(t, vm)
|
||||||
// check reference counter = 1+1+1024
|
// check reference counter = 1+1+1024
|
||||||
assert.Equal(t, 1+1+len(elements), vm.refs.size)
|
assert.Equal(t, 1+1+len(elements), int(vm.refs))
|
||||||
assert.Equal(t, 2, vm.estack.Len())
|
assert.Equal(t, 2, vm.estack.Len())
|
||||||
a := vm.estack.Peek(0).Array()
|
a := vm.estack.Peek(0).Array()
|
||||||
assert.Equal(t, len(elements), len(a))
|
assert.Equal(t, len(elements), len(a))
|
||||||
|
@ -1959,7 +1959,7 @@ func testCLEARITEMS(t *testing.T, item stackitem.Item) {
|
||||||
v.estack.PushVal(item)
|
v.estack.PushVal(item)
|
||||||
runVM(t, v)
|
runVM(t, v)
|
||||||
require.Equal(t, 2, v.estack.Len())
|
require.Equal(t, 2, v.estack.Len())
|
||||||
require.EqualValues(t, 2, v.refs.size) // empty collection + it's size
|
require.EqualValues(t, 2, int(v.refs)) // empty collection + it's size
|
||||||
require.EqualValues(t, 0, v.estack.Pop().BigInt().Int64())
|
require.EqualValues(t, 0, v.estack.Pop().BigInt().Int64())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue