vm: duplicate an item in Dup
TestDupByteArray and TestDupInt were failing before this patch.
This commit is contained in:
parent
c596a6b273
commit
60dfa05b19
4 changed files with 86 additions and 1 deletions
|
@ -159,6 +159,11 @@ func (c *Context) Value() interface{} {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dup implements StackItem interface.
|
||||||
|
func (c *Context) Dup() StackItem {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Context) atBreakPoint() bool {
|
func (c *Context) atBreakPoint() bool {
|
||||||
for _, n := range c.breakPoints {
|
for _, n := range c.breakPoints {
|
||||||
if n == c.ip {
|
if n == c.ip {
|
||||||
|
|
|
@ -346,7 +346,7 @@ func (s *Stack) Dup(n int) *Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Element{
|
return &Element{
|
||||||
value: e.value,
|
value: e.value.Dup(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@ import (
|
||||||
type StackItem interface {
|
type StackItem interface {
|
||||||
fmt.Stringer
|
fmt.Stringer
|
||||||
Value() interface{}
|
Value() interface{}
|
||||||
|
// Dup duplicates current StackItem.
|
||||||
|
Dup() StackItem
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeStackItem(v interface{}) StackItem {
|
func makeStackItem(v interface{}) StackItem {
|
||||||
|
@ -107,6 +109,12 @@ func (i *StructItem) String() string {
|
||||||
return "Struct"
|
return "Struct"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dup implements StackItem interface.
|
||||||
|
func (i *StructItem) Dup() StackItem {
|
||||||
|
// it's a reference type, so no copying here.
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
// Clone returns a Struct with all Struct fields copied by value.
|
// Clone returns a Struct with all Struct fields copied by value.
|
||||||
// Array fields are still copied by reference.
|
// Array fields are still copied by reference.
|
||||||
func (i *StructItem) Clone() *StructItem {
|
func (i *StructItem) Clone() *StructItem {
|
||||||
|
@ -148,6 +156,12 @@ func (i *BigIntegerItem) String() string {
|
||||||
return "BigInteger"
|
return "BigInteger"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dup implements StackItem interface.
|
||||||
|
func (i *BigIntegerItem) Dup() StackItem {
|
||||||
|
n := new(big.Int)
|
||||||
|
return &BigIntegerItem{n.Set(i.value)}
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
func (i *BigIntegerItem) MarshalJSON() ([]byte, error) {
|
func (i *BigIntegerItem) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(i.value)
|
return json.Marshal(i.value)
|
||||||
|
@ -179,6 +193,11 @@ func (i *BoolItem) String() string {
|
||||||
return "Bool"
|
return "Bool"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dup implements StackItem interface.
|
||||||
|
func (i *BoolItem) Dup() StackItem {
|
||||||
|
return &BoolItem{i.value}
|
||||||
|
}
|
||||||
|
|
||||||
// ByteArrayItem represents a byte array on the stack.
|
// ByteArrayItem represents a byte array on the stack.
|
||||||
type ByteArrayItem struct {
|
type ByteArrayItem struct {
|
||||||
value []byte
|
value []byte
|
||||||
|
@ -205,6 +224,13 @@ func (i *ByteArrayItem) String() string {
|
||||||
return "ByteArray"
|
return "ByteArray"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dup implements StackItem interface.
|
||||||
|
func (i *ByteArrayItem) Dup() StackItem {
|
||||||
|
a := make([]byte, len(i.value))
|
||||||
|
copy(a, i.value)
|
||||||
|
return &ByteArrayItem{a}
|
||||||
|
}
|
||||||
|
|
||||||
// ArrayItem represents a new ArrayItem object.
|
// ArrayItem represents a new ArrayItem object.
|
||||||
type ArrayItem struct {
|
type ArrayItem struct {
|
||||||
value []StackItem
|
value []StackItem
|
||||||
|
@ -231,6 +257,12 @@ func (i *ArrayItem) String() string {
|
||||||
return "Array"
|
return "Array"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dup implements StackItem interface.
|
||||||
|
func (i *ArrayItem) Dup() StackItem {
|
||||||
|
// reference type
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
// MapItem represents Map object.
|
// MapItem represents Map object.
|
||||||
type MapItem struct {
|
type MapItem struct {
|
||||||
value map[interface{}]StackItem
|
value map[interface{}]StackItem
|
||||||
|
@ -259,6 +291,12 @@ func (i *MapItem) Has(key StackItem) (ok bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dup implements StackItem interface.
|
||||||
|
func (i *MapItem) Dup() StackItem {
|
||||||
|
// reference type
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
// Add adds key-value pair to the map.
|
// Add adds key-value pair to the map.
|
||||||
func (i *MapItem) Add(key, value StackItem) {
|
func (i *MapItem) Add(key, value StackItem) {
|
||||||
i.value[toMapKey(key)] = value
|
i.value[toMapKey(key)] = value
|
||||||
|
@ -300,6 +338,12 @@ func (i *InteropItem) String() string {
|
||||||
return "InteropItem"
|
return "InteropItem"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dup implements StackItem interface.
|
||||||
|
func (i *InteropItem) Dup() StackItem {
|
||||||
|
// reference type
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
func (i *InteropItem) MarshalJSON() ([]byte, error) {
|
func (i *InteropItem) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(i.value)
|
return json.Marshal(i.value)
|
||||||
|
|
|
@ -2519,6 +2519,42 @@ func TestXSWAPBad2(t *testing.T) {
|
||||||
checkVMFailed(t, vm)
|
checkVMFailed(t, vm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDupInt(t *testing.T) {
|
||||||
|
prog := makeProgram(opcode.DUP, opcode.ABS)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(-1)
|
||||||
|
runVM(t, vm)
|
||||||
|
assert.Equal(t, 2, vm.estack.Len())
|
||||||
|
assert.Equal(t, int64(1), vm.estack.Pop().BigInt().Int64())
|
||||||
|
assert.Equal(t, int64(-1), vm.estack.Pop().BigInt().Int64())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDupByteArray(t *testing.T) {
|
||||||
|
prog := makeProgram(opcode.PUSHBYTES2, 1, 0,
|
||||||
|
opcode.DUP,
|
||||||
|
opcode.PUSH1,
|
||||||
|
opcode.LEFT,
|
||||||
|
opcode.PUSHBYTES1, 2,
|
||||||
|
opcode.CAT)
|
||||||
|
vm := load(prog)
|
||||||
|
runVM(t, vm)
|
||||||
|
assert.Equal(t, 2, vm.estack.Len())
|
||||||
|
assert.Equal(t, []byte{0x01, 0x02}, vm.estack.Pop().Bytes())
|
||||||
|
assert.Equal(t, []byte{0x01, 0x00}, vm.estack.Pop().Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDupBool(t *testing.T) {
|
||||||
|
prog := makeProgram(opcode.PUSH0, opcode.NOT,
|
||||||
|
opcode.DUP,
|
||||||
|
opcode.PUSH1, opcode.NOT,
|
||||||
|
opcode.BOOLAND)
|
||||||
|
vm := load(prog)
|
||||||
|
runVM(t, vm)
|
||||||
|
assert.Equal(t, 2, vm.estack.Len())
|
||||||
|
assert.Equal(t, false, vm.estack.Pop().Bool())
|
||||||
|
assert.Equal(t, true, vm.estack.Pop().Bool())
|
||||||
|
}
|
||||||
|
|
||||||
func makeProgram(opcodes ...opcode.Opcode) []byte {
|
func makeProgram(opcodes ...opcode.Opcode) []byte {
|
||||||
prog := make([]byte, len(opcodes)+1) // RET
|
prog := make([]byte, len(opcodes)+1) // RET
|
||||||
for i := 0; i < len(opcodes); i++ {
|
for i := 0; i < len(opcodes); i++ {
|
||||||
|
|
Loading…
Reference in a new issue