标签:14. gas lang 字母 了解 颠覆 continue ESS 网页
以太坊钱包顾名思义,就是管理以太坊地址,存储以太坊Token的工具,再简单点说,任何区块链网络都需要我们有自己的账户,管理账户的软件可称之为钱包,无论是炒币的还是研究以太坊开发的,钱包都是必不可少的。
说到以太坊钱包,第一个要说的当然就是Ethereum官方钱包+浏览器 Mist。Mist是一个全节点钱包(全节点钱包通俗的来说就是同步了全部的以太坊区块信息的钱包)。也就是说打开钱包后,电脑会自动同步全部的以太坊区块信息,如果设备和网络的条件过关的情况下,大概需要半天左右的时间。
最新版下载地址:https://github.com/ethereum/mist/releases/tag/v0.11.1
MyEtherWallet 是一个轻钱包,无需下载,在直接在网页上就可以完成所有的操作。
MetMask是一个以太坊钱包插件,目前支持Google跟FireFox浏览器,能够帮助用户方便地管理以太坊数字资产,支持所有的测试网络和私有链网络,是我们开发人员的必备钱包工具,下文将会讲解如何安装。
原以太坊基金会部分成员开发的钱包,也是一个全节点钱包。
下载地址: https://github.com/paritytech/parity-ethereum/releases
以太坊网络中的账户和典型的区块链账户没有太大区别,都由地址、公钥、私钥 3 部分构成,不论使用何种钱包创建的以太坊账户,在不同的以太网网络之间都是可以通用的,比如我在主网上创建了钱包账户,而切换到 任意 测试网络,如Kovan时仍然可以使用同样的账户,这种跨网络通用的账号机制实际上是内置在以太坊客户端之内的。
创建以太坊账户的方式有很多种,上文就提到了多种以太坊钱包,但我们要开发跑在浏览器中的 DApp,钱包集成在浏览器中就非常方便了,所以我们选择MetaMask作为我们的开发环境的钱包工具。
官方地址:https://metamask.io/
点击GET CHROME EXTENSOIN跳转至安装界面
点击右上角ADD TO CHROME
点击添加扩展程序按钮,等待安装即可,安装成功后,在浏览器右上角可以有该图标显示!
打开MetaMask图标,点击TRY IT NOW按钮开始创建账户
点击CONTINUE继续
创建密码
点击NEXT继续
将协议文字拖到最后,点击ACCEPT继续
点击ACCEPT继续
重要: 点击
获取助记词,将这12个英文字母抄写在纸上,妥善保存!
按照顺序选择助记词进行确认,确认完毕
点击VIEW ACCOUNT查看账户地址与二维码信息
可以根据需要,对账户名进行修改
此时,钱包创建完毕,接下来,为了开发需要,我们需要为几套测试环境申请测试ETH进行开发使用。
从上图可以看到我们钱包可以切换的环境,除了Main Ethereum Network之外的Network节点均为测试节点。
以太坊可以搭建私有的测试网络,不过由于以太坊是一个去中心化的平台,需要较多节点共同运作才能得到理想的测试效果,因此并不推荐自行搭建测试网络。
以太坊公开的测试网络共有4个,目前仍在运行的有3个。每个网络都有自己的创世区块和名字,按开始运行时间的早晚,依次为:
Morden是以太坊官方提供的测试网络,自2015年7月开始运行。到2016年11月时,由于难度×××已经严重影响出块速度,不得不退役,重新开启一条新的区块链。Morden的共识机制为PoW。
Ropsten也是以太坊官方提供的测试网络,是为了解决Morden难度×××问题而重新启动的一条区块链,目前仍在运行,共识机制为PoW。测试网络上的以太币并无实际价值,因此Ropsten的挖矿难度很低,目前在755M左右,仅仅只有主网络的0.07%。这样低的难度一方面使一台普通笔记本电脑的CPU也可以挖出区块,获得测试网络上的以太币,方便开发人员测试软件,但是却不能阻止×××。
PoW共识机制要求有足够强大的算力保证没有人可以随意生成区块,这种共识机制只有在具有实际价值的主网络中才会有效。测试网络上的以太币没有价值,也就不会有强大的算力投入来维护测试网络的安全,这就导致了测试网络的挖矿难度很低,即使几块普通的显卡,也足以进行一次51%×××,或者用垃圾交易阻塞区块链,×××的成本及其低廉。
2017年2月,Ropsten便遭到了一次利用测试网络的低难度进行的×××,×××者发送了千万级的垃圾交易,并逐渐把区块Gas上限从正常的4,700,000提高到了90,000,000,000,在一段时间内,影响了测试网络的运行。×××者发动这些×××,并不能获得利益。
为了解决测试网络中PoW共识机制的问题,以太坊钱包Parity的开发团队发起了一个新的测试网络Kovan。Kovan使用了权威证明(Proof-of-Authority)的共识机制,简称PoA。
PoW是用工作量来获得生成区块的权利,必须完成一定次数的计算后,发现一个满足条件的谜题答案,才能够生成有效的区块。
PoA是由若干个权威节点来生成区块,其他节点无权生成,这样也就不再需要挖矿。由于测试网络上的以太币无价值,权威节点仅仅是用来防止区块被随意生成,造成测试网络拥堵,完全是义务劳动,不存在作恶的动机,因此这种机制在测试网络上是可行的。
Kovan与主网络使用不同的共识机制,影响的仅仅是谁有权来生成区块,以及验证区块是否有效的方式,权威节点可以根据开发人员的申请生成以太币,并不影响开发者测试智能合约和其他功能。
Rinkeby也是以太坊官方提供的测试网络,使用PoA共识机制。与Kovan不同,以太坊团队提供了Rinkeby的PoA共识机制说明文档,理论上任何以太坊钱包都可以根据这个说明文档,支持Rinkeby测试网络,目前Rinkeby已经开始运行。
切换测试环境,点击DEPOSIT
点击GET ETHER
点击获取1个ETH测试币,可以点击多次
目前共计是11个,超出后报错“User is greedy”,比较直白:用户太贪了:-),如果测试币花不掉,也不要浪费,可以继续返回给测试币发送方。
可以根据实际数量选择捐赠的数量
成功获取到11个ETH测试币
https://gitter.im/kovan-testnet/faucet
打开了解跳转至gitter聊天室中,可以通过github账户或者twitter账户进行登录,加入faucet聊天室后,发送自己的账户地址到聊天列表中,笔者申请的账户地址为0x18850c9cE7B2274EbB0c78e6221844AC76715494
效果如下
笔者的github账户前几天申请过,所以第一次申请的时候提示我最近刚刚申请过,更换了登录账户后成功。
成功获取到3个ETH测试币
这个环境的测试币申请稍微复杂一点,要求接受充值的账户持有人必须以太坊账户地址发送到自己的社交网络中(如 Twitter、Facebook、Google Plus),同样,该工具限制了充值的频率;
0x18850c9cE7B2274EbB0c78e6221844AC76715494
贴入账户地址,点击发布
点击按钮公开分享
复制链接地址
https://plus.google.com/100168130519914964665/posts/eqQ6iBMAhbJ
https://www.rinkeby.io/#faucet
按需选择
网站已经获取到请求,开始处理,等待片刻充值完毕
获取到18.75个ETH测试币
三套测试环境的测试币我们均已获得,现在我们可以开始代码设计工作了。
Token是区块链实践中的一个重要概念,有多重要呢?有观点认为,Token可能是比区块链更伟大的发明,是一个与“公司”比肩的伟大发明。区块链是一个技术概念,Token是一个经济概念;与“公司”一样,Token带来了全新的组织形式和协作形式。
Token早期的叫法为代币,但现在更适合的翻译应该是“通证”。“通证”的概念超过了“代币”。通证是一种可流通的、加密的数字权益证明,这个权益,可以是财产、×××、学历证书、钥匙、门票、积分、荣誉、使用权等等任何事物。代币更像是资产的数字化,而通证则在此基础上,同时包含了数字化的资产,将原本无法量化、无法记账的东西,给量化、记账。
Token目前有两种,一种是在区块链网络中内置的,用于用户之间的转账交易,并奖励矿工,这种被理解为数字加密货币,比特币就属于这一种;另一种是在DApp或智能合约上自行铸造的,用于内部交易,这种更接近“通证”这个含义。
看起来,Token跟股权有点类似,但其实这两者的差别还是比较大的。Token比股权,最重要的就是多了流通凭证。股权只是权益凭证,缺乏流动性,投资者如果对公司运作方式不认可,会通过董事会来施压,而Token模式下,投资者如果对公司运作方式不认可,可以直接卖了token退出。这一点,对于传统的投资模式,可能会有比较大的颠覆。VC行业也迅速做出了反应,市场上兴起了一波数字币基金,与传统VC在出资人、投资流程、项目管理和退出方面有明显的差异。
综上所述,Token作为一种权益证明,是数字的、加密的、可流通的。鉴于Token这么多的优点和想象力,区块链行业提出一个新概念,叫“通证经济”,要把Token通证充分用起来,用通证来盘活人力、资本、项目、信用等生产要素,用新的利益机制,造就新的生产关系。这事儿如果能成,会激发指数级的创新,给我们的生产生活方式带来巨大的改变。
Token的走红,归功于以太坊及其订立的ERC20标准。基于这个标准,每一个人、每一家企业都可以在基于区块链的平台上发Token,这个Token是自定义的,可以代表任何权益和价值。
ERC-20最初作为一种尝试,旨在为以太坊(Ethereum)上的token合约提供一个特征与接口的共同标准,并且,它现在已经被证明是非常成功的了。ERC-20有很多好处,包括允许钱包显示数以百计不同token的账户余额;创建一个交易工具,只需提供token合约的地址就可以将更多token列入表中。创建ERC-20兼容token的好处很多,以至于在今天,很少有其他token合约用其他方式创建。
ERC是 Ethereum Request for Comment 的缩写,Request for Comment 是征求大家意见的意思,大家都希望 Ethereum 网络的未来技术走向不要集中在几个硏发人员的手里, 所以才开放给大家提出 Proposals (建议), 用来改进 Ethereum, 决定未来开发方向. 这就是每个人每件跟 Ethereum 未来发展有关的事情, 都能用 EIP 建议格式 (EIP template) 提出来. 只要被大家选上, 就会正式列入 EIPs 清单。
而且, 你会看到 EIP 定义或讨论 issues 里, 常常会看到它相关的 ERC, 也就是, 讨论过程中, 有一些要征求更多人意见时, 就会把它细节定义放在 ERC 里. 而且他们会用同一个号码, 比如 ERC-20就是对应到 EIP-20.
简单讲, 讨论项目, 一开始会用 EIP 提出建议, 结果与细节会定义在 ERC, 最后会 final (拍板定案), 放在 EIP 清单里 Finalized EIPs 区.
关于EIP-20(ERC-20 Token Standard)的标准说明可以直接参考官方文档,英文能力强的直接看原文即可。
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
为了节约读者时间,本文直接在代码设计这部分对该标准进行解读,便于读者更好地理解如何使用标准去设计开发自己的Token合约。
首先,我们看简单看一下现在主流的一些Token的项目介绍,我个人比较关注也比较看好火币Pro,所以姑且用HT给大家进行直观化的了解。
此处仅为学习交流,不代表任何炒币观点,如果读者有火币的人脉资源,倒是可以帮笔者引荐引荐。
HT(火币全球通用积分)是基于区块链发行和管理的积分系统,为火币官方发行的唯一积分。HT 将支持火币全球业务、全线产品,如:VIP 手续费折扣、认证商家保证金、火币积分专享活动、与热门币种交易、参与火币业务等。
以上信息中,我们姑且先关注一下总量: 500,000,000 HT,其他信息均为交易所信息,暂时不关注,现在,我们开始通过ERC20标准实现我们自己的Token合约。
首先定义一个合约EIP20Interface,将ERC20标准中需要实现的所有方法与事件全部进行引用,作为Token合约的父合约,用于被其他合约集成使用。
pragma solidity ^0.4.24;
contract EIP20Interface{
/*
//获取token名字,比如"BruceFeng Coin"
function name() view returns (string name);
//获取Token简称,比如"BFC"
function symbol() view returns (string symbol);
//获取小数位,比如以太坊的decimals为18
function decimals() view returns (uint8 decimals);
//4.获取token发布的总量,比如HT 5亿
function totalSupply() view returns (uint256 totalSupply);
/*
//获取token发布的总量,比如HT 5亿
function totalSupply() view returns (uint256 totalSupply);
*/
//获取_owner地址的余额
function balanceOf(address _owner) public view returns (uint256 balance);
//主动转账:当前地址主动发起转账,从当前地址向_to地址转入_value个Token
function transfer(address _to, uint256 _value)public returns (bool success);
//被动转账:允许_to地址从_from(一般为当前地址)向_to转_value个Token
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
//允许_spender从自己(调用方)账户转走_value个Token
function approve(address _spender, uint256 _value) returns (bool success);
//自己_owner查询__spender地址可以转走自己多少个Token
function allowance(address _owner, address _spender) view returns (uint256 remaining);
//转账的时候必须要调用的事件,比如Tranfer,TransferFrom
event Transfer(address indexed _from, address indexed _to, uint256 _value);
//成功执行approve方法后调用的事件
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
请严格参照3.规范解读中的英文网页进行对比查看,我们此处将网页中需要实现的方法全部贴入代码中,在下面会依次实现。
contract BFCToken is EIP20Interface {
// 合约体
}
创建一个新合约名为BFCToken作为子类集成EIP20Interface合约中的所有方法。
//1.获取token名字,比如"BruceFeng Coin"
string public name;
//2.获取Token简称,比如"BFC"
string public symbol;
//3.获取小数位,比如以太坊的decimals为18
uint8 public decimals;
//4.获取token发布的总量,比如HT 5亿
uint256 public totalSupply;
在合约标准中,通过function name() view returns (string name);
实现,由于这些变量是存储固定信息的变量,不参与任何运算,只为显示所需,所以,通过public类型进行声明即可自动提供变量值的获取方法,这是行业内的常规做法,大家可以先参考实现,所以,我们将获取这四个参数的函数都先注释掉。
这两个变量非常重要,请仔细思考
//存储地址余额
mapping(address=>uint256) balances ;
//存储允许转出的金额
mapping(address=>mapping(address=>uint256)) allowances;
balances 存储账户余额
如balance["0xca35b7d915458ef540ade6068dfe2f44e8fa733c"]=10000
key :0x18850c9cE7B2274EbB0c78e6221844AC76715494
value :
key : 0xca35b7d915458ef540ade6068dfe2f44e8fa733c
value : 100
value :
key : 0xxv3fe7d915458ef540ade6068dfe2f44e8fa34xb
value : 200
1.表示地址0x18850c9cE7B2274EbB0c78e6221844AC76715494允许地址0xca35b7d915458ef540ade6068dfe2f44e8fa733c从自己账户中转出100个TOKEN
map[0x18850c9cE7B2274EbB0c78e6221844AC76715494][0xca35b7d915458ef540ade6068dfe2f44e8fa733c]=100
2.表示地址0x18850c9cE7B2274EbB0c78e6221844AC76715494允许地址0xxv3fe7d915458ef540ade6068dfe2f44e8fa34xb从自己账户中转出200个TOKEN
map[0x18850c9cE7B2274EbB0c78e6221844AC76715494][0xxv3fe7d915458ef540ade6068dfe2f44e8fa34xb]=200
请仔细参考以上讲解说明,此处均为被动转账模式。
function BFCToken(string _name,string _symbol, uint8 _decimals,uint256 _totalSupply) public{
name = _name;
symbol = _symbol;
decimals = _decimals;
totalSupply = _totalSupply;
balances[msg.sender] = _totalSupply;
}
通过该函数定义部署Token合约时的传入参数
function balanceOf(address _owner) public view returns (uint256 balance){
return balances[_owner];
}
查询指定地址拥有该Token的数量
function transfer(address _to, uint256 _value)public returns (bool success){
require(_value >0 && balances[_to] + _value > balances[_to] && balances[msg.sender] > _value);
balances[_to] += _value;
balances[msg.sender] -= _value;
Transfer(msg.sender, _to,_value);
return true;
}
转账:从自己账户向地址
_to
地址转入_value
个Token
function approve(address _spender, uint256 _value) returns (bool success){
//定义依赖条件,转账金额>0 并且 被转账户余额>转账金额
require(_value >0 && balances[msg.sender] > _value);
//将转账金额存入allowances集合中,对应关系可参考···3.4定义存储变量···
allowances[msg.sender][_spender] = _value;
//触发Approval事件
Approval(msg.sender,_spender,_value);
return true;
}
允许
_spender
从自己(合约调用方msg.sender)账户转走_value
个Token
function allowance(address _owner, address _spender) view returns (uint256 remaining){
return allowances[_owner][_spender];
}
查询当前地址
_owner
(msg.sender)可以被_spender
地址多少个Token
function transferFrom(address _from, address _to, uint256 _value) returns (bool success){
//取出本次当前地址对中允许转账的金额
uint256 allowan = allowances[_from][_to];
/*定义依赖条件:
1. 允许转账的金额 > 转出的金额
2. 转出方地址的余额>=转出的金额
3. 转入方地址务必是当前账户地址
4. 转入方转账后地址务必大于原来余额
*/
require(allowan > _value && balances[_from] >= _value && _to == msg.sender && balances[_to] + _value>balances[_to]);
//将本次转账金额从允许转账金额中扣除
allowances[_from][_to] -= _value;
//将本次转账金额从转出方余额中扣除
balances[_from] -= _value;
//将本次转账金额加入到转入方余额中
balances[_to] += _value;
//触发Transfer事件
Transfer(_from,_to,_value);
return true;
}
pragma solidity ^0.4.24;
contract EIP20Interface{
//获取_owner地址的余额
function balanceOf(address _owner) public view returns (uint256 balance);
//转账:从自己账户向_to地址转入_value个Token
function transfer(address _to, uint256 _value)public returns (bool success);
//转账:从_from向_to转_value个Token
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
//允许_spender从自己(调用方)账户转走_value个Token
function approve(address _spender, uint256 _value) returns (bool success);
//自己_owner查询__spender地址可以转走自己多少个Token
function allowance(address _owner, address _spender) view returns (uint256 remaining);
//转账的时候必须要调用的时间,比如Tranfer,TransferFrom
event Transfer(address indexed _from, address indexed _to, uint256 _value);
//成功执行approve方法后调用的事件
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
contract BFCToken is EIP20Interface {
//1.获取token名字,比如"BruceFeng Coin"
string public name;
//2.获取Token简称,比如"BFC"
string public symbol;
//3.获取小数位,比如以太坊的decimals为18
uint8 public decimals;
//4.获取token发布的总量,比如HT 5亿
uint256 public totalSupply;
mapping(address=>uint256) balances ;
mapping(address=>mapping(address=>uint256)) allowances;
function BFCToken(string _name,string _symbol, uint8 _decimals,uint256 _totalSupply) public{
name = _name;
symbol = _symbol;
decimals = _decimals;
totalSupply = _totalSupply;
balances[msg.sender] = _totalSupply;
}
//获取_owner地址的余额
function balanceOf(address _owner) public view returns (uint256 balance){
return balances[_owner];
}
//转账:从自己账户向_to地址转入_value个Token
function transfer(address _to, uint256 _value)public returns (bool success){
require(_value >0 && balances[_to] + _value > balances[_to] && balances[msg.sender] > _value);
balances[_to] += _value;
balances[msg.sender] -= _value;
Transfer(msg.sender, _to,_value);
return true;
}
//转账:从_from向_to转_value个Token
function transferFrom(address _from, address _to, uint256 _value) returns (bool success){
uint256 allowan = allowances[_from][_to];
require(allowan > _value && balances[_from] >= _value && _to == msg.sender && balances[_to] + _value>balances[_to]);
allowances[_from][_to] -= _value;
balances[_from] -= _value;
balances[_to] += _value;
Transfer(_from,_to,_value);
return true;
}
//允许_spender从自己(调用方)账户转走_value个Token
function approve(address _spender, uint256 _value) returns (bool success){
require(_value >0 && balances[msg.sender] > _value);
allowances[msg.sender][_spender] = _value;
Approval(msg.sender,_spender,_value);
return true;
}
//自己_owner查询_spender地址可以转走自己多少个Token
function allowance(address _owner, address _spender) view returns (uint256 remaining){
return allowances[_owner][_spender];
}
}
调试环境: JavaScript VM
在将代码正式部署到以太坊测试网络前,我们先在JavaScript VM环境进行部署并进行调试
填写Token初始化参数,需要注意,发行总量=
_TotalSupply/_decimals
,此处发行了100000个BFC
直接获取参数值
部署成功
为了读者能够理顺后面的地址之间的关系,此处先进行说明
0xca35b7d915458ef540ade6068dfe2f44e8fa733c
0xdc04977a2078c8ffdf086d618d1f961b6c546222
用于转入Token的账户地址(下文简称为地址C):0x14723a09acff6d2a60dcdf7aa4aff308fddc160c
(可以从JavaScript VM环境的账户中选择一个即可)
在代码测试过程中,这几个地址千万不要混淆,地址B目前不需要使用,但部署到以太坊网络后需要使用,此处先作个铺垫。
查询地址A的Token余额
查询地址B的Token余额
注意点: 务必保证转账账户需要选择正确
从地址A给地址B转账1888个Token
查询地址B的Token余额
查询地址A的Token余额
地址B给地址A转账88个Token
查询地址B的Token余额
查询地址A的Token余额
其实被动转账这个概念是笔者自己定义的,让别人从自己这边取走东西,可以简单理解为被动,如此定义只是为了讲解的方便。
地址A允许地址B转走800个Token
allowance中填写: "0xca35b7d915458ef540ade6068dfe2f44e8fa733c","0x14723a09acff6d2a60dcdf7aa4aff308fddc160c"
查看地址B能从地址A中转出多少Token
此时地址A与地址B的余额分别为
地址A: 0: uint256: balance 9999999999999999998200
地址B: 0: uint256: balance 1800
地址B从地址A中转出230个Token,注意执行合约的Account是地址B
此时,地址B能从地址A中转出的Token余额为570,地址B的Token余额增加了230
此时,Token合约代码测试基本完毕,可以部署到以太坊网络中。
测试环境:本文选择使用Rinkeby环境进行合约部署
选择对应的测试环境跟账户,填写对应的Token合约参数,总量为10万
确认部署
部署确认
合约部署成功
获取合约配置参数,复制合约地址:
0x79334c31893ca7c59dd0bcf2a69189dd0db609c9
点击ADD Token
将合约地址粘贴进去,Token合约的简称跟位数都会直接显示
添加即可
添加成功
以上部署合约的账户地址(地址1)为: 0x18850c9cE7B2274EbB0c78e6221844AC76715494
要转入Token的账户地址(地址2)为:0x139f46dCb8DAE14dE0aE3F98B298A73393b7Cc43
地址2的账户信息
点击SEND执行转账操作
填写转入地址为地址2
信息确认
交易提交成功
交易确认成功
进入到地址2中进行Token添加
转账成功
读者可以继续执行转账测试工作,如从地址2转入地址1中。
本文所有内容均为学习交流使用,各位技术人在进行技术研究以及业务落地的过程中切记以遵守国家法律为前提,合法开展相关技术支撑的业务与市场活动。
最后,祝大家学习愉快!
标签:14. gas lang 字母 了解 颠覆 continue ESS 网页
原文地址:http://blog.51cto.com/clovemfong/2170725