Implemented following opcodes:
1) DUP 2) NIP 3) OVER 4) PICK
This commit is contained in:
parent
045db09af2
commit
d43dcf03cb
4 changed files with 296 additions and 0 deletions
|
@ -127,6 +127,37 @@ func (ras *RandomAccess) CopyTo(stack *RandomAccess) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set sets the n-item from the stack
|
||||||
|
// starting from the top of the stack with the new item.
|
||||||
|
// the n-item to replace is located at the position "len(stack)-index-1".
|
||||||
|
func (ras *RandomAccess) Set(index uint16, item Item) error {
|
||||||
|
stackSize := uint16(len(ras.vals))
|
||||||
|
if ok := index >= stackSize; ok {
|
||||||
|
return errors.New("index out of range")
|
||||||
|
}
|
||||||
|
|
||||||
|
n := stackSize - index - 1
|
||||||
|
ras.vals[n] = item
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes the n-item from the stack
|
||||||
|
// starting from the top of the stack. In other words
|
||||||
|
// the n-item to remove is located at the index "len(stack)-n-1"
|
||||||
|
func (ras *RandomAccess) Remove(n uint16) (Item, error) {
|
||||||
|
if int(n) >= len(ras.vals) {
|
||||||
|
return nil, errors.New("index out of range")
|
||||||
|
}
|
||||||
|
|
||||||
|
index := uint16(len(ras.vals)) - n - 1
|
||||||
|
item := ras.vals[index]
|
||||||
|
|
||||||
|
ras.vals = append(ras.vals[:index], ras.vals[index+1:]...)
|
||||||
|
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Convenience Functions
|
// Convenience Functions
|
||||||
|
|
||||||
// PopInt will remove the last stack item that was added
|
// PopInt will remove the last stack item that was added
|
||||||
|
|
|
@ -5,6 +5,10 @@ import "github.com/CityOfZion/neo-go/pkg/vm/stack"
|
||||||
type stackInfo func(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error)
|
type stackInfo func(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error)
|
||||||
|
|
||||||
var opFunc = map[stack.Instruction]stackInfo{
|
var opFunc = map[stack.Instruction]stackInfo{
|
||||||
|
stack.PICK: PICK,
|
||||||
|
stack.OVER: OVER,
|
||||||
|
stack.NIP: NIP,
|
||||||
|
stack.DUP: DUP,
|
||||||
stack.NUMEQUAL: NumEqual,
|
stack.NUMEQUAL: NumEqual,
|
||||||
stack.NUMNOTEQUAL: NumNotEqual,
|
stack.NUMNOTEQUAL: NumNotEqual,
|
||||||
stack.BOOLAND: BoolAnd,
|
stack.BOOLAND: BoolAnd,
|
||||||
|
|
|
@ -17,3 +17,67 @@ func PushNBytes(op stack.Instruction, ctx *stack.Context, istack *stack.Invocati
|
||||||
ctx.Estack.Push(ba)
|
ctx.Estack.Push(ba)
|
||||||
return NONE, nil
|
return NONE, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DUP duplicates the top stack item.
|
||||||
|
// Returns an error if stack is empty.
|
||||||
|
func DUP(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) {
|
||||||
|
|
||||||
|
item, err := ctx.Estack.Peek(0)
|
||||||
|
if err != nil {
|
||||||
|
return FAULT, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Estack.Push(item)
|
||||||
|
|
||||||
|
return NONE, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NIP removes the second top stack item.
|
||||||
|
// Returns error if the stack item contains
|
||||||
|
// only one element.
|
||||||
|
func NIP(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) {
|
||||||
|
|
||||||
|
_, err := ctx.Estack.Remove(1)
|
||||||
|
if err != nil {
|
||||||
|
return FAULT, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NONE, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OVER copies the second-to-top stack item onto the top.
|
||||||
|
// Returns an error if the stack item contains
|
||||||
|
// only one element.
|
||||||
|
func OVER(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) {
|
||||||
|
|
||||||
|
item, err := ctx.Estack.Peek(1)
|
||||||
|
if err != nil {
|
||||||
|
return FAULT, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Estack.Push(item)
|
||||||
|
|
||||||
|
return NONE, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PICK pops an integer n off of the stack and
|
||||||
|
// copies the n-item starting from
|
||||||
|
// the top of the stack onto the top stack item.
|
||||||
|
// Returns an error if the top stack item is not an
|
||||||
|
// integer or n-item does not exist.
|
||||||
|
func PICK(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) {
|
||||||
|
|
||||||
|
n, err := ctx.Estack.PopInt()
|
||||||
|
if err != nil {
|
||||||
|
return FAULT, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nItem, err := ctx.Estack.Peek(uint16(n.Value().Int64()))
|
||||||
|
if err != nil {
|
||||||
|
return FAULT, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Estack.Push(nItem)
|
||||||
|
|
||||||
|
return NONE, nil
|
||||||
|
}
|
||||||
|
|
197
pkg/vm/vm_ops_stackmani_test.go
Normal file
197
pkg/vm/vm_ops_stackmani_test.go
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/vm/stack"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDupOp(t *testing.T) {
|
||||||
|
|
||||||
|
v := VM{}
|
||||||
|
|
||||||
|
a, err := stack.NewInt(big.NewInt(3))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
ctx := stack.NewContext([]byte{})
|
||||||
|
ctx.Estack.Push(a)
|
||||||
|
|
||||||
|
v.executeOp(stack.DUP, ctx)
|
||||||
|
|
||||||
|
// Stack should have two items
|
||||||
|
assert.Equal(t, 2, ctx.Estack.Len())
|
||||||
|
|
||||||
|
item1, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
item2, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(3), item1.Value().Int64())
|
||||||
|
assert.Equal(t, int64(3), item2.Value().Int64())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNipOp(t *testing.T) {
|
||||||
|
|
||||||
|
v := VM{}
|
||||||
|
|
||||||
|
a, err := stack.NewInt(big.NewInt(3))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
b, err := stack.NewInt(big.NewInt(6))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
c, err := stack.NewInt(big.NewInt(9))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
ctx := stack.NewContext([]byte{})
|
||||||
|
ctx.Estack.Push(a).Push(b).Push(c)
|
||||||
|
|
||||||
|
v.executeOp(stack.NIP, ctx)
|
||||||
|
|
||||||
|
// Stack should have two items
|
||||||
|
assert.Equal(t, 2, ctx.Estack.Len())
|
||||||
|
|
||||||
|
itemC, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
itemA, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(3), itemA.Value().Int64())
|
||||||
|
assert.Equal(t, int64(9), itemC.Value().Int64())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOverOp(t *testing.T) {
|
||||||
|
|
||||||
|
v := VM{}
|
||||||
|
|
||||||
|
a, err := stack.NewInt(big.NewInt(3))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
b, err := stack.NewInt(big.NewInt(6))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
ctx := stack.NewContext([]byte{})
|
||||||
|
ctx.Estack.Push(a).Push(b)
|
||||||
|
|
||||||
|
// OVER copies the second top stack item a
|
||||||
|
// onto the top stack item b.
|
||||||
|
// the new stack will be [a,b,a].
|
||||||
|
v.executeOp(stack.OVER, ctx)
|
||||||
|
|
||||||
|
// Stack should have three items
|
||||||
|
assert.Equal(t, 3, ctx.Estack.Len())
|
||||||
|
|
||||||
|
itemA, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
itemB, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
itemA2, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(3), itemA.Value().Int64())
|
||||||
|
assert.Equal(t, int64(6), itemB.Value().Int64())
|
||||||
|
assert.Equal(t, int64(3), itemA2.Value().Int64())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPickOp(t *testing.T) {
|
||||||
|
|
||||||
|
v := VM{}
|
||||||
|
|
||||||
|
a, err := stack.NewInt(big.NewInt(3))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
b, err := stack.NewInt(big.NewInt(6))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
c, err := stack.NewInt(big.NewInt(9))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
d, err := stack.NewInt(big.NewInt(2))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
ctx := stack.NewContext([]byte{})
|
||||||
|
ctx.Estack.Push(a).Push(b).Push(c).Push(d)
|
||||||
|
|
||||||
|
// pop n (= d = 2) from the stack.
|
||||||
|
// we will copy the n-item which
|
||||||
|
// has index len(stack)-n-1 (= 3-2-1= 0)
|
||||||
|
// onto the top stack item.
|
||||||
|
// The final stack will be [a,b,c,a]
|
||||||
|
v.executeOp(stack.PICK, ctx)
|
||||||
|
|
||||||
|
// Stack should have four items
|
||||||
|
assert.Equal(t, 4, ctx.Estack.Len())
|
||||||
|
|
||||||
|
itemA, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
itemC, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
itemB, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
itemA2, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(3), itemA.Value().Int64())
|
||||||
|
assert.Equal(t, int64(9), itemC.Value().Int64())
|
||||||
|
assert.Equal(t, int64(6), itemB.Value().Int64())
|
||||||
|
assert.Equal(t, int64(3), itemA2.Value().Int64())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func TestXswapOp(t *testing.T) {
|
||||||
|
|
||||||
|
v := VM{}
|
||||||
|
|
||||||
|
sert.Nil(t, err)
|
||||||
|
|
||||||
|
ctx := stack.NewContext([]byte{})
|
||||||
|
ctx.Estack.Push(a).Push(b).Push(c).Push(d)
|
||||||
|
|
||||||
|
// pop n (= d = 2) from the stack.
|
||||||
|
// we wa, err := stack.NewInt(big.NewInt(3))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
b, err := stack.NewInt(big.NewInt(6))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
c, err := stack.NewInt(big.NewInt(9))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
d, err := stack.NewInt(big.NewInt(2))
|
||||||
|
asill swap the n-item which
|
||||||
|
// is located in position len(stack)-n-1 (= 3-2-1= 0)
|
||||||
|
// with the top stack item.
|
||||||
|
// The final stack will be [c,b,a]
|
||||||
|
v.executeOp(stack.XSWAP, ctx)
|
||||||
|
|
||||||
|
// Stack should have three items
|
||||||
|
assert.Equal(t, 3, ctx.Estack.Len())
|
||||||
|
|
||||||
|
itemA, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
itemB, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
itemC, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(3), itemA.Value().Int64())
|
||||||
|
assert.Equal(t, int64(6), itemB.Value().Int64())
|
||||||
|
assert.Equal(t, int64(9), itemC.Value().Int64())
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
Loading…
Reference in a new issue