Coverage Summary for Class: VM (org.ethereum.vm)
Class |
Method, %
|
Line, %
|
VM |
43.9%
(43/98)
|
33.2%
(369/1113)
|
VM$1 |
0%
(0/1)
|
0%
(0/1)
|
Total |
43.4%
(43/99)
|
33.1%
(369/1114)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 RSK Labs Ltd.
4 * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 package org.ethereum.vm;
21
22 import co.rsk.config.VmConfig;
23 import co.rsk.core.RskAddress;
24 import co.rsk.crypto.Keccak256;
25 import org.bouncycastle.util.BigIntegers;
26 import org.ethereum.config.blockchain.upgrades.ActivationConfig;
27 import org.ethereum.core.Repository;
28 import org.ethereum.crypto.HashUtil;
29 import org.ethereum.crypto.Keccak256Helper;
30 import org.ethereum.util.ByteUtil;
31 import org.ethereum.vm.MessageCall.MsgType;
32 import org.ethereum.vm.program.Program;
33 import org.ethereum.vm.program.Stack;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import java.math.BigInteger;
38 import java.util.ArrayList;
39 import java.util.Iterator;
40 import java.util.List;
41
42 import static org.ethereum.config.blockchain.upgrades.ConsensusRule.*;
43 import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
44 import static org.ethereum.vm.OpCode.CALL;
45
46
47 /**
48 * The Ethereum Virtual Machine (EVM) is responsible for initialization
49 * and executing a transaction on a contract.
50 *
51 * It is a quasi-Turing-complete machine; the quasi qualification
52 * comes from the fact that the computation is intrinsically bounded
53 * through a parameter, gas, which limits the total amount of computation done.
54 *
55 * The EVM is a simple stack-based architecture. The word size of the machine
56 * (and thus size of stack item) is 256-bit. This was chosen to facilitate
57 * the SHA3-256 hash scheme and elliptic-curve computations. The memory model
58 * is a simple word-addressed byte array. The stack has an unlimited size.
59 * The machine also has an independent storage model; this is similar in concept
60 * to the memory but rather than a byte array, it is a word-addressable word array.
61 *
62 * Unlike memory, which is volatile, storage is non volatile and is
63 * maintained as part of the system state. All locations in both storage
64 * and memory are well-defined initially as zero.
65 *
66 * The machine does not follow the standard von Neumann architecture.
67 * Rather than storing program code in generally-accessible memory or storage,
68 * it is stored separately in a virtual ROM interactable only though
69 * a specialised instruction.
70 *
71 * The machine can have exceptional execution for several reasons,
72 * including stack underflows and invalid instructions. These unambiguously
73 * and validly result in immediate halting of the machine with all state changes
74 * left intact. The one piece of exceptional execution that does not leave
75 * state changes intact is the out-of-gas (OOG) exception.
76 *
77 * Here, the machine halts immediately and reports the issue to
78 * the execution agent (either the transaction processor or, recursively,
79 * the spawning execution environment) and which will deal with it separately.
80 *
81 * @author Roman Mandeleil
82 * @since 01.06.2014
83 */
84 public class VM {
85
86 private static final Logger logger = LoggerFactory.getLogger("VM");
87 private static final Logger dumpLogger = LoggerFactory.getLogger("dump");
88 private static final String logString = "{} Op: [{}] Gas: [{}] Deep: [{}] Hint: [{}]";
89 private static final boolean computeGas = true; // for performance comp
90
91 /* Keeps track of the number of steps performed in this VM */
92 private int vmCounter = 0;
93
94 private static VMHook vmHook;
95
96 private final VmConfig vmConfig;
97 private final PrecompiledContracts precompiledContracts;
98
99 // Execution variables
100 private Program program;
101 private Stack stack;
102 private OpCode op;
103 private long oldMemSize ;
104
105 private String hint ;
106
107 private long memWords; // parameters for logging
108 private long gasCost;
109 private long gasBefore; // only for tracing
110 private boolean isLogEnabled;
111
112 public VM(VmConfig vmConfig, PrecompiledContracts precompiledContracts) {
113 this.vmConfig = vmConfig;
114 this.precompiledContracts = precompiledContracts;
115 isLogEnabled = logger.isInfoEnabled();
116 }
117
118 private void checkSizeArgument(long size) {
119 if (size > Program.MAX_MEMORY) { // Force exception
120 throw Program.ExceptionHelper.notEnoughOpGas(program, op, Long.MAX_VALUE, program.getRemainingGas());
121 }
122 }
123
124 private long calcMemGas(long oldMemSize, long newMemSize, long copySize) {
125 long currentGasCost = 0;
126
127 // Avoid overflows
128 checkSizeArgument(newMemSize);
129
130 // memory gas calc
131 // newMemSize has only 30 significant digits.
132 // Because of quadratic cost, we'll limit the maximim memSize to 30 bits = 2^30 = 1 GB.
133
134 // This comparison assumes (oldMemSize % 32 == 0)
135 if (newMemSize > oldMemSize) { // optimization to avoid div/mul
136 long memoryUsage = (newMemSize+31) / 32 * 32; // rounds up
137
138 if (memoryUsage > oldMemSize) {
139 memWords = (memoryUsage / 32); // 25 sig digits
140 long memWordsOld = (oldMemSize / 32);
141 long memGas;
142
143 // MemWords*MemWords has 50 sig digits, so this cannot overflow
144 memGas = GasCost.subtract(
145 GasCost.add(
146 GasCost.multiply(GasCost.MEMORY, memWords),
147 GasCost.multiply(memWords, memWords) / 512
148 ),
149 GasCost.add(
150 GasCost.multiply(GasCost.MEMORY, memWordsOld),
151 GasCost.multiply(memWordsOld, memWordsOld) / 512
152 )
153 );
154 currentGasCost = GasCost.add(currentGasCost, memGas);
155 }
156 }
157
158 // copySize is invalid if newMemSize > 2^63, but it only gets here if newMemSize is <= 2^30
159 if (copySize > 0) {
160 long copyGas = GasCost.multiply(GasCost.COPY_GAS, GasCost.add(copySize, 31) / 32);
161 currentGasCost = GasCost.add(currentGasCost, copyGas);
162 }
163
164 return currentGasCost;
165 }
166
167 public void step(Program aprogram) {
168 steps(aprogram,1);
169 }
170
171 public int getVmCounter() { // for profiling only
172 return vmCounter;
173 }
174
175 public void resetVmCounter() { // for profiling only
176 vmCounter =0;
177 }
178
179 protected void checkOpcode() {
180 if (op == null) {
181 throw Program.ExceptionHelper.invalidOpCode(program);
182 }
183 if (op.scriptVersion() > program.getScriptVersion()) {
184 throw Program.ExceptionHelper.invalidOpCode(program);
185 }
186
187 }
188
189 public static long limitedAddToMaxLong(long left, long right) {
190 try {
191 return Math.addExact(left, right);
192 } catch (ArithmeticException e) {
193 return Long.MAX_VALUE;
194 }
195 }
196
197 protected void spendOpCodeGas() {
198 if (!computeGas) {
199 return;
200 }
201
202 program.spendGas(gasCost, op.name());
203 }
204
205 protected void doSTOP() {
206 if (computeGas) {
207 gasCost = GasCost.STOP;
208 spendOpCodeGas();
209 }
210
211 // EXECUTION PHASE
212 program.setHReturn(EMPTY_BYTE_ARRAY);
213 program.stop();
214 }
215
216 protected void doADD() {
217 spendOpCodeGas();
218 // EXECUTION PHASE
219 DataWord word1 = program.stackPop();
220 DataWord word2 = program.stackPop();
221
222 if (isLogEnabled) {
223 hint = word1.value() + " + " + word2.value();
224 }
225
226 program.stackPush(word1.add(word2));
227 program.step();
228
229 }
230
231 protected void doMUL() {
232 spendOpCodeGas();
233 // EXECUTION PHASE
234 DataWord word1 = program.stackPop();
235 DataWord word2 = program.stackPop();
236
237 if (isLogEnabled) {
238 hint = word1.value() + " * " + word2.value();
239 }
240
241 program.stackPush(word1.mul(word2));
242 program.step();
243 }
244
245 protected void doSUB() {
246 spendOpCodeGas();
247 // EXECUTION PHASE
248 DataWord word1 = program.stackPop();
249 DataWord word2 = program.stackPop();
250
251 if (isLogEnabled) {
252 hint = word1.value() + " - " + word2.value();
253 }
254
255 program.stackPush(word1.sub(word2));
256 program.step();
257 }
258
259 protected void doDIV() {
260 spendOpCodeGas();
261 // EXECUTION PHASE
262 DataWord word1 = program.stackPop();
263 DataWord word2 = program.stackPop();
264
265 if (isLogEnabled) {
266 hint = word1.value() + " / " + word2.value();
267 }
268
269 program.stackPush(word1.div(word2));
270 program.step();
271 }
272
273 protected void doSDIV() {
274 spendOpCodeGas();
275 // EXECUTION PHASE
276 DataWord word1 = program.stackPop();
277 DataWord word2 = program.stackPop();
278
279 if (isLogEnabled) {
280 hint = word1.sValue() + " / " + word2.sValue();
281 }
282
283 program.stackPush(word1.sDiv(word2));
284 program.step();
285 }
286
287 protected void doMOD() {
288 spendOpCodeGas();
289 // EXECUTION PHASE
290 DataWord word1 = program.stackPop();
291 DataWord word2 = program.stackPop();
292
293 if (isLogEnabled) {
294 hint = word1.value() + " % " + word2.value();
295 }
296
297 program.stackPush(word1.mod(word2));
298 program.step();
299 }
300
301 protected void doSMOD() {
302 spendOpCodeGas();
303 // EXECUTION PHASE
304 DataWord word1 = program.stackPop();
305 DataWord word2 = program.stackPop();
306
307 if (isLogEnabled) {
308 hint = word1.sValue() + " #% " + word2.sValue();
309 }
310
311 program.stackPush(word1.sMod(word2));
312 program.step();
313 }
314
315 protected void doEXP() {
316 if (computeGas) {
317 DataWord exp = stack.get(stack.size() - 2);
318 int bytesOccupied = exp.bytesOccupied();
319 gasCost = GasCost.calculateTotal(GasCost.EXP_GAS, GasCost.EXP_BYTE_GAS, bytesOccupied);
320 }
321 spendOpCodeGas();
322 // EXECUTION PHASE
323 DataWord word1 = program.stackPop();
324 DataWord word2 = program.stackPop();
325
326 if (isLogEnabled) {
327 hint = word1.value() + " ** " + word2.value();
328 }
329
330 program.stackPush(word1.exp(word2));
331 program.step();
332 }
333
334 protected void doSIGNEXTEND() {
335 spendOpCodeGas();
336 // EXECUTION PHASE
337 DataWord word1 = program.stackPop();
338 long k = Program.limitToMaxLong(word1);
339
340 if (k<32) {
341 DataWord word2 = program.stackPop();
342 if (isLogEnabled) {
343 hint = word1 + " " + word2.value();
344 }
345
346 program.stackPush(word2.signExtend((byte) k));
347 }
348
349 program.step();
350 }
351
352 protected void doNOT() {
353 spendOpCodeGas();
354 // EXECUTION PHASE
355 DataWord word1 = program.stackPop().bnot();
356
357 if (isLogEnabled) {
358 hint = "" + word1.value();
359 }
360
361 program.stackPush(word1);
362 program.step();
363 }
364
365 protected void doLT() {
366 spendOpCodeGas();
367 // EXECUTION PHASE
368 // TODO: can be improved by not using BigInteger
369 DataWord word1 = program.stackPop();
370 DataWord word2 = program.stackPop();
371
372 if (isLogEnabled) {
373 hint = word1.value() + " < " + word2.value();
374 }
375
376 // TODO: We should compare the performance of BigInteger comparison with DataWord comparison:
377 if (word1.compareTo(word2) < 0) {
378 program.stackPush(DataWord.ONE);
379 } else {
380 program.stackPush(DataWord.ZERO);
381 }
382 program.step();
383 }
384
385 protected void doSLT() {
386 spendOpCodeGas();
387 // EXECUTION PHASE
388 // TODO: can be improved by not using BigInteger
389 DataWord word1 = program.stackPop();
390 DataWord word2 = program.stackPop();
391
392 if (isLogEnabled) {
393 hint = word1.sValue() + " < " + word2.sValue();
394 }
395
396 if (word1.sValue().compareTo(word2.sValue()) < 0) {
397 program.stackPush(DataWord.ONE);
398 } else {
399 program.stackPush(DataWord.ZERO);
400 }
401 program.step();
402 }
403
404 protected void doSGT() {
405 spendOpCodeGas();
406 // EXECUTION PHASE
407 // TODO: can be improved by not using BigInteger
408 DataWord word1 = program.stackPop();
409 DataWord word2 = program.stackPop();
410
411 if (isLogEnabled) {
412 hint = word1.sValue() + " > " + word2.sValue();
413 }
414
415 if (word1.sValue().compareTo(word2.sValue()) > 0) {
416 program.stackPush(DataWord.ONE);
417 } else {
418 program.stackPush(DataWord.ZERO);
419 }
420 program.step();
421 }
422
423 protected void doGT() {
424 spendOpCodeGas();
425 // EXECUTION PHASE
426 // TODO: can be improved by not using BigInteger
427 DataWord word1 = program.stackPop();
428 DataWord word2 = program.stackPop();
429
430 if (isLogEnabled) {
431 hint = word1.value() + " > " + word2.value();
432 }
433
434 if (word1.value().compareTo(word2.value()) > 0) {
435 program.stackPush(DataWord.ONE);
436 } else {
437 program.stackPush(DataWord.ZERO);
438 }
439
440 program.step();
441 }
442
443 protected void doEQ() {
444 spendOpCodeGas();
445 // EXECUTION PHASE
446 DataWord word1 = program.stackPop();
447 DataWord word2 = program.stackPop();
448
449 if (isLogEnabled) {
450 hint = word1.value() + " == " + word2.value();
451 }
452
453 if (word1.equalValue(word2)) {
454 program.stackPush(DataWord.ONE);
455 } else {
456 program.stackPush(DataWord.ZERO);
457 }
458
459 program.step();
460 }
461
462 protected void doISZERO() {
463 spendOpCodeGas();
464 // EXECUTION PHASE
465 DataWord word1 = program.stackPop();
466
467 DataWord result = word1.isZero() ? DataWord.ONE : DataWord.ZERO;
468
469 if (isLogEnabled) {
470 hint = "" + result.value();
471 }
472
473 program.stackPush(result);
474 program.step();
475 }
476
477 protected void doAND(){
478 spendOpCodeGas();
479 // EXECUTION PHASE
480 DataWord word1 = program.stackPop();
481 DataWord word2 = program.stackPop();
482
483 if (isLogEnabled) {
484 hint = word1.value() + " && " + word2.value();
485 }
486
487 program.stackPush(word1.and(word2));
488 program.step();
489 }
490
491 protected void doOR(){
492 spendOpCodeGas();
493 // EXECUTION PHASE
494 DataWord word1 = program.stackPop();
495 DataWord word2 = program.stackPop();
496
497 if (isLogEnabled) {
498 hint = word1.value() + " || " + word2.value();
499 }
500
501 program.stackPush(word1.or(word2));
502 program.step();
503 }
504
505 protected void doXOR(){
506 spendOpCodeGas();
507 // EXECUTION PHASE
508 DataWord word1 = program.stackPop();
509 DataWord word2 = program.stackPop();
510
511 if (isLogEnabled) {
512 hint = word1.value() + " ^ " + word2.value();
513 }
514
515 program.stackPush(word1.xor(word2));
516 program.step();
517 }
518
519 protected void doBYTE() {
520 spendOpCodeGas();
521 // EXECUTION PHASE
522 DataWord word1 = program.stackPop();
523 DataWord word2 = program.stackPop();
524 final DataWord result;
525 long wvalue = Program.limitToMaxLong(word1);
526 if (wvalue<32) {
527 byte tmp = word2.getData()[(int) wvalue];
528 byte[] newdata = new byte[32];
529 newdata[31] = tmp;
530 result = DataWord.valueOf(newdata);
531 } else {
532 result = DataWord.ZERO;
533 }
534
535 if (isLogEnabled) {
536 hint = "" + result.value();
537 }
538
539 program.stackPush(result);
540 program.step();
541 }
542
543 protected void doSHL() {
544 spendOpCodeGas();
545 // EXECUTION PHASE
546 DataWord word1 = program.stackPop();
547 DataWord word2 = program.stackPop();
548
549 if (isLogEnabled) {
550 hint = word1.value() + " << " + word2.value();
551 }
552
553 program.stackPush(word2.shiftLeft(word1));
554 program.step();
555
556 }
557
558 protected void doSHR() {
559 spendOpCodeGas();
560 // EXECUTION PHASE
561 DataWord word1 = program.stackPop();
562 DataWord word2 = program.stackPop();
563
564 if (isLogEnabled) {
565 hint = word1.value() + " >> " + word2.value();
566 }
567
568 program.stackPush(word2.shiftRight(word1));
569 program.step();
570
571 }
572
573 protected void doSAR() {
574 spendOpCodeGas();
575 // EXECUTION PHASE
576 DataWord word1 = program.stackPop();
577 DataWord word2 = program.stackPop();
578
579 if (isLogEnabled) {
580 hint = word1.value() + " >> " + word2.value();
581 }
582
583 program.stackPush(word2.shiftRightSigned(word1));
584 program.step();
585
586 }
587
588 protected void doADDMOD() {
589 spendOpCodeGas();
590 // EXECUTION PHASE
591 DataWord word1 = program.stackPop();
592 DataWord word2 = program.stackPop();
593 DataWord word3 = program.stackPop();
594 program.stackPush(word1.addmod(word2, word3));
595 program.step();
596 }
597
598 protected void doMULMOD() {
599 spendOpCodeGas();
600 // EXECUTION PHASE
601 DataWord word1 = program.stackPop();
602 DataWord word2 = program.stackPop();
603 DataWord word3 = program.stackPop();
604 program.stackPush(word1.mulmod(word2, word3));
605 program.step();
606 }
607
608 protected void doSHA3() {
609 DataWord size;
610 long sizeLong;
611 long newMemSize ;
612 if (computeGas) {
613 gasCost = GasCost.SHA3;
614 size = stack.get(stack.size() - 2);
615 sizeLong = Program.limitToMaxLong(size);
616 checkSizeArgument(sizeLong);
617 newMemSize = memNeeded(stack.peek(), sizeLong);
618 long chunkUsed = (sizeLong + 31) / 32;
619 gasCost = GasCost.calculateTotal(gasCost, GasCost.SHA3_WORD, chunkUsed);
620 gasCost = GasCost.add(gasCost, calcMemGas(oldMemSize, newMemSize, 0));
621
622 spendOpCodeGas();
623 }
624 // EXECUTION PHASE
625 DataWord memOffsetData = program.stackPop();
626 DataWord lengthData = program.stackPop();
627 byte[] buffer = program.memoryChunk(memOffsetData.intValue(), lengthData.intValue());
628
629 byte[] encoded = HashUtil.keccak256(buffer);
630 DataWord word = DataWord.valueOf(encoded);
631
632 if (isLogEnabled) {
633 hint = word.toString();
634 }
635
636 program.stackPush(word);
637 program.step();
638 }
639
640 protected void doADDRESS() {
641 spendOpCodeGas();
642 // EXECUTION PHASE
643 DataWord address = program.getOwnerAddress();
644
645 if (isLogEnabled) {
646 hint = "address: " + ByteUtil.toHexString(address.getLast20Bytes());
647 }
648
649 program.stackPush(address);
650 program.step();
651 }
652
653 protected void doBALANCE() {
654 if (computeGas) {
655 gasCost = GasCost.BALANCE;
656 spendOpCodeGas();
657 }
658 // EXECUTION PHASE
659 DataWord address = program.stackPop();
660 DataWord balance = program.getBalance(address); // TODO: should not allocate
661
662 if (isLogEnabled) {
663 hint = "address: "
664 + ByteUtil.toHexString(address.getLast20Bytes())
665 + " balance: " + balance.toString();
666 }
667
668 program.stackPush(balance);
669 program.step();
670 }
671
672 protected void doORIGIN(){
673 spendOpCodeGas();
674 // EXECUTION PHASE
675 DataWord originAddress = program.getOriginAddress();
676
677 if (isLogEnabled) {
678 hint = "address: " + ByteUtil.toHexString(originAddress.getLast20Bytes());
679 }
680
681 program.stackPush(originAddress);
682 program.step();
683 }
684
685 protected void doCALLER() {
686 spendOpCodeGas();
687 // EXECUTION PHASE
688 DataWord callerAddress = program.getCallerAddress();
689
690 if (isLogEnabled) {
691 hint = "address: " + ByteUtil.toHexString(callerAddress.getLast20Bytes());
692 }
693
694 program.stackPush(callerAddress);
695 program.step();
696 }
697
698 protected void doCALLVALUE() {
699 spendOpCodeGas();
700 // EXECUTION PHASE
701 DataWord callValue = program.getCallValue();
702
703 if (isLogEnabled) {
704 hint = "value: " + callValue;
705 }
706
707 program.stackPush(callValue);
708 program.step();
709 }
710
711 protected void doCALLDATALOAD() {
712 spendOpCodeGas();
713 // EXECUTION PHASE
714 DataWord dataOffs = program.stackPop();
715 DataWord value = program.getDataValue(dataOffs);
716
717 if (isLogEnabled) {
718 hint = "data: " + value;
719 }
720
721 program.stackPush(value);
722 program.step();
723 }
724
725 protected void doCALLDATASIZE() {
726 spendOpCodeGas();
727 // EXECUTION PHASE
728 DataWord dataSize = program.getDataSize();
729
730 if (isLogEnabled) {
731 hint = "size: " + dataSize.value();
732 }
733
734 program.stackPush(dataSize);
735 program.step();
736 }
737
738 protected void doCALLDATACOPY() {
739 if (computeGas) {
740 gasCost = GasCost.add(gasCost, computeDataCopyGas());
741 spendOpCodeGas();
742 }
743 // EXECUTION PHASE
744 DataWord memOffsetData = program.stackPop();
745 DataWord dataOffsetData = program.stackPop();
746 DataWord lengthData = program.stackPop();
747
748 byte[] msgData = program.getDataCopy(dataOffsetData, lengthData);
749
750 if (isLogEnabled) {
751 hint = "data: " + ByteUtil.toHexString(msgData);
752 }
753
754 program.memorySave(memOffsetData.intValue(), msgData);
755 program.step();
756 }
757
758 private long computeDataCopyGas() {
759 DataWord size = stack.get(stack.size() - 3);
760 long copySize = Program.limitToMaxLong(size);
761 checkSizeArgument(copySize);
762 long newMemSize = memNeeded(stack.peek(), copySize);
763 return calcMemGas(oldMemSize, newMemSize, copySize);
764 }
765
766 protected void doCODESIZE() {
767 if (computeGas) {
768 if (op == OpCode.EXTCODESIZE) {
769 gasCost = GasCost.EXT_CODE_SIZE;
770 }
771 spendOpCodeGas();
772 }
773 // EXECUTION PHASE
774 DataWord codeLength;
775 if (op == OpCode.CODESIZE) {
776 codeLength = DataWord.valueOf(program.getCode().length); // during initialization it will return the initialization code size
777 } else {
778 DataWord address = program.stackPop();
779 codeLength = DataWord.valueOf(program.getCodeLengthAt(address));
780 ActivationConfig.ForBlock activations = program.getActivations();
781 if (activations.isActive(RSKIP90)) {
782 PrecompiledContracts.PrecompiledContract precompiledContract = precompiledContracts.getContractForAddress(activations, address);
783 if (precompiledContract != null) {
784 codeLength = DataWord.valueOf(BigIntegers.asUnsignedByteArray(DataWord.MAX_VALUE));
785 }
786 }
787 }
788 if (isLogEnabled) {
789 hint = "size: " + codeLength;
790 }
791 program.stackPush(codeLength);
792 program.step();
793 }
794
795 protected void doEXTCODEHASH() {
796 if (computeGas) {
797 gasCost = GasCost.EXT_CODE_HASH;
798 spendOpCodeGas();
799 }
800
801 //EXECUTION PHASE
802 DataWord address = program.stackPop();
803
804 ActivationConfig.ForBlock activations = program.getActivations();
805 PrecompiledContracts.PrecompiledContract precompiledContract = precompiledContracts.getContractForAddress(activations, address);
806 boolean isPrecompiledContract = precompiledContract != null;
807
808 if (isPrecompiledContract) {
809 byte[] emptyHash = Keccak256Helper.keccak256(EMPTY_BYTE_ARRAY);
810 program.stackPush(DataWord.valueOf(emptyHash));
811
812 if (isLogEnabled) {
813 hint = "hash: " + ByteUtil.toHexString(emptyHash);
814 }
815 } else {
816 Keccak256 codeHash = program.getCodeHashAt(address,activations.isActive(RSKIP169));
817 //If account does not exist, 0 is pushed in stack
818 if (codeHash.equals(Keccak256.ZERO_HASH)) {
819 program.stackPush(DataWord.ZERO);
820 } else {
821 DataWord word = DataWord.valueOf(codeHash.getBytes());
822 program.stackPush(word);
823 }
824
825 if (isLogEnabled) {
826 hint = "hash: " + codeHash.toHexString();
827 }
828 }
829
830 program.step();
831 }
832
833 protected void doCODECOPY() {
834 DataWord size;
835 long newMemSize ;
836 long copySize;
837 if (computeGas) {
838
839 if (op == OpCode.EXTCODECOPY) {
840 gasCost = GasCost.EXT_CODE_COPY;
841 size = stack.get(stack.size() - 4);
842 copySize = Program.limitToMaxLong(size);
843 checkSizeArgument(copySize);
844 newMemSize = memNeeded(stack.get(stack.size() - 2), copySize);
845 gasCost = GasCost.add(gasCost, calcMemGas(oldMemSize, newMemSize, copySize));
846 } else {
847 size = stack.get(stack.size() - 3);
848 copySize = Program.limitToMaxLong(size);
849 checkSizeArgument(copySize);
850 newMemSize = memNeeded(stack.peek(), copySize);
851 gasCost = GasCost.add(gasCost, calcMemGas(oldMemSize, newMemSize, copySize));
852 }
853 spendOpCodeGas();
854 }
855 // EXECUTION PHASE
856 // case OpCodes.opCODECOPY:
857 // case OpCodes.opEXTCODECOPY
858
859 byte[] fullCode = EMPTY_BYTE_ARRAY;
860 if (op == OpCode.CODECOPY) {
861 fullCode = program.getCode();
862 }
863
864 if (op == OpCode.EXTCODECOPY) {
865 DataWord address = program.stackPop();
866 fullCode = program.getCodeAt(address);
867 }
868
869 DataWord memOffsetDW = program.stackPop();
870 DataWord codeOffsetDW = program.stackPop();
871 DataWord lengthDataDW = program.stackPop();
872
873 // Here size/offsets fit in ints are assumed: this is consistent with
874 // maximum memory size, which is 1 GB (program.MAX_MEMORY)
875 int memOffset = memOffsetDW .intValueSafe();
876 int codeOffset = codeOffsetDW.intValueSafe(); // where to start reading
877 int lengthData = lengthDataDW.intValueSafe(); // amount of bytes to copy
878
879 int sizeToBeCopied;
880 if ((long) codeOffset + lengthData > fullCode.length) {
881 // if user wants to read more info from code what actual code has then..
882 // if all code that users wants lies after code has ended..
883 if (codeOffset >=fullCode.length) {
884 sizeToBeCopied=0; // do not copy anything
885 } else {
886 sizeToBeCopied = fullCode.length - codeOffset; // copy only the remaining
887 }
888
889 } else
890 // Code is longer, so limit by user length value
891 {
892 sizeToBeCopied =lengthData;
893 }
894
895 // The part not copied must be filled with zeros, so here we allocate
896 // enough space to contain filling also.
897 byte[] codeCopy = new byte[lengthData];
898
899 if (codeOffset < fullCode.length) {
900 System.arraycopy(fullCode, codeOffset, codeCopy, 0, sizeToBeCopied);
901 }
902
903 if (isLogEnabled) {
904 hint = "code: " + ByteUtil.toHexString(codeCopy);
905 }
906
907 // TODO: an optimization to avoid double-copying would be to override programSave
908 // to receive a byte[] buffer and a length, and to create another method memoryZero(offset,length)
909 // to fill the gap.
910 program.memorySave(memOffset, codeCopy);
911
912 program.step();
913 }
914
915 protected void doRETURNDATASIZE() {
916 spendOpCodeGas();
917 DataWord dataSize = program.getReturnDataBufferSize();
918 if (isLogEnabled) {
919 hint = "size: " + dataSize.value();
920 }
921 program.stackPush(dataSize);
922 program.step();
923 }
924
925 protected void doRETURNDATACOPY() {
926 if (computeGas) {
927 gasCost = GasCost.add(gasCost, computeDataCopyGas());
928 spendOpCodeGas();
929 }
930
931 DataWord memOffsetData = program.stackPop();
932 DataWord dataOffsetData = program.stackPop();
933 DataWord lengthData = program.stackPop();
934
935 byte[] msgData = program.getReturnDataBufferData(dataOffsetData, lengthData)
936 .orElseThrow(() -> {
937 long returnDataSize = program.getReturnDataBufferSize().longValueSafe();
938 return new RuntimeException(String.format(
939 "Illegal RETURNDATACOPY arguments: offset (%s) + size (%s) > RETURNDATASIZE (%d)",
940 dataOffsetData, lengthData, returnDataSize));
941 });
942
943 if (isLogEnabled) {
944 hint = "data: " + ByteUtil.toHexString(msgData);
945 }
946
947 program.memorySave(memOffsetData.intValueSafe(), msgData);
948 program.step();
949 }
950
951 protected void doGASPRICE(){
952 spendOpCodeGas();
953 // EXECUTION PHASE
954 DataWord gasPrice = program.getGasPrice();
955
956 if (isLogEnabled) {
957 hint = "price: " + gasPrice.toString();
958 }
959
960 program.stackPush(gasPrice);
961 program.step();
962 }
963
964 protected void doTXINDEX() {
965 spendOpCodeGas();
966 // EXECUTION PHASE
967
968 DataWord transactionIndex = program.getTransactionIndex();
969
970 if (isLogEnabled) {
971 hint = "transactionIndex: " + transactionIndex;
972 }
973
974 program.stackPush(transactionIndex);
975 program.step();
976 }
977
978 protected void doBLOCKHASH() {
979 spendOpCodeGas();
980 // EXECUTION PHASE
981
982 DataWord blockIndexDW = program.stackPop();
983
984 DataWord blockHash = program.getBlockHash(blockIndexDW);
985
986 if (isLogEnabled) {
987 hint = "blockHash: " + blockHash;
988 }
989
990 program.stackPush(blockHash);
991 program.step();
992 }
993
994 protected void doCOINBASE() {
995 spendOpCodeGas();
996 // EXECUTION PHASE
997 DataWord coinbase = program.getCoinbase();
998
999 if (isLogEnabled) {
1000 hint = "coinbase: " + ByteUtil.toHexString(coinbase.getLast20Bytes());
1001 }
1002
1003 program.stackPush(coinbase);
1004 program.step();
1005 }
1006
1007 protected void doTIMESTAMP() {
1008 spendOpCodeGas();
1009 // EXECUTION PHASE
1010 DataWord timestamp = program.getTimestamp();
1011
1012 if (isLogEnabled) {
1013 hint = "timestamp: " + timestamp.value();
1014 }
1015
1016 program.stackPush(timestamp);
1017 program.step();
1018 }
1019
1020 protected void doNUMBER(){
1021 spendOpCodeGas();
1022 // EXECUTION PHASE
1023 DataWord number = program.getNumber();
1024
1025 if (isLogEnabled) {
1026 hint = "number: " + number.value();
1027 }
1028
1029 program.stackPush(number);
1030 program.step();
1031 }
1032
1033 protected void doDIFFICULTY() {
1034 spendOpCodeGas();
1035 // EXECUTION PHASE
1036 DataWord difficulty = program.getDifficulty();
1037
1038 if (isLogEnabled) {
1039 hint = "difficulty: " + difficulty;
1040 }
1041
1042 program.stackPush(difficulty);
1043 program.step();
1044 }
1045
1046 protected void doGASLIMIT() {
1047 spendOpCodeGas();
1048 // EXECUTION PHASE
1049 DataWord gaslimit = program.getGasLimit();
1050
1051 if (isLogEnabled) {
1052 hint = "gaslimit: " + gaslimit;
1053 }
1054
1055 program.stackPush(gaslimit);
1056 program.step();
1057 }
1058
1059 protected void doCHAINID() {
1060 spendOpCodeGas();
1061 // EXECUTION PHASE
1062 DataWord chainId = DataWord.valueOf(vmConfig.getChainId());
1063
1064 if (isLogEnabled) {
1065 hint = "chainId: " + chainId;
1066 }
1067
1068 program.stackPush(chainId);
1069 program.step();
1070 }
1071
1072 protected void doSELFBALANCE(){
1073 spendOpCodeGas();
1074 // EXECUTION PHASE
1075 DataWord balance = program.getBalance(program.getOwnerAddress());
1076
1077 if (isLogEnabled) {
1078 hint = "selfBalance: " + balance;
1079 }
1080
1081 program.stackPush(balance);
1082 program.step();
1083 }
1084
1085 protected void doPOP(){
1086 spendOpCodeGas();
1087 // EXECUTION PHASE
1088 program.stackPop();
1089 program.step();
1090 }
1091
1092 protected void doDUP() {
1093 spendOpCodeGas();
1094 // EXECUTION PHASE
1095 int n = op.val() - OpCode.DUP1.val() + 1;
1096 DataWord word1 = stack.get(stack.size() - n);
1097 program.stackPush(word1);
1098 program.step();
1099 }
1100
1101 protected void doDUPN() {
1102 spendOpCodeGas();
1103 // EXECUTION PHASE
1104 program.step();
1105
1106 int n = stack.pop().intValueCheck() + 1;
1107
1108 program.verifyStackSize(n);
1109 program.verifyStackOverflow(n, n + 1);
1110
1111 DataWord word1 = stack.get(stack.size() - n);
1112 program.stackPush(word1);
1113 program.step();
1114 }
1115
1116 protected void doSWAP(){
1117 spendOpCodeGas();
1118 // EXECUTION PHASE
1119 int n = op.val() - OpCode.SWAP1.val() + 2;
1120
1121 stack.swap(stack.size() - 1, stack.size() - n);
1122 program.step();
1123 }
1124
1125 protected void doSWAPN(){
1126 spendOpCodeGas();
1127 // EXECUTION PHASE
1128 program.step();
1129
1130 int n = stack.pop().intValueCheck() + 2;
1131
1132 program.verifyStackSize(n);
1133 program.verifyStackOverflow(n, n);
1134
1135 stack.swap(stack.size() - 1, stack.size() - n);
1136 program.step();
1137 }
1138
1139 protected void doLOG(){
1140 if (program.isStaticCall() && program.getActivations().isActive(RSKIP91)) {
1141 throw Program.ExceptionHelper.modificationException(program);
1142 }
1143
1144 DataWord size;
1145 long sizeLong;
1146 long newMemSize ;
1147 int nTopics = op.val() - OpCode.LOG0.val();
1148
1149 if (computeGas) {
1150 size = stack.get(stack.size() - 2);
1151 sizeLong = Program.limitToMaxLong(size);
1152 checkSizeArgument(sizeLong);
1153 newMemSize = memNeeded(stack.peek(), sizeLong);
1154
1155 long dataCost = GasCost.multiply(sizeLong, GasCost.LOG_DATA_GAS);
1156
1157 gasCost = GasCost.calculateTotal(GasCost.add(GasCost.LOG_GAS, dataCost), GasCost.LOG_TOPIC_GAS, nTopics);
1158 gasCost = GasCost.add(gasCost, calcMemGas(oldMemSize, newMemSize, 0));
1159
1160 spendOpCodeGas();
1161 }
1162 // EXECUTION PHASE
1163 DataWord address = program.getOwnerAddress();
1164
1165 DataWord memStart = stack.pop();
1166 DataWord memOffset = stack.pop();
1167
1168 List<DataWord> topics = new ArrayList<>();
1169 for (int i = 0; i < nTopics; ++i) {
1170 DataWord topic = stack.pop();
1171 topics.add(topic);
1172 }
1173
1174 // Int32 address values guaranteed by previous MAX_MEMORY checks
1175 byte[] data = program.memoryChunk(memStart.intValue(), memOffset.intValue());
1176
1177 LogInfo logInfo =
1178 new LogInfo(address.getLast20Bytes(), topics, data);
1179
1180 if (isLogEnabled) {
1181 hint = logInfo.toString();
1182 }
1183
1184 program.getResult().addLogInfo(logInfo);
1185 // Log topics taken from the stack are lost and never returned to the DataWord pool
1186 program.step();
1187 }
1188
1189 protected void doMLOAD(){
1190 long newMemSize ;
1191
1192 if (computeGas) {
1193 newMemSize = memNeeded(stack.peek(), 32);
1194 gasCost = GasCost.add(gasCost, calcMemGas(oldMemSize, newMemSize, 0));
1195 spendOpCodeGas();
1196 }
1197 // EXECUTION PHASE
1198 DataWord addr = program.stackPop();
1199 DataWord data = program.memoryLoad(addr);
1200
1201 if (isLogEnabled) {
1202 hint = "data: " + data;
1203 }
1204
1205 program.stackPush(data);
1206 program.step();
1207 }
1208
1209 protected void doMSTORE() {
1210 long newMemSize ;
1211
1212 if (computeGas) {
1213 newMemSize = memNeeded(stack.peek(), 32);
1214 gasCost = GasCost.add(gasCost, calcMemGas(oldMemSize, newMemSize, 0));
1215 spendOpCodeGas();
1216 }
1217 // EXECUTION PHASE
1218 DataWord addr = program.stackPop();
1219 DataWord value = program.stackPop();
1220
1221 if (isLogEnabled) {
1222 hint = "addr: " + addr + " value: " + value;
1223 }
1224
1225 program.memorySave(addr, value);
1226 program.step();
1227 }
1228
1229 protected void doMSTORE8(){
1230 long newMemSize ;
1231
1232 if (computeGas) {
1233 newMemSize = memNeeded(stack.peek(), 1);
1234 gasCost = GasCost.add(gasCost, calcMemGas(oldMemSize, newMemSize, 0));
1235
1236 spendOpCodeGas();
1237 }
1238 // EXECUTION PHASE
1239 DataWord addr = program.stackPop();
1240 DataWord value = program.stackPop();
1241 byte[] byteVal = {value.getData()[31]};
1242 //TODO: non-standard single byte memory storage, this should be documented
1243 program.memorySave(addr.intValue(), byteVal);
1244 program.step();
1245 }
1246
1247 protected void doSLOAD() {
1248 if (computeGas) {
1249 gasCost = GasCost.SLOAD;
1250 spendOpCodeGas();
1251 }
1252 // EXECUTION PHASE
1253 DataWord key = program.stackPop();
1254 DataWord val = program.storageLoad(key);
1255
1256 if (isLogEnabled) {
1257 hint = "key: " + key + " value: " + val;
1258 }
1259
1260 if (val == null) {
1261 val = DataWord.ZERO;
1262 }
1263
1264 program.stackPush(val);
1265 // key could be returned to the pool, but storageLoad semantics should be checked
1266 // to make sure storageLoad always gets a copy, not a reference.
1267 program.step();
1268 }
1269
1270 protected void doSSTORE() {
1271 if (program.isStaticCall() && program.getActivations().isActive(RSKIP91)) {
1272 throw Program.ExceptionHelper.modificationException(program);
1273 }
1274
1275 if (computeGas) {
1276 DataWord newValue = stack.get(stack.size() - 2);
1277 DataWord oldValue = program.storageLoad(stack.peek());
1278
1279 // From null to non-zero
1280 if (oldValue == null && !newValue.isZero()) {
1281 gasCost = GasCost.SET_SSTORE;
1282 }
1283
1284 // from non-zero to zero
1285 else if (oldValue != null && newValue.isZero()) {
1286 // todo: GASREFUND counter policyn
1287
1288 // refund step cost policy.
1289 program.futureRefundGas(GasCost.REFUND_SSTORE);
1290 gasCost = GasCost.CLEAR_SSTORE;
1291 } else
1292 // from zero to zero, or from non-zero to non-zero
1293 {
1294 gasCost = GasCost.RESET_SSTORE;
1295 }
1296
1297 spendOpCodeGas();
1298 }
1299 // EXECUTION PHASE
1300 DataWord addr = program.stackPop();
1301 DataWord value = program.stackPop();
1302
1303 if (isLogEnabled) {
1304 hint = "[" + program.getOwnerAddress() + "] key: " + addr + " value: " + value;
1305 }
1306
1307 program.storageSave(addr, value);
1308 program.step();
1309 }
1310
1311 protected void doJUMP(){
1312 spendOpCodeGas();
1313 // EXECUTION PHASE
1314 DataWord pos = program.stackPop();
1315 int nextPC = program.verifyJumpDest(pos);
1316
1317 if (isLogEnabled) {
1318 hint = "~> " + nextPC;
1319 }
1320
1321 program.setPC(nextPC);
1322 }
1323
1324 protected void doJUMPI(){
1325 spendOpCodeGas();
1326 // EXECUTION PHASE
1327 DataWord pos = program.stackPop();
1328 DataWord cond = program.stackPop();
1329
1330 if (!cond.isZero()) {
1331 int nextPC = program.verifyJumpDest(pos);
1332
1333 if (isLogEnabled) {
1334 hint = "~> " + nextPC;
1335 }
1336
1337 program.setPC(nextPC);
1338
1339 } else {
1340 program.step();
1341 }
1342 }
1343
1344 protected void doPC(){
1345 spendOpCodeGas();
1346 // EXECUTION PHASE
1347 int pc = program.getPC();
1348 DataWord pcWord = DataWord.valueOf(pc);
1349
1350 if (isLogEnabled) {
1351 hint = pcWord.toString();
1352 }
1353
1354 program.stackPush(pcWord);
1355 program.step();
1356 }
1357
1358 protected void doMSIZE(){
1359 spendOpCodeGas();
1360 // EXECUTION PHASE
1361 int memSize = program.getMemSize();
1362 DataWord wordMemSize = DataWord.valueOf(memSize);
1363
1364 if (isLogEnabled) {
1365 hint = Integer.toString(memSize);
1366 }
1367
1368 program.stackPush(wordMemSize);
1369 program.step();
1370 }
1371
1372 protected void doGAS(){
1373 spendOpCodeGas();
1374 // EXECUTION PHASE
1375 DataWord gas = DataWord.valueOf(program.getRemainingGas());
1376
1377 if (isLogEnabled) {
1378 hint = "" + gas;
1379 }
1380
1381 program.stackPush(gas);
1382 program.step();
1383 }
1384
1385 protected void doPUSH(){
1386 spendOpCodeGas();
1387 // EXECUTION PHASE
1388 program.step();
1389 int nPush = op.val() - OpCode.PUSH1.val() + 1;
1390
1391 DataWord data = program.sweepGetDataWord(nPush);
1392
1393 if (isLogEnabled) {
1394 hint = "" + ByteUtil.toHexString(data.getData());
1395 }
1396
1397 program.stackPush(data);
1398 }
1399
1400 protected void doJUMPDEST()
1401 {
1402 spendOpCodeGas();
1403 // EXECUTION PHASE
1404 program.step();
1405 }
1406
1407 protected void doCREATE(){
1408 if (program.isStaticCall() && program.getActivations().isActive(RSKIP91)) {
1409 throw Program.ExceptionHelper.modificationException(program);
1410 }
1411
1412 DataWord size;
1413 long sizeLong;
1414 long newMemSize ;
1415
1416 if (computeGas) {
1417 gasCost = GasCost.CREATE;
1418 size = stack.get(stack.size() - 3);
1419 sizeLong = Program.limitToMaxLong(size);
1420 checkSizeArgument(sizeLong);
1421 newMemSize = memNeeded(stack.get(stack.size() - 2), sizeLong);
1422 gasCost = GasCost.add(gasCost, calcMemGas(oldMemSize, newMemSize, 0));
1423
1424 spendOpCodeGas();
1425 }
1426 // EXECUTION PHASE
1427 DataWord value = program.stackPop();
1428 DataWord inOffset = program.stackPop();
1429 DataWord inSize = program.stackPop();
1430
1431 if (isLogEnabled) {
1432 logger.info(logString, String.format("%5s", "[" + program.getPC() + "]"),
1433 String.format("%-12s", op.name()),
1434 program.getRemainingGas(),
1435 program.getCallDeep(), hint);
1436 }
1437
1438 program.createContract(value, inOffset, inSize);
1439 program.step();
1440 }
1441
1442 protected void doCREATE2(){
1443 if (program.isStaticCall()) {
1444 throw Program.ExceptionHelper.modificationException(program);
1445 }
1446
1447 if (computeGas){
1448 long codeSize = stack.get(stack.size() - 3).longValueSafe();
1449 gasCost = GasCost.calculateTotal(
1450 GasCost.add(
1451 GasCost.CREATE,
1452 calcMemGas(oldMemSize, memNeeded(stack.get(stack.size() - 2), codeSize), 0)
1453 ),
1454 GasCost.SHA3_WORD,
1455 GasCost.add(codeSize, 31) / 32
1456 );
1457 spendOpCodeGas();
1458 }
1459
1460 DataWord value = program.stackPop();
1461 DataWord inOffset = program.stackPop();
1462 DataWord inSize = program.stackPop();
1463 DataWord salt = program.stackPop();
1464
1465 if (logger.isInfoEnabled()) {
1466 logger.info(logString, String.format("%5s", "[" + program.getPC() + "]"),
1467 String.format("%-12s", op.name()),
1468 program.getRemainingGas(),
1469 program.getCallDeep(), hint);
1470 }
1471
1472 program.createContract2(value, inOffset, inSize, salt);
1473
1474 program.step();
1475 }
1476
1477 protected void doCALL(){
1478 DataWord gas = program.stackPop();
1479 DataWord codeAddress = program.stackPop();
1480
1481 ActivationConfig.ForBlock activations = program.getActivations();
1482
1483 MessageCall msg = getMessageCall(gas, codeAddress, activations);
1484
1485 PrecompiledContracts.PrecompiledContract precompiledContract = precompiledContracts.getContractForAddress(activations, codeAddress);
1486
1487 if (precompiledContract != null) {
1488 program.callToPrecompiledAddress(msg, precompiledContract);
1489 } else {
1490 program.callToAddress(msg);
1491 }
1492
1493 program.step();
1494 }
1495
1496 private MessageCall getMessageCall(DataWord gas, DataWord codeAddress, ActivationConfig.ForBlock activations) {
1497 DataWord value = calculateCallValue(activations);
1498
1499 if (program.isStaticCall() && op == CALL && !value.isZero()) {
1500 throw Program.ExceptionHelper.modificationException(program);
1501 }
1502
1503 DataWord inDataOffs = program.stackPop();
1504 DataWord inDataSize = program.stackPop();
1505
1506 DataWord outDataOffs = program.stackPop();
1507 DataWord outDataSize = program.stackPop();
1508
1509 if (computeGas) {
1510 gasCost = computeCallGas(codeAddress, value, inDataOffs, inDataSize, outDataOffs, outDataSize);
1511 }
1512
1513 // gasCost doesn't include the calleeGas at this point
1514 // because we want to throw gasOverflow instead of notEnoughSpendingGas
1515 long requiredGas = gasCost;
1516 if (requiredGas > program.getRemainingGas()) {
1517 throw Program.ExceptionHelper.gasOverflow(program, BigInteger.valueOf(program.getRemainingGas()), BigInteger.valueOf(requiredGas));
1518 }
1519 long remainingGas = GasCost.subtract(program.getRemainingGas(), requiredGas);
1520 long minimumTransferGas = calculateGetMinimumTransferGas(value, remainingGas);
1521
1522 long userSpecifiedGas = Program.limitToMaxLong(gas);
1523 long specifiedGasPlusMin = activations.isActive(RSKIP150) ?
1524 GasCost.add(userSpecifiedGas, minimumTransferGas) :
1525 userSpecifiedGas + minimumTransferGas;
1526
1527 // If specified gas is higher than available gas then move all remaining gas to callee.
1528 // This will have one possibly undesired behavior: if the specified gas is higher than the remaining gas,
1529 // the callee will receive less gas than the parent expected.
1530 long calleeGas = Math.min(remainingGas, specifiedGasPlusMin);
1531
1532 if (computeGas) {
1533 gasCost = GasCost.add(gasCost, calleeGas);
1534 spendOpCodeGas();
1535 }
1536
1537 if (isLogEnabled) {
1538 hint = "addr: " + ByteUtil.toHexString(codeAddress.getLast20Bytes())
1539 + " gas: " + calleeGas
1540 + " inOff: " + inDataOffs.shortHex()
1541 + " inSize: " + inDataSize.shortHex();
1542 logger.info(logString, String.format("%5s", "[" + program.getPC() + "]"),
1543 String.format("%-12s", op.name()),
1544 program.getRemainingGas(),
1545 program.getCallDeep(), hint);
1546 }
1547
1548 program.memoryExpand(outDataOffs, outDataSize);
1549
1550 return new MessageCall(
1551 MsgType.fromOpcode(op),
1552 DataWord.valueOf(calleeGas), codeAddress, value, inDataOffs, inDataSize,
1553 outDataOffs, outDataSize);
1554 }
1555
1556 private DataWord calculateCallValue(ActivationConfig.ForBlock activations) {
1557 DataWord value;
1558 if (activations.isActive(RSKIP103)) {
1559 // value is always zero in a DELEGATECALL or STATICCALL operation
1560 value = op == OpCode.DELEGATECALL || op == OpCode.STATICCALL ? DataWord.ZERO : program.stackPop();
1561 } else {
1562 // value is always zero in a DELEGATECALL operation
1563 value = op == OpCode.DELEGATECALL ? DataWord.ZERO : program.stackPop();
1564 }
1565 return value;
1566 }
1567
1568 private long calculateGetMinimumTransferGas(DataWord value, long remainingGas) {
1569 // We give the callee a basic stipend whenever we transfer value,
1570 // basically to avoid problems when invoking a contract's default function.
1571 long minimumTransferGas = 0;
1572
1573 if (!value.isZero()) {
1574
1575 minimumTransferGas = GasCost.add(minimumTransferGas, GasCost.STIPEND_CALL);
1576 if (remainingGas < minimumTransferGas) {
1577 throw Program.ExceptionHelper.notEnoughSpendingGas(program, op.name(), minimumTransferGas);
1578 }
1579 }
1580
1581 return minimumTransferGas;
1582 }
1583
1584 private long computeCallGas(DataWord codeAddress,
1585 DataWord value,
1586 DataWord inDataOffs,
1587 DataWord inDataSize,
1588 DataWord outDataOffs,
1589 DataWord outDataSize) {
1590 long callGas = GasCost.CALL;
1591
1592 //check to see if account does not exist and is not a precompiled contract
1593 if (op == OpCode.CALL && !program.getStorage().isExist(new RskAddress(codeAddress))) {
1594 callGas = GasCost.add(callGas, GasCost.NEW_ACCT_CALL);
1595 }
1596 // RSKIP103: we don't need to check static call nor delegate call since value will always be zero
1597 if (!value.isZero()) {
1598 callGas = GasCost.add(callGas, GasCost.VT_CALL);
1599 }
1600
1601 long inSizeLong = Program.limitToMaxLong(inDataSize);
1602 long outSizeLong = Program.limitToMaxLong(outDataSize);
1603
1604 long in = memNeeded(inDataOffs, inSizeLong); // in offset+size
1605 long out = memNeeded(outDataOffs, outSizeLong); // out offset+size
1606 long newMemSize = Long.max(in, out);
1607 callGas = GasCost.add(callGas, calcMemGas(oldMemSize, newMemSize, 0));
1608 return callGas;
1609 }
1610
1611 protected void doREVERT(){
1612 doRETURN();
1613 program.getResult().setRevert();
1614 }
1615
1616 protected void doRETURN(){
1617 DataWord size;
1618 long sizeLong;
1619 long newMemSize ;
1620
1621 size = stack.get(stack.size() - 2);
1622
1623 if (computeGas) {
1624 gasCost = GasCost.RETURN;
1625 sizeLong = Program.limitToMaxLong(size);
1626 checkSizeArgument(sizeLong);
1627 newMemSize = memNeeded(stack.peek(), sizeLong);
1628 gasCost = GasCost.add(gasCost, calcMemGas(oldMemSize, newMemSize, 0));
1629 spendOpCodeGas();
1630 }
1631 // EXECUTION PHASE
1632 DataWord offset = program.stackPop();
1633 program.stackPop(); // pops size
1634
1635 byte[] hReturn = program.memoryChunk(offset.intValue(), size.intValue());
1636 program.setHReturn(hReturn);
1637
1638 if (isLogEnabled) {
1639 hint = "data: " + ByteUtil.toHexString(hReturn)
1640 + " offset: " + offset.value()
1641 + " size: " + size.value();
1642 }
1643
1644 program.step();
1645 program.stop();
1646 }
1647
1648 protected void doSUICIDE(){
1649 if (program.isStaticCall() && program.getActivations().isActive(RSKIP91)) {
1650 throw Program.ExceptionHelper.modificationException(program);
1651 }
1652
1653 if (computeGas) {
1654 gasCost = GasCost.SUICIDE;
1655 DataWord suicideAddressWord = stack.get(stack.size() - 1);
1656 if (!program.getStorage().isExist(new RskAddress(suicideAddressWord))) {
1657 gasCost = GasCost.add(gasCost, GasCost.NEW_ACCT_SUICIDE);
1658 }
1659 spendOpCodeGas();
1660 }
1661 // EXECUTION PHASE
1662 DataWord address = program.stackPop();
1663 program.suicide(address);
1664
1665 if (isLogEnabled) {
1666 hint = "address: " + ByteUtil.toHexString(program.getOwnerAddress().getLast20Bytes());
1667 }
1668
1669 program.stop();
1670 }
1671
1672 protected void executeOpcode() {
1673 // Execute operation
1674 ActivationConfig.ForBlock activations = program.getActivations();
1675 switch (op.val()) {
1676 /**
1677 * Stop and Arithmetic Operations
1678 */
1679 case OpCodes.OP_STOP: doSTOP();
1680 break;
1681 case OpCodes.OP_ADD: doADD();
1682 break;
1683 case OpCodes.OP_MUL: doMUL();
1684 break;
1685 case OpCodes.OP_SUB: doSUB();
1686 break;
1687 case OpCodes.OP_DIV: doDIV();
1688 break;
1689 case OpCodes.OP_SDIV: doSDIV();
1690 break;
1691 case OpCodes.OP_MOD: doMOD();
1692 break;
1693 case OpCodes.OP_SMOD: doSMOD();
1694 break;
1695 case OpCodes.OP_EXP: doEXP();
1696 break;
1697 case OpCodes.OP_SIGNEXTEND: doSIGNEXTEND();
1698 break;
1699 case OpCodes.OP_NOT: doNOT();
1700 break;
1701 case OpCodes.OP_LT: doLT();
1702 break;
1703 case OpCodes.OP_SLT: doSLT();
1704 break;
1705 case OpCodes.OP_SGT: doSGT();
1706 break;
1707 case OpCodes.OP_GT: doGT();
1708 break;
1709 case OpCodes.OP_EQ: doEQ();
1710 break;
1711 case OpCodes.OP_ISZERO: doISZERO();
1712 break;
1713 /**
1714 * Bitwise Logic Operations
1715 */
1716 case OpCodes.OP_AND: doAND();
1717 break;
1718 case OpCodes.OP_OR: doOR();
1719 break;
1720 case OpCodes.OP_XOR: doXOR();
1721 break;
1722 case OpCodes.OP_BYTE: doBYTE();
1723 break;
1724 case OpCodes.OP_ADDMOD: doADDMOD();
1725 break;
1726 case OpCodes.OP_MULMOD: doMULMOD();
1727 break;
1728 case OpCodes.OP_SHL:
1729 if (!activations.isActive(RSKIP120)) {
1730 throw Program.ExceptionHelper.invalidOpCode(program);
1731 }
1732 doSHL();
1733 break;
1734 case OpCodes.OP_SHR:
1735 if (!activations.isActive(RSKIP120)) {
1736 throw Program.ExceptionHelper.invalidOpCode(program);
1737 }
1738 doSHR();
1739 break;
1740 case OpCodes.OP_SAR:
1741 if (!activations.isActive(RSKIP120)) {
1742 throw Program.ExceptionHelper.invalidOpCode(program);
1743 }
1744 doSAR();
1745 break;
1746 /**
1747 * SHA3
1748 */
1749 case OpCodes.OP_SHA_3: doSHA3();
1750 break;
1751
1752 /**
1753 * Environmental Information
1754 */
1755 case OpCodes.OP_ADDRESS: doADDRESS();
1756 break;
1757 case OpCodes.OP_BALANCE: doBALANCE();
1758 break;
1759 case OpCodes.OP_ORIGIN: doORIGIN();
1760 break;
1761 case OpCodes.OP_CALLER: doCALLER();
1762 break;
1763 case OpCodes.OP_CALLVALUE: doCALLVALUE();
1764 break;
1765 case OpCodes.OP_CALLDATALOAD: doCALLDATALOAD();
1766 break;
1767 case OpCodes.OP_CALLDATASIZE: doCALLDATASIZE();
1768 break;
1769 case OpCodes.OP_CALLDATACOPY: doCALLDATACOPY();
1770 break;
1771 case OpCodes.OP_CODESIZE:
1772 case OpCodes.OP_EXTCODESIZE: doCODESIZE();
1773 break;
1774 case OpCodes.OP_CODECOPY:
1775 case OpCodes.OP_EXTCODECOPY: doCODECOPY();
1776 break;
1777
1778
1779 case OpCodes.OP_EXTCODEHASH:
1780 if (!activations.isActive(RSKIP140)) {
1781 throw Program.ExceptionHelper.invalidOpCode(program);
1782 }
1783 doEXTCODEHASH();
1784 break;
1785 case OpCodes.OP_RETURNDATASIZE: doRETURNDATASIZE();
1786 break;
1787 case OpCodes.OP_RETURNDATACOPY: doRETURNDATACOPY();
1788 break;
1789 case OpCodes.OP_GASPRICE: doGASPRICE();
1790 break;
1791
1792 /**
1793 * Block Information
1794 */
1795 case OpCodes.OP_BLOCKHASH: doBLOCKHASH();
1796 break;
1797 case OpCodes.OP_COINBASE: doCOINBASE();
1798 break;
1799 case OpCodes.OP_TIMESTAMP: doTIMESTAMP();
1800 break;
1801 case OpCodes.OP_NUMBER: doNUMBER();
1802 break;
1803 case OpCodes.OP_DIFFICULTY: doDIFFICULTY();
1804 break;
1805 case OpCodes.OP_GASLIMIT: doGASLIMIT();
1806 break;
1807 case OpCodes.OP_CHAINID:
1808 if (!activations.isActive(RSKIP152)) {
1809 throw Program.ExceptionHelper.invalidOpCode(program);
1810 }
1811 doCHAINID();
1812 break;
1813 case OpCodes.OP_SELFBALANCE:
1814 if (!activations.isActive(RSKIP151)) {
1815 throw Program.ExceptionHelper.invalidOpCode(program);
1816 }
1817 doSELFBALANCE();
1818 break;
1819 case OpCodes.OP_TXINDEX:
1820 if (activations.isActive(RSKIP191)) {
1821 throw Program.ExceptionHelper.invalidOpCode(program);
1822 }
1823
1824 doTXINDEX();
1825
1826 break;
1827
1828 case OpCodes.OP_POP: doPOP();
1829 break;
1830 case OpCodes.OP_DUP_1:
1831 case OpCodes.OP_DUP_2:
1832 case OpCodes.OP_DUP_3:
1833 case OpCodes.OP_DUP_4:
1834 case OpCodes.OP_DUP_5:
1835 case OpCodes.OP_DUP_6:
1836 case OpCodes.OP_DUP_7:
1837 case OpCodes.OP_DUP_8:
1838 case OpCodes.OP_DUP_9:
1839 case OpCodes.OP_DUP_10:
1840 case OpCodes.OP_DUP_11:
1841 case OpCodes.OP_DUP_12:
1842 case OpCodes.OP_DUP_13:
1843 case OpCodes.OP_DUP_14:
1844 case OpCodes.OP_DUP_15:
1845 case OpCodes.OP_DUP_16: doDUP();
1846 break;
1847 case OpCodes.OP_SWAP_1:
1848 case OpCodes.OP_SWAP_2:
1849 case OpCodes.OP_SWAP_3:
1850 case OpCodes.OP_SWAP_4:
1851 case OpCodes.OP_SWAP_5:
1852 case OpCodes.OP_SWAP_6:
1853 case OpCodes.OP_SWAP_7:
1854 case OpCodes.OP_SWAP_8:
1855 case OpCodes.OP_SWAP_9:
1856 case OpCodes.OP_SWAP_10:
1857 case OpCodes.OP_SWAP_11:
1858 case OpCodes.OP_SWAP_12:
1859 case OpCodes.OP_SWAP_13:
1860 case OpCodes.OP_SWAP_14:
1861 case OpCodes.OP_SWAP_15:
1862 case OpCodes.OP_SWAP_16: doSWAP();
1863 break;
1864 case OpCodes.OP_SWAPN:
1865 if (activations.isActive(RSKIP191)) {
1866 throw Program.ExceptionHelper.invalidOpCode(program);
1867 }
1868
1869 doSWAPN();
1870
1871 break;
1872
1873 case OpCodes.OP_LOG_0:
1874 case OpCodes.OP_LOG_1:
1875 case OpCodes.OP_LOG_2:
1876 case OpCodes.OP_LOG_3:
1877 case OpCodes.OP_LOG_4: doLOG();
1878 break;
1879 case OpCodes.OP_MLOAD: doMLOAD();
1880 break;
1881 case OpCodes.OP_MSTORE: doMSTORE();
1882 break;
1883 case OpCodes.OP_MSTORE_8: doMSTORE8();
1884 break;
1885 case OpCodes.OP_SLOAD: doSLOAD();
1886 break;
1887 case OpCodes.OP_SSTORE: doSSTORE();
1888 break;
1889 case OpCodes.OP_JUMP: doJUMP();
1890 break;
1891 case OpCodes.OP_JUMPI: doJUMPI();
1892 break;
1893 case OpCodes.OP_PC: doPC();
1894 break;
1895 case OpCodes.OP_MSIZE: doMSIZE();
1896 break;
1897 case OpCodes.OP_GAS: doGAS();
1898 break;
1899
1900 case OpCodes.OP_PUSH_1:
1901 case OpCodes.OP_PUSH_2:
1902 case OpCodes.OP_PUSH_3:
1903 case OpCodes.OP_PUSH_4:
1904 case OpCodes.OP_PUSH_5:
1905 case OpCodes.OP_PUSH_6:
1906 case OpCodes.OP_PUSH_7:
1907 case OpCodes.OP_PUSH_8:
1908 case OpCodes.OP_PUSH_9:
1909 case OpCodes.OP_PUSH_10:
1910 case OpCodes.OP_PUSH_11:
1911 case OpCodes.OP_PUSH_12:
1912 case OpCodes.OP_PUSH_13:
1913 case OpCodes.OP_PUSH_14:
1914 case OpCodes.OP_PUSH_15:
1915 case OpCodes.OP_PUSH_16:
1916 case OpCodes.OP_PUSH_17:
1917 case OpCodes.OP_PUSH_18:
1918 case OpCodes.OP_PUSH_19:
1919 case OpCodes.OP_PUSH_20:
1920 case OpCodes.OP_PUSH_21:
1921 case OpCodes.OP_PUSH_22:
1922 case OpCodes.OP_PUSH_23:
1923 case OpCodes.OP_PUSH_24:
1924 case OpCodes.OP_PUSH_25:
1925 case OpCodes.OP_PUSH_26:
1926 case OpCodes.OP_PUSH_27:
1927 case OpCodes.OP_PUSH_28:
1928 case OpCodes.OP_PUSH_29:
1929 case OpCodes.OP_PUSH_30:
1930 case OpCodes.OP_PUSH_31:
1931 case OpCodes.OP_PUSH_32: doPUSH();
1932 break;
1933 case OpCodes.OP_JUMPDEST: doJUMPDEST();
1934 break;
1935 case OpCodes.OP_CREATE: doCREATE();
1936 break;
1937 case OpCodes.OP_CREATE2:
1938 if (!activations.isActive(RSKIP125)) {
1939 throw Program.ExceptionHelper.invalidOpCode(program);
1940 }
1941 doCREATE2();
1942 break;
1943 case OpCodes.OP_CALL:
1944 case OpCodes.OP_CALLCODE:
1945 case OpCodes.OP_DELEGATECALL:
1946 doCALL();
1947 break;
1948 case OpCodes.OP_STATICCALL:
1949 if (!activations.isActive(RSKIP91)) {
1950 throw Program.ExceptionHelper.invalidOpCode(program);
1951 }
1952 doCALL();
1953 break;
1954 case OpCodes.OP_RETURN: doRETURN();
1955 break;
1956 case OpCodes.OP_REVERT: doREVERT();
1957 break;
1958 case OpCodes.OP_SUICIDE: doSUICIDE();
1959 break;
1960 case OpCodes.OP_DUPN:
1961 if (activations.isActive(RSKIP191)) {
1962 throw Program.ExceptionHelper.invalidOpCode(program);
1963 }
1964
1965 doDUPN();
1966
1967 break;
1968 case OpCodes.OP_HEADER:
1969 //fallthrough to default case until implementation's ready
1970
1971 default:
1972 // It should never execute this line.
1973 // We rise an exception to prevent DoS attacks that halt the node, in case of a bug.
1974 throw Program.ExceptionHelper.invalidOpCode(program);
1975 }
1976 }
1977
1978 protected void logOpCode() {
1979 if (isLogEnabled && !op.equals(OpCode.CALL)
1980 && !op.equals(OpCode.CALLCODE)
1981 && !op.equals(OpCode.CREATE)) {
1982 logger.info(logString, String.format("%5s", "[" + program.getPC() + "]"),
1983 String.format("%-12s",
1984 op.name()), program.getRemainingGas(),
1985 program.getCallDeep(), hint);
1986 }
1987 }
1988
1989 public void steps(Program aprogram, long steps) {
1990 program = aprogram;
1991 stack = program.getStack();
1992
1993 try {
1994
1995 for(long s=0;s<steps;s++) {
1996 if (program.isStopped()) {
1997 break;
1998 }
1999
2000 if (vmConfig.vmTrace()) {
2001 program.saveOpTrace();
2002 }
2003
2004 op = OpCode.code(program.getCurrentOp());
2005
2006 checkOpcode();
2007 program.setLastOp(op.val());
2008 program.verifyStackSize(op.require());
2009 program.verifyStackOverflow(op.require(), op.ret()); //Check not exceeding stack limits
2010
2011 //TODO: There is no need to compute oldMemSize for arithmetic opcodes.
2012 //But this three initializations and memory computations could be done
2013 //in opcodes requiring memory access only.
2014 oldMemSize = program.getMemSize();
2015
2016
2017 if (isLogEnabled) {
2018 hint = "";
2019 }
2020
2021 gasCost = op.getTier().asInt();
2022
2023 if (vmConfig.dumpBlock() >= 0) {
2024 gasBefore = program.getRemainingGas();
2025 memWords = 0; // parameters for logging
2026 }
2027
2028 // Log debugging line for VM
2029 if (vmConfig.dumpBlock() >= 0 && program.getNumber().intValue() == vmConfig.dumpBlock()) {
2030 this.dumpLine(op, gasBefore, gasCost , memWords, program);
2031 }
2032
2033 if (vmHook != null) {
2034 vmHook.step(program, op);
2035 }
2036 executeOpcode();
2037
2038 if (vmConfig.vmTrace()) {
2039 program.saveOpGasCost(gasCost);
2040 }
2041
2042 logOpCode();
2043 vmCounter++;
2044 } // for
2045 } catch (RuntimeException e) {
2046 logger.error("VM halted", e);
2047 program.spendAllGas();
2048 program.resetFutureRefund();
2049 program.stop();
2050 throw e;
2051 } finally {
2052 if (isLogEnabled) { // this must be prevented because it's slow!
2053 program.fullTrace();
2054 }
2055 }
2056 }
2057
2058 public void initDebugData() {
2059 gasBefore = 0;
2060 memWords = 0;
2061 }
2062
2063 public void play(Program program) {
2064 try {
2065 if (vmHook != null) {
2066 vmHook.startPlay(program);
2067 }
2068
2069 initDebugData();
2070 this.steps(program,Long.MAX_VALUE);
2071
2072 if (vmHook != null) {
2073 vmHook.stopPlay(program);
2074 }
2075
2076 } catch (RuntimeException e) {
2077 program.setRuntimeFailure(e);
2078 }
2079 }
2080
2081 public static void setVmHook(VMHook vmHook) {
2082 VM.vmHook = vmHook;
2083 }
2084
2085 /**
2086 * Utility to calculate new total memory size needed for an operation.
2087 * <br/> Basically just offset + size, unless size is 0, in which case the result is also 0.
2088 *
2089 * @param offset starting position of the memory
2090 * @param size number of bytes needed
2091 * @return offset + size, unless size is 0. In that case memNeeded is also 0.
2092 */
2093
2094 private static long memNeeded(DataWord offset, long size) {
2095 return (size==0)? 0 : limitedAddToMaxLong(Program.limitToMaxLong(offset.value()),size);
2096 }
2097
2098 /*
2099 * Dumping the VM state at the current operation in various styles
2100 * - standard Not Yet Implemented
2101 * - standard+ (owner address, program counter, operation, gas left)
2102 * - pretty (stack, memory, storage, level, contract,
2103 * vmCounter, internalSteps, operation
2104 gasBefore, gasCost, memWords)
2105 */
2106 private void dumpLine(OpCode op, long gasBefore, long gasCost, long memWords, Program program) {
2107 Repository storage = program.getStorage();
2108 RskAddress ownerAddress = new RskAddress(program.getOwnerAddress());
2109 if ("standard+".equals(vmConfig.dumpStyle())) {
2110 switch (op) {
2111 case STOP:
2112 case RETURN:
2113 case SUICIDE:
2114 Iterator<DataWord> keysIterator = storage.getStorageKeys(ownerAddress);
2115 while (keysIterator.hasNext()) {
2116 DataWord key = keysIterator.next();
2117 DataWord value = storage.getStorageValue(ownerAddress, key);
2118 dumpLogger.trace("{} {}",
2119 ByteUtil.toHexString(key.getNoLeadZeroesData()),
2120 ByteUtil.toHexString(value.getNoLeadZeroesData()));
2121 }
2122 break;
2123 default:
2124 break;
2125 }
2126 String addressString = ByteUtil.toHexString(program.getOwnerAddress().getLast20Bytes());
2127 String pcString = ByteUtil.toHexString(DataWord.valueOf(program.getPC()).getNoLeadZeroesData());
2128 String opString = ByteUtil.toHexString(new byte[]{op.val()});
2129 String gasString = Long.toHexString(program.getRemainingGas());
2130
2131 dumpLogger.trace("{} {} {} {}", addressString, pcString, opString, gasString);
2132 } else if ("pretty".equals(vmConfig.dumpStyle())) {
2133 dumpLogger.trace("-------------------------------------------------------------------------");
2134 dumpLogger.trace(" STACK");
2135 program.getStack().forEach(item -> dumpLogger.trace("{}", item));
2136 dumpLogger.trace(" MEMORY");
2137 String memoryString = program.memoryToString();
2138 if (!"".equals(memoryString)) {
2139 dumpLogger.trace("{}", memoryString);
2140 }
2141
2142 dumpLogger.trace(" STORAGE");
2143 Iterator<DataWord> keysIterator = storage.getStorageKeys(ownerAddress);
2144 while (keysIterator.hasNext()) {
2145 DataWord key = keysIterator.next();
2146 DataWord value = storage.getStorageValue(ownerAddress, key);
2147 dumpLogger.trace("{}: {}",
2148 key.shortHex(),
2149 value.shortHex());
2150 }
2151
2152 int level = program.getCallDeep();
2153 String contract = ByteUtil.toHexString(program.getOwnerAddress().getLast20Bytes());
2154 String internalSteps = String.format("%4s", Integer.toHexString(program.getPC())).replace(' ', '0').toUpperCase();
2155 dumpLogger.trace("{} | {} | #{} | {} : {} | {} | -{} | {}x32",
2156 level, contract, vmCounter, internalSteps, op,
2157 gasBefore, gasCost, memWords);
2158 }
2159 }
2160 }