编者按:你可能想不到,最不被人注意的挖矿环节,却有可能成为区块链技术中最有可能被干扰的一环。近日,James Prestwich在Medium上发表了一篇文章详细介绍了区块链矿工操纵交易的各种可能性。他指出,矿工不是你的朋友。但他们也不是你的敌人。他们不想伤害你,他们只是无法避免有些事情发生而已。
共识层错觉
以太坊是一个运行智能合约的去中心化平台:应用程序完全按照编程运行,不存在停机、审查、欺诈或第三方干扰的可能性。
作为开发人员,我们喜欢相信这样的一个共识层:它能负责处理所有的硬分布式系统问题,并让我们自己编写应用程序。无论矿工们做什么,他们的行为都发生在共识层。开发者们则在应用层使用着智能合约:优雅的程序在以太坊虚拟机(EVM)上永远完美地运行着。我们的去中心化应用程序(DAPPs)与一个永不停止的Ethereal(一个专业的协议分析软件,它可以帮助调试应用层协议)计算机进行交互,并依赖于它的完整性。
我们知道,EVM是由共识驱动的,只要它能够起作用,我们就不需要过多地关注它。我们不担心矿工。毕竟,没有人需要了解半导体是如何工作的,或者是现代CPU的电路是如何设计的。但不幸的是,这种层与层之间不过的分割是一种错觉——共识层错觉让我们忘记了矿工并不是我们的朋友。
在实践中,合约和共识之间的界限比市场营销所显示的更大,更容易折叠,更加模糊。“块”的生产会影响EVM的状态,从而影响到对智能合约的调用。反过来这也会影响到去中心化应用程序的运行以及使用这些程序的用户。如果区块的产生速度很慢,去中心化应用程序的运行速度就会很慢;如果区块的产生速度很快,去中心化应用程序的运行速度就会很块;如果区块空了,中心化应用程序就会被冻结。
共识层一直在无意间干扰着去中心化应用程序。但有时,它的干扰也可能是有意的,毕竟共识层是由矿工控制的。矿工们为赚钱而工作。如果共识层支持应用层能盈利,一切都能正常运行。但是,如果矿工们能够通过干预应用层来赚更多钱,他们最终会这么做。
挖矿的跑步机
矿工不是你的朋友。但他们也不是你的敌人。他们不想伤害你,他们只是无法避免——这是他们的天性,工作量证明需要他们。矿工必须进行激烈的竞争,才能获得非常微薄的利润。他们被困在挖矿的跑步机上,跑得最快的人控制着速度。
每当矿工们弄清楚如何更快或更便宜地解决问题时,困难就会增加。当困难增加时,每一个哈希值就会变得不那么有价值。如果你的哈希率(每秒处理数据的速度)保持不变,你得到的报酬也会越来越少。这迫使着矿工不断地重新投资,来获取收益。矿工只能通过不断的消费、不断的优化和不断的竞争来获利。无法进行竞争的矿工们会从跑步机上摔下来。
如果你的利润率是1%,那么收入下降1%,你的利润就是0了。如果一名矿工的哈希率落后一点,他们就会落在后面。如果不注意的话,他们就会在跑步机加速的时候掉下来。另一方面,收入增长1%将会使利润翻倍。一个效率稍高的矿工将有更多的钱用于再投资更多的硬件。他们将会获得更大的优势,直到其他矿工无法与之竞争。工作量证明迫使矿工们找到这些小的优势,并用它们把其他矿工从跑步机上推下去。简单来说,提高挖矿盈利的能力有两种方法:增加收入,或减少开支。收入来自于区块奖励和交易费用。开支来自于电力、硬件、员工、办公场所等。
目前,矿商们正在通过一些明显、而且易于优化的方面进行竞争,比如寻找更便宜的电力或更好的硬件。不幸的是,在这些方面进行优化的回报正在递减——找到更便宜的电力变得越来越难,GPU的可优化空间也接近了内存带宽的限制,ASIC也接近了晶体管大小的物理限制。目前,这些优化仍然能够带来利益。但在某些时候,这些能够优化的空间将会耗尽,而矿工们将被迫寻找更精细、且不那么明显的优化空间。
的确能有一些非常有效的优化。不幸的是,他们会伤害你。我想集中讨论的是,矿工通过从依赖区块链的人员和系统中获取资金来增加收入和减少开支的方法。当你在阅读这篇文章时,请记住,矿工们并不想拿走你的钱,但他们必须拿走你的钱。工作量证明要求他们竞争。
矿工如何干预
矿工可以通过多种方式干预EVM和运行在其上的应用程序。由于每个矿工都控制着自己“挖”出来的区块,所以他们也能控制那个区块的状态变化。让我们在高层次上找出来一些最简单的方法。对于每一种情况,我们都会试着找出来干扰的策略,以及在这个策略中谁会受到伤害,矿工如何赚钱。
交易重新排序
交易是用区块来处理的。每个区块都有一个规范的顺序,来处理交易的状态变化。一般情况下,矿工按顺序将每笔交易应用到EVM状态。生产区块的矿工控制着区块交易的顺序。从本质上讲,通过控制一个区块的交易顺序,矿商也控制着交易状态变化的顺序。
比如说我想把钱转给朋友。我将用三个功能做一个简单的合约:deposit、unlock和retrieve。调用deposit锁定资金,每当我想给他转账的时候,我unlock 5以太(Ether),然后我的朋友调用向他发送资金的retrieve,来收到这笔钱。如果一个矿工在同一个区块中看到了一个unlock交易和一个retrieve交易。他们可以重新排列它们,以便优先处理retrieve交易,然后再处理unlock交易。但是处理retrieve的时候,unlock还没有被处理,所以当unlock处理完了之后,我的朋友不得不再提交一次retrieve交易,并支付第二笔交易费用。
通过对交易状态的重新排序,矿工们可以影响合约执行的结果。这意味着,在一定程度上,他们可以控制EVM的状态。这对于管理许多用户之间交互的大型公共合约来说尤其糟糕。矿工们可以获得的交易越多,对最终状态的控制就越强。
合约开发商必须对区块中的交易进行任意重新排序的情况有应对方案,否则就有可能让他们的用户面临额外费用或其他意外伤害。
交易插入
当交易在一个区块中被处理时,矿工们将不会受到其他人正在进行的交易的限制,他们也可以进行自己的交易。矿工们掌握着以太。他们可以在一个块链里进行投机,在块链交易中买或卖,就像我们其他人一样。但是,由于矿工决定交易的顺序,有些时候他们会把一些块链的head给切掉。
让我们再设计一个简单的智能合约。这一次,爱丽丝(Alice)想玩一个猜谜游戏。爱丽丝在她的合约里放了5个以太。这些以太币将会奖励给那个最接近她所想到的数字的那个人。爱丽丝调用了commit来把数字哈希,所以她不能改变自己的想法。任何人都可以通过调用guess来提交猜测。2个区块后,爱丽丝将会调用reveal来告诉大家,这个数字是什么。
有了这个简单的猜谜游戏,爱丽丝就无法作弊了,但矿工作弊却很容易,矿工可以一直等着,直到爱丽丝调用reveal告诉大家数字的时候再进行猜测。他会在区块完成之前看到结果。即使大卫(David)也猜到了答案,矿工也能从重现安排大卫交易的顺序,来获得这场猜测的胜利。
当普通用户进行交易时,他们会将其发送给矿工,来将其放入一个区块之中。用户必须承诺在确定交易的结果之前进行交易。另一方面,矿工们可以等到他们建造一个区块之后,再决定是否进行交易。这意味着,矿工除了拥有能够重新安排交易的权力以外,还能获得比普通用户更多的信息。这让矿工在任何块链系统中都具有强大的优势。
任何时候,只要用户和矿工通过智能合约进行交易,矿工就有可能插入或重新排列交易,来使自己受益。通常情况下,这些钱都是用来给普通用户的。
智能合约开发者应该在设计他们的系统时考虑到这种用户不平等。
强制错误
矿商可以利用交易重新排序和插入来干扰智能合约的调用。有时候,他们甚至会让调用完全失败。我们称之为“强制错误”。当矿工将状态修改为不期望而导致调用失败时,就会发生强制错误。他们通过插入影响该状态的交易来实现这一点。
让我们为一个市场建立一个简单的合约。我会调用sell列出一些以固定价格出售的代币。任何人都可以调用buy来购买我的一些代币。
这里的矿工可以检查鲍勃(Bob)对buy的调用,并决定他是否也想买那个代币。如果他想买,他就能买到足够的代币,让鲍勃的交易出错。如果鲍勃去购买2.5 GNT,那矿工就能确保剩下的代币不够了。鲍勃的交易将会出错,而矿工将获取交易费用。鲍勃不情愿地资助了矿工购买GNT的交易,结果却一无所获。
这一攻击对于较老版本的Solidity来说尤其糟糕。较老的assert和throw关键字会给矿工带来所有的附加的“gas”,这将导致非常高的费用,但却没有完成什么工作。较新的require和revert关键字将“gas”用量限制在实际完成的工作中。
强制错误允许矿工们因拒绝工作而获得一定的报酬。当交易出错时,状态就会恢复。如果一名矿工能够稳定地使调用出现错误,他们甚至不需要处理状态变化。对于一个矿工来说,理想的区块是充满了错误交易的区块。全额收取费用,状态却没发生什么变化。
智能合约开发者可以通过检查他们的revert和require的声明来缓解这一问题。如果矿工能够稳定地导致你的合约出错,他们就可以从你的用户那里收取额外的费用。根据经验,如果一个调用依赖于可以被另一个用户更改的状态,那么它就容易受到强制错误的影响。
审查制度
在决定如何对区块内的交易进行排序时,矿工也可以选择忽略交易。他们可能出于政治或经济原因而这么做。用户无法确保矿工将会在一个区块内纳入给定的交易。
假设爱丽丝想把自己变成一个存钱罐。她可能会建立一份简单的合约,让她在1万个区块之后就可以提取资金。爱丽丝是个很不错的人,想确保如果她死了,钱就会转给某人。因此,她让矿工们拿走5万个区块之后的钱。
每一个矿工都有强烈的动机不把爱丽丝的收回交易包括进去。毕竟,如果她从不收回,那么他们就会在未来有机会赚到钱。除非矿工们让她离开,否则她就不能收回。即使没有矿工合谋审查爱丽丝或任何类型的51%的攻击,他们也可能会决定审查这笔交易。
这意味着,任何合约都不能假定用户的交易是及时到达的。你必须考虑到不可预知的矿工审查制度。合约无法判断矿工想要审查交易,因此必须为任意的延迟做好准备。
逐步升级的问题
一个系统中的资金越多,矿工就越有可能陷入困境。随着我们建立更大的交易所、更复杂的赌场,并为块链增添越来越多的价值的时候,矿工们有更大的动机去干预了。
共识并不是我们的去中心化程序下面的一层,这两者是紧密联系在一起的。当我们编写软件时,我们并不关心硅的物理特性——因为硅并没有积极地试图拿走我们的钱。不幸的是,EVM并不是直接在硅上运行,而是通过矿工来运行——如果矿工不能被信任,那么EVM就不能被信任。
Solidity开发人员必须编写一个针对他们的计算机程序。EVM本身就是一个拜占庭式的系统。任何有可能失败的部分都会在最糟糕的时刻这样做。我们对加密货币、挖矿和智能合约的理解还为时过早。矿工们并没有积极寻求以牺牲用户为代价的方式来获取利润。但随着以太坊的成长,我们总有一天会记住这是去中心化应用程序的黄金时代。
矿工不是你的朋友或敌人——他们是我们共识体系中的一股自然力量。未能将其计算在内而进行规划的系统,最终将会输给聪明的矿工。