Coverage Summary for Class: Program (org.ethereum.vm.program)

Class Method, % Line, %
Program 32.8% (38/116) 16.9% (111/656)
Program$AddressCollisionException 0% (0/1) 0% (0/2)
Program$BadJumpDestinationException 0% (0/1) 0% (0/2)
Program$ExceptionHelper 0% (0/14) 0% (0/15)
Program$IllegalOperationException 0% (0/1) 0% (0/2)
Program$OutOfGasException 0% (0/1) 0% (0/2)
Program$StackTooLargeException 0% (0/1) 0% (0/3)
Program$StackTooSmallException 0% (0/1) 0% (0/2)
Program$StaticCallModificationException 0% (0/1) 0% (0/2)
Total 27.7% (38/137) 16.2% (111/686)


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.program; 21  22 import co.rsk.config.VmConfig; 23 import co.rsk.core.Coin; 24 import co.rsk.core.RskAddress; 25 import co.rsk.crypto.Keccak256; 26 import co.rsk.pcc.NativeContract; 27 import co.rsk.peg.Bridge; 28 import co.rsk.remasc.RemascContract; 29 import co.rsk.rpc.modules.trace.CallType; 30 import co.rsk.rpc.modules.trace.CreationData; 31 import co.rsk.rpc.modules.trace.ProgramSubtrace; 32 import co.rsk.vm.BitSet; 33 import com.google.common.annotations.VisibleForTesting; 34 import org.ethereum.config.Constants; 35 import org.ethereum.config.blockchain.upgrades.ActivationConfig; 36 import org.ethereum.config.blockchain.upgrades.ConsensusRule; 37 import org.ethereum.core.Block; 38 import org.ethereum.core.BlockFactory; 39 import org.ethereum.core.Repository; 40 import org.ethereum.core.Transaction; 41 import org.ethereum.crypto.HashUtil; 42 import org.ethereum.util.ByteUtil; 43 import org.ethereum.util.FastByteComparisons; 44 import org.ethereum.vm.*; 45 import org.ethereum.vm.MessageCall.MsgType; 46 import org.ethereum.vm.PrecompiledContracts.PrecompiledContract; 47 import org.ethereum.vm.exception.VMException; 48 import org.ethereum.vm.program.invoke.*; 49 import org.ethereum.vm.program.listener.CompositeProgramListener; 50 import org.ethereum.vm.program.listener.ProgramListenerAware; 51 import org.ethereum.vm.trace.*; 52 import org.slf4j.Logger; 53 import org.slf4j.LoggerFactory; 54  55 import javax.annotation.Nonnull; 56 import java.math.BigInteger; 57 import java.util.*; 58  59 import static co.rsk.util.ListArrayUtil.*; 60 import static java.lang.String.format; 61 import static org.ethereum.util.BIUtil.*; 62 import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY; 63  64 /** 65  * @author Roman Mandeleil 66  * @since 01.06.2014 67  */ 68 public class Program { 69  // These logs should never be in Info mode in production 70  private static final Logger logger = LoggerFactory.getLogger("VM"); 71  private static final Logger gasLogger = LoggerFactory.getLogger("gas"); 72  73  public static final long MAX_MEMORY = (1<<30); 74  75  //Max size for stack checks 76  private static final int MAX_STACKSIZE = 1024; 77  private static final String CALL_PRECOMPILED_CAUSE = "call pre-compiled"; 78  79  private final ActivationConfig.ForBlock activations; 80  private final Transaction transaction; 81  82  private final ProgramInvoke invoke; 83  private final ProgramInvokeFactory programInvokeFactory = new ProgramInvokeFactoryImpl(); 84  85  private ProgramOutListener listener; 86  private final ProgramTraceListener traceListener; 87  private final CompositeProgramListener programListener = new CompositeProgramListener(); 88  89  private final Stack stack; 90  private final Memory memory; 91  private final Storage storage; 92  private byte[] returnDataBuffer; 93  94  private final ProgramResult result = new ProgramResult(); 95  private final ProgramTrace trace; 96  97  private final byte[] ops; 98  private int pc; 99  private byte lastOp; 100  private boolean stopped; 101  private byte exeVersion; // currently limited to 0..127 102  private byte scriptVersion; // currently limited to 0..127 103  private int startAddr; 104  105  private BitSet jumpdestSet; 106  107  private final VmConfig config; 108  private final PrecompiledContracts precompiledContracts; 109  private final BlockFactory blockFactory; 110  111  private boolean isLogEnabled; 112  private boolean isGasLogEnabled; 113  114  private RskAddress rskOwnerAddress; 115  116  private final Set<DataWord> deletedAccountsInBlock; 117  118  public Program( 119  VmConfig config, 120  PrecompiledContracts precompiledContracts, 121  BlockFactory blockFactory, 122  ActivationConfig.ForBlock activations, 123  byte[] ops, 124  ProgramInvoke programInvoke, 125  Transaction transaction, 126  Set<DataWord> deletedAccounts) { 127  this.config = config; 128  this.precompiledContracts = precompiledContracts; 129  this.blockFactory = blockFactory; 130  this.activations = activations; 131  this.transaction = transaction; 132  isLogEnabled = logger.isInfoEnabled(); 133  isGasLogEnabled = gasLogger.isInfoEnabled(); 134  135  if (isLogEnabled ) { 136  logger.warn("WARNING! VM logging is enabled. This will make the VM 200 times slower. Do not use in production."); 137  } 138  139  if (isGasLogEnabled) { 140  gasLogger.warn("WARNING! Gas logging is enabled. This will the make VM 200 times slower. Do not use in production."); 141  } 142  143  this.invoke = programInvoke; 144  145  this.ops = nullToEmpty(ops); 146  147  this.trace = createProgramTrace(config, programInvoke); 148  this.memory = setupProgramListener(new Memory()); 149  this.stack = setupProgramListener(new Stack()); 150  this.stack.ensureCapacity(1024); // faster? 151  this.storage = setupProgramListener(new Storage(programInvoke)); 152  this.deletedAccountsInBlock = new HashSet<>(deletedAccounts); 153  154  precompile(); 155  traceListener = new ProgramTraceListener(config); 156  } 157  158  private static ProgramTrace createProgramTrace(VmConfig config, ProgramInvoke programInvoke) { 159  if (!config.vmTrace()) { 160  return new EmptyProgramTrace(); 161  } 162  163  if ((config.vmTraceOptions() & VmConfig.LIGHT_TRACE) != 0) { 164  return new SummarizedProgramTrace(programInvoke); 165  } 166  167  return new DetailedProgramTrace(config, programInvoke); 168  } 169  170  /** 171  * Defines the depth of the call stack inside the EVM. 172  * Changed to a value more similar to Ethereum's with EIP150 173  * since RSKIP150. 174  */ 175  public int getMaxDepth() { 176  if (activations.isActive(ConsensusRule.RSKIP150)) { 177  return 400; 178  } 179  return 1024; 180  } 181  182  public int getCallDeep() { 183  return invoke.getCallDeep(); 184  } 185  186  private InternalTransaction addInternalTx(byte[] nonce, DataWord gasLimit, RskAddress senderAddress, RskAddress receiveAddress, 187  Coin value, byte[] data, String note) { 188  if (transaction == null) { 189  return null; 190  } 191  192  byte[] senderNonce = isEmpty(nonce) ? getStorage().getNonce(senderAddress).toByteArray() : nonce; 193  194  return getResult().addInternalTransaction( 195  transaction, 196  getCallDeep(), 197  senderNonce, 198  getGasPrice(), 199  gasLimit, 200  senderAddress.getBytes(), 201  receiveAddress.getBytes(), 202  value.getBytes(), 203  data, 204  note); 205  } 206  207  private <T extends ProgramListenerAware> T setupProgramListener(T traceListenerAware) { 208  if (programListener.isEmpty()) { 209  programListener.addListener(traceListener); 210  } 211  212  traceListenerAware.setTraceListener(traceListener); 213  return traceListenerAware; 214  } 215  216  public byte getOp(int pc) { 217  return (getLength(ops) <= pc) ? 0 : ops[pc]; 218  } 219  220  public byte getCurrentOp() { 221  return isEmpty(ops) ? 0 : ops[pc]; 222  } 223  224  /** 225  * Last Op can only be set publicly (no getLastOp method), is used for logging. 226  */ 227  public void setLastOp(byte op) { 228  this.lastOp = op; 229  } 230  231  private void stackPushZero() { 232  stackPush(DataWord.ZERO); 233  } 234  235  private void stackPushOne() { 236  stackPush(DataWord.ONE); 237  } 238  239  private void stackClear(){ 240  stack.clear(); 241  } 242  243  public void stackPush(DataWord stackWord) { 244  verifyStackOverflow(0, 1); //Sanity Check 245  stack.push(stackWord); 246  } 247  248  public Stack getStack() { 249  return this.stack; 250  } 251  252  public int getPC() { 253  return pc; 254  } 255  256  public void setPC(DataWord pc) { 257  this.setPC(pc.intValue()); 258  } 259  260  public void setPC(int pc) { 261  this.pc = pc; 262  263  if (this.pc >= ops.length) { 264  stop(); 265  } 266  } 267  268  public boolean isStopped() { 269  return stopped; 270  } 271  272  public void stop() { 273  stopped = true; 274  } 275  276  public void setHReturn(byte[] buff) { 277  getResult().setHReturn(buff); 278  } 279  280  public void step() { 281  setPC(pc + 1); 282  } 283  284  285  public DataWord sweepGetDataWord(int n) { 286  if (pc + n > ops.length) { 287  stop(); 288  // In this case partial data is copied. At least Ethereumj does this 289  // Asummes LSBs are zero. assignDataRange undestands this semantics. 290  } 291  292  DataWord dw = DataWord.valueOf(ops, pc, n); 293  pc += n; 294  if (pc >= ops.length) { 295  stop(); 296  } 297  298  return dw; 299  } 300  301  public DataWord stackPop() { 302  return stack.pop(); 303  } 304  305  /** 306  * Verifies that the stack is at least <code>stackSize</code> 307  * 308  * @param stackSize int 309  * @throws StackTooSmallException If the stack is 310  * smaller than <code>stackSize</code> 311  */ 312  public void verifyStackSize(int stackSize) { 313  if (stackSize < 0 || stack.size() < stackSize) { 314  throw ExceptionHelper.tooSmallStack(this, stackSize, stack.size()); 315  } 316  } 317  318  public void verifyStackOverflow(int argsReqs, int returnReqs) { 319  if ((stack.size() - argsReqs + returnReqs) > MAX_STACKSIZE) { 320  throw new StackTooLargeException("Expected: overflow " + MAX_STACKSIZE + " elements stack limit"); 321  } 322  } 323  324  public int getMemSize() { 325  return memory.size(); 326  } 327  328  public void memorySave(DataWord addrB, DataWord value) { 329  // 330  memory.write(addrB.intValue(), value.getData(), value.getData().length, false); 331  } 332  333  private void memorySaveLimited(int addr, byte[] data, int dataSize) { 334  memory.write(addr, data, dataSize, true); 335  } 336  337  public void memorySave(int addr, byte[] value) { 338  memory.write(addr, value, value.length, false); 339  } 340  341  public void memoryExpand(DataWord outDataOffs, DataWord outDataSize) { 342  if (!outDataSize.isZero()) { 343  memory.extend(outDataOffs.intValue(), outDataSize.intValue()); 344  } 345  } 346  347  /** 348  * Allocates a piece of memory and stores value at given offset address 349  * 350  * @param addr is the offset address 351  * @param allocSize size of memory needed to write 352  * @param value the data to write to memory 353  */ 354  public void memorySave(int addr, int allocSize, byte[] value) { 355  memory.extendAndWrite(addr, allocSize, value); 356  } 357  358  359  public DataWord memoryLoad(DataWord addr) { 360  return memory.readWord(addr.intValue()); 361  } 362  363  public byte[] memoryChunk(int offset, int size) { 364  return memory.read(offset, size); 365  } 366  367  /** 368  * Allocates extra memory in the program for 369  * a specified size, calculated from a given offset 370  * 371  * @param offset the memory address offset 372  * @param size the number of bytes to allocate 373  */ 374  public void allocateMemory(int offset, int size) { 375  memory.extend(offset, size); 376  } 377  378  public void suicide(DataWord obtainerAddress) { 379  380  RskAddress owner = getOwnerRskAddress(); 381  Coin balance = getStorage().getBalance(owner); 382  RskAddress obtainer = new RskAddress(obtainerAddress); 383  384  if (!balance.equals(Coin.ZERO)) { 385  logger.info("Transfer to: [{}] heritage: [{}]", obtainer, balance); 386  387  addInternalTx(null, null, owner, obtainer, balance, null, "suicide"); 388  389  if (FastByteComparisons.compareTo(owner.getBytes(), 0, 20, obtainer.getBytes(), 0, 20) == 0) { 390  // if owner == obtainer just zeroing account according to Yellow Paper 391  getStorage().addBalance(owner, balance.negate()); 392  } else { 393  getStorage().transfer(owner, obtainer, balance); 394  } 395  } 396  // In any case, remove the account 397  getResult().addDeleteAccount(this.getOwnerAddress()); 398  399  SuicideInvoke invoke = new SuicideInvoke(DataWord.valueOf(owner.getBytes()), obtainerAddress, DataWord.valueOf(balance.getBytes())); 400  ProgramSubtrace subtrace = ProgramSubtrace.newSuicideSubtrace(invoke); 401  402  getTrace().addSubTrace(subtrace); 403  } 404  405  public void send(DataWord destAddress, Coin amount) { 406  407  RskAddress owner = getOwnerRskAddress(); 408  RskAddress dest = new RskAddress(destAddress); 409  Coin balance = getStorage().getBalance(owner); 410  411  if (isNotCovers(balance, amount)) { 412  return; // does not do anything. 413  } 414  415  if (isLogEnabled) { 416  logger.info("Transfer to: [{}] amount: [{}]", 417  dest, 418  amount); 419  } 420  421  addInternalTx(null, null, owner, dest, amount, null, "send"); 422  423  getStorage().transfer(owner, dest, amount); 424  } 425  426  public Repository getStorage() { 427  return this.storage; 428  } 429  430  @SuppressWarnings("ThrowableResultOfMethodCallIgnored") 431  public void createContract(DataWord value, DataWord memStart, DataWord memSize) { 432  RskAddress senderAddress = new RskAddress(getOwnerAddress()); 433  434  byte[] nonce = getStorage().getNonce(senderAddress).toByteArray(); 435  byte[] newAddressBytes = HashUtil.calcNewAddr(getOwnerAddress().getLast20Bytes(), nonce); 436  RskAddress newAddress = new RskAddress(newAddressBytes); 437  438  createContract(senderAddress, nonce, value, memStart, memSize, newAddress, false); 439  } 440  441  @SuppressWarnings("ThrowableResultOfMethodCallIgnored") 442  public void createContract2(DataWord value, DataWord memStart, DataWord memSize, DataWord salt) { 443  RskAddress senderAddress = new RskAddress(getOwnerAddress()); 444  byte[] programCode = memoryChunk(memStart.intValue(), memSize.intValue()); 445  446  byte[] newAddressBytes = HashUtil.calcSaltAddr(senderAddress, programCode, salt.getData()); 447  byte[] nonce = getStorage().getNonce(senderAddress).toByteArray(); 448  RskAddress newAddress = new RskAddress(newAddressBytes); 449  450  createContract(senderAddress, nonce, value, memStart, memSize, newAddress, true); 451  } 452  453  private void createContract( RskAddress senderAddress, byte[] nonce, DataWord value, DataWord memStart, DataWord memSize, RskAddress contractAddress, boolean isCreate2) { 454  if (getCallDeep() == getMaxDepth()) { 455  logger.debug("max depth reached creating a new contract inside contract run: [{}]", senderAddress); 456  stackPushZero(); 457  return; 458  } 459  460  Coin endowment = new Coin(value.getData()); 461  if (isNotCovers(getStorage().getBalance(senderAddress), endowment)) { 462  stackPushZero(); 463  return; 464  } 465  466  // [1] FETCH THE CODE FROM THE MEMORY 467  byte[] programCode = memoryChunk(memStart.intValue(), memSize.intValue()); 468  469  if (isLogEnabled) { 470  logger.info("creating a new contract inside contract run: [{}]", senderAddress); 471  } 472  473  // actual gas subtract 474  long gasLimit = getRemainingGas(); 475  spendGas(gasLimit, "internal call"); 476  477  478  if (byTestingSuite()) { 479  // This keeps track of the contracts created for a test 480  getResult().addCallCreate(programCode, EMPTY_BYTE_ARRAY, 481  gasLimit, 482  value.getNoLeadZeroesData()); 483  } 484  485  // [3] UPDATE THE NONCE 486  // (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION) 487  if (!byTestingSuite()) { 488  getStorage().increaseNonce(senderAddress); 489  } 490  // Start tracking repository changes for the constructor of the contract 491  Repository track = getStorage().startTracking(); 492  493  ProgramResult programResult = ProgramResult.empty(); 494  495  if (getActivations().isActive(ConsensusRule.RSKIP125) && 496  deletedAccountsInBlock.contains(DataWord.valueOf(contractAddress.getBytes()))) { 497  // Check if the address was previously deleted in the same block 498  499  programResult.setException(ExceptionHelper.addressCollisionException(this, contractAddress)); 500  if (isLogEnabled) { 501  logger.debug("contract run halted by Exception: contract: [{}], exception: ", 502  contractAddress, 503  programResult.getException()); 504  } 505  506  track.rollback(); 507  stackPushZero(); 508  509  return; 510  } 511  512  boolean existingAccount = track.isExist(contractAddress); 513  514  //In case of hashing collisions, check for any balance before createAccount() 515  if (existingAccount) { 516  // Hashing collisions in CREATE are rare, but in CREATE2 are possible 517  // We check for the nonce to non zero and that the code to be not empty 518  // if any of this conditions is true, the contract creation fails 519  520  byte[] code = track.getCode(contractAddress); 521  boolean hasNonEmptyCode = (code != null && code.length != 0); 522  boolean nonZeroNonce = track.getNonce(contractAddress).longValue() != 0; 523  524  if (getActivations().isActive(ConsensusRule.RSKIP125) && (hasNonEmptyCode || nonZeroNonce)) { 525  // Contract collision we fail with exactly the same behavior as would arise if 526  // the first byte in the init code were an invalid opcode 527  programResult.setException(ExceptionHelper.addressCollisionException(this, contractAddress)); 528  if (isLogEnabled) { 529  logger.debug("contract run halted by Exception: contract: [{}], exception: ", 530  contractAddress, 531  programResult.getException()); 532  } 533  534  // The programResult is empty and internalTx was not created so we skip this part 535  /*if (internalTx == null) { 536  throw new NullPointerException(); 537  } 538  539  internalTx.reject(); 540  programResult.rejectInternalTransactions(); 541  programResult.rejectLogInfos();*/ 542  543  track.rollback(); 544  stackPushZero(); 545  546  return; 547  } 548  } 549  550  track.createAccount(contractAddress, existingAccount); 551  track.setupContract(contractAddress); 552  553  if (getActivations().isActive(ConsensusRule.RSKIP125)) { 554  track.increaseNonce(contractAddress); 555  } 556  557  // [4] TRANSFER THE BALANCE 558  track.addBalance(senderAddress, endowment.negate()); 559  Coin newBalance = Coin.ZERO; 560  if (!byTestingSuite()) { 561  newBalance = track.addBalance(contractAddress, endowment); 562  } 563  564  565  // [5] COOK THE INVOKE AND EXECUTE 566  programResult = getProgramResult(senderAddress, nonce, value, contractAddress, endowment, programCode, gasLimit, track, newBalance, programResult, isCreate2); 567  if (programResult == null) { 568  return; 569  } 570  571  // REFUND THE REMAIN GAS 572  refundRemainingGas(gasLimit, programResult); 573  } 574  575  private void refundRemainingGas(long gasLimit, ProgramResult programResult) { 576  if (programResult.getGasUsed() >= gasLimit) { 577  return; 578  } 579  long refundGas = GasCost.subtract(gasLimit, programResult.getGasUsed()); 580  refundGas(refundGas, "remaining gas from the internal call"); 581  if (isGasLogEnabled) { 582  gasLogger.info("The remaining gas is refunded, account: [{}], gas: [{}] ", 583  ByteUtil.toHexString(getOwnerAddress().getLast20Bytes()), 584  refundGas 585  ); 586  } 587  } 588  589  private ProgramResult getProgramResult(RskAddress senderAddress, byte[] nonce, DataWord value, 590  RskAddress contractAddress, Coin endowment, byte[] programCode, 591  long gasLimit, Repository track, Coin newBalance, ProgramResult programResult, boolean isCreate2) { 592  593  594  InternalTransaction internalTx = addInternalTx(nonce, getGasLimit(), senderAddress, RskAddress.nullAddress(), endowment, programCode, "create"); 595  ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke( 596  this, DataWord.valueOf(contractAddress.getBytes()), getOwnerAddress(), value, gasLimit, 597  newBalance, null, track, this.invoke.getBlockStore(), false, byTestingSuite()); 598  599  returnDataBuffer = null; // reset return buffer right before the call 600  601  if (!isEmpty(programCode)) { 602  VM vm = new VM(config, precompiledContracts); 603  Program program = new Program(config, precompiledContracts, blockFactory, activations, programCode, programInvoke, internalTx, deletedAccountsInBlock); 604  vm.play(program); 605  programResult = program.getResult(); 606  607  if (programResult.getException() == null && !programResult.isRevert()) { 608  getTrace().addSubTrace(ProgramSubtrace.newCreateSubtrace(new CreationData(programCode, programResult.getHReturn(), contractAddress), program.getProgramInvoke(), program.getResult(), program.getTrace().getSubtraces(), isCreate2)); 609  } 610  } 611  612  if (programResult.getException() != null || programResult.isRevert()) { 613  if (isLogEnabled) { 614  logger.debug("contract run halted by Exception: contract: [{}], exception: ", 615  contractAddress, 616  programResult.getException()); 617  } 618  619  if (internalTx == null) { 620  throw new NullPointerException(); 621  } 622  623  internalTx.reject(); 624  programResult.rejectInternalTransactions(); 625  programResult.rejectLogInfos(); 626  627  track.rollback(); 628  stackPushZero(); 629  if (programResult.getException() != null) { 630  return null; 631  } else { 632  returnDataBuffer = result.getHReturn(); 633  } 634  } else { 635  // CREATE THE CONTRACT OUT OF RETURN 636  byte[] code = programResult.getHReturn(); 637  int codeLength = getLength(code); 638  639  long storageCost = GasCost.multiply(GasCost.CREATE_DATA, codeLength); 640  long afterSpend = programInvoke.getGas() - storageCost - programResult.getGasUsed(); 641  642  if (afterSpend < 0) { 643  programResult.setException( 644  ExceptionHelper.notEnoughSpendingGas( 645  this, 646  "No gas to return just created contract", 647  storageCost)); 648  } else if (codeLength > Constants.getMaxContractSize()) { 649  programResult.setException( 650  ExceptionHelper.tooLargeContractSize( 651  this, 652  Constants.getMaxContractSize(), 653  codeLength)); 654  } else { 655  programResult.spendGas(storageCost); 656  track.saveCode(contractAddress, code); 657  } 658  659  track.commit(); 660  661  getResult().addDeleteAccounts(programResult.getDeleteAccounts()); 662  getResult().addLogInfos(programResult.getLogInfoList()); 663  664  // IN SUCCESS PUSH THE ADDRESS INTO THE STACK 665  stackPush(DataWord.valueOf(contractAddress.getBytes())); 666  } 667  668  return programResult; 669  } 670  671  public static long limitToMaxLong(DataWord gas) { 672  return gas.longValueSafe(); 673  674  } 675  676  public static long limitToMaxLong(BigInteger gas) { 677  try { 678  long r = gas.longValueExact(); 679  if (r<0) // check if this can happen 680  { 681  return Long.MAX_VALUE; 682  } 683  return r; 684  } catch (ArithmeticException e) { 685  return Long.MAX_VALUE; 686  } 687  } 688  689  public static long multiplyLimitToMaxLong(long a,long b) { 690  long d; 691  692  try { 693  d = Math.multiplyExact(a, b); 694  } catch (ArithmeticException e) { 695  d = Long.MAX_VALUE; 696  } 697  return d; 698  } 699  700  /** 701  * That method is for internal code invocations 702  * <p/> 703  * - Normal calls invoke a specified contract which updates itself 704  * - Stateless calls invoke code from another contract, within the context of the caller 705  * 706  * @param msg is the message call object 707  */ 708  public void callToAddress(MessageCall msg) { 709  710  if (getCallDeep() == getMaxDepth()) { 711  stackPushZero(); 712  refundGas(msg.getGas().longValue(), " call deep limit reach"); 713  return; 714  } 715  716  byte[] data = memoryChunk(msg.getInDataOffs().intValue(), msg.getInDataSize().intValue()); 717  718  // FETCH THE SAVED STORAGE 719  RskAddress codeAddress = new RskAddress(msg.getCodeAddress()); 720  RskAddress senderAddress = getOwnerRskAddress(); 721  RskAddress contextAddress = msg.getType().isStateless() ? senderAddress : codeAddress; 722  723  if (isLogEnabled) { 724  logger.info("{} for existing contract: address: [{}], outDataOffs: [{}], outDataSize: [{}] ", msg.getType().name(), 725  contextAddress, msg.getOutDataOffs().longValue(), msg.getOutDataSize().longValue()); 726  } 727  728  Repository track = getStorage().startTracking(); 729  730  // 2.1 PERFORM THE VALUE (endowment) PART 731  Coin endowment = new Coin(msg.getEndowment().getData()); 732  Coin senderBalance = track.getBalance(senderAddress); 733  if (isNotCovers(senderBalance, endowment)) { 734  stackPushZero(); 735  refundGas(msg.getGas().longValue(), "refund gas from message call"); 736  this.cleanReturnDataBuffer(); 737  738  return; 739  } 740  741  // FETCH THE CODE 742  byte[] programCode = getStorage().isExist(codeAddress) ? getStorage().getCode(codeAddress) : EMPTY_BYTE_ARRAY; 743  // programCode can be null 744  745  // Always first remove funds from sender 746  track.addBalance(senderAddress, endowment.negate()); 747  748  Coin contextBalance; 749  750  if (byTestingSuite()) { 751  // This keeps track of the calls created for a test 752  getResult().addCallCreate(data, contextAddress.getBytes(), 753  msg.getGas().longValueSafe(), 754  msg.getEndowment().getNoLeadZeroesData()); 755  756  return; 757  } 758  759  contextBalance = track.addBalance(contextAddress, endowment); 760  761  // CREATE CALL INTERNAL TRANSACTION 762  InternalTransaction internalTx = addInternalTx(null, getGasLimit(), senderAddress, contextAddress, endowment, programCode, "call"); 763  764  boolean callResult; 765  766  if (!isEmpty(programCode)) { 767  callResult = executeCode(msg, contextAddress, contextBalance, internalTx, track, programCode, senderAddress, data); 768  } else { 769  track.commit(); 770  callResult = true; 771  refundGas(GasCost.toGas(msg.getGas().longValue()), "remaining gas from the internal call"); 772  773  DataWord callerAddress = DataWord.valueOf(senderAddress.getBytes()); 774  DataWord ownerAddress = DataWord.valueOf(contextAddress.getBytes()); 775  DataWord transferValue = DataWord.valueOf(endowment.getBytes()); 776  777  TransferInvoke invoke = new TransferInvoke(callerAddress, ownerAddress, msg.getGas().longValue(), transferValue); 778  ProgramResult result = new ProgramResult(); 779  780  ProgramSubtrace subtrace = ProgramSubtrace.newCallSubtrace(CallType.fromMsgType(msg.getType()), invoke, result, null, Collections.emptyList()); 781  782  getTrace().addSubTrace(subtrace); 783  784  this.cleanReturnDataBuffer(); 785  } 786  787  // 4. THE FLAG OF SUCCESS IS ONE PUSHED INTO THE STACK 788  if (callResult) { 789  stackPushOne(); 790  } 791  else { 792  stackPushZero(); 793  } 794  } 795  796  private void cleanReturnDataBuffer() { 797  if (getActivations().isActive(ConsensusRule.RSKIP171)) { 798  // reset return data buffer when call did not create a new call frame 799  returnDataBuffer = null; 800  } 801  } 802  803  private ProgramInvoke getProgramInvoke() { 804  return this.invoke; 805  } 806  807  private boolean executeCode( 808  MessageCall msg, 809  RskAddress contextAddress, 810  Coin contextBalance, 811  InternalTransaction internalTx, 812  Repository track, 813  byte[] programCode, 814  RskAddress senderAddress, 815  byte[] data) { 816  817  returnDataBuffer = null; // reset return buffer right before the call 818  ProgramResult childResult; 819  820  ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke( 821  this, DataWord.valueOf(contextAddress.getBytes()), 822  msg.getType() == MsgType.DELEGATECALL ? getCallerAddress() : getOwnerAddress(), 823  msg.getType() == MsgType.DELEGATECALL ? getCallValue() : msg.getEndowment(), 824  limitToMaxLong(msg.getGas()), contextBalance, data, track, this.invoke.getBlockStore(), 825  msg.getType() == MsgType.STATICCALL || isStaticCall(), byTestingSuite()); 826  827  VM vm = new VM(config, precompiledContracts); 828  Program program = new Program(config, precompiledContracts, blockFactory, activations, programCode, programInvoke, internalTx, deletedAccountsInBlock); 829  830  vm.play(program); 831  childResult = program.getResult(); 832  833  getTrace().addSubTrace(ProgramSubtrace.newCallSubtrace(CallType.fromMsgType(msg.getType()), program.getProgramInvoke(), program.getResult(), msg.getCodeAddress(), program.getTrace().getSubtraces())); 834  835  getTrace().merge(program.getTrace()); 836  getResult().merge(childResult); 837  838  boolean childCallSuccessful = true; 839  840  if (childResult.getException() != null || childResult.isRevert()) { 841  if (isGasLogEnabled) { 842  gasLogger.debug("contract run halted by Exception: contract: [{}], exception: ", 843  contextAddress, 844  childResult .getException()); 845  } 846  847  internalTx.reject(); 848  childResult.rejectInternalTransactions(); 849  childResult.rejectLogInfos(); 850  851  track.rollback(); 852  // when there's an exception we skip applying results and refunding gas, 853  // and we only do that when the call is successful or there's a REVERT operation. 854  if (childResult.getException() != null) { 855  return false; 856  } 857  858  childCallSuccessful = false; 859  } else { 860  // 4. THE FLAG OF SUCCESS IS ONE PUSHED INTO THE STACK 861  track.commit(); 862  } 863  864  865  866  // 3. APPLY RESULTS: childResult.getHReturn() into out_memory allocated 867  byte[] buffer = childResult.getHReturn(); 868  int offset = msg.getOutDataOffs().intValue(); 869  int size = msg.getOutDataSize().intValue(); 870  871  memorySaveLimited(offset, buffer, size); 872  873  returnDataBuffer = buffer; 874  875  // 5. REFUND THE REMAIN GAS 876  BigInteger refundGas = msg.getGas().value().subtract(toBI(childResult.getGasUsed())); 877  if (isPositive(refundGas)) { 878  // Since the original gas transferred was < Long.MAX_VALUE then the refund 879  // also fits in a long. 880  // SUICIDE refunds 24.000 and SSTORE clear refunds 15.000 gas. 881  // The accumulated refund can not exceed half the gas used 882  // for the current context (i.e. the initial call) 883  // Therefore, the regundGas also fits in a long. 884  refundGas(refundGas.longValue(), "remaining gas from the internal call"); 885  if (isGasLogEnabled) { 886  gasLogger.info("The remaining gas refunded, account: [{}], gas: [{}] ", senderAddress, refundGas); 887  } 888  } 889  return childCallSuccessful; 890  } 891  892  public void spendGas(long gasValue, String cause) { 893  if (isGasLogEnabled) { 894  gasLogger.info("[{}] Spent for cause: [{}], gas: [{}]", invoke.hashCode(), cause, gasValue); 895  } 896  897  if (getRemainingGas() < gasValue) { 898  throw ExceptionHelper.notEnoughSpendingGas(this, cause, gasValue); 899  } 900  901  getResult().spendGas(gasValue); 902  } 903  904  public void restart() { 905  setPC(startAddr); 906  stackClear(); 907  clearUsedGas(); 908  stopped=false; 909  } 910  911  private void clearUsedGas() { 912  getResult().clearUsedGas(); 913  } 914  915  public void spendAllGas() { 916  spendGas(getRemainingGas(), "Spending all remaining"); 917  } 918  919  private void refundGas(long gasValue, String cause) { 920  if (isGasLogEnabled) { 921  gasLogger.info("[{}] Refund for cause: [{}], gas: [{}]", invoke.hashCode(), cause, gasValue); 922  } 923  getResult().refundGas(gasValue); 924  } 925  926  public void futureRefundGas(long gasValue) { 927  if (isLogEnabled) { 928  logger.info("Future refund added: [{}]", gasValue); 929  } 930  getResult().addFutureRefund(gasValue); 931  } 932  933  public void resetFutureRefund() { 934  getResult().resetFutureRefund(); 935  } 936  937  public void storageSave(DataWord word1, DataWord word2) { 938  storageSave(word1.getData(), word2.getData()); 939  } 940  941  private void storageSave(byte[] key, byte[] val) { 942  // DataWord constructor some times reference the passed byte[] instead 943  // of making a copy. 944  DataWord keyWord = DataWord.valueOf(key); 945  DataWord valWord = DataWord.valueOf(val); 946  947  getStorage().addStorageRow(getOwnerRskAddress(), keyWord, valWord); 948  } 949  950  private RskAddress getOwnerRskAddress() { 951  if (rskOwnerAddress == null) { 952  rskOwnerAddress = new RskAddress(getOwnerAddress()); 953  } 954  955  return rskOwnerAddress; 956  } 957  958  public byte[] getCode() { 959  return Arrays.copyOf(ops, ops.length); 960  } 961  962  public Keccak256 getCodeHashAt(RskAddress addr, boolean standard) { 963  if(standard) { 964  return invoke.getRepository().getCodeHashStandard(addr); 965  } 966  else { 967  return invoke.getRepository().getCodeHashNonStandard(addr); 968  } 969  } 970  971  public Keccak256 getCodeHashAt(DataWord address, boolean standard) { return getCodeHashAt(new RskAddress(address), standard); } 972  973  public int getCodeLengthAt(RskAddress addr) { 974  return invoke.getRepository().getCodeLength(addr); 975  } 976  977  public int getCodeLengthAt(DataWord address) { 978  return getCodeLengthAt(new RskAddress(address)); 979  } 980  981  public byte[] getCodeAt(DataWord address) { 982  return getCodeAt(new RskAddress(address)); 983  } 984  985  private byte[] getCodeAt(RskAddress addr) { 986  byte[] code = invoke.getRepository().getCode(addr); 987  return nullToEmpty(code); 988  } 989  990  public DataWord getOwnerAddress() { 991  return invoke.getOwnerAddress(); 992  } 993  994  public DataWord getBlockHash(DataWord dw) { 995  long blockIndex = dw.longValueSafe(); 996  // always returns positive, returns Integer.MAX_VALUE on overflows 997  // block number would normally overflow int32 after ~1000 years (at 1 block every 10 seconds) 998  // So int32 arithmetic is ok, but we use int64 anyway. 999  return getBlockHash(blockIndex); 1000  } 1001  1002  public DataWord getBlockHash(long index) { 1003  long bn = this.getNumber().longValue(); 1004  if ((index < bn) && (index >= Math.max(0, bn - 256))) { 1005  return DataWord.valueOf(this.invoke.getBlockStore().getBlockHashByNumber(index, getPrevHash().getData())); 1006  } else { 1007  return DataWord.ZERO; 1008  } 1009  } 1010  1011  public DataWord getBalance(DataWord address) { 1012  Coin balance = getStorage().getBalance(new RskAddress(address)); 1013  return DataWord.valueOf(balance.getBytes()); 1014  } 1015  1016  public DataWord getOriginAddress() { 1017  return invoke.getOriginAddress(); 1018  } 1019  1020  public DataWord getCallerAddress() { 1021  return invoke.getCallerAddress(); 1022  } 1023  1024  public DataWord getGasPrice() { 1025  return invoke.getMinGasPrice(); 1026  } 1027  1028  public long getRemainingGas() { 1029  return invoke.getGas()- getResult().getGasUsed(); 1030  } 1031  1032  public DataWord getCallValue() { 1033  return invoke.getCallValue(); 1034  } 1035  1036  public DataWord getDataSize() { 1037  return invoke.getDataSize(); 1038  } 1039  1040  public DataWord getDataValue(DataWord index) { 1041  return invoke.getDataValue(index); 1042  } 1043  1044  public byte[] getDataCopy(DataWord offset, DataWord length) { 1045  return invoke.getDataCopy(offset, length); 1046  } 1047  1048  public DataWord storageLoad(DataWord key) { 1049  return getStorage().getStorageValue(getOwnerRskAddress(), key); 1050  } 1051  1052  public DataWord getPrevHash() { 1053  return invoke.getPrevHash(); 1054  } 1055  1056  public DataWord getCoinbase() { 1057  return invoke.getCoinbase(); 1058  } 1059  1060  public DataWord getTimestamp() { 1061  return invoke.getTimestamp(); 1062  } 1063  1064  public DataWord getNumber() { 1065  return invoke.getNumber(); 1066  } 1067  1068  public DataWord getTransactionIndex() { 1069  return invoke.getTransactionIndex(); 1070  } 1071  1072  public DataWord getDifficulty() { 1073  return invoke.getDifficulty(); 1074  } 1075  1076  public DataWord getGasLimit() { 1077  return invoke.getGaslimit(); 1078  } 1079  1080  public boolean isStaticCall() { 1081  return invoke.isStaticCall(); 1082  } 1083  1084  public ProgramResult getResult() { 1085  return result; 1086  } 1087  1088  public void setRuntimeFailure(RuntimeException e) { 1089  getResult().setException(e); 1090  } 1091  1092  public String memoryToString() { 1093  if (memory.size()>100000) { 1094  return "<Memory too long to show>"; 1095  } else { 1096  return memory.toString(); 1097  } 1098  } 1099  1100  public void fullTrace() { 1101  1102  if (logger.isTraceEnabled() || listener != null) { 1103  1104  StringBuilder stackData = new StringBuilder(); 1105  for (int i = 0; i < stack.size(); ++i) { 1106  stackData.append(" ").append(stack.get(i)); 1107  if (i < stack.size() - 1) { 1108  stackData.append("\n"); 1109  } 1110  } 1111  1112  if (stackData.length() > 0) { 1113  stackData.insert(0, "\n"); 1114  } 1115  1116  RskAddress ownerAddress = new RskAddress(getOwnerAddress()); 1117  StringBuilder storageData = new StringBuilder(); 1118  if (getStorage().isContract(ownerAddress)) { 1119  Iterator<DataWord> it = getStorage().getStorageKeys(ownerAddress); 1120  while (it.hasNext()) { 1121  DataWord key = it.next(); 1122  storageData.append(" ").append(key).append(" -> "). 1123  append(getStorage().getStorageValue(ownerAddress, key)).append('\n'); 1124  } 1125  if (storageData.length() > 0) { 1126  storageData.insert(0, "\n"); 1127  } 1128  } 1129  1130  StringBuilder memoryData = new StringBuilder(); 1131  StringBuilder oneLine = new StringBuilder(); 1132  if (memory.size() > 320) { 1133  memoryData.append("... Memory Folded.... ") 1134  .append("(") 1135  .append(memory.size()) 1136  .append(") bytes"); 1137  } 1138  else { 1139  for (int i = 0; i < memory.size(); ++i) { 1140  1141  byte value = memory.readByte(i); 1142  oneLine.append(ByteUtil.oneByteToHexString(value)).append(" "); 1143  1144  if ((i + 1) % 16 == 0) { 1145  String tmp = format("[%4s]-[%4s]", Integer.toString(i - 15, 16), 1146  Integer.toString(i, 16)).replace(" ", "0"); 1147  memoryData.append("").append(tmp).append(" "); 1148  memoryData.append(oneLine); 1149  if (i < memory.size()) { 1150  memoryData.append("\n"); 1151  } 1152  oneLine.setLength(0); 1153  } 1154  } 1155  } 1156  if (memoryData.length() > 0) { 1157  memoryData.insert(0, "\n"); 1158  } 1159  1160  StringBuilder opsString = new StringBuilder(); 1161  for (int i = 0; i < ops.length; ++i) { 1162  1163  String tmpString = Integer.toString(ops[i] & 0xFF, 16); 1164  tmpString = tmpString.length() == 1 ? "0" + tmpString : tmpString; 1165  1166  if (i != pc) { 1167  opsString.append(tmpString); 1168  } else { 1169  opsString.append(" >>").append(tmpString).append(""); 1170  } 1171  1172  } 1173  if (pc >= ops.length) { 1174  opsString.append(" >>"); 1175  } 1176  if (opsString.length() > 0) { 1177  opsString.insert(0, "\n "); 1178  } 1179  1180  logger.trace(" -- OPS -- {}", opsString); 1181  logger.trace(" -- STACK -- {}", stackData); 1182  logger.trace(" -- MEMORY -- {}", memoryData); 1183  logger.trace(" -- STORAGE -- {}\n", storageData); 1184  logger.trace("\n Spent Gas: [{}]/[{}]\n Left Gas: [{}]\n", 1185  getResult().getGasUsed(), 1186  invoke.getGas(), 1187  getRemainingGas()); 1188  1189  StringBuilder globalOutput = new StringBuilder("\n"); 1190  if (stackData.length() > 0) { 1191  stackData.append("\n"); 1192  } 1193  1194  if (pc != 0) { 1195  globalOutput.append("[Op: ").append(OpCode.code(lastOp).name()).append("]\n"); 1196  } 1197  1198  globalOutput.append(" -- OPS -- ").append(opsString).append("\n"); 1199  globalOutput.append(" -- STACK -- ").append(stackData).append("\n"); 1200  globalOutput.append(" -- MEMORY -- ").append(memoryData).append("\n"); 1201  globalOutput.append(" -- STORAGE -- ").append(storageData).append("\n"); 1202  1203  if (getResult().getHReturn() != null) { 1204  globalOutput.append("\n HReturn: ").append( 1205  ByteUtil.toHexString(getResult().getHReturn())); 1206  } 1207  1208  // sophisticated assumption that msg.data != codedata 1209  // means we are calling the contract not creating it 1210  byte[] txData = invoke.getDataCopy(DataWord.ZERO, getDataSize()); 1211  if (!Arrays.equals(txData, ops)) { 1212  globalOutput.append("\n msg.data: ").append(ByteUtil.toHexString(txData)); 1213  } 1214  globalOutput.append("\n\n Spent Gas: ").append(getResult().getGasUsed()); 1215  1216  if (listener != null) { 1217  listener.output(globalOutput.toString()); 1218  } 1219  } 1220  } 1221  1222  public void saveOpTrace() { 1223  if (this.pc < ops.length) { 1224  trace.addOp(ops[pc], pc, getCallDeep(), getRemainingGas(), this.memory, this.stack, this.storage); 1225  } 1226  } 1227  1228  public void saveOpGasCost(long gasCost) { 1229  trace.saveGasCost(gasCost); 1230  } 1231  1232  public ProgramTrace getTrace() { 1233  return trace; 1234  } 1235  1236  private int processAndSkipCodeHeader(int offset) { 1237  int ret = offset; 1238  if (ops.length >= 4) { 1239  OpCode op = OpCode.code(ops[0]); 1240  if ((op != null) && op == OpCode.HEADER) { 1241  // next byte is executable format version 1242  // header length in bytes 1243  int exe = ops[1] & 0xff; 1244  // limit to positive to prevent version 0xff < 0x00 1245  exeVersion = (byte) Math.min(exe, 127); 1246  1247  // limit to positive to prevent version 0xff < 0x00 1248  int script = ops[2] & 0xff; 1249  scriptVersion = (byte) Math.min(script, 127); 1250  int extHeaderLen = ops[3] & 0xff; 1251  ret = offset + 4 + extHeaderLen; 1252  startAddr = ret; 1253  pc = ret; 1254  } 1255  } 1256  return ret; 1257  } 1258  1259  private void precompile() { 1260  int i = 0; 1261  exeVersion = 0; 1262  scriptVersion = 0; 1263  startAddr = 0; 1264  pc = 0; 1265  i = processAndSkipCodeHeader(i); 1266  computeJumpDests(i); 1267  } 1268  1269  private void computeJumpDests(int start) { 1270  if (jumpdestSet == null) { 1271  jumpdestSet = new BitSet(ops.length); 1272  } 1273  1274  for (int i = start; i < ops.length; ++i) { 1275  OpCode op = OpCode.code(ops[i]); 1276  1277  if (op == null) { 1278  continue; 1279  } 1280  1281  if (op == OpCode.JUMPDEST) { 1282  jumpdestSet.set(i); 1283  } 1284  1285  if (op.asInt() >= OpCode.PUSH1.asInt() && op.asInt() <= OpCode.PUSH32.asInt()) { 1286  i += op.asInt() - OpCode.PUSH1.asInt() + 1; 1287  } 1288  } 1289  } 1290  1291  public DataWord getReturnDataBufferSize() { 1292  return DataWord.valueOf(getReturnDataBufferSizeI()); 1293  } 1294  1295  private int getReturnDataBufferSizeI() { 1296  return returnDataBuffer == null ? 0 : returnDataBuffer.length; 1297  } 1298  1299  public Optional<byte[]> getReturnDataBufferData(DataWord off, DataWord size) { 1300  long endPosition = (long) off.intValueSafe() + size.intValueSafe(); 1301  if (endPosition > getReturnDataBufferSizeI()) { 1302  return Optional.empty(); 1303  } 1304  1305  if (returnDataBuffer == null) { 1306  return Optional.of(new byte[0]); 1307  } 1308  1309  byte[] copiedData = Arrays.copyOfRange(returnDataBuffer, off.intValueSafe(), Math.toIntExact(endPosition)); 1310  return Optional.of(copiedData); 1311  } 1312  1313  public ActivationConfig.ForBlock getActivations() { 1314  return activations; 1315  } 1316  1317  public void addListener(ProgramOutListener listener) { 1318  this.listener = listener; 1319  } 1320  1321  public int verifyJumpDest(DataWord nextPC) { 1322  // This is painstankly slow 1323  if (nextPC.occupyMoreThan(4)) { 1324  throw ExceptionHelper.badJumpDestination(this, -1); 1325  } 1326  int ret = nextPC.intValue(); // could be negative 1327  if (ret < 0 || ret >= jumpdestSet.size() || !jumpdestSet.get(ret)) { 1328  throw ExceptionHelper.badJumpDestination(this, ret); 1329  } 1330  return ret; 1331  } 1332  1333  public void callToPrecompiledAddress(MessageCall msg, PrecompiledContract contract) { 1334  1335  if (getCallDeep() == getMaxDepth()) { 1336  stackPushZero(); 1337  this.refundGas(msg.getGas().longValue(), " call deep limit reach"); 1338  1339  return; 1340  } 1341  1342  Repository track = getStorage().startTracking(); 1343  1344  RskAddress senderAddress = getOwnerRskAddress(); 1345  RskAddress codeAddress = new RskAddress(msg.getCodeAddress()); 1346  RskAddress contextAddress = msg.getType().isStateless() ? senderAddress : codeAddress; 1347  1348  Coin endowment = new Coin(msg.getEndowment().getData()); 1349  Coin senderBalance = track.getBalance(senderAddress); 1350  if (senderBalance.compareTo(endowment) < 0) { 1351  stackPushZero(); 1352  this.refundGas(msg.getGas().longValue(), "refund gas from message call"); 1353  this.cleanReturnDataBuffer(); 1354  1355  return; 1356  } 1357  1358  byte[] data = this.memoryChunk(msg.getInDataOffs().intValue(), 1359  msg.getInDataSize().intValue()); 1360  1361  // Charge for endowment - is not reversible by rollback 1362  track.transfer(senderAddress, contextAddress, new Coin(msg.getEndowment().getData())); 1363  1364  // we are assuming that transfer is already creating destination account even if the amount is zero 1365  if (!track.isContract(codeAddress)) { 1366  track.setupContract(codeAddress); 1367  } 1368  1369  if (byTestingSuite()) { 1370  // This keeps track of the calls created for a test 1371  this.getResult().addCallCreate(data, 1372  codeAddress.getBytes(), 1373  msg.getGas().longValueSafe(), 1374  msg.getEndowment().getNoLeadZeroesData()); 1375  1376  stackPushOne(); 1377  return; 1378  } 1379  1380  // Special initialization for Bridge, Remasc and NativeContract contracts 1381  if (contract instanceof Bridge || contract instanceof RemascContract || contract instanceof NativeContract) { 1382  // CREATE CALL INTERNAL TRANSACTION 1383  InternalTransaction internalTx = addInternalTx( 1384  null, 1385  getGasLimit(), 1386  senderAddress, 1387  contextAddress, 1388  endowment, 1389  EMPTY_BYTE_ARRAY, 1390  "call" 1391  ); 1392  1393  // Propagate the "local call" nature of the originating transaction down to the callee 1394  internalTx.setLocalCallTransaction(this.transaction.isLocalCallTransaction()); 1395  1396  Block executionBlock = blockFactory.newBlock( 1397  blockFactory.getBlockHeaderBuilder() 1398  .setParentHash(getPrevHash().getData()) 1399  .setCoinbase(new RskAddress(getCoinbase().getLast20Bytes())) 1400  .setDifficultyFromBytes(getDifficulty().getData()) 1401  .setNumber(getNumber().longValue()) 1402  .setGasLimit(getGasLimit().getData()) 1403  .setTimestamp(getTimestamp().longValue()) 1404  .build(), 1405  Collections.emptyList(), 1406  Collections.emptyList() 1407  ); 1408  1409  contract.init(internalTx, executionBlock, track, this.invoke.getBlockStore(), null, result.getLogInfoList()); 1410  } 1411  1412  long requiredGas = contract.getGasForData(data); 1413  if (requiredGas > msg.getGas().longValue()) { 1414  this.refundGas(0, CALL_PRECOMPILED_CAUSE); //matches cpp logic 1415  this.stackPushZero(); 1416  track.rollback(); 1417  this.cleanReturnDataBuffer(); 1418  } else { 1419  if (getActivations().isActive(ConsensusRule.RSKIP197)) { 1420  executePrecompiledAndHandleError(contract, msg, requiredGas, track, data); 1421  } else { 1422  executePrecompiled(contract, msg, requiredGas, track, data); 1423  } 1424  } 1425  } 1426  1427  /** 1428  * This is for compatibility before RSKIP197, no error handling was implemented when calling to precompiled contracts. 1429  * 1430  * This method shouldn't be modified, all new changes should go to executePrecompiledAndHandleError() method 1431  */ 1432  @Deprecated 1433  private void executePrecompiled(PrecompiledContract contract, MessageCall msg, long requiredGas, Repository track, byte[] data) { 1434  try { 1435  this.refundGas(msg.getGas().longValue() - requiredGas, CALL_PRECOMPILED_CAUSE); 1436  byte[] out = contract.execute(data); 1437  if (getActivations().isActive(ConsensusRule.RSKIP90)) { 1438  this.returnDataBuffer = out; 1439  } 1440  saveOutAfterExecution(msg, out); 1441  this.stackPushOne(); 1442  track.commit(); 1443  } catch (VMException e) { 1444  throw new RuntimeException(e); 1445  } 1446  } 1447  1448  /** 1449  * This is after RSKIP197, where we fix the way in which error is handled after a precompiled execution. 1450  */ 1451  private void executePrecompiledAndHandleError(PrecompiledContract contract, MessageCall msg, long requiredGas, Repository track, byte[] data) { 1452  try { 1453  logger.trace("Executing Precompiled contract..."); 1454  this.returnDataBuffer = contract.execute(data); 1455  logger.trace("Executing Precompiled setting output."); 1456  this.memorySaveLimited(msg.getOutDataOffs().intValue(), this.returnDataBuffer, msg.getOutDataSize().intValue()); 1457  this.stackPushOne(); 1458  track.commit(); 1459  } catch (VMException e) { 1460  logger.trace("Precompiled execution error. Pushing Zero to stack and performing rollback.", e); 1461  this.stackPushZero(); 1462  track.rollback(); 1463  this.returnDataBuffer = null; 1464  } finally { 1465  final long refundingGas = msg.getGas().longValue() - requiredGas; 1466  this.refundGas(refundingGas, CALL_PRECOMPILED_CAUSE); 1467  } 1468  } 1469  1470  /** 1471  * This is for compatibility before RSKIP197. {@code memorySaveLimited()} should be called directly instead. 1472  */ 1473  @Deprecated 1474  private void saveOutAfterExecution(MessageCall msg, byte[] out) { 1475  logger.trace("Executing Precompiled saving memory."); 1476  // Avoid saving null returns to memory and limit the memory it can use. 1477  // If we're behind RSK150 activation, don't care about the null return, just save. 1478  if (getActivations().isActive(ConsensusRule.RSKIP150) && out != null) { 1479  this.memorySaveLimited(msg.getOutDataOffs().intValue(), out, msg.getOutDataSize().intValue()); 1480  } else if (!getActivations().isActive(ConsensusRule.RSKIP150)) { 1481  this.memorySave(msg.getOutDataOffs().intValue(), out); 1482  } 1483  } 1484  1485  private boolean byTestingSuite() { 1486  return invoke.byTestingSuite(); 1487  } 1488  1489  public interface ProgramOutListener { 1490  void output(String out); 1491  } 1492  1493  @SuppressWarnings("serial") 1494  public static class OutOfGasException extends RuntimeException { 1495  1496  public OutOfGasException(String message, Object... args) { 1497  super(format(message, args)); 1498  } 1499  } 1500  1501  @SuppressWarnings("serial") 1502  public static class IllegalOperationException extends RuntimeException { 1503  1504  public IllegalOperationException(String message, Object... args) { 1505  super(format(message, args)); 1506  } 1507  } 1508  1509  @SuppressWarnings("serial") 1510  public static class BadJumpDestinationException extends RuntimeException { 1511  1512  public BadJumpDestinationException(String message, Object... args) { 1513  super(format(message, args)); 1514  } 1515  } 1516  1517  1518  @SuppressWarnings("serial") 1519  public static class StackTooSmallException extends RuntimeException { 1520  1521  public StackTooSmallException(String message, Object... args) { 1522  super(format(message, args)); 1523  } 1524  } 1525  1526  1527  @SuppressWarnings("serial") 1528  public static class StaticCallModificationException extends RuntimeException { 1529  public StaticCallModificationException(String message, Object... args) { 1530  super(format(message, args)); 1531  } 1532  } 1533  1534  public static class AddressCollisionException extends RuntimeException { 1535  public AddressCollisionException(String message) { 1536  super(message); 1537  } 1538  } 1539  1540  public static class ExceptionHelper { 1541  1542  private ExceptionHelper() { } 1543  1544  public static StaticCallModificationException modificationException(@Nonnull Program program) { 1545  return new StaticCallModificationException("Attempt to call a state modifying opcode inside STATICCALL: tx[%s]", extractTxHash(program)); 1546  } 1547  1548  public static OutOfGasException notEnoughOpGas(@Nonnull Program program, OpCode op, long opGas, long programGas) { 1549  return new OutOfGasException("Not enough gas for '%s' operation executing: opGas[%d], programGas[%d], tx[%s]", op, opGas, programGas, extractTxHash(program)); 1550  } 1551  1552  public static OutOfGasException notEnoughOpGas(Program program, OpCode op, DataWord opGas, DataWord programGas) { 1553  return notEnoughOpGas(program, op, opGas.longValue(), programGas.longValue()); 1554  } 1555  1556  public static OutOfGasException notEnoughOpGas(Program program, OpCode op, BigInteger opGas, BigInteger programGas) { 1557  return notEnoughOpGas(program, op, opGas.longValue(), programGas.longValue()); 1558  } 1559  1560  public static OutOfGasException notEnoughSpendingGas(@Nonnull Program program, String cause, long gasValue) { 1561  return new OutOfGasException("Not enough gas for '%s' cause spending: invokeGas[%d], gas[%d], usedGas[%d], tx[%s]", 1562  cause, program.invoke.getGas(), gasValue, program.getResult().getGasUsed(), extractTxHash(program)); 1563  } 1564  1565  public static OutOfGasException gasOverflow(@Nonnull Program program, BigInteger actualGas, BigInteger gasLimit) { 1566  return new OutOfGasException("Gas value overflow: actualGas[%d], gasLimit[%d], tx[%s]", actualGas.longValue(), gasLimit.longValue(), extractTxHash(program)); 1567  } 1568  public static OutOfGasException gasOverflow(@Nonnull Program program, long actualGas, BigInteger gasLimit) { 1569  return new OutOfGasException("Gas value overflow: actualGas[%d], gasLimit[%d], tx[%s]", actualGas, gasLimit.longValue(), extractTxHash(program)); 1570  } 1571  public static IllegalOperationException invalidOpCode(@Nonnull Program program) { 1572  return new IllegalOperationException("Invalid operation code: opcode[%s], tx[%s]", ByteUtil.toHexString(new byte[] {program.getCurrentOp()}, 0, 1), extractTxHash(program)); 1573  } 1574  1575  public static BadJumpDestinationException badJumpDestination(@Nonnull Program program, int pc) { 1576  return new BadJumpDestinationException("Operation with pc isn't 'JUMPDEST': PC[%d], tx[%s]", pc, extractTxHash(program)); 1577  } 1578  1579  public static StackTooSmallException tooSmallStack(@Nonnull Program program, int expectedSize, int actualSize) { 1580  return new StackTooSmallException("Expected stack size %d but actual %d, tx: %s", expectedSize, actualSize, extractTxHash(program)); 1581  } 1582  1583  public static RuntimeException tooLargeContractSize(@Nonnull Program program, int maxSize, int actualSize) { 1584  return new RuntimeException(format("Maximum contract size allowed %d but actual %d, tx: %s", maxSize, actualSize, extractTxHash(program))); 1585  } 1586  1587  public static AddressCollisionException addressCollisionException(@Nonnull Program program, RskAddress address) { 1588  return new AddressCollisionException("Trying to create a contract with existing contract address: 0x" + address + ", tx: " + extractTxHash(program)); 1589  } 1590  1591  @Nonnull 1592  private static String extractTxHash(@Nonnull Program program) { 1593  return program.transaction == null ? "<null>" : "0x" + program.transaction.getHash().toHexString(); 1594  } 1595  } 1596  1597  @SuppressWarnings("serial") 1598  public class StackTooLargeException extends RuntimeException { 1599  public StackTooLargeException(String message) { 1600  super(message); 1601  } 1602  } 1603  1604  /** 1605  * used mostly for testing reasons 1606  */ 1607  public byte[] getMemory() { 1608  return memory.read(0, memory.size()); 1609  } 1610  1611  /** 1612  * used mostly for testing reasons 1613  */ 1614  public void initMem(byte[] data) { 1615  this.memory.write(0, data, data.length, false); 1616  } 1617  1618  public byte getExeVersion() { 1619  return exeVersion; 1620  } 1621  public byte getScriptVersion() { 1622  return scriptVersion; 1623  } 1624  public int getStartAddr(){ 1625  return startAddr; 1626  } 1627  1628  @VisibleForTesting 1629  public BitSet getJumpdestSet() { return this.jumpdestSet; } 1630 }