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:
Evgenii Stratonikov 2020-05-06 16:31:52 +03:00
parent b83ee77698
commit 7fcd537b09
3 changed files with 118 additions and 1 deletions

View file

@ -10,7 +10,9 @@ import (
"math/big"
"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/util"
"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) {
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
}
}

View file

@ -127,6 +127,10 @@ var stringerTestCases = []struct {
input: NewInteropItem(nil),
result: "InteropItem",
},
{
input: NewPointerItem(0, nil),
result: "Pointer",
},
}
func TestStringer(t *testing.T) {
@ -314,6 +318,32 @@ var equalsTestCases = map[string][]struct {
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) {

View file

@ -266,6 +266,7 @@ func TestCONVERT(t *testing.T) {
NewArrayItem(arr), NewArrayItem(nil),
NewStructItem(arr), NewStructItem(nil),
NewMapItem(), m, NewInteropItem(struct{}{}),
NewPointerItem(0, []byte{}),
}
for i := range trueCases {
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))
ptr := NewPointerItem(1, []byte{1})
t.Run("Pointer->Pointer", testCONVERT(PointerT, ptr, ptr))
t.Run("Null->", func(t *testing.T) {
types := []StackItemType{
BooleanT, ByteArrayT, IntegerT, ArrayT, StructT, MapT, InteropT,
BooleanT, ByteArrayT, IntegerT, ArrayT, StructT, MapT, InteropT, PointerT,
}
for i := range types {
t.Run(types[i].String(), testCONVERT(types[i], NullItem{}, NullItem{}))