Exemplo n.º 1
0
  public void createContract(DataWord value, DataWord memStart, DataWord memSize) {

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

    // [1] FETCH THE CODE FROM THE MEMORY
    ByteBuffer programCode = memoryChunk(memStart, memSize);

    byte[] senderAddress = this.getOwnerAddress().getLast20Bytes();
    if (logger.isInfoEnabled())
      logger.info(
          "creating a new contract inside contract run: [{}]", Hex.toHexString(senderAddress));

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

    // [2] CREATE THE CONTRACT ADDRESS
    byte[] nonce = result.getRepository().getNonce(senderAddress).toByteArray();
    byte[] newAddress = HashUtil.calcNewAddr(this.getOwnerAddress().getLast20Bytes(), nonce);
    result.getRepository().createAccount(newAddress);

    // [3] UPDATE THE NONCE
    // (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
    result.getRepository().increaseNonce(senderAddress);

    // [4] TRANSFER THE BALANCE
    BigInteger endowment = value.value();
    BigInteger senderBalance = result.getRepository().getBalance(senderAddress);
    if (senderBalance.compareTo(endowment) < 0) {
      stackPushZero();
      return;
    }
    result.getRepository().addBalance(senderAddress, endowment.negate());
    result.getRepository().addBalance(newAddress, endowment);

    RepositoryImpl trackRepositoryImpl = result.getRepository().getTrack();
    trackRepositoryImpl.startTracking();

    // [5] COOK THE INVOKE AND EXECUTE
    ProgramInvoke programInvoke =
        ProgramInvokeFactory.createProgramInvoke(
            this,
            new DataWord(newAddress),
            DataWord.ZERO,
            new DataWord(gas),
            BigInteger.ZERO,
            null,
            trackRepositoryImpl,
            this.invokeData.getCallDeep() + 1);

    VM vm = new VM();
    Program program = new Program(programCode.array(), programInvoke);
    vm.play(program);
    ProgramResult result = program.getResult();
    this.result.addDeleteAccounts(result.getDeleteAccounts());

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

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

    // 4. CREATE THE CONTRACT OUT OF RETURN
    byte[] code = result.getHReturn().array();
    trackRepositoryImpl.saveCode(newAddress, code);

    // IN SUCCESS PUSH THE ADDRESS INTO THE STACK
    stackPush(new DataWord(newAddress));
    trackRepositoryImpl.commit();

    // 5. REFUND THE REMAIN GAS
    long refundGas = gas - result.getGasUsed();
    if (refundGas > 0) {
      this.refundGas(refundGas, "remain gas from the internal call");
      if (logger.isInfoEnabled()) {

        logger.info(
            "The remaining gas is refunded, account: [ {} ], gas: [ {} ] ",
            Hex.toHexString(this.getOwnerAddress().getLast20Bytes()),
            refundGas);
      }
    }
  }