天天看點

使用java類庫web3j将智能合約部署到私有鍊上逾時TransactionTimeoutException

無法使用web3j(Java用戶端)将智能合約部署到私有鍊上,錯誤提示資訊是逾時。

我用web3j與我在Azure中建立的私有鍊進行互動。我使用Remix和Metamask建立了以太坊智能合約,并且能夠從Java中檢視該智能合約。

但是,我無法從Java部署或建立合同。我遵循了web3j的指令但是抛出了這個:

1.錯誤提示:

Transaction receipt was not generated after 600 seconds for transaction

2.報錯原因是:

org.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());
    }           

Token.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 (Generated from 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的源代碼,發現由于挖掘節點在

40

次重試後不接受交易,其休眠持續時間為

15000

,是以引發交易

TransactionTimeoutException

,并且不生成

TransactionReceipt

。從

TransactionManager.java

看下面的web3j代碼:

Source of the Exception

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的智能合約

Contract

類,使用預設的GAS_PRICE和GAS_LIMIT限制。參見下面更新的代碼

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

OK,完事大吉。

原文《以太坊常見問題和錯誤》中的:

http://cw.hubwiz.com/card/c/ethereum-FAQ/1/1/7/

另外推薦幾個很受歡迎全網稀缺的互動教程:

  • web3j ,主要是針對java和android程式員圍繞web3j庫進行區塊鍊以太坊開發的講解。
  • python以太坊 ,主要是針對python圍繞web3.py進行區塊鍊以太坊應用開發的講解。
  • php以太坊 ,主要是介紹使用php進行智能合約開發互動,進行賬号建立、交易、轉賬、代币開發以及過濾器和事件等内容。
  • 以太坊開發 ,主要是介紹使用node.js、mongodb、區塊鍊、ipfs實作去中心化電商DApp實戰,适合進階。
  • 以太坊教程 ,主要介紹智能合約與dapp應用開發,适合入門。