package vm import "github.com/bytom/math/checked" func opToAltStack(vm *virtualMachine) error { err := vm.applyCost(2) if err != nil { return err } if len(vm.dataStack) == 0 { return ErrDataStackUnderflow } // no standard memory cost accounting here vm.altStack = append(vm.altStack, vm.dataStack[len(vm.dataStack)-1]) vm.dataStack = vm.dataStack[:len(vm.dataStack)-1] return nil } func opFromAltStack(vm *virtualMachine) error { err := vm.applyCost(2) if err != nil { return err } if len(vm.altStack) == 0 { return ErrAltStackUnderflow } // no standard memory cost accounting here vm.dataStack = append(vm.dataStack, vm.altStack[len(vm.altStack)-1]) vm.altStack = vm.altStack[:len(vm.altStack)-1] return nil } func op2Drop(vm *virtualMachine) error { err := vm.applyCost(2) if err != nil { return err } for i := 0; i < 2; i++ { _, err = vm.pop(false) if err != nil { return err } } return nil } func op2Dup(vm *virtualMachine) error { return nDup(vm, 2) } func op3Dup(vm *virtualMachine) error { return nDup(vm, 3) } func nDup(vm *virtualMachine, n int) error { err := vm.applyCost(int64(n)) if err != nil { return err } if len(vm.dataStack) < n { return ErrDataStackUnderflow } for i := 0; i < n; i++ { err = vm.push(vm.dataStack[len(vm.dataStack)-n], false) if err != nil { return err } } return nil } func op2Over(vm *virtualMachine) error { err := vm.applyCost(2) if err != nil { return err } if len(vm.dataStack) < 4 { return ErrDataStackUnderflow } for i := 0; i < 2; i++ { err = vm.push(vm.dataStack[len(vm.dataStack)-4], false) if err != nil { return err } } return nil } func op2Rot(vm *virtualMachine) error { err := vm.applyCost(2) if err != nil { return err } if len(vm.dataStack) < 6 { return ErrDataStackUnderflow } newStack := make([][]byte, 0, len(vm.dataStack)) newStack = append(newStack, vm.dataStack[:len(vm.dataStack)-6]...) newStack = append(newStack, vm.dataStack[len(vm.dataStack)-4:]...) newStack = append(newStack, vm.dataStack[len(vm.dataStack)-6]) newStack = append(newStack, vm.dataStack[len(vm.dataStack)-5]) vm.dataStack = newStack return nil } func op2Swap(vm *virtualMachine) error { err := vm.applyCost(2) if err != nil { return err } if len(vm.dataStack) < 4 { return ErrDataStackUnderflow } newStack := make([][]byte, 0, len(vm.dataStack)) newStack = append(newStack, vm.dataStack[:len(vm.dataStack)-4]...) newStack = append(newStack, vm.dataStack[len(vm.dataStack)-2:]...) newStack = append(newStack, vm.dataStack[len(vm.dataStack)-4]) newStack = append(newStack, vm.dataStack[len(vm.dataStack)-3]) vm.dataStack = newStack return nil } func opIfDup(vm *virtualMachine) error { err := vm.applyCost(1) if err != nil { return err } item, err := vm.top() if err != nil { return err } if AsBool(item) { err = vm.push(item, false) if err != nil { return err } } return nil } func opDepth(vm *virtualMachine) error { err := vm.applyCost(1) if err != nil { return err } err = vm.pushInt64(int64(len(vm.dataStack)), false) if err != nil { return err } return nil } func opDrop(vm *virtualMachine) error { err := vm.applyCost(1) if err != nil { return err } _, err = vm.pop(false) if err != nil { return err } return nil } func opDup(vm *virtualMachine) error { return nDup(vm, 1) } func opNip(vm *virtualMachine) error { err := vm.applyCost(1) if err != nil { return err } top, err := vm.top() if err != nil { return err } // temporarily pop off the top value with no standard memory accounting vm.dataStack = vm.dataStack[:len(vm.dataStack)-1] _, err = vm.pop(false) if err != nil { return err } // now put the top item back vm.dataStack = append(vm.dataStack, top) return nil } func opOver(vm *virtualMachine) error { err := vm.applyCost(1) if err != nil { return err } if len(vm.dataStack) < 2 { return ErrDataStackUnderflow } err = vm.push(vm.dataStack[len(vm.dataStack)-2], false) if err != nil { return err } return nil } func opPick(vm *virtualMachine) error { err := vm.applyCost(2) if err != nil { return err } n, err := vm.popInt64(false) if err != nil { return err } if n < 0 { return ErrBadValue } off, ok := checked.AddInt64(n, 1) if !ok { return ErrBadValue } if int64(len(vm.dataStack)) < off { return ErrDataStackUnderflow } err = vm.push(vm.dataStack[int64(len(vm.dataStack))-(off)], false) if err != nil { return err } return nil } func opRoll(vm *virtualMachine) error { err := vm.applyCost(2) if err != nil { return err } n, err := vm.popInt64(false) if err != nil { return err } if n < 0 { return ErrBadValue } off, ok := checked.AddInt64(n, 1) if !ok { return ErrBadValue } err = rot(vm, off) if err != nil { return err } return nil } func opRot(vm *virtualMachine) error { err := vm.applyCost(2) if err != nil { return err } err = rot(vm, 3) if err != nil { return err } return nil } func rot(vm *virtualMachine, n int64) error { if n < 1 { return ErrBadValue } if int64(len(vm.dataStack)) < n { return ErrDataStackUnderflow } index := int64(len(vm.dataStack)) - n newStack := make([][]byte, 0, len(vm.dataStack)) newStack = append(newStack, vm.dataStack[:index]...) newStack = append(newStack, vm.dataStack[index+1:]...) newStack = append(newStack, vm.dataStack[index]) vm.dataStack = newStack return nil } func opSwap(vm *virtualMachine) error { err := vm.applyCost(1) if err != nil { return err } l := len(vm.dataStack) if l < 2 { return ErrDataStackUnderflow } vm.dataStack[l-1], vm.dataStack[l-2] = vm.dataStack[l-2], vm.dataStack[l-1] return nil } func opTuck(vm *virtualMachine) error { err := vm.applyCost(1) if err != nil { return err } if len(vm.dataStack) < 2 { return ErrDataStackUnderflow } top2 := make([][]byte, 2) copy(top2, vm.dataStack[len(vm.dataStack)-2:]) // temporarily remove the top two items without standard memory accounting vm.dataStack = vm.dataStack[:len(vm.dataStack)-2] err = vm.push(top2[1], false) if err != nil { return err } vm.dataStack = append(vm.dataStack, top2...) return nil }