diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index a8c1df58c..11c7b3647 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -337,6 +337,14 @@ func (v *VM) execute(ctx *Context, op Instruction) { v.estack.Push(b) v.estack.Push(a) + case PICK: + n := int(v.estack.Pop().BigInt().Int64()) + if n < 0 { + panic("negative stack item returned") + } + a := v.estack.Peek(n) + v.estack.Push(a) + case ROLL: n := int(v.estack.Pop().BigInt().Int64()) if n < 0 { diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index b9ec5ee74..e80eabfb0 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -264,6 +264,39 @@ func TestNZfalse(t *testing.T) { assert.Equal(t, false, vm.estack.Pop().Bool()) } +func TestPICKbadNoitem(t *testing.T) { + prog := makeProgram(PICK) + vm := load(prog) + vm.estack.PushVal(1) + vm.Run() + assert.Equal(t, true, vm.state.HasFlag(faultState)) +} + +func TestPICKbadNegative(t *testing.T) { + prog := makeProgram(PICK) + vm := load(prog) + vm.estack.PushVal(-1) + vm.Run() + assert.Equal(t, true, vm.state.HasFlag(faultState)) +} + +func TestPICKgood(t *testing.T) { + prog := makeProgram(PICK) + result := 2 + vm := load(prog) + vm.estack.PushVal(0) + vm.estack.PushVal(1) + vm.estack.PushVal(result) + vm.estack.PushVal(3) + vm.estack.PushVal(4) + vm.estack.PushVal(5) + vm.estack.PushVal(3) + vm.Run() + assert.Equal(t, false, vm.state.HasFlag(faultState)) + assert.Equal(t, int64(result), vm.estack.Pop().BigInt().Int64()) +} + + func makeProgram(opcodes ...Instruction) []byte { prog := make([]byte, len(opcodes)+1) // RET for i := 0; i < len(opcodes); i++ {