北大肖臻《区块链技术与应用》学习笔记14
TheDAO
DAO——dencentralized Autonomous Organization
重入攻击的案例:以太坊的分裂
比特币实现了去中心化的货币,以太坊实现了区中心化的合约,产生了一个新概念,let's dencentralized enerything. DAO概念就是在这个背景中产生的。
传统社会当中组织是建立在某种法律文件基础上,区块链上DAO去中心化自制组织就是建立在代码基础上的,组织的规章制度是写在代码里的,通过区块链的共识协议来维护规章制度的正常执行。
The DAO: 2016年的众筹投资的组织
The DAO有点像众筹的投资基金,只不过投资的钱的来源是在区块链上大家众筹的方法得到的,本质是运行在以太坊的智能合约。如果想参与The DAO,可以把以太币发给智能合约,换回The DAO的代币,需要决定投资的项目是大家投票决定的,代币越多投票的权重越大,投资有了收益也是按照智能合约当中规定的分配制度分配利润。
DAC:Dencentralized Autonomous Corporation,和DAO类似,但是DAC是出于盈利目的的,DAO的话可以是出于非盈利目的,比如公益事业。DAC在现实中并不具有公司具有的法人地位。
The DAO设立初期的筹集速度非常快,比传统的众筹网站快很多。但是The DAO只存活了三个月,问题出现在哪里?
比如说你是一个The DAO的投资者,如何取回之前的投资和收益?The DAO基金里采用拆分的方法实现,split the DAO,也是一种建立子基金的方法,叫child DAO。设计理念是这样的,The DAO的投资项目是大家用手里的代币投票决定的,如果有一小部分人的投资理念和大家不一样,这一小部分就可以用拆分的方法从The DAO里面独立出来,成立一个自己的子基金,叫child DAO,拆分的时候他们手中的代币是要被收回去的,然后换成相应数量的以太币,然后用这些以太币成立子基金,就可以投自己想投的项目了。拆分的极端案例就是一个人单个成立一个子基金,也就是child DAO只有他一个人,这也是投资者取回投资和收益的唯一途径,The DAO没有设置withdrew函数,所以只能用拆分的方法取回投资。拆分之前有7天的辩论期,讨论拆分的合理性,可加入性等;拆分之后有28天的锁定期,28天之后以太币才能被取出来。
拆分的理念是没有问题的,问题出现在了split DAO的实现上。

withdraw是先把钱还给调用这个函数的人,然后把The DAO中的总金额减少相应的数量,再把调用的账户清0。应该做的是先把账户清0,然后再转账,黑客就是利用这个漏洞进行了重入攻击,转走了五千万以太币。
之后就开始讨论是否要利用这28天的时间回滚交易,一方认为回滚,另一方认为不用,因为只是以太坊的一个智能合约出现了漏洞,坚持维护不可篡改。Vitalik Buterin团队认为因为该事件影响非常大,The DAO又占据了超过10%的以太币,too big to fail,所以还是决定回滚了交易。
那么如何补救呢?
分叉攻击,在被黑客攻击前的一个区块开始挖,直到长于原来的那条链。但是这样是不可行的,因为原来的那条链上还是有很多其他合法的交易,一旦回滚就导致全部交易都回滚,不仅仅是黑客攻击的交易。

