OSDN Git Service

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