区块链是一个伟大的发明,它改变了生产关系。不少生态,有了区块链技术,能够由全公司员工的"全员合伙人"变成了全平台的”全体合伙人”了,是真正的共享经济模式。css
什么意思呢?举例来讲,如今不少互联网平台,好比淘宝,普通消费者只是一个利益贡献者,这个平台运营的好很差跟用户没有关系。但在有代币的平台上,每个用户的角色都发生了转变:他们不仅仅是某个平台的用户,还持有了它的代币。这些代币通常都是有限的,使用这个平台的人数越多,代币的需求就会越旺盛,代币在市场上供需就会倾斜,就会涨价。因此这时候用户跟平台方,实际上是站在同一边的。也就是说,在+互联网时代,经过使用互联网技术提高信息流通效率后,消费者培养了淘宝这个独角兽平台,可是这个受益主要被马云团队享受,创造了一个中国首富,平台的广大用户并无获得平台增加红利的好处。可是,在+区块链时代,全部的用户都是平台的利益相关方,都是创业者。他们会随着这个平台的增加而一块儿受益,这个梦想的力量也就会更大。 目前DAPP业务生态中,不少项目不自带钱包或者交易所的。我认为DAPP只带钱包功能将会是一个基本配置。以下图理解, 1) 当生态中没有TOKEN经济时,这个平台是固态的,谁是用户,谁是利益平台最终受益方,是静态固化的。这是通用的+互联网模式,海量的用户制造了BATJ等独角兽企业,但他们永远只是贡献者,自身没有从中分享更多的利益。 2) 当生态中包含TOKEN,而后经过上交易所完成利益变换时,我认为这时的生态是液态的。生态中的利益兑换能够经过交易所进行转换。可是这样没法去中心化,没法去中介化,存在着不便捷和被收费的问题。这种模式下,没法造成通证经济的自循环生态。同时因为交易所的资产安全,被攻击,对现实金融生态的影响等缘由,是不少国家明令禁止的。 3) 当生态中除了TOKEN,还自带钱包后,我认为这个区块链生态才过渡到气态。在气态下,通证和资产的兑换是无处不在,很是方便的。认同这个平台的管理方和用户方自成循环体系,高效的促进了生态内的资产流通。html
以辉哥看,DAPP自带钱包将会是区块链项目的一个标配功能。前端
Ethereum Wallet客户端对应的是Mist项目,如今此客户端大多都称为Ethereum Wallet,也有称做Mist客户端的,知道它们两个指的是同一个客户端便可。此客户端使用JavaScript进行开发,支持windows、linux和OSX三类操做系统,是一个图形化操做界面的客户端。介绍到这里,你们可能就明白了,若是你想经过API来调用以太坊的接口,选择此方式是行不通的。 Ethereum Wallet客户端主要是为用户提供可视化操做的客户端,下载安装以后经过相应的图形化界面便可进行建立帐户、转帐、查询余额等操做。 Ethereum Wallet客户端主要功能: 1] 建立帐户 2] 兑换以太币:内置了比特币、其它竞争币与以太币兑换功能 3] 部署智能合约:代币合约、众筹合约、自治组织合约等 4] 以太币转帐操做 5] 备份钱包等其余功能 以上全部功能操做都是启动客户端程序以后,经过操做界面或菜单进行操做。智能合约部分须要事先编写好对应的代码,经过客户端进行发布。 属于此类独立钱包APP应用的还有imToken等。node
Geth是go-ethereum项目的客户端,也是目前使用最普遍的客户端。支持windows、linux和OSX三类操做系统。针对此系统网上有大量的资料能够参考,github上的wiki文档使用说明也比较详细,【点击跳转到文档地址】。经过此客户端能够进行基本全部的以太坊相关操做。linux
1] Geth客户端主要功能:android
使用Geth客户端能够经过对接API(目前交易平台经常使用的方式),或直接经过命令行进行操做。与Ethereum Wallet相比,没有可视化的操做界面,基本上都是经过命令来完成的。 Geth钱包是Ethereum生态的技术实现的一部分,不是为了给终端用户使用的应用型钱包。ios
DAPP自带钱包是在Geth基础上开发出来的移动端 App或者网页版钱包,例如彩贝APP帐号自带的ColorBay通证转帐功能的钱包。这个钱包依附于彩贝APP,不能独立存在。git
根据私钥存储的位置可分为两类: 1)中心化私钥存储的钱包,好比火币的钱包; 2)去中心化钱包,私钥存储在用户端,好比 imtoken 钱包,彩贝钱包。github
去中心化钱包不是本节要讲的重点,这里只给你们简单介绍一下。不管是中心化的钱包或去中心化的钱包,在 App 层面都是很轻量级的,App 内是不会内置一个 Geth 节点,交易的查询或发送都是经过服务器来进行操做,不一样点是交易签名的私钥由谁来保管和负责。 去中心化的钱包有个关键词:助记词。能够用下面的表达式来形容助记词的做用:web
私钥 = 助记词 = keystore+密码
复制代码
经过上面的公式能够看出助记词的重要做用,也是去中心钱包功能的一个亮点。当在这类钱包中建立一个帐户以后,钱包会根据生成的私钥文件,生成一套助记词,可为英文可为中文,经过助记词能够反向计算出 keystore + 密码。助记词由用户手抄存放在安全的地方,当进行交易时,输入助记词对交易进行签名,发送交易。当助记词丢失,也就意味着失去了私钥,而钱包通常不会保存用户的私钥信息,资产将永久丢失。 去中心化钱包的好处是不用担忧平台从中做梗,不用担忧平台被黑客攻击而致使资产损失,但要求我的有必定的私钥保存能力。
所谓中心化钱包就是将全部的私钥文件存储在钱包服务商的服务器内,由服务商来保管这些私钥文件,也就是说资产属于你,但私钥不禁你保管。这样作的好处是用户根本不用记住私钥,只用记住在平台所开设的帐户、登陆密码和支付密码便可。即便忘记了密码,仍是能够经过平台提供的忘记密码进行找回,固然,这样就不具备去中心化钱包的优势了。 彩贝钱包属于依附彩贝生态的中心化钱包,帮助彩贝社区完成通证经济的闭环生态建设。
钱包对外呈现可能有不一样的功能,充值、提现、转帐等,但从本质上来讲只有一个功能,那就是转帐。区块链本质上就是一个帐本,记录着一笔笔交易,钱包固然离不开这个本质。 具体功能说明: 1)充值是钱包的外部帐户向钱包的地址转帐; 2)提现是钱包的帐户向钱包以外的地址转帐; 3)转帐功能包括钱包内地址互转和向钱包外地址转帐; 在这个过程中也对应着钱包帐户资金的增长与减小。
用户在使用钱包的时候确定须要有一个属于当前帐户对应在区块链上的地址,这个地址如何生成呢?很多开发人员是这样实现的:每次当用户注册时就调用 Geth 节点的personal_newAccount方法生成一个地址,并将地址存放在 Geth 节点默认的位置。这种方式能够实现,但从技术上和安全上来说是不可取的。 性能瓶颈之一,调用 Geth 节点生成地址很是耗时,特别是当节点在处理一些同步或高消耗的工做时。 性能瓶颈之二,当 Geth 节点下的私钥愈来愈多,Geth 启动会变得漫长。 安全问题,Geth 节点对外要广播交易,又要保存敏感的私钥信息,安全问题巨大。 **优化以后的作法是事先批量生成地址,当用户注册时只用把地址分配给用户便可。**这样作的好处是: 私钥的存储与 Geth 节点相隔离,确保私钥与外网的隔离性,从而确保私钥的安全; 性能的保障,当用户注册时只是将数据库的数据创建了一个关联,而不用去执行费时的加密算法来生成私钥和文件。 此种方法生成 Web3j 提供了相应的建立方法,可在无 Geth 节点的状况下经过代码直接生成符合私钥规则的公私钥。固然,若是有开发能力也能够经过 Geth 的源代码中的私钥生成方法抽离出一个单独的与网络无关的生产私钥程序。
在比特币的钱包中,有子帐户的概念,只须要在一个总帐户下建立 N 多子帐号,用户充值到此子帐号的比特币一样的会显示在钱包上,同时又提供了查询一个地址全部交易的方法。遗憾的是以太币并无提供此类接口,只能经过遍历区块交易的方法来判断是否有对应帐户的充值交易。 相关操做: 1)查询区块高度,比对是不是新生成的区块,eth_blockNumber; 2)查看区块内容及详细交易,eth_gethBlockByNumber; 比对交易的 toAddress 是否为本钱包的地址,若是是则记录此笔交易到数据库,并记录交易状态(pending、确认次数等); 3) 保证入库和记帐的幂等性,由于会屡次查询到同一笔交易。 4)确认次数 并非咱们查询区块链中的交易就说明这边交易已经成功了,比特币是默认确认12此以后,此交易几乎不会被篡改,以太坊默认6次,那么怎么计算确认次数呢?
确认次数 = 当前区块高度 - 交易所在区块高度 + 1
此处注意事项:交易有可能会被孤立,在执行此公式时须要验证一下区块中此交易是否仍是在那个区块上,是否已经被回滚。一样的,要作好幂等性保障。
提现交易一样涉及到上提到的知识点,同时它又有须要额外注意的事项。 提现地址的合法性检查,可参考源代码中的校验,此合法性检查能够避免后续不少问题的出现,好比 nonce 值的维护。 交易的金额检查,nonce 值检查,特别是私钥与 Geth 节点分离以后本身来维护私钥时 nonce 值会是一个很大的问题,好比前一笔交易失败,nonce 值须要回退,此时后一笔交易已经发出,由于前一笔 nonce 没有被补齐,后一笔迟迟不会被交易。这些都须要业务进行特殊判断和处理。 查询一个地址 nonce,eth_getTransactionCount。
提现与转帐都是发起一笔交易,在以太坊的 json-rpc 中已经提到能够经过 eth_sendTransaction 和 personal_sendTransaction 直接进行转帐,这是 Geth 节点所支持的。转帐前能够经过 unlock 方法先将帐户解锁,这些以前章节都有提到过。 但针对私钥单独存储的状况,上面的方式并不适用,可经过将交易先签名再广播的模式:
更多功能查看官网的go-ethereum GETH钱包[RPC,API]连接。
建立DAPP 钱包或者PC WEB钱包,须要在Geth基础上实现功能。本章介绍2个库模块,下降钱包实现的难度。
Hooked-web3-Provider模块库(官网地址)提供自定义程序提供方(custom provider),它使用HTTP与geth通讯。这个提供方的独特之处在于,它容许使用密钥签署合约实例的sendTransation()调用,所以再也不须要建立交易的数据部分了。自定义程序提供方实际上重写了web3.eth.sendTransaction()方法的实现,因此基本上它容许签署合约实例的sendTransaction()调用以及web3.eth.sendTransation()调用。合约实例的sendTransaction()方法在内部生成交易数据,并调用web3.eth.sendTransation()广播交易。
LightWallet是一个实现BIP32,BIP39和BIP44(官网地址)的HD钱包。LightWallet提供API来建立和签署交易,或者使用LightWallet生成的地址和密钥加密和解密数据。 LightWallet API被分红4个命名空间,即keystore、signing、encryption和txutils。signing、encrpytion和txutils分别用来提供API以签名交易,非对称的密码和建立交易,而keystore命名空间用于建立keystore、生成种子等。keystore是一个存储加密种子和密钥的对象。若是使用Hooked-Web3-Provider,keystore命名空间实现交易签名者方法,该方法要求签署we3.eth.sendTransation()调用。所以keystore命名空间对于在其中发现的地址能够自动建立和签署交易。实际上,LightWallet的主要目的是成为Hooked-Web3-Provider的一个签名提供方。 能够配置密钥存储实例,来建立和签署交易或者加密和解密数据。签署交易用secp256k1参数,加密和解密用curve25519参数。 LightWallet的种子是一个12词的助记符,容易记住但不容易进行破解。它不是任意12个词,而是LightWallet生成的种子。LightWallet生成的种子在选择词和其余东西方面有特定的属性。
此环境代码部署在辉哥的Ubuntu虚拟机上测试成功。若是不懂如何安装Ubuntu虚拟机的,可参考《第一课 如何在WINDOWS环境下搭建以太坊开发环境》文章完成配置。
WebWallet钱包目录主要有如下文件和目录,各目录功能描述解释以下: WebWallet │ app.js -管理整个应用的App对象 │ package.json -环境配置文件 ├─node_modules -Nodeb.js库模块,不作修改 │
└─public ├─css │ bootstrap.min.css -前端排版文件 │
├─html │ index.html - 前端主页 │
└─js hooked-web3-provider-Formatted.min.js - 格式化可读的“hooked-web3-provider.min.js”文件,供阅读参考 hooked-web3-provider.min.js - 实现hooked-web3-provider功能库文件 lightwallet-Formatted.min.js - 格式化可读的“lightwallet.min.js”文件 lightwallet.min.js - 实现lightwallet功能库文件 main.js - 本案例实现主要函数 web3.min.js -web3.js的实现文件
重点实现代码在main.js文件中。 1, generate_seed函数代码
function generate_seed()
{
/*产生12个单词的助记词*/
var new_seed = lightwallet.keystore.generateRandomSeed();
document.getElementById("seed").value = new_seed;
/*产生钱包地址*/
generate_addresses(new_seed);
}
复制代码
generate_seed函数功能: 调用lightwallet函数产生seed助记词,产生钱包地址。
2, generate_addresses函数代码
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({
password: password,
seedPhrase: seed
}, function (err, ks) {
/*以用户密码做为输出,产生的Uint8类型的数组的对称密钥,这个密钥用于加密和解密keystore*/
ks.keyFromPassword(password, function (err, pwDerivedKey) {
if(err)
{
document.getElementById("info").innerHTML = err;
}
else
{
/*经过seed助记词密码在keystore产生totalAddresses个地址/私钥对。这个地址/私钥对可经过ks.getAddresses()函数调用返回*/
ks.generateNewAddress(pwDerivedKey, totalAddresses);
var addresses = ks.getAddresses();
/*【注意】为了能在其余PC浏览器可以访问,此处IP要改成UBUNTU所在的GETH环境的IP*/
//var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
var web3 = new Web3(new Web3.providers.HttpProvider("http://192.168.0.106:8545"));
var html = "";
/*组装地址/私钥对为HTML,以便显示*/
for(var count = 0; count < addresses.length; count++)
{
var address = addresses[count];
/*根据地址和pwDerivedKey生成私钥*/
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;
}
});
});
}
复制代码
generate_seed函数功能说明: 根据助记词和须要的地址数量产生帐户地址,并显示出来。 【说明】lightwallet实现了相同的SEED能够产生相同的帐户地址。
3. send_ether函数代码
function send_ether()
{
var seed = document.getElementById("seed").value;
/*seed是否有效?*/
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) {
/*以用户密码做为输出,产生的Uint8类型的数组的对称密钥,这个密钥用于加密和解密keystore*/
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);
};
/*【注意】为了能在其余PC浏览器可以访问,此处IP要改成UBUNTU所在的GETH环境的IP*/
/*新建HookedWeb3Provider, 参考https://www.npmjs.com/package/hooked-web3-provider*/
/**
var provider = new HookedWeb3Provider({
host: "http://localhost:8545",
transaction_signer: ks*/
var provider = new HookedWeb3Provider({
host: "http://192.168.1.135:8545",
transaction_signer: ks
});
/*以HookedWeb3Provider为对象产生web3,
不一样于宠物商店案例的new Web3.providers.HttpProvider('http://localhost:8545');*/
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");
/*从源地址钱包向目标地址钱包发送value的以太币*/
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;
}
})
}
});
});
}
复制代码
send_ether函数功能说明: 该函数实现ETH转帐功能。 【说明】为了在你的测试机上能够跑通代码,必定注意修改IP地址为代码所在的机器IP。
由于辉哥在本地配置的Ubuntu虚拟机屏幕比较小,采用使用Xshell 4进行SSH远程登陆的方式,采用本地windows chrome浏览器的方式进行演示的方式。各位看官也能够直接在Ubuntu上操做的方式完成。 Ubuntu机器的ip地址为“192.168.1.135”,相关的main.js的2处IP地址也改成了“192.168.1.135”,并更新部署到Ubuntu工做目录下。 ##5.1 启动GETH开发实例 启动Ubuntu远程链接后,窗口输入命令用于运行GETH环境。
geth --dev --rpc --rpccorsdomain "*" --rpcaddr "0.0.0.0" --rpcport "8545" --mine --unlock=0 --datadir testNet console 2>> test.log
针对GETH的命令参数稍做解释,具体参考文章《第五课 以太坊客户端Geth命令用法-参数详解》。 说明: 1) --dev表示启动开发环境; 2)--rpc表示启用HTTP-RPC服务器; 3)--rpccorsdomain "*"表示用于容许一些特定域与geth通讯。*通配符表示可与任何域名通讯。 4)--rpcaddr "0.0.0.0" 表示geth服务器能够到达哪一个IP地址。默认的是127.0.0.1。将它的值改成0.0.0.0,这表示该服务器可使用任何IP地址到达。 5) --rpcport "8545" 表示HTTP-RPC服务器监听端口(默认值:8545) 6) --mine表示打开挖矿 1) --unlock=0表示解锁帐号0,geth默认建立的帐户,命令启动后系统提示“Passphrase:”回车输入密码为空后便可解锁帐号0。 运行成功后,输入“eth.accounts”能够看到geth自动建立的一个默认帐户地址为“0x5eaba24091f993917fb35188add523c501dc1354”。
在XShell 4新开一个窗口连接,进入到辉哥工程目录~/work/WebWallet,而后启动本APP。
node app.js
操做截图以下:
1. 打开WEB钱包网址
3. 给目标地址发送ETH 回到geth环境,从系统帐户account[0]给目标帐户地址打100个ETH。
eth.sendTransaction({from: '0x5eaba24091f993917fb35188add523c501dc1354', to: '0xe45d865ed260fdf2409f66d4a9499a664943079c', value: web3.toWei(100, "ether")})
操做截图以下:
至此,把DAPP应用中,为何须要钱包功能,钱包功能的分类,一个演示基本的钱包实现基本讲明白了。须要学习更多内容可参考官网接口文档和说明。 #6. 知识对接服务 咱们在知识星球开通了区块链入门专栏,用于存放本项目的工程源码等内容,并创建专项微信群用于技术交流,欢迎加入。
1,ethereumjs-tx www.npmjs.com/package/eth… Github代码: github.com/ethereumjs/… 2,hooked-web3-provider www.npmjs.com/package/hoo… Github代码: github.com/consensys/h… 3,web端钱包源码 1)eth web: github.com/ConsenSys/e… 2).android: github.com/walleth/wal… 3).IOS: github.com/ethers-io/E… 4,WEB3.JS完整文档 github.com/ethereum/wi… WEB3.JS代码 github.com/ethereum/we… 5,go-ethereum GETH钱包[RPC,API] github.com/ethereum/go… 6,以太坊钱包的开发 blog.csdn.net/u011494083/… blog.csdn.net/u011494083/… github.com/ethereum/wi… 7,第08课:开发以太坊钱包的基本思路与安全[中心化钱包和去中心化钱包讲的不错] blog.csdn.net/su_bo_2010/… 8,以太坊客户端Ethereum Wallet与Geth区别简介 blog.csdn.net/wuxianbing2… 9,[以太坊源代码分析] V. 从钱包到客户端 blog.csdn.net/teaspring/a… 10,【区块链开发】从零构建基于以太坊(Ethereum)钱包Parity联盟链 ke.qq.com/course/2546… 11,基于以太坊的电子钱包开发分析 mp.weixin.qq.com/s/YQNlYozCv… 12,《区块链项目开发指南》- Narayan Prusty[India] 13,BIP32,BIP39协议-关于HD钱包和助记种子规范 github.com/bitcoin/bip… 14,格式化JS工具 tool.oschina.net/codeformat/… 15,第03课:以太坊常见 JSON-RPC 接口解析 blog.csdn.net/su_bo_2010/…