补救原则:回滚必须精确定位,只能是回滚黑客盗取以太币的交易,其他发生的正常交易不能受到影响。
第一步:锁定黑客的账户
第二步:把黑客盗走的以太币撤回去,清退The DAO基金的钱。
以太坊团队发布了一个软件升级,在这个升级的软件里增加了一条规则,凡是跟The DAO这个基金账户相关的,不允许做任何交易。这是一个软分叉,因为是加了一条交易规则,更新的矿工挖出的区块旧矿工是认可的,因为旧矿工不知道这个规则,但是旧矿工挖出的区块新矿工有可能不认可。遗憾的是这个升级的系统有一个bug,是关于和The DAO相关的交易要不要收取汽油费,团队没有设置收取汽油费导致denial of service攻击越来越多,许多矿工便选择回滚到软件升级前的版本,软分叉失败。
硬分叉:通过软件升级把The DAO账户上的所有资金强行转到另外一个新的智能合约上去,新的智能合约只有一个功能就是退钱,把代币退回成以太币。用软件升级的方法强行重新记账,本来转账要有合法的签名,这里就不管这些了,凡是The DAO账户的资金,不管本人同意不同意都要强行转到新的智能合约上去,升级的软件规定了强制执行的具体的日期,挖到第192w块个区块的时候,自动执行不需要合法签名。最后分成了两派,支持硬分叉和不支持硬分叉,投票之后决定成功硬分叉。
ETH and ETC(ehtereum classic)
但是还是有一部分人决定维护”真正的“以太坊,所以导致以太坊现在是新旧链并存。这样就导致分叉初期出现很多重放攻击,因为两条链的代码账本和私钥都是一样的。后来给两条链上加了chain id,从此分成了两条完全独立的区块链。
Question: 不论是硬分叉还是软分叉,为什么不单单冻结黑客账户,要冻结The DAO智能合约的全部账户和交易?
因为The DAO这个智能合约是有bug的,但是这个bug是没有办法修复的,区块链不可篡改,所以必须要让整个合约都作废才可以。
ETH问题总结
- Is smart contract really smart? smart contract is anything but smart.
智能合约就是一段写死的自动执行的合约代码,并不智能,而且写好之后就不能修改。
- Irrevocability is a double edged sword.(不可撤销是一把双刃剑)
一方面不可篡改性增加了合约的公信力,所有人都只能按照合约中的规则来,没有人能够篡改这个规则;
另一方面不可篡改性意味着如果规则有漏洞,想要修补漏洞或者软件升级都是很困难的,硬分叉是非常麻烦的,和传统的中心化系统相比,没有办法及时发布补丁修复,必须征得绝大多数矿工的同意才行。硬分叉的时候又需要说明理由,一旦说明理由又会泄露系统的安全漏洞,有恶意的攻击者会在还没来得及升级前抢先发动攻击。
另外,即使我们已经发现了系统漏洞,已经有人进行恶意攻击了,想要冻结账户终止交易都是很困难的,比如个人的私钥泄露,没有办法进行软分叉,因为没有办法发行一个软件的更新并设置凡是跟这个账户相关的交易都是不合法的,这才能够冻结,但是对于个人账户来说明显是不可能的,只能把账户剩下的钱尽快转到安全的账户。智能合约一旦发布到区块链上,没有办法阻止对它的调用。比如The DAO事件,1/3的钱被黑客盗走了,剩下的2/3的钱也非常危险,没有办法阻止别人调用智能合约,唯一的办法是用黑客的方法把钱转到另一个安全的合约。
- Nothing is irrevocable.(没有什么是不可修改的)
篡改是很难的,但是遇到特殊情况也是可以篡改的。
分叉攻击可以篡改区块链的交易,The DAO攻击之后以太坊团队也是强行修改数据使得交易恢复被攻击之前的账户状态。所以在生活中不可篡改不是绝对的。
- Is solidity the right programming language?(solidity是正确的编程语言吗)
solidity语言设计上有什么问题?为什么会有重入攻击?
solidity的语言特性是反自然的,一般的理解,我给你转账,你是一个被动的接受者,你不可能反过来调用我,但是solidity的语言特性是说我给你转账的操作等于隐性地调用了你的fallback函数,结果你就可以再来调用我。这个和生活常识不同所以安全漏洞容易被忽略。
有人提出应该用函数式的编程语言,函数式语言(例如:ocaml)比较安全不容易出现这种漏洞,而且从长远看要实现的是对智能合约功能的理论上要证明他的正确性。formal verification:理想化能够证明这一段智能合约语言的编写只能实现我们想让他实现的功能,现实中是不存在的。
编写智能合约的语言应该有什么样的表达力?
solidity 语言是图灵完备的,但是会有漏洞,比特币脚本语言比较简单,目前没有发现任何漏洞。能不能找到一个比比特币语言复杂又比solidity简单的语言?不容易出现安全漏洞。
找不到的。未来发展:可以向常用的智能合约提供一些模板,也有可能有专门编写智能合约的机构就像律师事务所一样。
去中心化的系统像如区块链都是开源的,也就是透明的,因为必须要让所有的节点都执行同样的内容才能达成共识。
开源的一个好处就是增加合约的公信力,接受群众的监督。
有些人认为开源的另外一个好处是安全,因为全世界的人都在看着这些代码,但是已经看到智能合约代码出现漏洞,全世界这么多双眼睛看着开源代码,为什么会出现错误呢?这种现象叫做many eyeball fallacy错误认知的意思,相当于misbelief。但实际上是真正有时间看代码的人少之又少,看的人不是很多,也不一定能看得懂。
- what does decentralized mean?(去中心化的含义)
区块链的追随者一般都是去中心化理念的追随者。
以太坊的硬分叉是以太坊的开发团队说了算的吗?
不是,以太坊的团队升级软件之后,也是90%绝大多数的矿工用行动支持了硬分叉,剩下的一小部分虽然没有支持,但是也依然在旧链上继续挖矿,以太坊团队也没有办法强制所有人都升级软件。去中心化并不是不能修改已经制定的规则,而是修改规则要用去中心化的方式进行。硬分叉的成功是因为90%的矿工认为以太坊团队的措施是符合公众利益的。
而分叉正好是去中心化系统的体现,因为只有去中心化系统,用户才可以选择分叉,中心化系统只能选择继续或者放弃。存在分叉的现象恰恰是民主的体现,比如系统私自增多以太币供给量,使得以太币贬值,矿工就可以选择分叉继续维护原来的以太币。
- Decentralized Distributed(分布式系统)
一个去中心化的系统一定是分布式的,如果这个系统只运行在一台计算机上,显然不能叫去中心化;但是分布式系统不一定是去中心化的,即使这个系统运行在成千上万的计算机上,如果计算机都是由同一个组织管辖的,那也不是去中心化,比如谷歌的search engine;在一个分布式的平台上可以运行一个中心化的应用,也可以运行一个去中心化的应用。
比特币和以太坊都是交易驱动的状态机,state machine的特点是让系统中几千台机器重复做同一组操作,付出很大的代价来维护状态的一致性,这个并不是分布式系统常用的工作模式,大多数的分布式是让每台机器做不同的事情,然后再把各台机器的工作结果汇总起来,目的是比单机速度快。状态机的目的是为了比一台计算机的处理速度快,而是为了容错。状态机最早的应用场景:mission critical application.应用程序必须无间断的对外提供服务,哪怕宕机一分钟都会造成很大的损失,所以他才有好几组计算机重复同一组操作,这样即使有一台计算机故障,剩下的计算机也可以对外提供服务。 eg: airtraffic control; stock exchange; space shuttle.这样付出的代价是效率很低,几台机器合在一起比一台机器慢,因为需要同步状态,而且集群里的数目越多速度越慢,所以传统利用状态机的应用,机器的数目都是比较少的,可能就是个位数字。
智能合约是编写控制逻辑的,只有那些互不信任的实体之间建立共识的操作才需要写在智能合约里。大规模存储和计算不适用,又慢又贵,因为要耗汽油费,云服务更好。
美链
很多代币在以太坊做ICO,Initial coin offering. 致使以太币价格大涨。

