Exemple #1
0
  public DataWord memoryLoad(int address) {

    allocateMemory(address, DataWord.ZERO.getData().length);

    DataWord newMem = new DataWord();
    System.arraycopy(memory.array(), address, newMem.getData(), 0, newMem.getData().length);

    return newMem;
  }
Exemple #2
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;
  }
Exemple #3
0
  public void setPC(DataWord pc) {

    this.pc = pc.intValue();

    if (this.pc == ops.length) {
      stop();
    }

    if (this.pc > ops.length) {
      stop();
      throw new RuntimeException("pc overflow pc=" + pc);
    }
  }
Exemple #4
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());
  }
  @Ignore // TODO #POC9
  @Test // contractB call contractA with data to storage
  public void test2() {

    /**
     * #The code will run ------------------
     *
     * <p>contract A: 77045e71a7a2c50903d88e564cd72fab11e82051 --------------- a = msg.data[0] b =
     * msg.data[1]
     *
     * <p>contract.storage[a] contract.storage[b]
     *
     * <p>contract B: 83c5541a6c8d2dbad642f385d8d06ca9b6c731ee ----------- a = msg((tx.gas / 10 *
     * 8), 0x77045e71a7a2c50903d88e564cd72fab11e82051, 0, [11, 22, 33], 3, 6)
     */
    long expectedVal_1 = 11;
    long expectedVal_2 = 22;

    // Set contract into Database
    String callerAddr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";

    String contractA_addr = "77045e71a7a2c50903d88e564cd72fab11e82051";
    String contractB_addr = "83c5541a6c8d2dbad642f385d8d06ca9b6c731ee";

    String code_a = "60006020023560005260016020023560205260005160005560205160015500";
    String code_b =
        "6000601f5360e05960e05952600060c05901536060596020015980602001600b9052806040016016905280606001602190526080905260007377045e71a7a2c50903d88e564cd72fab11e820516103e8f1602060000260a00160200151600052";

    byte[] caller_addr_bytes = Hex.decode(callerAddr);

    byte[] contractA_addr_bytes = Hex.decode(contractA_addr);
    byte[] codeA = Hex.decode(code_a);

    byte[] contractB_addr_bytes = Hex.decode(contractB_addr);
    byte[] codeB = Hex.decode(code_b);

    ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
    pi.setOwnerAddress(contractB_addr_bytes);
    Repository repository = pi.getRepository();

    repository.createAccount(contractA_addr_bytes);
    repository.saveCode(contractA_addr_bytes, codeA);

    repository.createAccount(contractB_addr_bytes);
    repository.saveCode(contractB_addr_bytes, codeB);

    repository.createAccount(caller_addr_bytes);
    repository.addBalance(caller_addr_bytes, new BigInteger("100000000000000000000"));

    // ****************** //
    //  Play the program  //
    // ****************** //
    VM vm = new VM();
    Program program = new Program(codeB, pi);

    try {
      while (!program.isStopped()) vm.step(program);
    } catch (RuntimeException e) {
      program.setRuntimeFailure(e);
    }

    System.out.println();
    System.out.println("============ Results ============");

    System.out.println("*** Used gas: " + program.getResult().getGasUsed());

    DataWord value_1 = repository.getStorageValue(contractA_addr_bytes, new DataWord(00));
    DataWord value_2 = repository.getStorageValue(contractA_addr_bytes, new DataWord(01));

    repository.close();
    assertEquals(expectedVal_1, value_1.longValue());
    assertEquals(expectedVal_2, value_2.longValue());

    // TODO: check that the value pushed after exec is 1
  }
  @Ignore
  @Test // contractB call itself with code from contractA
  public void test6() {
    /**
     * #The code will run ------------------
     *
     * <p>contract A: 945304eb96065b2a98b57a48a06ae28d285a71b5 ---------------
     *
     * <p>PUSH1 0 CALLDATALOAD SLOAD NOT PUSH1 9 JUMPI STOP PUSH1 32 CALLDATALOAD PUSH1 0
     * CALLDATALOAD SSTORE
     *
     * <p>contract B: 0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 ----------- { (MSTORE 0
     * 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32
     * 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa) [[ 0 ]] (CALLSTATELESS
     * 1000000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 64 0) }
     */

    // Set contract into Database
    byte[] caller_addr_bytes = Hex.decode("cd1722f3947def4cf144679da39c4c32bdc35681");

    byte[] contractA_addr_bytes = Hex.decode("945304eb96065b2a98b57a48a06ae28d285a71b5");
    byte[] contractB_addr_bytes = Hex.decode("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6");

    byte[] codeA = Hex.decode("60003554156009570060203560003555");
    byte[] codeB =
        Hex.decode(
            "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa6020526000604060406000601773945304eb96065b2a98b57a48a06ae28d285a71b5620f4240f3600055");

    ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
    pi.setOwnerAddress(contractB_addr_bytes);
    pi.setGasLimit(10000000000000l);

    Repository repository = pi.getRepository();
    repository.createAccount(contractA_addr_bytes);
    repository.saveCode(contractA_addr_bytes, codeA);
    repository.addBalance(contractA_addr_bytes, BigInteger.valueOf(23));

    repository.createAccount(contractB_addr_bytes);
    repository.saveCode(contractB_addr_bytes, codeB);
    repository.addBalance(contractB_addr_bytes, new BigInteger("1000000000000000000"));

    repository.createAccount(caller_addr_bytes);
    repository.addBalance(caller_addr_bytes, new BigInteger("100000000000000000000"));

    // ****************** //
    //  Play the program  //
    // ****************** //
    VM vm = new VM();
    Program program = new Program(codeB, pi);

    try {
      while (!program.isStopped()) vm.step(program);
    } catch (RuntimeException e) {
      program.setRuntimeFailure(e);
    }

    System.out.println();
    System.out.println("============ Results ============");
    System.out.println("*** Used gas: " + program.getResult().getGasUsed());

    DataWord memValue1 = program.memoryLoad(new DataWord(0));
    DataWord memValue2 = program.memoryLoad(new DataWord(32));

    DataWord storeValue1 = repository.getStorageValue(contractB_addr_bytes, new DataWord(00));

    repository.close();

    assertEquals(
        "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", memValue1.toString());
    assertEquals(
        "aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa", memValue2.toString());

    assertEquals("0x1", storeValue1.shortHex());

    // TODO: check that the value pushed after exec is 1
  }
  @Ignore
  @Test // contractB call contractA with return expectation
  public void test3() {

    /**
     * #The code will run ------------------
     *
     * <p>contract A: 77045e71a7a2c50903d88e564cd72fab11e82051 ---------------
     *
     * <p>a = 11 b = 22 c = 33 d = 44 e = 55 f = 66
     *
     * <p>[asm 192 0 RETURN asm]
     *
     * <p>contract B: 83c5541a6c8d2dbad642f385d8d06ca9b6c731ee ----------- a = msg((tx.gas / 10 *
     * 8), 0x77045e71a7a2c50903d88e564cd72fab11e82051, 0, [11, 22, 33], 3, 6)
     */
    long expectedVal_1 = 11;
    long expectedVal_2 = 22;
    long expectedVal_3 = 33;
    long expectedVal_4 = 44;
    long expectedVal_5 = 55;
    long expectedVal_6 = 66;

    // Set contract into Database
    byte[] caller_addr_bytes = Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826");

    byte[] contractA_addr_bytes = Hex.decode("77045e71a7a2c50903d88e564cd72fab11e82051");
    byte[] contractB_addr_bytes = Hex.decode("83c5541a6c8d2dbad642f385d8d06ca9b6c731ee");

    byte[] codeA =
        Hex.decode("600b60005260166020526021604052602c6060526037608052604260a05260c06000f2");
    byte[] codeB =
        Hex.decode(
            "6000601f5360e05960e05952600060c05901536060596020015980602001600b9052806040016016905280606001602190526080905260007377045e71a7a2c50903d88e564cd72fab11e820516103e8f1602060000260a00160200151600052");

    ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
    pi.setOwnerAddress(contractB_addr_bytes);
    Repository repository = pi.getRepository();
    repository.createAccount(contractA_addr_bytes);
    repository.saveCode(contractA_addr_bytes, codeA);

    repository.createAccount(contractB_addr_bytes);
    repository.saveCode(contractB_addr_bytes, codeB);

    repository.createAccount(caller_addr_bytes);
    repository.addBalance(caller_addr_bytes, new BigInteger("100000000000000000000"));

    // ****************** //
    //  Play the program  //
    // ****************** //
    VM vm = new VM();
    Program program = new Program(codeB, pi);

    try {
      while (!program.isStopped()) vm.step(program);
    } catch (RuntimeException e) {
      program.setRuntimeFailure(e);
    }

    System.out.println();
    System.out.println("============ Results ============");
    System.out.println("*** Used gas: " + program.getResult().getGasUsed());

    DataWord value1 = program.memoryLoad(new DataWord(32));
    DataWord value2 = program.memoryLoad(new DataWord(64));
    DataWord value3 = program.memoryLoad(new DataWord(96));
    DataWord value4 = program.memoryLoad(new DataWord(128));
    DataWord value5 = program.memoryLoad(new DataWord(160));
    DataWord value6 = program.memoryLoad(new DataWord(192));

    repository.close();

    assertEquals(expectedVal_1, value1.longValue());
    assertEquals(expectedVal_2, value2.longValue());
    assertEquals(expectedVal_3, value3.longValue());
    assertEquals(expectedVal_4, value4.longValue());
    assertEquals(expectedVal_5, value5.longValue());
    assertEquals(expectedVal_6, value6.longValue());

    // TODO: check that the value pushed after exec is 1
  }
Exemple #8
0
 public void storageSave(DataWord word1, DataWord word2) {
   storageSave(word1.getData(), word2.getData());
 }
Exemple #9
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");
    }
  }
Exemple #10
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);
      }
    }
  }
Exemple #11
0
 public ByteBuffer memoryChunk(DataWord offsetData, DataWord sizeData) {
   return memoryChunk(offsetData.intValue(), sizeData.intValue());
 }
Exemple #12
0
 public DataWord memoryLoad(DataWord addr) {
   return memoryLoad(addr.intValue());
 }
Exemple #13
0
 public void memorySave(DataWord addrB, DataWord value) {
   memorySave(addrB.intValue(), value.getData());
 }