github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/protocol/vm/numeric.go (about)

     1  package vm
     2  
     3  import (
     4  	"math"
     5  
     6  	"github.com/bytom/bytom/math/checked"
     7  )
     8  
     9  func op1Add(vm *virtualMachine) error {
    10  	err := vm.applyCost(2)
    11  	if err != nil {
    12  		return err
    13  	}
    14  	n, err := vm.popInt64(true)
    15  	if err != nil {
    16  		return err
    17  	}
    18  	res, ok := checked.AddInt64(n, 1)
    19  	if !ok {
    20  		return ErrRange
    21  	}
    22  	return vm.pushInt64(res, true)
    23  }
    24  
    25  func op1Sub(vm *virtualMachine) error {
    26  	err := vm.applyCost(2)
    27  	if err != nil {
    28  		return err
    29  	}
    30  	n, err := vm.popInt64(true)
    31  	if err != nil {
    32  		return err
    33  	}
    34  	res, ok := checked.SubInt64(n, 1)
    35  	if !ok {
    36  		return ErrRange
    37  	}
    38  	return vm.pushInt64(res, true)
    39  }
    40  
    41  func op2Mul(vm *virtualMachine) error {
    42  	err := vm.applyCost(2)
    43  	if err != nil {
    44  		return err
    45  	}
    46  	n, err := vm.popInt64(true)
    47  	if err != nil {
    48  		return err
    49  	}
    50  	res, ok := checked.MulInt64(n, 2)
    51  	if !ok {
    52  		return ErrRange
    53  	}
    54  	return vm.pushInt64(res, true)
    55  }
    56  
    57  func op2Div(vm *virtualMachine) error {
    58  	err := vm.applyCost(2)
    59  	if err != nil {
    60  		return err
    61  	}
    62  	n, err := vm.popInt64(true)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	return vm.pushInt64(n>>1, true)
    67  }
    68  
    69  func opNegate(vm *virtualMachine) error {
    70  	err := vm.applyCost(2)
    71  	if err != nil {
    72  		return err
    73  	}
    74  	n, err := vm.popInt64(true)
    75  	if err != nil {
    76  		return err
    77  	}
    78  	res, ok := checked.NegateInt64(n)
    79  	if !ok {
    80  		return ErrRange
    81  	}
    82  	return vm.pushInt64(res, true)
    83  }
    84  
    85  func opAbs(vm *virtualMachine) error {
    86  	err := vm.applyCost(2)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	n, err := vm.popInt64(true)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	if n == math.MinInt64 {
    95  		return ErrRange
    96  	}
    97  	if n < 0 {
    98  		n = -n
    99  	}
   100  	return vm.pushInt64(n, true)
   101  }
   102  
   103  func opNot(vm *virtualMachine) error {
   104  	err := vm.applyCost(2)
   105  	if err != nil {
   106  		return err
   107  	}
   108  	n, err := vm.popInt64(true)
   109  	if err != nil {
   110  		return err
   111  	}
   112  	return vm.pushBool(n == 0, true)
   113  }
   114  
   115  func op0NotEqual(vm *virtualMachine) error {
   116  	err := vm.applyCost(2)
   117  	if err != nil {
   118  		return err
   119  	}
   120  	n, err := vm.popInt64(true)
   121  	if err != nil {
   122  		return err
   123  	}
   124  	return vm.pushBool(n != 0, true)
   125  }
   126  
   127  func opAdd(vm *virtualMachine) error {
   128  	err := vm.applyCost(2)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	y, err := vm.popInt64(true)
   133  	if err != nil {
   134  		return err
   135  	}
   136  	x, err := vm.popInt64(true)
   137  	if err != nil {
   138  		return err
   139  	}
   140  	res, ok := checked.AddInt64(x, y)
   141  	if !ok {
   142  		return ErrRange
   143  	}
   144  	return vm.pushInt64(res, true)
   145  }
   146  
   147  func opSub(vm *virtualMachine) error {
   148  	err := vm.applyCost(2)
   149  	if err != nil {
   150  		return err
   151  	}
   152  	y, err := vm.popInt64(true)
   153  	if err != nil {
   154  		return err
   155  	}
   156  	x, err := vm.popInt64(true)
   157  	if err != nil {
   158  		return err
   159  	}
   160  	res, ok := checked.SubInt64(x, y)
   161  	if !ok {
   162  		return ErrRange
   163  	}
   164  	return vm.pushInt64(res, true)
   165  }
   166  
   167  func opMul(vm *virtualMachine) error {
   168  	err := vm.applyCost(8)
   169  	if err != nil {
   170  		return err
   171  	}
   172  	y, err := vm.popInt64(true)
   173  	if err != nil {
   174  		return err
   175  	}
   176  	x, err := vm.popInt64(true)
   177  	if err != nil {
   178  		return err
   179  	}
   180  	res, ok := checked.MulInt64(x, y)
   181  	if !ok {
   182  		return ErrRange
   183  	}
   184  	return vm.pushInt64(res, true)
   185  }
   186  
   187  func opDiv(vm *virtualMachine) error {
   188  	err := vm.applyCost(8)
   189  	if err != nil {
   190  		return err
   191  	}
   192  	y, err := vm.popInt64(true)
   193  	if err != nil {
   194  		return err
   195  	}
   196  	x, err := vm.popInt64(true)
   197  	if err != nil {
   198  		return err
   199  	}
   200  	if y == 0 {
   201  		return ErrDivZero
   202  	}
   203  	res, ok := checked.DivInt64(x, y)
   204  	if !ok {
   205  		return ErrRange
   206  	}
   207  	return vm.pushInt64(res, true)
   208  }
   209  
   210  func opMod(vm *virtualMachine) error {
   211  	err := vm.applyCost(8)
   212  	if err != nil {
   213  		return err
   214  	}
   215  	y, err := vm.popInt64(true)
   216  	if err != nil {
   217  		return err
   218  	}
   219  	x, err := vm.popInt64(true)
   220  	if err != nil {
   221  		return err
   222  	}
   223  	if y == 0 {
   224  		return ErrDivZero
   225  	}
   226  
   227  	res, ok := checked.ModInt64(x, y)
   228  	if !ok {
   229  		return ErrRange
   230  	}
   231  
   232  	// Go's modulus operator produces the wrong result for mixed-sign
   233  	// operands
   234  	if res != 0 && (x >= 0) != (y >= 0) {
   235  		res += y
   236  	}
   237  
   238  	return vm.pushInt64(res, true)
   239  }
   240  
   241  func opLshift(vm *virtualMachine) error {
   242  	err := vm.applyCost(8)
   243  	if err != nil {
   244  		return err
   245  	}
   246  	y, err := vm.popInt64(true)
   247  	if err != nil {
   248  		return err
   249  	}
   250  	if y < 0 {
   251  		return ErrBadValue
   252  	}
   253  	x, err := vm.popInt64(true)
   254  	if err != nil {
   255  		return err
   256  	}
   257  	if x == 0 || y == 0 {
   258  		return vm.pushInt64(x, true)
   259  	}
   260  
   261  	res, ok := checked.LshiftInt64(x, y)
   262  	if !ok {
   263  		return ErrRange
   264  	}
   265  
   266  	return vm.pushInt64(res, true)
   267  }
   268  
   269  func opRshift(vm *virtualMachine) error {
   270  	err := vm.applyCost(8)
   271  	if err != nil {
   272  		return err
   273  	}
   274  	y, err := vm.popInt64(true)
   275  	if err != nil {
   276  		return err
   277  	}
   278  	x, err := vm.popInt64(true)
   279  	if err != nil {
   280  		return err
   281  	}
   282  	if y < 0 {
   283  		return ErrBadValue
   284  	}
   285  	return vm.pushInt64(x>>uint64(y), true)
   286  }
   287  
   288  func opBoolAnd(vm *virtualMachine) error {
   289  	err := vm.applyCost(2)
   290  	if err != nil {
   291  		return err
   292  	}
   293  	b, err := vm.pop(true)
   294  	if err != nil {
   295  		return err
   296  	}
   297  	a, err := vm.pop(true)
   298  	if err != nil {
   299  		return err
   300  	}
   301  	return vm.pushBool(AsBool(a) && AsBool(b), true)
   302  }
   303  
   304  func opBoolOr(vm *virtualMachine) error {
   305  	err := vm.applyCost(2)
   306  	if err != nil {
   307  		return err
   308  	}
   309  	b, err := vm.pop(true)
   310  	if err != nil {
   311  		return err
   312  	}
   313  	a, err := vm.pop(true)
   314  	if err != nil {
   315  		return err
   316  	}
   317  	return vm.pushBool(AsBool(a) || AsBool(b), true)
   318  }
   319  
   320  const (
   321  	cmpLess = iota
   322  	cmpLessEqual
   323  	cmpGreater
   324  	cmpGreaterEqual
   325  	cmpEqual
   326  	cmpNotEqual
   327  )
   328  
   329  func opNumEqual(vm *virtualMachine) error {
   330  	return doNumCompare(vm, cmpEqual)
   331  }
   332  
   333  func opNumEqualVerify(vm *virtualMachine) error {
   334  	err := vm.applyCost(2)
   335  	if err != nil {
   336  		return err
   337  	}
   338  	y, err := vm.popInt64(true)
   339  	if err != nil {
   340  		return err
   341  	}
   342  	x, err := vm.popInt64(true)
   343  	if err != nil {
   344  		return err
   345  	}
   346  	if x == y {
   347  		return nil
   348  	}
   349  	return ErrVerifyFailed
   350  }
   351  
   352  func opNumNotEqual(vm *virtualMachine) error {
   353  	return doNumCompare(vm, cmpNotEqual)
   354  }
   355  
   356  func opLessThan(vm *virtualMachine) error {
   357  	return doNumCompare(vm, cmpLess)
   358  }
   359  
   360  func opGreaterThan(vm *virtualMachine) error {
   361  	return doNumCompare(vm, cmpGreater)
   362  }
   363  
   364  func opLessThanOrEqual(vm *virtualMachine) error {
   365  	return doNumCompare(vm, cmpLessEqual)
   366  }
   367  
   368  func opGreaterThanOrEqual(vm *virtualMachine) error {
   369  	return doNumCompare(vm, cmpGreaterEqual)
   370  }
   371  
   372  func doNumCompare(vm *virtualMachine, op int) error {
   373  	err := vm.applyCost(2)
   374  	if err != nil {
   375  		return err
   376  	}
   377  	y, err := vm.popInt64(true)
   378  	if err != nil {
   379  		return err
   380  	}
   381  	x, err := vm.popInt64(true)
   382  	if err != nil {
   383  		return err
   384  	}
   385  	var res bool
   386  	switch op {
   387  	case cmpLess:
   388  		res = x < y
   389  	case cmpLessEqual:
   390  		res = x <= y
   391  	case cmpGreater:
   392  		res = x > y
   393  	case cmpGreaterEqual:
   394  		res = x >= y
   395  	case cmpEqual:
   396  		res = x == y
   397  	case cmpNotEqual:
   398  		res = x != y
   399  	}
   400  	return vm.pushBool(res, true)
   401  }
   402  
   403  func opMin(vm *virtualMachine) error {
   404  	err := vm.applyCost(2)
   405  	if err != nil {
   406  		return err
   407  	}
   408  	y, err := vm.popInt64(true)
   409  	if err != nil {
   410  		return err
   411  	}
   412  	x, err := vm.popInt64(true)
   413  	if err != nil {
   414  		return err
   415  	}
   416  	if x > y {
   417  		x = y
   418  	}
   419  	return vm.pushInt64(x, true)
   420  }
   421  
   422  func opMax(vm *virtualMachine) error {
   423  	err := vm.applyCost(2)
   424  	if err != nil {
   425  		return err
   426  	}
   427  	y, err := vm.popInt64(true)
   428  	if err != nil {
   429  		return err
   430  	}
   431  	x, err := vm.popInt64(true)
   432  	if err != nil {
   433  		return err
   434  	}
   435  	if x < y {
   436  		x = y
   437  	}
   438  	return vm.pushInt64(x, true)
   439  }
   440  
   441  func opWithin(vm *virtualMachine) error {
   442  	err := vm.applyCost(4)
   443  	if err != nil {
   444  		return err
   445  	}
   446  	max, err := vm.popInt64(true)
   447  	if err != nil {
   448  		return err
   449  	}
   450  	min, err := vm.popInt64(true)
   451  	if err != nil {
   452  		return err
   453  	}
   454  	x, err := vm.popInt64(true)
   455  	if err != nil {
   456  		return err
   457  	}
   458  	return vm.pushBool(x >= min && x < max, true)
   459  }