这些发行的代币没有自己的区块链,而是以智能合约的形式运行在以太坊的EVM平台上,发行代币的智能合约对应的是以太坊状态树中的一个节点,这个节点有他自己的账户余额,就相当于这个智能合约一共有多少个以太币,就是这个发行代币的智能合约他的总资产是多少个以太币,然后在合约里每个账户有多少代币是作为存储树中的变量,存储在智能合约的账户里,代币的发行,转账,销毁都是通过调用智能合约中的函数来实现的,每个代币都可以制定自己的转换规则,比如1个以太币=100个代币,比如外部账户给这个智能合约转一个以太币,智能合约就会给你在合约里的代币账户发送100个代币,每个账户的余额都是维护在发行代币的智能合约的存储树里面。
ERC: Ethereum request for comments.
美链的代币叫BEC,比如我有很多BEC,给十个不同的账户发送代币,调用这个batchTransfer 函数,每个人发送100个代币,那么这个batchTransfer函数先从我的账户上扣掉1000个代币,然后给十个账户分别增加100个代币。
batchTransfer函数的实现

batchTransfer函数有两个参数,第一个参数是数组,接收(代币)者的地址,函数中规定接受者的数目最多是20个,第二个参数value是转账的金额,先算一下总金额amount,recevier的数目和每人接收的代币计算;然后检查一下发起调用的账户msg.sender确实是有这么多代币的。之后把发起账户的代币数目减去amount,下面一个循环是给每一个接收者接收value这么多的代币。
这次的问题出在红框中的乘法如歌value值特别大的时候,乘法有可能溢出,发生溢出之后算出的amount可能是一个很小的值,所以后面从调用者的账户减去的时候是一部分很小的代币,但是底下仍然是按照value给每个receiver增加这么多代币。这样做造成了系统中凭空多发行了很多代币。
攻击细节
一堆数字是函数调用的参数,函数有两个参数,分别对应那串数字的前两行,第一个参数是地址,第一行给出的实际上是第一个参数出现的具体位置,这里是16进制的,40也就是64,也就是说第一个参数出现在第64个字节的位置,每一行是32个字节,所以实际上是从第2号开始出现的。第二行是这个value的值,这是个很大的数,前面是8,后面都是0,第三行是这个数组的具体内容,数组的长度,是2,接下来两行是两个接收的地址。
参数的特征:第二行amount是8,再乘以2,算出来的amount恰好溢出为0,add(value)的时候还是加原来特别大的那一串数目。

