分层确定性钱包开发的代码实现(HD钱包服务)
HD Wallets的全称是Hierachical Deterministic Wallets, 对应中文是 分层确定性钱包。
这种钱包能够使用一组助记词来管理所有的账户的所有币种,在比特币的BIP32提案中提出,通过种子来生成主私钥,然后派生海量的子私钥和地址。种子很长,为了方便记录,转换为一组单词记录,这是BIP39提出的。
生成钱包地址的基本流程:1 生成一组助记词 2 助记词转化成种子(通过PBKDF2) 3 种子生成根私钥(通过HMAC-SHA512) 4 通过根私钥生成子私钥
本文的目的是带着读者用代码实现一个HD钱包开发。
开发过程中要用到两个第三方库,一个是Hooked-Web3-Provider,一个是LightWallet。
Hooked-Web3-Provider使用HTTP与geth通信,可以使用秘钥来签署调用交易sendTransaction的实例,因此不需要创建交易数据部分。直接调用sendTransaction完成生成交易数据,发送交易,广播给全网。
LightWallet是一个实现BIP32、BIP39和BIP44的HD钱包。
LightWallet提供API来创建和签署交易,或者使用LightWallet生成的地址和密钥加密和解密数据。它的主要目的是为Hooked-Web3-Provider提供一个签名提供方。它的命名空间有四个,即keystore、signing、encryption和txutils。
signing、encryption和txutils三个命名空间分别用来签名,非对称加密,生成交易,它们的名字大概能反应出各自的功能。keystore命名空间用来生成种子,keystor,这是一个存储加密种子和秘钥的对象。keystore对于其中发现的地址可以自动签名。
HD 钱包中的密钥是用"路径"命名的,且每个级别之间用斜杠(/)字符来表示。由主私钥衍生出的私钥起始以"m"打头。因此,第一个母密钥生成的子私钥是 m/0。第一个公共钥匙是 M/0。第一个子密钥的子密钥就是 m/0/1,以此类推。
密钥的"祖先"是从右向左读,直到你达到了衍生出的它的主密钥。举个例 子,标识符 m/x/y/z 描述的是子密钥 m/x/y 的第 z 个子密钥。而子密钥 m/x/y 又是 m/x 的第 y 个子密钥。m/x 又是 m 的第 x 个子密钥。
代码实现
1. 启动geth网络
假设已经安装好geth。使用命令启动geth网络:
geth --networkid 15 --dev --dev.period 1 --rpc --rpcapi "db,eth,net,web3,miner,personal" --rpccorsdomain "*" --rpcaddr "0.0.0.0" --rpcport "8545" console 2>>log
这个命令指定了networkid是15,当然这是随便取的。 --dev --dev.period 1 --dev是开发网络,但是geth后面的版本中为了方便开发,如果不加--dev.period 1 不会自动挖矿。 --rpcaddr "0.0.0.0" 这样设置是为了让所有的网络都能连上geth。 指定端口8545. console表明启动玩登录到控制台。
2.构建前端
项目代码结构(参考《区块链项目开发指南》):
app.js内容如下:
var express = require("express"); var app = express(); app.use(express.static("public"));app.get("/", function(req, res){res.sendFile(__dirname + "/public/html/index.html"); })app.listen(8080);
构建前端的一个node服务。
index.html 页面:
<!DOCTYPE html> <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><meta http-equiv="x-ua-compatible" content="ie=edge"><link rel="stylesheet" href="/css/bootstrap.min.css"></head><body><div class="container"><div class="row"><div class="col-md-6 offset-md-3"><br><div class="alert alert-info" id="info" role="alert">Create or use your existing wallet.</div><form><div class="form-group"><label for="seed">Enter 12-word seed</label><input type="text" class="form-control" id="seed"></div><button type="button" class="btn btn-primary" οnclick="generate_addresses()">Generate Details</button><button type="button" class="btn btn-primary" οnclick="generate_seed()">Generate New Seed</button></form><hr><h2 class="text-xs-center">Address, Keys and Balances of the seed</h2><ol id="list"></ol><hr><h2 class="text-xs-center">Send ether</h2><form><div class="form-group"><label for="address1">From address</label><input type="text" class="form-control" id="address1"></div><div class="form-group"><label for="address2">To address</label><input type="text" class="form-control" id="address2"></div><div class="form-group"><label for="ether">Ether</label><input type="text" class="form-control" id="ether"></div><button type="button" class="btn btn-primary" οnclick="send_ether()">Send Ether</button></form></div></div></div><script src="/js/web3.min.js"></script><script src="/js/hooked-web3-provider.min.js"></script><script src="/js/lightwallet.min.js"></script><script src="/js/main.js"></script></body> </html>
重点在main.js
generate_seed函数:
function generate_seed() {var new_seed = lightwallet.keystore.generateRandomSeed(); //生成一个随机的种子document.getElementById("seed").value = new_seed; //放到页面generate_addresses(new_seed); }var totalAddresses = 0;function generate_addresses(seed) {if(seed == undefined){seed = document.getElementById("seed").value;}if(!lightwallet.keystore.isSeedValid(seed)) //判断种子是否是有效的种子{document.getElementById("info").innerHTML = "Please enter a valid seed";return;}totalAddresses = prompt("How many addresses do you want to generate"); //用户输入想生成的账户的个数if(!Number.isInteger(parseInt(totalAddresses))) //确保输入是一个数字{document.getElementById("info").innerHTML = "Please enter valid number of addresses";return;}var password = Math.random().toString(); //随机生成一个密码 这个密码可以由用户输入,也可以自动生成。这里为了方便,提升体验,自动生成一个。lightwallet.keystore.createVault({
// 使用createVault方法创建keystore实例。createVault用一个对象和// 一个回调函数作为参数。对象可以有4种属性:password、seedPharse、// salt和hdPathString。password是必选项,其他的都是可选项。如果不提// 供seedPharse,它会生成和使用一个随机seed。拼接salt与password,以// 提高对称密钥加密技术的安全性,因为攻击者不仅要找到password还得// 找到salt。如果不提供salt,它就会随机生成。keystore命名空间存储未加// 密的salt。hdPathString用于为keystore命名空间提供默认衍生路径,即生// 成地址、签署交易等。如果不提供衍生路径,则使用该衍生路径。如果// 不提供hdPathString,则默认值为m/0'/0'/0'。这个衍生路径的默认目的是// 签名。可以创建新的衍生路径或者使用keystore实例的// addHdDerivationPath()方法重写当前衍生路径的purpose。还可以使用// keystore实例的setDefaultHdDerivationPath()方法改变默认衍生路径。// 最后,一旦keystore命名空间被创建,就通过回调函数返回实例。所// 以,这里仅用keyword和seed创建了一个keystore。
password: password,seedPhrase: seed}, function (err, ks) {ks.keyFromPassword(password, function (err, pwDerivedKey) { //使用这个方法生成对应数量的地址和秘钥if(err){document.getElementById("info").innerHTML = err;}else{ks.generateNewAddress(pwDerivedKey, totalAddresses);var addresses = ks.getAddresses(); var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); //创建web3和本地的连接,如果是远程把localhost改成对应的ip即可。var html = "";for(var count = 0; count < addresses.length; count++){var address = addresses[count];var private_key = ks.exportPrivateKey(address, pwDerivedKey); //使用该方法解码和检索地址私钥。var balance = web3.eth.getBalance("0x" + address);html = html + "<li>";html = html + "<p><b>Address: </b>0x" + address + "</p>";html = html + "<p><b>Private Key: </b>0x" + private_key + "</p>";html = html + "<p><b>Balance: </b>" + web3.fromWei(balance, "ether") + " ether</p>";html = html + "</li>";}document.getElementById("list").innerHTML = html;}});}); }
发送eth:
function send_ether() {var seed = document.getElementById("seed").value;if(!lightwallet.keystore.isSeedValid(seed)){document.getElementById("info").innerHTML = "Please enter a valid seed";return;}var password = Math.random().toString();lightwallet.keystore.createVault({password: password,seedPhrase: seed}, function (err, ks) {ks.keyFromPassword(password, function (err, pwDerivedKey) {if(err){document.getElementById("info").innerHTML = err;}else{ks.generateNewAddress(pwDerivedKey, totalAddresses);ks.passwordProvider = function (callback) {callback(null, password);};var provider = new HookedWeb3Provider({host: "http://localhost:8545",transaction_signer: ks}); //利用ks做交易的签署者。它调用ks的hasAddress方法和signTransactions方法
var web3 = new Web3(provider);var from = document.getElementById("address1").value;var to = document.getElementById("address2").value;var value = web3.toWei(document.getElementById("ether").value, "ether");web3.eth.sendTransaction({from: from,to: to,value: value,gas: 21000}, function(error, result){if(error){ document.getElementById("info").innerHTML = error;}else{document.getElementById("info").innerHTML = "Txn hash: " + result;}})}});}); }
测试:
到项目根目录,执行 npm install 加载相关库。
执行 node app.js 启动前端服务。端口8080. 访问 localhost:8080
点击 generate new seed ,输入2,生成两个账户。
然后进入到一开始打开的geth客户端,通过 eth.accounts 查看geth下的账号。复制地址,通过eth.getBalance("XX") 来获取地址余额。
转入一部分余额到上面生成的地址中,例如0xb4c7cf322956f0345b613f246d5d2f4ba03028f6.
eth.sendTransaction({from: "0x8d1c1dd6f48c33c97924e5f310905e1822a6cbd0", to: "0xb4c7cf322956f0345b613f246d5d2f4ba03028f6", value: web3.toWei(100, "ether")})
点击页面的 generate details 刷新,同样的seed会生成同样的账户。
这个时候会发现账户多出100eth。然后可以测试钱包内地址,钱包对钱包外地址转账。
项目giithub地址:https://github.com/figo050518/wallet
转载于:https://www.cnblogs.com/gzhlt/p/10027796.html
分层确定性钱包开发的代码实现(HD钱包服务)相关推荐
- 分层确定性钱包 HD Wallet 介绍
分层确定性钱包 HD Wallet 介绍 文章来源:ConsenLabs 以太坊,区块链(Blockchain), 2017/10/20 14:06 3296 钱包是用于发送和接受代币的客户端,就像我 ...
- 分层确定性钱包 HD Wallet 钱包归集
分层确定性的概念早在 BIP32 提案提出.根据比特币核心开发者 Gregory Maxwell 的原始描述和讨论,Pieter Wuille 在2012 年 02月 11日整理完善提交 BIP32, ...
- 数字货币 分层确定性钱包(HD Wallets)
HD Wallets的全称是Hierachical Deterministic Wallets, 对应中文是 分层确定性钱包. 分层确定性的概念在BIP32提案提出. 根据比特币核心开发者 Grego ...
- 分层确定性钱包(HD Wallets)
HD Wallets的全称是Hierachical Deterministic Wallets, 对应中文是 分层确定性钱包. 分层确定性的概念在BIP32提案提出.根据比特币核心开发者 Gregor ...
- 分层确定性钱包-以太坊创建钱包
基本概念 所有问题大体可以分为三类:区块链基本概念,钱包安全知识以及钱包转账交易 区块链的基本特性 去中心化 因为整个网络没有中心统治者.系统依靠的是网络上多个参与者的公平约束,所以任意每几个节点的权 ...
- 代码结构设计得最好的多链支持的 HD 钱包服务端代码
代码库地址: https://github.com/SavourDao/savour-hd Savour HD 是 Savour 项目的钱包的 HD. 后端服务,使用 golang 编写,提供 grp ...
- 数字货币钱包开发需要注意哪些问题?
10月24日,也就是上周五,国家明确提出要把区块链作为未来科技的主攻方向,从国家层面上,区块链被钦点成未来核心技术创新的突破口,可以肯定的是,区块链技术将在之后加大投入与研究.今日,区块链概念股百股涨 ...
- 数字货币HD钱包 BIP32、BIP44、BIP39 简介
数字钱包概念 钱包用来存钱的,在区块链中,我们的数字资产都会对应到一个账户地址上, 只有拥有账户的钥匙(私钥)才可以对资产进行消费(用私钥对消费交易签名). 私钥和地址的关系如下: (图来自精通比特币 ...
- 以太坊钱包开发系列 - 创建钱包账号
想知道更多关于区块链技术知识,请百度[链客区块链技术问答社区] 链客,有问必答!! 以太坊去中心化网页钱包开发系列,将从零开始开发出一个可以实际使用的钱包,本系列文章是理论与实战相结合,一共有四篇:创 ...
最新文章
- 37 windows_37_Thread_InterLock 线程-原子锁
- 使用泛型查询数据小例
- C/C++中宏使用总结
- android call require api level
- 递推:Ybtoj: D.4 序列个数
- 【渝粤教育】电大中专学前儿童科学教育 (14)作业 题库
- 分享GitHub上一些嵌入式相关的高星开源项目
- JAVA Swing GUI设计 WindowBuilder Pro Container使用大全2——JPanel使用
- 这个“猫窝”太豪华?硅谷宠物猫住1500美元公寓
- 两种模式的资源管理器代码之———— 重命名文件夹
- myeclipse svn 删除文件或者文件夹
- JavaWeb公交调度系统的设计与实现
- 泰坦尼克号数据_泰坦尼克号数据分析案例实战
- 微信html 全屏显示,关于微信上网页图片点击全屏放大效果
- 中国货币供应量全球第一的反思
- Hyperf基础使用
- 小花经过春雨的一番滋润
- 南理工计算机学院贾修一,南京理工大学考研研究生导师简介-贾修一
- 视觉中国财报背后的版权门余波
- 记录一次Specified key was too long的问题