forked from TrueCloudLab/neoneo-go
Implemented following opcodes:
1) DUPFROMALTSTACK 2) TOALTSTACK 3) FROMALTSTACK 4) XDROP
This commit is contained in:
parent
045db09af2
commit
7e20b604b4
4 changed files with 242 additions and 28 deletions
|
@ -158,3 +158,19 @@ func (ras *RandomAccess) PopBoolean() (*Boolean, error) {
|
||||||
}
|
}
|
||||||
return item.Boolean()
|
return item.Boolean()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
|
@ -5,34 +5,38 @@ 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.NUMEQUAL: NumEqual,
|
stack.XDROP: XDROP,
|
||||||
stack.NUMNOTEQUAL: NumNotEqual,
|
stack.FROMALTSTACK: FROMALTSTACK,
|
||||||
stack.BOOLAND: BoolAnd,
|
stack.TOALTSTACK: TOALTSTACK,
|
||||||
stack.BOOLOR: BoolOr,
|
stack.DUPFROMALTSTACK: DUPFROMALTSTACK,
|
||||||
stack.LT: Lt,
|
stack.NUMEQUAL: NumEqual,
|
||||||
stack.LTE: Lte,
|
stack.NUMNOTEQUAL: NumNotEqual,
|
||||||
stack.GT: Gt,
|
stack.BOOLAND: BoolAnd,
|
||||||
stack.GTE: Gte,
|
stack.BOOLOR: BoolOr,
|
||||||
stack.SHR: Shr,
|
stack.LT: Lt,
|
||||||
stack.SHL: Shl,
|
stack.LTE: Lte,
|
||||||
stack.INC: Inc,
|
stack.GT: Gt,
|
||||||
stack.DEC: Dec,
|
stack.GTE: Gte,
|
||||||
stack.DIV: Div,
|
stack.SHR: Shr,
|
||||||
stack.MOD: Mod,
|
stack.SHL: Shl,
|
||||||
stack.NZ: Nz,
|
stack.INC: Inc,
|
||||||
stack.MUL: Mul,
|
stack.DEC: Dec,
|
||||||
stack.ABS: Abs,
|
stack.DIV: Div,
|
||||||
stack.NOT: Not,
|
stack.MOD: Mod,
|
||||||
stack.SIGN: Sign,
|
stack.NZ: Nz,
|
||||||
stack.NEGATE: Negate,
|
stack.MUL: Mul,
|
||||||
stack.ADD: Add,
|
stack.ABS: Abs,
|
||||||
stack.SUB: Sub,
|
stack.NOT: Not,
|
||||||
stack.PUSHBYTES1: PushNBytes,
|
stack.SIGN: Sign,
|
||||||
stack.PUSHBYTES75: PushNBytes,
|
stack.NEGATE: Negate,
|
||||||
stack.RET: RET,
|
stack.ADD: Add,
|
||||||
stack.EQUAL: EQUAL,
|
stack.SUB: Sub,
|
||||||
stack.THROWIFNOT: THROWIFNOT,
|
stack.PUSHBYTES1: PushNBytes,
|
||||||
stack.THROW: THROW,
|
stack.PUSHBYTES75: PushNBytes,
|
||||||
|
stack.RET: RET,
|
||||||
|
stack.EQUAL: EQUAL,
|
||||||
|
stack.THROWIFNOT: THROWIFNOT,
|
||||||
|
stack.THROW: THROW,
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
@ -17,3 +17,66 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DUPFROMALTSTACK duplicates the item on top of alternative stack and
|
||||||
|
// puts it on top of evaluation stack.
|
||||||
|
// Returns an error if the alt stack is empty.
|
||||||
|
func DUPFROMALTSTACK(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) {
|
||||||
|
|
||||||
|
item, err := ctx.Astack.Peek(0)
|
||||||
|
if err != nil {
|
||||||
|
return FAULT, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Estack.Push(item)
|
||||||
|
|
||||||
|
return NONE, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TOALTSTACK pops an item off of the evaluation stack and
|
||||||
|
// pushes it on top of the alternative stack.
|
||||||
|
// Returns an error if the alternative stack is empty.
|
||||||
|
func TOALTSTACK(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) {
|
||||||
|
|
||||||
|
item, err := ctx.Estack.Pop()
|
||||||
|
if err != nil {
|
||||||
|
return FAULT, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Astack.Push(item)
|
||||||
|
|
||||||
|
return NONE, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FROMALTSTACK pops an item off of the alternative stack and
|
||||||
|
// pushes it on top of the evaluation stack.
|
||||||
|
// Returns an error if the evaluation stack is empty.
|
||||||
|
func FROMALTSTACK(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) {
|
||||||
|
|
||||||
|
item, err := ctx.Astack.Pop()
|
||||||
|
if err != nil {
|
||||||
|
return FAULT, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Estack.Push(item)
|
||||||
|
|
||||||
|
return NONE, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// XDROP pops an integer n off of the stack and
|
||||||
|
// removes the n-item from the stack starting from
|
||||||
|
// the top of the stack.
|
||||||
|
func XDROP(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
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Estack.Remove(uint16(n.Value().Uint64()))
|
||||||
|
if err != nil {
|
||||||
|
return FAULT, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NONE, nil
|
||||||
|
}
|
||||||
|
|
131
pkg/vm/vm_ops_stackmani_test.go
Normal file
131
pkg/vm/vm_ops_stackmani_test.go
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/vm/stack"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDupFromAltStackOp(t *testing.T) {
|
||||||
|
|
||||||
|
v := VM{}
|
||||||
|
|
||||||
|
a, err := stack.NewInt(big.NewInt(10))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
b, err := stack.NewInt(big.NewInt(2))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
ctx := stack.NewContext([]byte{})
|
||||||
|
ctx.Estack.Push(a)
|
||||||
|
ctx.Astack.Push(b)
|
||||||
|
|
||||||
|
v.executeOp(stack.DUPFROMALTSTACK, ctx)
|
||||||
|
|
||||||
|
assert.Equal(t, 1, ctx.Astack.Len())
|
||||||
|
assert.Equal(t, 2, ctx.Estack.Len())
|
||||||
|
|
||||||
|
itemE, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
itemA, err := ctx.Astack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(2), itemE.Value().Int64())
|
||||||
|
assert.Equal(t, int64(2), itemA.Value().Int64())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToAltStackOp(t *testing.T) {
|
||||||
|
|
||||||
|
v := VM{}
|
||||||
|
|
||||||
|
a, err := stack.NewInt(big.NewInt(10))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
b, err := stack.NewInt(big.NewInt(2))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
ctx := stack.NewContext([]byte{})
|
||||||
|
ctx.Estack.Push(a)
|
||||||
|
ctx.Astack.Push(b)
|
||||||
|
|
||||||
|
v.executeOp(stack.TOALTSTACK, ctx)
|
||||||
|
|
||||||
|
assert.Equal(t, 2, ctx.Astack.Len())
|
||||||
|
assert.Equal(t, 0, ctx.Estack.Len())
|
||||||
|
|
||||||
|
item, err := ctx.Astack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(10), item.Value().Int64())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromAltStackOp(t *testing.T) {
|
||||||
|
|
||||||
|
v := VM{}
|
||||||
|
|
||||||
|
a, err := stack.NewInt(big.NewInt(10))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
b, err := stack.NewInt(big.NewInt(2))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
ctx := stack.NewContext([]byte{})
|
||||||
|
ctx.Estack.Push(a)
|
||||||
|
ctx.Astack.Push(b)
|
||||||
|
|
||||||
|
v.executeOp(stack.FROMALTSTACK, ctx)
|
||||||
|
|
||||||
|
assert.Equal(t, 0, ctx.Astack.Len())
|
||||||
|
assert.Equal(t, 2, ctx.Estack.Len())
|
||||||
|
|
||||||
|
item, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(2), item.Value().Int64())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXDropOp(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)
|
||||||
|
ctx.Estack.Push(b)
|
||||||
|
ctx.Estack.Push(c)
|
||||||
|
ctx.Estack.Push(d)
|
||||||
|
|
||||||
|
// pop n (= d = 2) from the stack.
|
||||||
|
// we will remove the n-item which
|
||||||
|
// is located at position
|
||||||
|
// len(stack)-n-1 = 3-2-1 = 0.
|
||||||
|
// Therefore a is removed from the stack.
|
||||||
|
// Only b, c remain on the stack.
|
||||||
|
v.executeOp(stack.XDROP, ctx)
|
||||||
|
|
||||||
|
assert.Equal(t, 2, ctx.Estack.Len())
|
||||||
|
|
||||||
|
itemC, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
itemB, err := ctx.Estack.PopInt()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(6), itemB.Value().Int64())
|
||||||
|
assert.Equal(t, int64(9), itemC.Value().Int64())
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue