forked from TrueCloudLab/neoneo-go
vm: implement Pointer stack item
Pointer is a generic address type in VM. It is used for calling lambda-expressions.
This commit is contained in:
parent
b83ee77698
commit
7fcd537b09
3 changed files with 118 additions and 1 deletions
|
@ -10,7 +10,9 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -857,3 +859,84 @@ func (i *InteropItem) Convert(typ StackItemType) (StackItem, error) {
|
||||||
func (i *InteropItem) MarshalJSON() ([]byte, error) {
|
func (i *InteropItem) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(i.value)
|
return json.Marshal(i.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PointerItem represents VM-level instruction pointer.
|
||||||
|
type PointerItem struct {
|
||||||
|
pos int
|
||||||
|
script []byte
|
||||||
|
hash util.Uint160
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPointerItem returns new pointer on the specified position.
|
||||||
|
func NewPointerItem(pos int, script []byte) *PointerItem {
|
||||||
|
return &PointerItem{
|
||||||
|
pos: pos,
|
||||||
|
script: script,
|
||||||
|
hash: hash.Hash160(script),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements StackItem interface.
|
||||||
|
func (p *PointerItem) String() string {
|
||||||
|
return "Pointer"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements StackItem interface.
|
||||||
|
func (p *PointerItem) Value() interface{} {
|
||||||
|
return p.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dup implements StackItem interface.
|
||||||
|
func (p *PointerItem) Dup() StackItem {
|
||||||
|
return &PointerItem{
|
||||||
|
pos: p.pos,
|
||||||
|
script: p.script,
|
||||||
|
hash: p.hash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool implements StackItem interface.
|
||||||
|
func (p *PointerItem) Bool() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// TryBytes implements StackItem interface.
|
||||||
|
func (p *PointerItem) TryBytes() ([]byte, error) {
|
||||||
|
return nil, errors.New("can't convert Pointer to ByteArray")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TryInteger implements StackItem interface.
|
||||||
|
func (p *PointerItem) TryInteger() (*big.Int, error) {
|
||||||
|
return nil, errors.New("can't convert Pointer to Integer")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equals implements StackItem interface.
|
||||||
|
func (p *PointerItem) Equals(s StackItem) bool {
|
||||||
|
if p == s {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
ptr, ok := s.(*PointerItem)
|
||||||
|
return ok && p.pos == ptr.pos && p.hash == ptr.hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToContractParameter implements StackItem interface.
|
||||||
|
func (p *PointerItem) ToContractParameter(map[StackItem]bool) smartcontract.Parameter {
|
||||||
|
return smartcontract.NewParameter(smartcontract.AnyType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type implements StackItem interface.
|
||||||
|
func (p *PointerItem) Type() StackItemType {
|
||||||
|
return PointerT
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert implements StackItem interface.
|
||||||
|
func (p *PointerItem) Convert(typ StackItemType) (StackItem, error) {
|
||||||
|
switch typ {
|
||||||
|
case PointerT:
|
||||||
|
return p, nil
|
||||||
|
case BooleanT:
|
||||||
|
return NewBoolItem(p.Bool()), nil
|
||||||
|
default:
|
||||||
|
return nil, errInvalidConversion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -127,6 +127,10 @@ var stringerTestCases = []struct {
|
||||||
input: NewInteropItem(nil),
|
input: NewInteropItem(nil),
|
||||||
result: "InteropItem",
|
result: "InteropItem",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: NewPointerItem(0, nil),
|
||||||
|
result: "Pointer",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStringer(t *testing.T) {
|
func TestStringer(t *testing.T) {
|
||||||
|
@ -314,6 +318,32 @@ var equalsTestCases = map[string][]struct {
|
||||||
result: true,
|
result: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"pointer": {
|
||||||
|
{
|
||||||
|
item1: NewPointerItem(0, []byte{}),
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item1: NewPointerItem(1, []byte{1}),
|
||||||
|
item2: NewPointerItem(1, []byte{1}),
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item1: NewPointerItem(1, []byte{1}),
|
||||||
|
item2: NewPointerItem(2, []byte{1}),
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item1: NewPointerItem(1, []byte{1}),
|
||||||
|
item2: NewPointerItem(1, []byte{2}),
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item1: NewPointerItem(0, []byte{}),
|
||||||
|
item2: NewBigIntegerItem(big.NewInt(0)),
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEquals(t *testing.T) {
|
func TestEquals(t *testing.T) {
|
||||||
|
|
|
@ -266,6 +266,7 @@ func TestCONVERT(t *testing.T) {
|
||||||
NewArrayItem(arr), NewArrayItem(nil),
|
NewArrayItem(arr), NewArrayItem(nil),
|
||||||
NewStructItem(arr), NewStructItem(nil),
|
NewStructItem(arr), NewStructItem(nil),
|
||||||
NewMapItem(), m, NewInteropItem(struct{}{}),
|
NewMapItem(), m, NewInteropItem(struct{}{}),
|
||||||
|
NewPointerItem(0, []byte{}),
|
||||||
}
|
}
|
||||||
for i := range trueCases {
|
for i := range trueCases {
|
||||||
t.Run(getName(trueCases[i], BooleanT), testBool(trueCases[i], NewBoolItem(true)))
|
t.Run(getName(trueCases[i], BooleanT), testBool(trueCases[i], NewBoolItem(true)))
|
||||||
|
@ -329,9 +330,12 @@ func TestCONVERT(t *testing.T) {
|
||||||
|
|
||||||
t.Run("Map->Map", testCONVERT(MapT, m, m))
|
t.Run("Map->Map", testCONVERT(MapT, m, m))
|
||||||
|
|
||||||
|
ptr := NewPointerItem(1, []byte{1})
|
||||||
|
t.Run("Pointer->Pointer", testCONVERT(PointerT, ptr, ptr))
|
||||||
|
|
||||||
t.Run("Null->", func(t *testing.T) {
|
t.Run("Null->", func(t *testing.T) {
|
||||||
types := []StackItemType{
|
types := []StackItemType{
|
||||||
BooleanT, ByteArrayT, IntegerT, ArrayT, StructT, MapT, InteropT,
|
BooleanT, ByteArrayT, IntegerT, ArrayT, StructT, MapT, InteropT, PointerT,
|
||||||
}
|
}
|
||||||
for i := range types {
|
for i := range types {
|
||||||
t.Run(types[i].String(), testCONVERT(types[i], NullItem{}, NullItem{}))
|
t.Run(types[i].String(), testCONVERT(types[i], NullItem{}, NullItem{}))
|
||||||
|
|
Loading…
Reference in a new issue