Ejemplo n.º 1
0
  public DataWord getBalance(DataWord address) {
    if (invokeData == null) return DataWord.ZERO_EMPTY_ARRAY;

    BigInteger balance = result.getRepository().getBalance(address.getLast20Bytes());
    DataWord balanceData = new DataWord(balance.toByteArray());

    return balanceData;
  }
Ejemplo n.º 2
0
  public void suicide(DataWord obtainer) {

    DataWord balance = getBalance(this.getOwnerAddress());
    // 1) pass full endowment to the obtainer
    if (logger.isInfoEnabled())
      logger.info(
          "Transfer to: [ {} ] heritage: [ {} ]",
          Hex.toHexString(obtainer.getLast20Bytes()),
          balance.longValue());

    this.result.getRepository().addBalance(obtainer.getLast20Bytes(), balance.value());
    this.result
        .getRepository()
        .addBalance(this.getOwnerAddress().getLast20Bytes(), balance.value().negate());

    // 2) mark the account as for delete
    result.addDeleteAccount(this.getOwnerAddress());
  }
Ejemplo n.º 3
0
  /**
   * That method implement internal calls and code invocations
   *
   * @param gas - gas to pay for the call, remaining gas will be refunded to the caller
   * @param toAddressDW - address to call
   * @param endowmentValue - the value that can be transfer along with the code execution
   * @param inDataOffs - start of memory to be input data to the call
   * @param inDataSize - size of memory to be input data to the call
   * @param outDataOffs - start of memory to be output of the call
   * @param outDataSize - size of memory to be output data to the call
   */
  public void callToAddress(
      DataWord gas,
      DataWord toAddressDW,
      DataWord endowmentValue,
      DataWord inDataOffs,
      DataWord inDataSize,
      DataWord outDataOffs,
      DataWord outDataSize) {

    ByteBuffer data = memoryChunk(inDataOffs, inDataSize);

    // FETCH THE SAVED STORAGE
    byte[] toAddress = toAddressDW.getLast20Bytes();

    // FETCH THE CODE
    byte[] programCode = this.result.getRepository().getCode(toAddress);

    if (logger.isInfoEnabled())
      logger.info(
          "calling for existing contract: address: [ {} ], outDataOffs: [ {} ], outDataSize: [ {} ]  ",
          Hex.toHexString(toAddress),
          outDataOffs.longValue(),
          outDataSize.longValue());

    byte[] senderAddress = this.getOwnerAddress().getLast20Bytes();

    // 2.1 PERFORM THE GAS VALUE TX
    // (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
    if (this.getGas().longValue() - gas.longValue() < 0) {
      logger.info(
          "No gas for the internal call, \n" + "fromAddress={}, toAddress={}",
          Hex.toHexString(senderAddress),
          Hex.toHexString(toAddress));
      this.stackPushZero();
      return;
    }

    BigInteger endowment = endowmentValue.value();
    BigInteger senderBalance = result.getRepository().getBalance(senderAddress);
    if (senderBalance.compareTo(endowment) < 0) {
      stackPushZero();
      return;
    }
    result.getRepository().addBalance(senderAddress, endowment.negate());

    if (invokeData.byTestingSuite()) {
      logger.info("[testing suite] - omit real call");

      stackPushOne();

      this.getResult()
          .addCallCreate(
              data.array(),
              toAddressDW.getLast20Bytes(),
              gas.getNoLeadZeroesData(),
              endowmentValue.getNoLeadZeroesData());

      return;
    }

    //  actual gas subtract
    this.spendGas(gas.intValue(), "internal call");

    RepositoryImpl trackRepositoryImpl = result.getRepository().getTrack();
    trackRepositoryImpl.startTracking();
    trackRepositoryImpl.addBalance(toAddress, endowmentValue.value());

    ProgramInvoke programInvoke =
        ProgramInvokeFactory.createProgramInvoke(
            this,
            toAddressDW,
            endowmentValue,
            gas,
            result.getRepository().getBalance(toAddress),
            data.array(),
            trackRepositoryImpl,
            this.invokeData.getCallDeep() + 1);

    ProgramResult result = null;

    if (programCode != null && programCode.length != 0) {
      VM vm = new VM();
      Program program = new Program(programCode, programInvoke);
      vm.play(program);
      result = program.getResult();
      this.result.addDeleteAccounts(result.getDeleteAccounts());
    }

    if (result != null
        && result.getException() != null
        && result.getException() instanceof Program.OutOfGasException) {
      logger.info("contract run halted by OutOfGas: contract={}", Hex.toHexString(toAddress));

      trackRepositoryImpl.rollback();
      stackPushZero();
      return;
    }

    // 3. APPLY RESULTS: result.getHReturn() into out_memory allocated
    if (result != null) {
      ByteBuffer buffer = result.getHReturn();
      int allocSize = outDataSize.intValue();
      if (buffer != null && allocSize > 0) {
        int retSize = buffer.limit();
        int offset = outDataOffs.intValue();
        if (retSize > allocSize) {
          this.memorySave(offset, buffer.array());
        } else {
          this.memorySave(offset, allocSize, buffer.array());
        }
      }
    }

    // 4. THE FLAG OF SUCCESS IS ONE PUSHED INTO THE STACK
    trackRepositoryImpl.commit();
    stackPushOne();

    // 5. REFUND THE REMAIN GAS
    if (result != null) {
      BigInteger refundGas = gas.value().subtract(BigInteger.valueOf(result.getGasUsed()));
      if (refundGas.compareTo(BigInteger.ZERO) == 1) {

        this.refundGas(refundGas.intValue(), "remaining gas from the internal call");
        logger.info(
            "The remaining gas refunded, account: [ {} ], gas: [ {} ] ",
            Hex.toHexString(senderAddress),
            refundGas.toString());
      }
    } else {
      this.refundGas(gas.intValue(), "remaining gas from the internal call");
    }
  }