mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-23 23:25:22 +00:00
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"
|
||||
"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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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{}))
|
||||
|
|
Loading…
Reference in a new issue