最新內容會更新在主站深入淺出區塊鏈社群
原文連結:以太坊(安卓)錢包系列2 - 匯入賬號及賬號管理
這是如何開發一款以太坊(安卓)錢包系列第2篇,如何匯入賬號。有時使用者可能已經有一個賬號,這篇文章接來介紹下,如何實現匯入使用者已經存在的賬號。
匯入賬號預備知識
從使用者需求上來講,匯入使用者已經存在的賬號是有必要的。 不過從安全性考慮,當你之前使用的是一個非官方、非開源的錢包產品時(尤其是小眾錢包),或者之前沒有對私鑰、助記詞、Keysotre檔案小心儲存時。
正確的做法是提示使用者:
- 在新的錢包重新建立一個錢包賬號、並安全備份(因為之前的可能已經不安全);
- 然後在老錢包裡把所有的幣轉移到新賬號。
匯入賬號有3種方式:
- 通過私鑰匯入
- 通過KeyStore 匯入
- 通過助記詞匯入
通過私鑰匯入賬號
關鍵是用使用者輸入的私鑰建立一個橢圓曲線祕鑰對,然後用這個祕鑰對建立錢包,程式碼如下:
(程式碼在程式碼庫中的app/src/pro/upchain/wallet/utils/ETHWalletUtils.java
檔案中)
public static ETHWallet loadWalletByPrivateKey(String privateKey, String pwd) {
Credentials credentials = null;
ECKeyPair ecKeyPair = ECKeyPair.create(Numeric.toBigInt(privateKey));
return generateWallet(generateNewWalletName(), pwd, ecKeyPair);
}
返回語句中的 generateWallet(),在系列1-通過助記詞建立賬號 已經介紹過,通過橢圓曲線祕鑰對建立錢包。
loadWalletByPrivateKey()中第2個引數密碼pwd,在私鑰生成賬號這個過程並不需要pwd,它是用來加密儲存私鑰,即為了生成keystore檔案。
通過KeyStore檔案匯入賬號
關於KeyStore檔案,不瞭解的可以閱讀下賬號Keystore檔案匯入匯出。
關鍵步驟:
- KeyStore 文字內容解析WalletFile例項;
- 使用密碼 解碼 WalletFile 生成橢圓曲線祕鑰對建立錢包。
/**
* @param keystore 原json檔案內容
* @param pwd keystore解密密碼
* @return
*/
public static ETHWallet loadWalletByKeystore(String keystore, String pwd) {
try {
WalletFile walletFile = null;
walletFile = objectMapper.readValue(keystore, WalletFile.class);
return generateWallet(generateNewWalletName(), pwd, Wallet.decrypt(pwd, walletFile));
} catch (IOException e) {
} catch (CipherException e) {
}
return null;
}
通過助記詞匯入賬號
匯入和上一篇中,建立非常相似,不同的是,種子由使用者提供的助記詞生成。
使用助記詞匯入賬號時,還需要使用者選擇(或輸入)一個推倒路徑(參考BIP44),關鍵步驟是:
- 通過助記詞建立隨機數種子;
- 通過 種子 + 路徑 派生生成私鑰 建立錢包 ;
/**
* 通過匯入助記詞,匯入錢包
*
* @param path bip44路徑
* @param list 助記詞
* @param pwd 密碼
* @return
*/
public static ETHWallet importMnemonic(String path, String mnemonic, String pwd) {
List<String> list = Arrays.asList(mnemonic.split(" "));
if (!path.startsWith("m") && !path.startsWith("M")) {
//引數非法
return null;
}
String[] pathArray = path.split("/");
if (pathArray.length <= 1) {
//內容不對
return null;
}
String passphrase = "";
long creationTimeSeconds = System.currentTimeMillis() / 1000;
DeterministicSeed ds = new DeterministicSeed(list, null, passphrase, creationTimeSeconds);
return generateWalletByMnemonic(generateNewWalletName(), ds, pathArray, pwd);
}
generateWalletByMnemonic在上一篇中已經介紹過,
賬號儲存(儲存到資料庫)
很多同學肯定已經注意到, 不管通過什麼方式構造的賬號,都會最終構造為一個ETHWallet 錢包物件,他的定義如下:
@Entity
public class ETHWallet {
@Id(autoincrement = true)
private Long id;
public String address;
private String name;
private String password; // 經過加密後的pwd
private String keystorePath;
private String mnemonic;
private boolean isCurrent; // 是否是當前選中的錢包
private boolean isBackup; // 是否備份過
}
前面構造的ETHWallet是隻存在於內容之中, 在應用程式退出之後,這個資料將丟失, 因此我們需要把它序列化到
序列化資料庫中儲存起來,在下一次進入應用的時候載入資料庫還原出賬號。
greenDAO
greenDAO 是一個將物件對映到 SQLite 資料庫中的輕量且快速的 ORM 解決方案,以下是一個greenDAO的作用示意圖:
這裡我們也使用了 greenDAO 來把ETHWallet物件對映到 SQLite 資料庫, greenDAO的用法這裡只簡單說明,不詳細闡述,大家可以跟隨官方提供的introduction 和 how-to-get-started。
物件對映儲存
把ETHWallet對映的到資料庫,需要給類加上@Entity註解,這樣greenDAO會生成幾個類:DaoMaster
、DaoSession
及 ETHWalletDao
幫我們完成構建資料庫表等操作。
在使用ETHWalletDao插入到資料庫之前需要先進行一個初始化,通常初始化放在應用程式入口中進行,如:pro.upchain.wallet.UpChainWalletApp的onCreate()中執行,初始化程式碼如下:
protected void init() {
DaoMaster.DevOpenHelper mHelper = new DaoMaster.DevOpenHelper(this, "wallet", null);
SQLiteDatabase db = mHelper.getWritableDatabase();
DaoSession daoSession = new DaoMaster(db).newSession();
ETHWalletDao ethWalletDao = daoSession.getETHWalletDao();
}
有了greenDAO為我們生成的輔助類,插入到資料庫就很簡單了,一行程式碼:
ethWalletDao.insert(ethWallet); //
ethWallet為ETHWallet例項, 前面不管是新建立還是匯入的賬號都會構造這樣一個例項。
多賬號管理
考慮到使用者可能會建立多個賬號,因此需要確定一個當前選定的賬號,一般情況下,使用者新建立的賬號應該作為當前選中的的賬號,同時其他賬號應該取消選中, 我們完善下賬號儲存邏輯, 如下:
(程式碼在程式碼庫中的app/src/pro/upchain/wallet/utils/WalletDaoUtils.java
檔案中)
/**
* 插入新建立錢包
*
* @param ethWallet 錢
*/
public static void insertNewWallet(ETHWallet ethWallet) {
updateCurrent(-1); // 取消其他站賬號選中狀態
ethWallet.setCurrent(true);
ethWalletDao.insert(ethWallet);
}
/**
* 更新選中錢包
*
* @param id 錢包ID
*/
public static ETHWallet updateCurrent(long id) {
// 載入所有錢包賬號
List<ETHWallet> ethWallets = ethWalletDao.loadAll();
ETHWallet currentWallet = null;
for (ETHWallet ethwallet : ethWallets) {
if (id != -1 && ethwallet.getId() == id) {
ethwallet.setCurrent(true);
currentWallet = ethwallet;
} else {
ethwallet.setCurrent(false);
}
ethWalletDao.update(ethwallet);
}
return currentWallet;
}
打通賬號建立與儲存
以通過私鑰匯入賬號進行儲存為例,把建立賬號和儲存賬號打通,這裡我們使用響應式程式設計 ReactiveX,
這部分作為訂閱者福利,發表在我的小專欄,趁還未漲價,趕緊訂閱吧,超值的!
學習資料
- RxAndroid 瞭解更多響應式程式設計
- introduction 和 how-to-get-started 瞭解greenDAO。
我建立了一個專門討論錢包開發的微信群,加微信:xlbxiong 備註:錢包。