建立一個以太坊錢包有多種方式,通常狀況下能夠經過geth、EtherumWallet等客戶端。對於前端,可使用插件MetaMask進行建立。這幾種方式技術實現雖然不一樣,但底層原理是一致的。本文主要介紹如何經過web3j架構建立一個以太坊的冷錢包,從而實現將這一過程部署在服務端或者android端。html
文中涉及到的技術棧有:前端
Web3j :輕量級java庫,用於鏈接以太坊客戶端或節點java
Infura :以太坊基礎設施,用於訪問以太坊主網絡或測試網絡android
Java:編程語言git
不管是java工程仍是android工程,web3j都提供了maven和grade 兩種依賴方式:github
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>3.3.1</version>
</dependency>
複製代碼
compile ('org.web3j:core:3.3.1')
複製代碼
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>3.3.1-android</version>
</dependency>
複製代碼
compile ('org.web3j:core:3.3.1-android')
複製代碼
值得注意的是,目前的web3j對於高版本JDK存在不兼容的問題,若是出現以下相似的問題,直接更換JDK爲version 8便可。web
Could not determine Java version using executable /Library/Java/JavaVirtualMachines/jdk-10.jdk/Contents/Home/bin/java.算法
以太坊的客戶端實現有多種,但不少都須要在本地同步全部的節點數據而佔用大量硬盤存儲空間,而且須要消耗同步的時間。Infura就是提供一種中心化的服務,經過web3.js或者web3j使前端或服務端能便捷的訪問以太坊全部節點。能夠理解爲一種以太坊客戶端的雲端版本。使用過程須要註冊,一個專屬的訪問token。本文中使用的客戶端都是Infura提供的Rinkeby測試網絡。編程
在以太坊中,錢包(wallet)和帳戶(account)是兩個不一樣的概念。帳戶是以太坊的核心,由一對祕鑰組成-公鑰和私鑰。帳戶能夠分爲兩種,外部帳戶和合約帳戶。而錢包是指保存 地址、公鑰、私鑰的文件或其餘機構,每一個錢包文件至少包含一個帳戶。建立錢包的同時也是建立一個以太坊帳戶的過程不一樣的客戶端建立錢包的方式不一致但原理相同,有關錢包是具體是如何生成的能夠查看另外這篇文章。json
/*************建立一個錢包文件**************/
private void creatAccount() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, CipherException, IOException {
String walletFileName0="";//文件名
String walletFilePath0="/Users/yepeng/MyGitHub/z_wallet_temp";
//錢包文件保持路徑,請替換位本身的某文件夾路徑
walletFileName0 = WalletUtils.generateNewWalletFile("123456", new File(walletFilePath0), false);
//WalletUtils.generateFullNewWalletFile("password1",new File(walleFilePath1));
//WalletUtils.generateLightNewWalletFile("password2",new File(walleFilePath2));
log.info("walletName: "+walletFileName0);
}
複製代碼
錢包構建的過程當中須要輸入的三個參數,分別設置錢包的密碼、保存路徑、以及是否輕量級錢包。
執行建立函數後,會自動在指定路徑生成一個json 文件,即錢包keyfiles。
錢包文件結構:
生成錢包的逆向過程 爲加載錢包。
加載錢包的過程須要提供錢包文件和密碼
/********加載錢包文件**********/
private void loadWallet() throws IOException, CipherException {
String walleFilePath="/Users/yepeng/MyGitHub/z_wallet_temp/UTC--2018-04-10T02-51-24.815000000Z--12571f46ec3f81f7ebe79112be5883194d683787.json";
String passWord="123456";
credentials = WalletUtils.loadCredentials(passWord, walleFilePath);
String address = credentials.getAddress();
BigInteger publicKey = credentials.getEcKeyPair().getPublicKey();
BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey();
log.info("address="+address);
log.info("public key="+publicKey);
log.info("private key="+privateKey);
}
複製代碼
函數運行的結果:
經過工具類 WalletUtols的函數 loadCredentials(),會返回一個對象Credentials,這個對象即包含了錢包文件的全部信息,包括地址、祕鑰對。
至此,錢包的建立和加載已經完成,但這一過程所有發生在本地,並未同步到以太坊區塊鏈。查詢地址餘額前,須要鏈接以太坊結點。
web3j是鏈接java端與以太坊的橋樑,廣播交易,查詢帳戶都須要經過web3j實體。web3j支持經過http進行構建,並且兼容了infura。在本文中,使用的是infura的測試網絡Rinkeby。
/*******鏈接以太坊客戶端**************/
private void conectETHclient() throws IOException {
//鏈接方式1:使用infura 提供的客戶端
web3j = Web3j.build(new HttpService("https://rinkeby.infura.io/zmd7VgRt9go0x6qlJ2Mk"));// TODO: 2018/4/10 token更改成本身的
//鏈接方式2:使用本地客戶端
//web3j = Web3j.build(new HttpService("127.0.0.1:7545"));
//測試是否鏈接成功
String web3ClientVersion = web3j.web3ClientVersion().send().getWeb3ClientVersion();
log.info("version=" + web3ClientVersion);
}
複製代碼
web3j實體構建完成後,能夠打印出版本號以測試是否鏈接成功。若是成功,就能夠作其餘的事情了。值得注意的是,web3j採用的是RxJava的設計,因此許多函數的返回值是 Request,這個對象有兩種執行方式,異步和同步,即send()和sendAsyn()。
查詢帳戶的餘額的方式:
/***********查詢指定地址的餘額***********/
private void getBlanceOf() throws IOException {
if (web3j == null) return;
String address = "0x41F1dcbC0794BAD5e94c6881E7c04e4F98908a87";//等待查詢餘額的地址
//第二個參數:區塊的參數,建議選最新區塊
EthGetBalance balance = web3j.ethGetBalance(address, DefaultBlockParameter.valueOf("latest")).send();
//格式轉化 wei-ether
String blanceETH = Convert.fromWei(balance.getBalance().toString(), Convert.Unit.ETHER).toPlainString().concat(" ether");
log.info(blanceETH);
}
複製代碼
其中核心方法 web3j.ethGetBalance(address, defaultBlockParameter) 中的第二個參數比較特殊,指默認的區塊參數。當請求餘額的方法做用與以太坊的區塊網絡時,這個參數決定了查詢區塊的高度。
HEX String
- 一個整數塊號String "earliest"
爲最先/起源塊String "latest"
- 爲最新的採礦塊String "pending"
- 待處理狀態/交易通常狀況下,選擇「latest」便可。
以太坊中,若是沒有特殊標示,數字的單位都是小數點後18位,所以查詢帳戶餘額有必要將wei轉化成ether。
做爲一個錢包,除了保存帳戶資產外,最重要的就是轉帳或交易了,利用web3j能夠便捷的實現eth的轉移。
/ /****************交易*****************/
private void transto() throws Exception {
if (web3j == null) return;
if (credentials == null) return;
//開始發送0.01 =eth到指定地址
String address_to = "0x41F1dcbC0794BAD5e94c6881E7c04e4F98908a87";
TransactionReceipt send = Transfer.sendFunds(web3j, credentials, address_to, BigDecimal.ONE, Convert.Unit.FINNEY).send();
log.info("Transaction complete:");
log.info("trans hash=" + send.getTransactionHash());
log.info("from :" + send.getFrom());
log.info("to:" + send.getTo());
log.info("gas used=" + send.getGasUsed());
log.info("status: " + send.getStatus());
}
複製代碼
核心方法須要提供4個參數:
等待片刻後,會返回轉帳結果
能夠看到交易hash、轉入轉出地址、gas消耗等信息。同時能夠在etherscan-rinkeby上進行查看本次交易詳情
上面的代碼已經完成了一個以太坊錢包所需的全部基本功能,包括建立、加載、轉帳、查詢。本文中採用的網絡是infura提供的Rinkeby測試網絡,建立的錢包地址爲 0x12571F46Ec3f81F7EbE79112Be5883194d683787。
在具體的業務場景中,只要將測試網絡更換爲以太坊主網絡便可。