java和android app如何使用web3j開發以太坊智慧合約並進行交易
從廣義上講,有web3j支援三種型別的以太坊交易:
- 1.以太幣從一方交易到另一方
- 2.建立一個智慧合約
- 3.與智慧合約交易
為了進行這些交易,必須有以太幣(以太坊區塊鏈的代幣)存在於交易發生的以太坊賬戶中。這是為了支付gas成本,這是為支付參與交易的以太坊客戶端的交易執行成本,支付了這個成本就能將結果提交到以太坊區塊鏈上。獲得以太幣的說明下文會說到。
此外,我們還可以查詢智慧合約的狀態。
如何獲得以太幣Ether
要想獲得以太幣Ether你有兩種途徑可以選擇: - 1.自己開採挖礦 - 2.從別人那裡獲取以太幣
在私有鏈中自己挖礦,或者公共測試鏈(testnet
)是非常簡單直接的。但是,在主要的公有鏈(mainnet
)中,它需要很多很明顯的專用GPU時間,除非你已經擁有多個專用GPU的礦機,否則基本上不太可行。如果你希望使用私有鏈,則在這個官方文件中有一些指導。
要購買以太幣Ether,你需要通過交易所。由於不同的地區有不同的交易所,你還需要研究自己去哪兒合適。官方文件中包含多個交易所,是一個很好的參考。
以太坊測試鏈(testnets)
針對Ethereum以太坊有許多專用測試網路或者叫測試鏈,他們由各種客戶端支援。
- 1.Rinkeby:只支援geth客戶端。
- 2.Kovan:只支援Parity客戶端。
- 3.Ropsten:支援geth和Parity客戶端。
對於開發,建議你使用Rinkeby
或KoVan
測試鏈。這是因為他們使用的工作量證明POA
共識機制,確保交易和塊能夠一致並及時的建立。Ropsten
測試鏈,雖然最接近公有鏈(Mainnet
),但是因為它使用的工作量證明是POW
共識機制,過去已受到攻擊,對以太坊開發人員來說往往有更多的問題。
你可以通過Rinkeby
測試鏈的Rinkeby Crypto Fauce
請求以太坊幣,具體怎麼做可以看這裡https://www.rinkeby.io/。
有關如何請求Kovan
測試鏈的細節可以在這裡找到。
如果你需要在Ropsten
上的得到一些以太幣,將你的錢包地址的訊息釋出到web3j gitter channel,然後會傳送一些給你。
在testnet測試鏈或者私有鏈上挖掘
在ethereum以太坊測試鏈testnet
中,挖掘難度低於公有鏈mainnet
。這意味著你可以用普通的CPU,比如你的膝上型電腦來挖掘新的以太幣。你需要做的是執行一個以太坊客戶端,例如geth
或Parity
,開始做一些儲備。進一步的資料可在他們的官方網站上獲得。
- geth :https://github.com/ethereum/go-ethereum/wiki/Mining
- Parity :https://github.com/paritytech/parity/wiki/Mining
一旦你開採了一些以太幣,你就可以開始使用以太坊區塊鏈了。
然而,如上所述,使用Kovan
或者Rinkeby
測試網路更簡單些。
gas
當在Ethereum以太坊發生交易時,必須為執行該交易的客戶端支付交易成本,將該交易的輸出提交到以太坊區塊鏈Ethereum blockchain。
此成本是通過gas來測量的,其中gas是用於在以太坊虛擬機器中執行交易指令的數量。請參閱官方文件以獲取更多資訊。
當你使用以太坊客戶端時,這意味著,有兩個引數用來指示你希望花費多少以太來完成傳輸:
- gas price :氣體價格,這是每單位gas中以太的消耗量。Web3j使用的預設價格為22000000000 wei(22×10-8 Ether)。這是在交易管理中定義的。
- gas limit:氣體最大量,這是你願意在交易執行上花費的gas的最大總量。單個交易在一個以太坊區塊中有多大的上限,通常將該值限制為小於6700000。當前的gas限制在這裡查https://ethstats.net/。
這兩個引數共同決定了你願意花費在交易成本上的最大量的以太幣Ether。也就是說,你花費的gas不會超過gas price * gas limit
。gas價格也會影響交易發生的速度,這取決於其他交易是否能為礦工提供更有利的gas價格。
你可能需要調整這些引數以確保交易能及時進行。
交易機制
當你用一些以太幣Ether建立了一個有效的帳戶時,你可以使用兩種機制來與以太坊進行交易。
- 通過以太坊ethereum客戶端進行認證簽名交易
- 離線交易簽名認證
這兩種機制都是Web3j所支援的。
通過以太坊ethereum客戶端進行認證簽名交易
為了通過以太坊客戶端進行交易,首先需要確保你正在使用的客戶端知道你的錢包地址。最好是執行自己的以太坊客戶端,比如geth
/Parity
,以便可以更方便的做到這一點。一旦你有一個客戶端執行,你可以建立一個以太坊錢包,通過:
- geth Wiki包含了geth支援的良好執行的不同機制,例如匯入私有金鑰檔案,並通過控制檯建立新的以太坊帳戶。
- 或者,你可以通過客戶端使用JSON-RPC管理命令,例如用
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( , , BigInteger.valueOf(), // we use default gas limit "0x..." );
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中。
離線交易簽名認證Offline transaction signing
如果你不想管理自己的以太坊客戶端,或者不想向以太坊客戶端提供諸如密碼之類的錢包詳細資訊,那麼就通過離線交易認證簽名。
離線交易簽名認證允許你在web3j中使用你的以太坊錢包簽署交易,允許你完全控制你的私有憑據。然後,離線建立的交易可以被髮送到網路上的任何以太坊客戶端,只要它是一個有效的交易,它會將交易傳播到其他節點。
如果需要,還可以執行程式外交易簽名認證。這可以通過重寫ECKeyPair的sign
方法來實現。
建立和使用錢包檔案Ethereum wallet file
為了離線離線交易,你需要有你的錢包檔案或與私密錢包/賬戶相關的公共和私人金鑰。
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
型別,但是它不需要通過具體的賬號地址來請求,因為可以從簽名中推斷出來。
為了建立和簽署原生交易,交易的順序如下:
- 1.確定交易發起者帳戶的下一個可用隨機數
nonce
- 2.建立
RawTransaction
物件 - 3.使用遞迴長度字首編碼(RLP即Recursive Length Prefix)對
RawTransaction
物件進行編碼 - 4.簽署
RawTransaction
物件 - 5.將
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()
有關建立和傳送原始事務的完整示例,請參閱 CreateRawTransactionIT。
交易隨機數nonce
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
請求的以太坊客戶端知道要使用哪個錢包來代表訊息傳送者併傳送該交易。如上所述,對於離線簽名認證簽署的原始交易而言,這不是必須的。
接下來的部分概述了不同交易型別所需的關鍵交易屬性。下列屬性對所有人都是不變: - Gas price 天然氣氣體價格 - Gas limit 天然氣氣體限制 - Nonce 隨機數 - from 傳送地址
Transaction
和RawTransaction
物件在所有後續示例中都可互換使用。
以太幣從一方交易到另一方
在雙方之間傳送以太幣Ether需要交易物件的最少量的資訊:
- to :目的地錢包地址
value:價值,希望傳送到目的地的以太幣數量
BigInteger value = Convert.toWei("1.0", Convert.Unit.ETHER).toBigInteger(); RawTransaction rawTransaction = RawTransaction.createEtherTransaction( , , , , 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|", BigDecimal.valueOf(1.0), Convert.Unit.ETHER).send();
使用智慧合約打包器smart contract wrappers
當使用下面列出的智慧合約打包器時,將不得不手動執行從Solidity到本機Java型別的所有轉換。使用Solidity smart contract wrappers是非常有效的,它負責所有的程式碼生成和轉換。
建立一個智慧合約
要部署新的智慧合約,需要提供以下屬性:
- value :在智慧合約中希望存放的以太坊Ether量(如果沒有提供預設為零)
- data :十六進位制格式化、編譯的智慧合約建立程式碼
// using a raw transaction RawTransaction rawTransaction = RawTransaction.createContractTransaction( , , , , "0x "); // 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( , , , , , "0x " + encodedConstructor);
// send...
與智慧合約交易
要與現有的智慧合約進行交易,需要提供以下屬性:
- to:智慧合同地址
- value:在智慧合約中你希望存放的以太幣Ether量(如果智慧合約接受以太幣Ether的話)
- data: 已編碼的函式選擇器和自變數引數
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( , , , contractAddress, , 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(, contractAddress, encodedFunction), DefaultBlockParameterName.LATEST) .sendAsync().get();
List someTypes = FunctionReturnDecoder.decode( response.getValue(), function.getOutputParameters());
注意:如果一個無效的函式呼叫被執行,或者得到一個空null返回結果時,返回值將是一個Collections.emptyList例項。
- web3j教程,主要是針對java和android程式設計師進行區塊鏈以太坊開發的web3j開發詳解。
匯智網原創翻譯,原文訪問這裡
相關文章
- eth以太坊智慧合約交易平臺開發
- android和java程式設計師使用web3j進行區塊鏈以太坊開發詳解AndroidJava程式設計師Web區塊鏈
- 使用Remix編譯和部署以太坊智慧合約REM編譯
- java使用spring boot和web3j開發以太坊區塊鏈dappJavaSpring BootWeb區塊鏈APP
- 以太坊智慧合約gas如何估計?
- 如何打造安全的以太坊智慧合約
- 以太坊智慧合約開發第二篇:理解以太坊相關概念
- 以太坊蜜罐智慧合約分析
- 以太坊智慧合約開發第四篇:實現Hello World智慧合約
- 以太坊智慧合約開發第六篇:truffle開發框架框架
- 以太坊智慧合約升級策略
- 以太坊智慧合約-猜數字
- 以太坊智慧合約開發第七篇:智慧合約與網頁互動網頁
- olidity語言開發以太坊智慧合約中的繼承繼承
- 以太坊智慧合約開發第五篇:字串拼接—Solidity字串Solid
- 使用truffle部署以太坊智慧合約到區塊鏈區塊鏈
- 以太坊智慧合約call注入攻擊
- 技術工坊|深度探索以太坊智慧合約(深圳)
- 智慧合約開發(3)—— 以太坊虛擬機器(EVM)基礎虛擬機
- Conflux與以太坊合約開發工具區別UX
- 以太坊中如何獲取另外一個智慧合約部署的合約地址?
- 怎樣通過java用web3j查詢以太坊交易資訊?JavaWeb
- 區塊鏈——以太坊、智慧合約簡介區塊鏈
- 以太坊智慧合約 Hexagon 存在溢位漏洞Go
- 以太坊智慧合約開發環境搭建以及第一個Dapp開發環境APP
- Polygon馬蹄鏈在以太坊上的智慧合約開發應用Go
- 以太坊開發實戰學習-合約安全(八)
- 如何使用Meteor開發以太坊DappAPP
- 什麼是以太坊?什麼是智慧合約?
- 以太坊智慧合約開發第三篇:安裝節點工具Ganache
- 第三課 如何實現以太坊最簡智慧合約“Hello World”的執行
- 以太坊原始碼分析(18)以太坊交易執行分析原始碼
- 如何取消以太坊智慧合約授權,防止被黑客盜取Token?黑客
- 區塊鏈2.0以太坊智慧合約solidity之helloworld區塊鏈Solid
- 【精通以太坊】——第九章 智慧合約安全
- php工程師進行以太坊開發的教程PHP工程師
- 合約交易系統開發|智慧合約交易平臺原始碼搭建原始碼
- 以太坊Solidity程式語言開發框架————4、編譯合約Solid框架編譯