OSDN Git Service

Merge pull request #201 from Bytom/v0.1
[bytom/vapor.git] / vendor / github.com / bytom / protocol / vm / numeric.go
diff --git a/vendor/github.com/bytom/protocol/vm/numeric.go b/vendor/github.com/bytom/protocol/vm/numeric.go
new file mode 100644 (file)
index 0000000..09486d2
--- /dev/null
@@ -0,0 +1,459 @@
+package vm
+
+import (
+       "math"
+
+       "github.com/bytom/math/checked"
+)
+
+func op1Add(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       n, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       res, ok := checked.AddInt64(n, 1)
+       if !ok {
+               return ErrRange
+       }
+       return vm.pushInt64(res, true)
+}
+
+func op1Sub(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       n, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       res, ok := checked.SubInt64(n, 1)
+       if !ok {
+               return ErrRange
+       }
+       return vm.pushInt64(res, true)
+}
+
+func op2Mul(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       n, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       res, ok := checked.MulInt64(n, 2)
+       if !ok {
+               return ErrRange
+       }
+       return vm.pushInt64(res, true)
+}
+
+func op2Div(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       n, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       return vm.pushInt64(n>>1, true)
+}
+
+func opNegate(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       n, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       res, ok := checked.NegateInt64(n)
+       if !ok {
+               return ErrRange
+       }
+       return vm.pushInt64(res, true)
+}
+
+func opAbs(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       n, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       if n == math.MinInt64 {
+               return ErrRange
+       }
+       if n < 0 {
+               n = -n
+       }
+       return vm.pushInt64(n, true)
+}
+
+func opNot(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       n, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       return vm.pushBool(n == 0, true)
+}
+
+func op0NotEqual(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       n, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       return vm.pushBool(n != 0, true)
+}
+
+func opAdd(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       y, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       x, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       res, ok := checked.AddInt64(x, y)
+       if !ok {
+               return ErrRange
+       }
+       return vm.pushInt64(res, true)
+}
+
+func opSub(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       y, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       x, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       res, ok := checked.SubInt64(x, y)
+       if !ok {
+               return ErrRange
+       }
+       return vm.pushInt64(res, true)
+}
+
+func opMul(vm *virtualMachine) error {
+       err := vm.applyCost(8)
+       if err != nil {
+               return err
+       }
+       y, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       x, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       res, ok := checked.MulInt64(x, y)
+       if !ok {
+               return ErrRange
+       }
+       return vm.pushInt64(res, true)
+}
+
+func opDiv(vm *virtualMachine) error {
+       err := vm.applyCost(8)
+       if err != nil {
+               return err
+       }
+       y, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       x, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       if y == 0 {
+               return ErrDivZero
+       }
+       res, ok := checked.DivInt64(x, y)
+       if !ok {
+               return ErrRange
+       }
+       return vm.pushInt64(res, true)
+}
+
+func opMod(vm *virtualMachine) error {
+       err := vm.applyCost(8)
+       if err != nil {
+               return err
+       }
+       y, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       x, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       if y == 0 {
+               return ErrDivZero
+       }
+
+       res, ok := checked.ModInt64(x, y)
+       if !ok {
+               return ErrRange
+       }
+
+       // Go's modulus operator produces the wrong result for mixed-sign
+       // operands
+       if res != 0 && (x >= 0) != (y >= 0) {
+               res += y
+       }
+
+       return vm.pushInt64(res, true)
+}
+
+func opLshift(vm *virtualMachine) error {
+       err := vm.applyCost(8)
+       if err != nil {
+               return err
+       }
+       y, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       if y < 0 {
+               return ErrBadValue
+       }
+       x, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       if x == 0 || y == 0 {
+               return vm.pushInt64(x, true)
+       }
+
+       res, ok := checked.LshiftInt64(x, y)
+       if !ok {
+               return ErrRange
+       }
+
+       return vm.pushInt64(res, true)
+}
+
+func opRshift(vm *virtualMachine) error {
+       err := vm.applyCost(8)
+       if err != nil {
+               return err
+       }
+       y, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       x, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       if y < 0 {
+               return ErrBadValue
+       }
+       return vm.pushInt64(x>>uint64(y), true)
+}
+
+func opBoolAnd(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       b, err := vm.pop(true)
+       if err != nil {
+               return err
+       }
+       a, err := vm.pop(true)
+       if err != nil {
+               return err
+       }
+       return vm.pushBool(AsBool(a) && AsBool(b), true)
+}
+
+func opBoolOr(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       b, err := vm.pop(true)
+       if err != nil {
+               return err
+       }
+       a, err := vm.pop(true)
+       if err != nil {
+               return err
+       }
+       return vm.pushBool(AsBool(a) || AsBool(b), true)
+}
+
+const (
+       cmpLess = iota
+       cmpLessEqual
+       cmpGreater
+       cmpGreaterEqual
+       cmpEqual
+       cmpNotEqual
+)
+
+func opNumEqual(vm *virtualMachine) error {
+       return doNumCompare(vm, cmpEqual)
+}
+
+func opNumEqualVerify(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       y, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       x, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       if x == y {
+               return nil
+       }
+       return ErrVerifyFailed
+}
+
+func opNumNotEqual(vm *virtualMachine) error {
+       return doNumCompare(vm, cmpNotEqual)
+}
+
+func opLessThan(vm *virtualMachine) error {
+       return doNumCompare(vm, cmpLess)
+}
+
+func opGreaterThan(vm *virtualMachine) error {
+       return doNumCompare(vm, cmpGreater)
+}
+
+func opLessThanOrEqual(vm *virtualMachine) error {
+       return doNumCompare(vm, cmpLessEqual)
+}
+
+func opGreaterThanOrEqual(vm *virtualMachine) error {
+       return doNumCompare(vm, cmpGreaterEqual)
+}
+
+func doNumCompare(vm *virtualMachine, op int) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       y, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       x, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       var res bool
+       switch op {
+       case cmpLess:
+               res = x < y
+       case cmpLessEqual:
+               res = x <= y
+       case cmpGreater:
+               res = x > y
+       case cmpGreaterEqual:
+               res = x >= y
+       case cmpEqual:
+               res = x == y
+       case cmpNotEqual:
+               res = x != y
+       }
+       return vm.pushBool(res, true)
+}
+
+func opMin(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       y, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       x, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       if x > y {
+               x = y
+       }
+       return vm.pushInt64(x, true)
+}
+
+func opMax(vm *virtualMachine) error {
+       err := vm.applyCost(2)
+       if err != nil {
+               return err
+       }
+       y, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       x, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       if x < y {
+               x = y
+       }
+       return vm.pushInt64(x, true)
+}
+
+func opWithin(vm *virtualMachine) error {
+       err := vm.applyCost(4)
+       if err != nil {
+               return err
+       }
+       max, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       min, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       x, err := vm.popInt64(true)
+       if err != nil {
+               return err
+       }
+       return vm.pushBool(x >= min && x < max, true)
+}