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); } } }