红框中是接收地址接收的代币,每个地址都接收到了很大一部分代币,
被攻击之后暂停提币的功能,防止黑客携款逃走。两天之后回滚交易,事件影响没有The DAO影响深远。


反思
在进行数学运算的时候一定要考虑溢出的可能性。solidity有一个safeMath库,里面提供的操作运算都会自动检测有没有出现溢出。
C语言里,两个数相乘会有一定的精度损失,再除以一个数,不一定会得到和另外一个数一模一样的数。但是在solidity里面是不存在的,因为都是整数,256位的整数。

课程总结
- 区块链应用的争议
区块链概念滥用:好像区块链可以解决所有问题,无论是效率问题还是监管问题等等。
例如:保险理赔放在区块链上使得转账速度更快,保险理赔慢并不是支付系统本身的局限性,而是人工核保的时间较长,一旦金额确定,银行转账比加密货币转账要方便快捷的多。而区块链本身并不能解决核保这方面的问题。
还有说区块链可以防伪溯源的,比如说有机蔬菜的生产到销售都是可以放在区块链上的,应用没有问题,主要问题是区块链不能自己输入数据,如果第一次输入的数据就是错误的,区块链技术不可篡改也没有办法检测出哪些数据是不真实的。
信任机制:在互不信任的实体之间建立共识,有些人认为这是一个伪命题,因为互不信任的实体之间是无法交易的,比如说网上购物,不信任对方,给了钱不发货怎么办?货品有质量问题怎么办?
去中心化的不一定就是最好的,很多问题去中心化解决不了,中心化的机构像如信用卡就可以很好解决一些信用卡被盗等问题。中心化和去中心化两者并不是水火不相容的,也可以完美结合起来使得效果更好。
- 区块链的不可篡改性
区块链因为交易一旦打包上链就不能撤回了,转账后悔之后没有办法取消,信用卡可以申诉退钱,但是BTC转账之后都不能撤销了。
这种说法是有问题的,所谓的退款都是发生一个新的交易,退钱。比特币也可以再退款,发生一个新的交易,这个和不可篡改是没有关系的。
还有一些质疑是和法律监管和保护相关的,大部分的支付还是受法律保护的,区块链支付现在是缺乏监管的状态,监管有好有坏,发生了不好的事情监管可以帮你保护自己的利益,但是没有监管只能白白损失。
法律的监管和保护和支付手段是没有关系的。
BTC就不应该和已有的支付手段竞争,它应该发挥自己的特长,用在已有的支付方式解决的不是很好的地方,比如跨境支付。
货币的支付方式可以和信息传播的方式融合在一起。
下一代互联网可能是价值交换网络。支付渠道和信息渠道相互融合,使得价值获得和信息获得一样方便。
Information can flow freely on the internet, but payment can not.
- 支付方式的效率
BTC和以太坊的耗能都是非常大的,好像现有的支付方式好很多。
第一:加密货币本来就不是用来和已有的支付方式竞争;第二:区块链的发展以及共识协议的改进,一些新的加密货币已经在支付效率上已经是大大提高了;第三点:评价支付的效率要放在当时的历史背景之下比较。
- 智能合约
智能合约出现漏洞之后有些人觉得还是自然语言的法律合同更好,老百姓还看得懂。
对于这种观点,首先要意识到程序化是个大趋势,我们有没有ATM机出现了各种故障而不用它?并不会,所以智能合约的故障是无关紧要的,技术的革新会不断完善。
去中心化不是万能的。

浙公网安备 33010602011771号