区块链技术笔记(二):智能合约 代币(Token)等
文库划重点:很多专业人士希望把Token翻译成通证,而不是代币。“通证”更加符合单词原意,符合事物本质,也希望避免被当作货币监管。
智能合约(Smart Contract)是区块链一个重要的功能。说到智能合约,我们得把视野从比特币转到以太坊,因为完整的支持智能合约是以太坊和比特币的重大差别。
让我们发个币吧
听说区块链上可以发币,想发行一个自己的币 ①?来,直接上代码!
我希望你即使不懂代码,也要放下对未知的恐惧,静下心来一行一行读。毕竟这代码简单到大多数人都能看懂。
contract XMT {
mapping (address => uint) public balanceOf;
function XMT() public {
balanceOf[msg.sender] = 1000;
}
function transfer(address to, uint value) public {
require(balanceOf[msg.sender] >= value);
require(balanceOf[to] + value >= balanceOf[to]);
balanceOf[msg.sender] -= value;
balanceOf[to] += value;
}
}
惊人之处来了。如上代码不是概念性的伪代码,而是可以运行的真实代码。
首先它定义了一个记录每个账户有多少余额的数组: balanceOf 。
mapping (address => uint) public balanceOf;
看不懂的同学就把它当作有两列的表格,第一列是账号,第二列是余额。用 balanceOf [ 账号 ] 就可以查到这个账号的余额,也可以更改余额。
接下来是两个功能:初始化和转账。
初始化函数XMT( )很简单,就是合约建立的时候,任性的把1000个币全都给创建者。
balanceOf[msg.sender] = 1000;
大家要问,币是怎么产生的?没什么产生过程,想给谁多少就是多少。初始的时候写一个亿也就有了一个亿的币。如此随意的就能产生币,希望会引发大家在夜深人静的时候,对于货币到底是什么这样的深层思考。
我们接着看:
转账代码 transfer( ) 核心是两句:
balanceOf[msg.sender] -= value;
balanceOf[to] += value;
谁发起的转账,就把他(msg.sender)的账户余额减去转账金额(value)那么多,然后把收款人(to)的余额加上那么多②。
别小看这两句话。仔细琢磨一下,这其实就是账户和转账的本质。这简单的两句话是银行体系这么多年花了多少的硬件软件,人力物力才能达到的效果。
大家常常听说谁谁谁又发币了。从技术角度,就是在以太坊上部署了包含这三行代码的一个合约。在以太坊的官方网站上就有一段100多行的标准代码:https://ethereum.org/token。这段代码里面还有其他一些功能,比如可以给这个代币指定名称,符号,还有授权转账,销毁等功能。大家只要拷贝这个代码,指定你的新币的名称(比如 Xiaomao Token),符号(比如:XMT) ⑦,还有初始发行量比如:1,000,000,000),一个新的币就诞生了。整个过程3分钟应该够了。把参数改一下再部署一下代码,第二个新币又诞生了。
这新生的货币,虽然没啥用,但在安全性方面和以太币天生是一样的。这就像家长给孩子发了一些饭票,而这饭票的防伪技术和美元一模一样。看起来相当的大材小用,但如果把发货币成本降到几乎为零,把防伪能力提升到已知的最高水平,随着时间的推移,难说不会产生什么重要的应用。
部署代码
代码看懂了,下一步呢?怎么运行这代码?这代码到底在哪里运行呢?接着我们看部署过程。
部署代码,你需要在以太坊的客户端里,把这段代码粘贴进去,并且按“部署”按钮。客户端就会把这种人可以读懂的代码③编译成字节码,然后生成一笔从你的地址,发给一个空地址(0x0)的交易,并把字节码存在一个给定的字段里面(叫input),签名后发到整个网络上。接下来的操作和普通交易完全一样。矿工收到了以后立刻开始打包,算nonce,找到了以后再发送给全网络。这个可以被执行的代码,就永久的以只可读取不可更改的方式,存在了区块链上。
智能合约建立后会返回一个地址。每个币都唯一的对应于一个智能合约,也就是对应于一个地址。比如著名的EOS币,就是地址为 0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0 的智能合约发行的。你可以把这个地址想象成以太坊世界里的门牌号。币是以这个唯一的门牌号来区分的,而不是那三位的名字。
调用合约
现在,合约的代码安全的存在区块链上了。那么接下来这些代码什么时候执行呢?
一个智能合约里面有多个函数。调用智能合约里的一个函数,和发起一笔普通转账交易一样。很多的客户端已经内置进去了。你提供合约的地址,提供调用的函数,以及传入参数,然后发送消息就开始执行了⑤。你可以把它理解为从门牌号的屋子里面拿东西或者放东西进到给定的屋子。
消息发出以后,所有的矿工都执行这段代码,并且试图把结果打包到自己的数据块中,胜出的矿工获得挖矿的收益。所有的节点收到这个新的区块,也用自己的虚拟机执行一遍代码,确认结果和收到的块内结果无异之后才当作合法区块接受。
区块链就是通过这种超额的浪费,看似无意义的算nonce,看似无意义的反反复复,没完没了的执行同一段代码,来保证了一个安全的系统。这事儿就跟早上叠被子晚上还得展开一样,看似不产生价值,实则是房(shu)间(ju)整(an)洁(quan)不可或缺的一环。
花费 Gas
既然代码要被所有节点反复执行,那么问题就来了:要是谁写了巨长无比的代码,或者谁写了有问题的代码,死循环不结束了怎么办?以太坊的解决方法就是引入gas,每执行一个操作都是收费的。怎么收费呢?
首先每个交易的代码执行量越大,需要的gas就越多。字节码每一个操作都有固定的gas花销。以发币代码为例,如下是以太坊给我发的账单。总共执行了320步字节码的操作。有的操作很便宜,比如压栈(PUSH1),只要3个单位的gas,有的就很贵,比如在区块链上存数据(SSTORE)就一下子花了20,000个单位,而读取数据(SLOAD) 中等, 200个单位。如下加在一起就是1,300,213个单位的gas。只要执行这段代码,就是要这么多gas,好像汽车修理店工时的概念。
提交的时候每个人都可以出价,声明自己愿意为每个单位gas付多少钱(price)。这个有点像修理店的每工时的价钱。比如你可以出8 gwei/gas,或20 gwei/gas ⑥。矿工们大多数都是按照这个价钱排序优先打包出钱多的。出钱少就慢,甚至没人理。
矿工的费用 = gas单位数 * 单位价格。
如下图所示交易,1,300,213 gas * 2 gwei/gas = 2,600,426 gwei,或0.002600426 以太币,折合1.832美元。最终把这笔交易打包进区块链的矿工获得这部分费用。
除了价格以外,还需要指定一个gas limit,就是你为了这段代码最多愿意付多少单位的gas。这就是为了预防代码出现问题,无限循环下去,直到把你的账户里的钱耗尽为止。如上图,gas limit设为1,300,213个,这段代码实际上也只用了1,300,213个单位的gas,还好,正好没有超过限制。否则超过了程序执行会嘎然而止,已经花的gas不退。
智能合约的价值
智能合约第一次认可了代码的自主权。代码可以拥财产,可以和人一样平等的在区块链上交易。一个合约的代码一旦发布,谁都改不了了,连上帝都无能为力。这就是信任的来源。大家可以像坚信自然定律一样坚信这个合约如代码所写的执行。你不需要相信任何人,只需要认真的读智能合约的代码,就可以确定性的知道这个合约将如何执行。
如上从技术层面简单的介绍了一下智能合约的过程。但智能合约和区块链真正的价值不在技术,而是它们对于价值传递以及信任建立的贡献。
我们看到的人类发展总是多条线并进,一条是生产效率,蒸汽机,电力,计算机,互联网,人工智能等都在这条线上;区块链是生产关系的进步这条线上的,这条线上曾经有过货币,现代公司制度,股票,现在有了区块链。
晚一些我再聊一下它对信任的贡献,还有可能对于社会的改变。
后注
① 很多专业人士希望把token翻译成通证,而不是代币。“通证”更加符合单词原意,符合事物本质,也希望避免被当作货币监管。这像极了“网志”和“博客”两个译名之争。结果博客被接受,更加准确,拗口,后来出现的网志不再有人提起(“网志”是否后来出现并不确定——哈希力量注)。这个结果或许可以预测通证这个翻译的结果。
②Transfer函数前面的两句require,第一个是要求你的余额必须大于转账金额,第二个是要求转账金额不要过大以至于大于256位整数能容纳的数字。msg.sender 是内置的,可以获取消息的发送人的地址。
③可以搜索Remix,或MyEtherWallet。Solidity的语法和JavaScript很像,专门用于以太坊上编写智能合约。
④这里解释一下技术细节。建立合约的时候,用户发起一笔发款人为自己,收款人为空地址 0x0 的交易,并把字节码放到交易里面叫做输入(Input)的字段里面。矿工就会生成一个新的合约地址并把代码存在这个地址里。
⑤技术实现,其实是在交易数据的Input字段加上了一个编码后的数字。比如这串数字:a9059cbb00000000000000000000000007fdf7518745170e3d9de26874578b6c0a72b9dc0000000000000000000000000000000000000000000000000000000000000010
颜色是我为了区分加的,前四字节a9059cbb是函数名 ,"transfer(address,uint256)"这个字符串的SHA3-256哈希结果a9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b的前4位,用来指定是哪一个函数,根据函数定义,就知道后32位是第一个参数:地址 ,也就是0x07fdf7518745170e3d9de26874578b6c0a72b9dc。接下来32个字节是
金额 ,相当于十进制16。大家看得出,现在的区块链从抽象水平上基本上还停留在计算机的DOS和汇编语言的时代。
⑥ 1 gwei 就是 1,000,000,000 个wei。这个g就跟内存单位多少GB的G是一个概念,就是10亿的意思。10的18次方个wei就等于一个以太币。所以1 gwei看起来很大,其实也就是10的9次方分之1个以太币而已。一个以太币在我写这篇文章的时候是764美元,你大概有概念了是多少钱了吧。
⑦ 发币时候指定的名称,符号,仅仅就是一个字付串,是可以重复的。你可以发一个币叫USD,RMB,或任何你能想象的名字。Token是以发行这个Token的智能合约的地址唯一指定的,和名字无关。
收录于哈希力量,手机站省略本文固定网址