OSDN Git Service

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