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
|
||||
}
|
||||
|
||||
// Dup implements StackItem interface.
|
||||
func (c *Context) Dup() StackItem {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Context) atBreakPoint() bool {
|
||||
for _, n := range c.breakPoints {
|
||||
if n == c.ip {
|
||||
|
|
|
@ -346,7 +346,7 @@ func (s *Stack) Dup(n int) *Element {
|
|||
}
|
||||
|
||||
return &Element{
|
||||
value: e.value,
|
||||
value: e.value.Dup(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ import (
|
|||
type StackItem interface {
|
||||
fmt.Stringer
|
||||
Value() interface{}
|
||||
// Dup duplicates current StackItem.
|
||||
Dup() StackItem
|
||||
}
|
||||
|
||||
func makeStackItem(v interface{}) StackItem {
|
||||
|
@ -107,6 +109,12 @@ func (i *StructItem) String() string {
|
|||
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.
|
||||
// Array fields are still copied by reference.
|
||||
func (i *StructItem) Clone() *StructItem {
|
||||
|
@ -148,6 +156,12 @@ func (i *BigIntegerItem) String() string {
|
|||
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.
|
||||
func (i *BigIntegerItem) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.value)
|
||||
|
@ -179,6 +193,11 @@ func (i *BoolItem) String() string {
|
|||
return "Bool"
|
||||
}
|
||||
|
||||
// Dup implements StackItem interface.
|
||||
func (i *BoolItem) Dup() StackItem {
|
||||
return &BoolItem{i.value}
|
||||
}
|
||||
|
||||
// ByteArrayItem represents a byte array on the stack.
|
||||
type ByteArrayItem struct {
|
||||
value []byte
|
||||
|
@ -205,6 +224,13 @@ func (i *ByteArrayItem) String() string {
|
|||
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.
|
||||
type ArrayItem struct {
|
||||
value []StackItem
|
||||
|
@ -231,6 +257,12 @@ func (i *ArrayItem) String() string {
|
|||
return "Array"
|
||||
}
|
||||
|
||||
// Dup implements StackItem interface.
|
||||
func (i *ArrayItem) Dup() StackItem {
|
||||
// reference type
|
||||
return i
|
||||
}
|
||||
|
||||
// MapItem represents Map object.
|
||||
type MapItem struct {
|
||||
value map[interface{}]StackItem
|
||||
|
@ -259,6 +291,12 @@ func (i *MapItem) Has(key StackItem) (ok bool) {
|
|||
return
|
||||
}
|
||||
|
||||
// Dup implements StackItem interface.
|
||||
func (i *MapItem) Dup() StackItem {
|
||||
// reference type
|
||||
return i
|
||||
}
|
||||
|
||||
// Add adds key-value pair to the map.
|
||||
func (i *MapItem) Add(key, value StackItem) {
|
||||
i.value[toMapKey(key)] = value
|
||||
|
@ -300,6 +338,12 @@ func (i *InteropItem) String() string {
|
|||
return "InteropItem"
|
||||
}
|
||||
|
||||
// Dup implements StackItem interface.
|
||||
func (i *InteropItem) Dup() StackItem {
|
||||
// reference type
|
||||
return i
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (i *InteropItem) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.value)
|
||||
|
|
|
@ -2519,6 +2519,42 @@ func TestXSWAPBad2(t *testing.T) {
|
|||
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 {
|
||||
prog := make([]byte, len(opcodes)+1) // RET
|
||||
for i := 0; i < len(opcodes); i++ {
|
||||
|
|
Loading…
Reference in a new issue