從廣義上講,有web3j支持三種類型的以太坊交易:html
爲了進行這些交易,必須有以太幣(以太坊區塊鏈的代幣)存在於交易發生的以太坊帳戶中。這是爲了支付gas成本,這是爲支付參與交易的以太坊客戶端的交易執行成本,支付了這個成本就能將結果提交到以太坊區塊鏈上。得到以太幣的說明下文會說到。java
此外,咱們還能夠查詢智能合約的狀態。node
要想得到以太幣Ether你有兩種途徑能夠選擇:android
在私有鏈中本身挖礦,或者公共測試鏈(testnet
)是很是簡單直接的。可是,在主要的公有鏈(mainnet
)中,它須要不少很明顯的專用GPU時間,除非你已經擁有多個專用GPU的礦機,不然基本上不太可行。若是你但願使用私有鏈,則在這個官方文檔中有一些指導。ios
要購買以太幣Ether,你須要經過交易所。因爲不一樣的地區有不一樣的交易所,你還須要研究本身去哪兒合適。官方文檔中包含多個交易所,是一個很好的參考。git
針對Ethereum以太坊有許多專用測試網絡或者叫測試鏈,他們由各類客戶端支持。程序員
對於開發,建議你使用Rinkeby
或KoVan
測試鏈。這是由於他們使用的工做量證實POA
共識機制,確保交易和塊可以一致並及時的建立。Ropsten
測試鏈,雖然最接近公有鏈(Mainnet
),可是由於它使用的工做量證實是POW
共識機制,過去已受到攻擊,對以太坊開發人員來講每每有更多的問題。github
你能夠經過Rinkeby
測試鏈的Rinkeby Crypto Fauce
請求以太坊幣,具體怎麼作能夠看這裏https://www.rinkeby.io/。web
有關如何請求Kovan
測試鏈的細節能夠在這裏找到。mongodb
若是你須要在Ropsten
上的獲得一些以太幣,將你的錢包地址的消息發佈到web3j gitter channel,而後會發送一些給你。
在ethereum以太坊測試鏈testnet
中,挖掘難度低於公有鏈mainnet
。這意味着你能夠用普通的CPU,好比你的筆記本電腦來挖掘新的以太幣。你須要作的是運行一個以太坊客戶端,例如geth
或Parity
,開始作一些儲備。進一步的資料可在他們的官方網站上得到。
一旦你開採了一些以太幣,你就能夠開始使用以太坊區塊鏈了。
然而,如上所述,使用Kovan
或者Rinkeby
測試網絡更簡單些。
當在Ethereum以太坊發生交易時,必須爲執行該交易的客戶端支付交易成本,將該交易的輸出提交到以太坊區塊鏈Ethereum blockchain。
此成本是經過gas來測量的,其中gas是用於在以太坊虛擬機中執行交易指令的數量。請參閱官方文檔以獲取更多信息。
當你使用以太坊客戶端時,這意味着,有兩個參數用來指示你但願花費多少以太來完成傳輸:
這兩個參數共同決定了你願意花費在交易成本上的最大量的以太幣Ether。也就是說,你花費的gas不會超過gas price * gas limit
。gas價格也會影響交易發生的速度,這取決於其餘交易是否能爲礦工提供更有利的gas價格。
你可能須要調整這些參數以確保交易能及時進行。
當你用一些以太幣Ether建立了一個有效的賬戶時,你可使用兩種機制來與以太坊進行交易。
這兩種機制都是Web3j所支持的。
爲了經過以太坊客戶端進行交易,首先須要確保你正在使用的客戶端知道你的錢包地址。最好是運行本身的以太坊客戶端,好比geth
/Parity
,以即可以更方便的作到這一點。一旦你有一個客戶端運行,你能夠建立一個以太坊錢包,經過:
personal_newAccount
爲geth
/Parity
建立新以太坊帳戶。經過建立你的錢包文件,你能夠經過web3j打開賬戶,首先建立支持geth
/Parity
管理命令的web3j實例:
Admin web3j = Admin.build(new HttpService());
而後,你能夠解鎖賬戶,並若是是成功的,就能夠發送一個交易:
PersonalUnlockAccount personalUnlockAccount = web3j.personalUnlockAccount("0x000...", "a password").send(); if (personalUnlockAccount.accountUnlocked()) { // send a transaction }
以這種方式發送的交易應該經過EthSendTransaction建立,使用Transaction類型:
Transaction transaction = Transaction.createContractTransaction( <from address>, <nonce>, BigInteger.valueOf(<gas price>), // we use default gas limit "0x...<smart contract code to execute>" ); org.web3j.protocol.core.methods.response.EthSendTransaction transactionResponse = parity.ethSendTransaction(ethSendTransaction) .send(); String transactionHash = transactionResponse.getTransactionHash(); // poll for transaction response via org.web3j.protocol.Web3j.ethGetTransactionReceipt(<txHash>)
其中nonce
值得到方式,下文會提到。 有關此交易工做流的詳細信息,請參閱 DeployContractIT和Scenario。
web3j支持的各類管理命令的進一步細節在Management APIs中。
若是你不想管理本身的以太坊客戶端,或者不想向以太坊客戶端提供諸如密碼之類的錢包詳細信息,那麼就經過離線交易認證簽名。
離線交易簽名認證容許你在web3j中使用你的以太坊錢包簽署交易,容許你徹底控制你的私有憑據。而後,離線建立的交易能夠被髮送到網絡上的任何以太坊客戶端,只要它是一個有效的交易,它會將交易傳播到其餘節點。
若是須要,還能夠執行進程外交易簽名認證。這能夠經過重寫ECKeyPair的sign
方法來實現。
爲了離線脫機交易,你須要有你的錢包文件或與私密錢包/帳戶相關的公共和私人密鑰。
web3j可以爲你生成一個新的安全的以太坊錢包文件Ethereum wallet file,或者與也能夠經過私鑰來和現有的錢包文件一塊兒工做。
建立新的錢包文件:
String fileName = WalletUtils.generateNewWalletFile( "your password", new File("/path/to/destination"));
加載憑據從錢包文件:
Credentials credentials = WalletUtils.loadCredentials( "your password", "/path/to/walletfile");
而後這些憑據會被用來簽署交易,請參閱Web3安全存儲定義錢包文件規範Web3 Secret Storage Definition
要使脫機簽名交易獲得簽署,須要設定一個RawTransaction類型。RawTransaction
相似於前面提到的Transaction
類型,可是它不須要經過具體的帳號地址來請求,由於能夠從簽名中推斷出來。
爲了建立和簽署原生交易,交易的順序以下:
nonce
RawTransaction
對象RawTransaction
對象進行編碼RawTransaction
對象RawTransaction
對象發送到節點進行處理nonce
是一個不斷增加的數值,用來惟一地標識交易。一個nonce
只能使用一次,直到交易被挖掘完成,能夠以相同的隨機數發送交易的多個版本,可是一旦其中一個被挖掘完成,其餘後續提交的都將被拒絕。
一旦得到下一個可用的nonce
,該值就能夠用來建立transaction
對象:
RawTransaction rawTransaction = RawTransaction.createEtherTransaction( nonce, <gas price>, <gas limit>, <toAddress>, <value>);
而後能夠對交易進行簽名和編碼:
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, <credentials>); String hexValue = Numeric.toHexString(signedMessage);
其中憑據是根據建立和使用錢包文件加載的。
而後使用eth_SendRawTransaction發送交易:
EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get(); String transactionHash = ethSendTransaction.getTransactionHash(); // poll for transaction response via org.web3j.protocol.Web3j.ethGetTransactionReceipt(<txHash>)
有關建立和發送原始事務的完整示例,請參閱 CreateRawTransactionIT。
nonce
是一個不斷增加的數值,用來惟一地標識交易。一個nonce
只能使用一次,直到交易被挖掘完成,能夠以相同的隨機數發送交易的多個版本,可是一旦其中一個被挖掘完成,其餘後續提交的都將被拒絕。
能夠經過eth_getTransactionCount
方法得到下一個可用的nonce
:
EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount( address, DefaultBlockParameterName.LATEST).sendAsync().get(); BigInteger nonce = ethGetTransactionCount.getTransactionCount();
而後可使用nonce
建立你的交易對象:
RawTransaction rawTransaction = RawTransaction.createEtherTransaction( nonce, <gas price>, <gas limit>, <toAddress>, <value>);
web3j中的不一樣類型的交易都使用Transaction
和RawTransaction
對象。關鍵的區別是交易對象必須始終有一個地址,以便處理eth_sendTransaction
請求的以太坊客戶端知道要使用哪一個錢包來表明消息發送者併發送該交易。如上所述,對於離線簽名認證簽署的原始交易而言,這不是必須的。
接下來的部分概述了不一樣交易類型所需的關鍵交易屬性。下列屬性對全部人都是不變:
Transaction
和RawTransaction
對象在全部後續示例中均可互換使用。
在雙方之間發送以太幣Ether須要交易對象的最少許的信息:
BigInteger value = Convert.toWei("1.0", Convert.Unit.ETHER).toBigInteger(); RawTransaction rawTransaction = RawTransaction.createEtherTransaction( <nonce>, <gas price>, <gas limit>, <toAddress>, value); // send...
可是,建議你使用TransferClass來發送以太幣Ether,它負責對nonce
管理和經過不斷的輪詢爲你提供響應:
Web3j web3 = Web3j.build(new HttpService()); // defaults to http://localhost:8545/ Credentials credentials = WalletUtils.loadCredentials("password", "/path/to/walletfile"); TransactionReceipt transactionReceipt = Transfer.sendFunds( web3, credentials, "0x<address>|<ensName>", BigDecimal.valueOf(1.0), Convert.Unit.ETHER).send();
當使用下面列出的智能合約打包器時,將不得不手動執行從Solidity到本機Java類型的全部轉換。使用Solidity smart contract wrappers是很是有效的,它負責全部的代碼生成和轉換。
要部署新的智能合約,須要提供如下屬性:
// using a raw transaction RawTransaction rawTransaction = RawTransaction.createContractTransaction( <nonce>, <gasPrice>, <gasLimit>, <value>, "0x <compiled smart contract code>"); // send... // get contract address EthGetTransactionReceipt transactionReceipt = web3j.ethGetTransactionReceipt(transactionHash).send(); if (transactionReceipt.getTransactionReceipt.isPresent()) { String contractAddress = transactionReceipt.get().getContractAddress(); } else { // try again }
若是智能合約包含構造函數,則必須對關聯的構造函數字段值進行編碼,並將其附加到編譯的智能合約代碼中compiled smart contract code
:
String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new Type(value), ...)); // using a regular transaction Transaction transaction = Transaction.createContractTransaction( <fromAddress>, <nonce>, <gasPrice>, <gasLimit>, <value>, "0x <compiled smart contract code>" + encodedConstructor); // send...
要與現有的智能合約進行交易,須要提供如下屬性:
web3j負責函數編碼,有關實現的進一步細節,請參閱應用程序二進制接口部分Application Binary Interface。
Function function = new Function<>( "functionName", // function we're calling Arrays.asList(new Type(value), ...), // Parameters to pass as Solidity Types Arrays.asList(new TypeReference<Type>() {}, ...)); String encodedFunction = FunctionEncoder.encode(function) Transaction transaction = Transaction.createFunctionCallTransaction( <from>, <gasPrice>, <gasLimit>, contractAddress, <funds>, encodedFunction); org.web3j.protocol.core.methods.response.EthSendTransaction transactionResponse = web3j.ethSendTransaction(transaction).sendAsync().get(); String transactionHash = transactionResponse.getTransactionHash(); // wait for response using EthGetTransactionReceipt...
不管消息簽名的返回類型如何,都不可能從事務性函數調用返回值。可是,使用過濾器捕獲函數返回的值是可能的。詳情請參閱過濾器和事件部分。
這種功能是由eth_call經過JSON-RPC
調用來實現的。
eth_call容許你調用智能合約上的方法來查詢某個值。此函數沒有關聯交易成本,這是由於它不改變任何智能合約方法的狀態,它只返回它們的值:
Function function = new Function<>( "functionName", Arrays.asList(new Type(value)), // Solidity Types in smart contract functions Arrays.asList(new TypeReference<Type>() {}, ...)); String encodedFunction = FunctionEncoder.encode(function) org.web3j.protocol.core.methods.response.EthCall response = web3j.ethCall( Transaction.createEthCallTransaction(<from>, contractAddress, encodedFunction), DefaultBlockParameterName.LATEST) .sendAsync().get(); List<Type> someTypes = FunctionReturnDecoder.decode( response.getValue(), function.getOutputParameters());
注意:若是一個無效的函數調用被執行,或者獲得一個空null返回結果時,返回值將是一個Collections.emptyList實例。
匯智網原創翻譯,轉載請標明出處。原文訪問其官方博客