Solidity

由於 TransactionTimeoutException,無法使用 Web3j(Java 客戶端)將合約部署到私有區塊鏈

  • July 12, 2017

我正在使用 Web3j 與我在 Azure 中創建的私有區塊鍊網路進行互動。

我已經使用 Remix 和 Metamask 創建了合約,並且能夠從 Java 中查看該合約。

但是我無法從 Java 部署或創建契約。我按照連結https://github.com/web3j/web3j中的說明進行操作。

我不斷收到Transaction receipt was not generated after 600 seconds for transactionorg.web3j.protocol.exceptions.TransactionTimeoutException

ContractRunner.java

   public static void main(String args[]) throws InterruptedException, ExecutionException, IOException, CipherException, TransactionTimeoutException {
       Web3j web3 = Web3j.build(new HttpService("http://xxxxxxxxx.westus.cloudapp.azure.com:8545/"));  // defaults to http://localhost:8545/
       Web3ClientVersion web3ClientVersion = web3.web3ClientVersion().sendAsync().get();
       String clientVersion = web3ClientVersion.getWeb3ClientVersion();
       System.out.println(clientVersion);
       Credentials credentials = WalletUtils.loadCredentials("MyPassword", "C:\\Users\\adheep_m\\AppData\\Roaming\\Ethereum\\keystore\\UTC--2017-07-07T13-52-18.006069200Z--3b0d3fa08f0e0b3da8fe1f8ac0e05861bfdada25");
       System.out.println(credentials.getAddress());

       Token contract = Token.deploy(web3,credentials,BigInteger.valueOf(3000000),BigInteger.valueOf(3000000),BigInteger.valueOf(0)).get();
       System.out.println(contract.getContractAddress());
   }

令牌.sol

pragma solidity ^0.4.0;

contract Token {
mapping (address => uint) public balances;

function Token() {
   balances[msg.sender] = 1000000;
}

function transfer(address _to, uint _amount) {
   if (balances[msg.sender] < _amount) {
       throw;
   }

   balances[msg.sender] -= _amount;
   balances[_to] += _amount;
}

}

Token.java(從 Web3j 生成)

public final class Token extends Contract {
   private static final String BINARY = "6060604052341561000f57600080fd5b5b600160a060020a0333166000908152602081905260409020620f424090555b5b6101678061003f6000396000f300606060405263ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166327e235e38114610048578063a9059cbb14610086575b600080fd5b341561005357600080fd5b61007473ffffffffffffffffffffffffffffffffffffffff600435166100b7565b60405190815260200160405180910390f35b341561009157600080fd5b6100b573ffffffffffffffffffffffffffffffffffffffff600435166024356100c9565b005b60006020819052908152604090205481565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040902054819010156100fc57600080fd5b73ffffffffffffffffffffffffffffffffffffffff338116600090815260208190526040808220805485900390559184168152208054820190555b50505600a165627a7a7230582081fd33c821a86127abf00c9fafe2e14e4db6279ab9dd788e3ad3597d2280b6cf0029";

   private Token(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
       super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit);
   }

   private Token(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
       super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit);
   }

   public Future<Uint256> balances(Address param0) {
       Function function = new Function("balances", 
               Arrays.<Type>asList(param0), 
               Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {}));
       return executeCallSingleValueReturnAsync(function);
   }

   public Future<TransactionReceipt> transfer(Address _to, Uint256 _amount) {
       Function function = new Function("transfer", Arrays.<Type>asList(_to, _amount), Collections.<TypeReference<?>>emptyList());
       return executeTransactionAsync(function);
   }

   public static Future<Token> deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, BigInteger initialWeiValue) {
       return deployAsync(Token.class, web3j, credentials, gasPrice, gasLimit, BINARY, "", initialWeiValue);
   }

   public static Future<Token> deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, BigInteger initialWeiValue) {
       return deployAsync(Token.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, "", initialWeiValue);
   }

   public static Token load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
       return new Token(contractAddress, web3j, credentials, gasPrice, gasLimit);
   }

   public static Token load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
       return new Token(contractAddress, web3j, transactionManager, gasPrice, gasLimit);
   }
}

我不確定程式碼有什麼問題。任何幫助將不勝感激。謝謝!

我終於弄清楚我的程式碼出了什麼問題。我調試了 Web3j 程式碼,發現由於 Mining 節點在重試後不接受事務,並且拋出40了睡眠持續時間並且沒有生成。請參閱下面的 Web3j 程式碼15000``TransactionTimeoutException``TransactionReceipt``TransactionManager.java

異常的來源

private static final int SLEEP_DURATION = 15000;
private static final int ATTEMPTS = 40;

private TransactionReceipt getTransactionReceipt(
       String transactionHash, int sleepDuration, int attempts)
       throws IOException, InterruptedException, TransactionTimeoutException {

   Optional<TransactionReceipt> receiptOptional =
           sendTransactionReceiptRequest(transactionHash);
   for (int i = 0; i < attempts; i++) {
       if (!receiptOptional.isPresent()) {
           Thread.sleep(sleepDuration);
           receiptOptional = sendTransactionReceiptRequest(transactionHash);
       } else {
           return receiptOptional.get();
       }
   }

   throw new TransactionTimeoutException("Transaction receipt was not generated after " +
           ((sleepDuration * attempts) / 1000 +
                   " seconds for transaction: " + transactionHash));
}

原因

在打破我的腦袋後,我發現問題在於低 GAS_PRICE 和 GAS_LIMIT。由於價值低,礦工沒有探勘我的交易

使固定

我更新了我的程式碼以使用 Web3j 類中的預設 GAS_PRICE 和 GAS_LIMIT Contract。請參閱下面的更新程式碼

   BigInteger GAS = Contract.GAS_LIMIT;
   BigInteger GAS_PRICE = Contract.GAS_PRICE;

   Token contract = Token.deploy(web3,credentials,GAS_PRICE,GAS,ETHER);
   System.out.println("Deployed Contract at "+contract.getContractAddress());

我不確定您是如何在 Azure 上配置區塊鏈的,我假設您在創建私有區塊鏈時已經創建了一個探勘節點,如果是這樣,我們需要使用 SSH 連接到該節點,因此,查找挖礦節點地址,您可以在以下位置找到它:

部署 > Microsoft-azure-blockchain.azure-multi ….

現在,複製前面的行(SSH-TO-FIRST-TX-NODE)並將其粘貼到本地電腦的 CMD 上,輸入yes問題yes/no,然後它會要求您輸入密碼,使用您在創建區塊鏈時使用的相同密碼。

連接到節點後,輸入geth attach,這將為您打開geth控制台,一旦打開輸入miner.start(1),參數1是礦工可以執行的執行緒數,您可以傳遞更大的數字。

引用自:https://ethereum.stackexchange.com/questions/20889