今天早上,Cosmos发布v0.34.6补丁,紧急修复了可能导致严重后果的漏洞。现在来分析一下问题所在和可能导致的后果。
导致漏洞的原因
和其他DPOS共识的链一样,Cosmos中参与共识出块的节点有限,只有股权排名前100的验证人节点才是有效验证人。持币用户可以将atom(CosmosHub主网代币)委托给验证人节点,称作委托人。验证人或委托人都可以将委托的币取回,不过这需要一个21天的周期,也就是说我的抵押股权变为可流通代币需要经过一定的锁定期。DPOS区块链通常都会这样设计,这是为了维系网络的稳定性,避免抵押代币在外部市场价格剧烈波动时,网络的总抵押量也随之短期内大幅波动,毕竟DPOS区块链的价值是需要用作共识依据的抵押代币来背书的。但由于Cosmos的三处看似合理的设计,组合在一块却产生了严重的漏洞。
1. 不一致的解绑锁定期
Cosmos中,一个验证人如果因为掉线,双签或者取回过多的自抵押代币(数量低于设定的min_self_bond),便会从活跃的Bonded状态,经过一段时间的UnBonding状态,最后变为UnBonded状态。非Bonded状态的验证人,无论抵押池还有多少token,都不再参与共识。当委托人从一个验证人解绑委托的token时,会进行判断:
- 如果验证人此时是Bonded状态,解绑需要经历21天的时间。
- 如果验证人处于UnBonding状态,委托人从该验证人解绑定需要的锁定期等于该验证人的锁定期(小于或等于21天)。
- 如果验证人处于UnBonded状态,则不需要锁定期,委托人抵押的股权可立即变回代币。
这样设计的本意的是,当验证人节点因作恶或意外被Jail(关小黑屋)后,委托人可以尽快取回抵押的股权,避免造成损失。
2. 立即生效的转委托
委托人在将代币抵押给一个验证人后,如果想要抵押给另一个验证人,可使用转委托功能,不必先从源验证人上解绑,然后再委托给目标验证人。这样的设定是为了方便委托人可随时在不同验证人之间做选择,如发现某个验证人佣金更低,或是当前验证人频繁掉线,可以尽快转移股权,避免损失。
3. 转委托不限制目标验证人状态
转委托操作不限制目标验证人节点的状态,也就是说,你不光可以转委托给一个Bonded状态的验证人,也能转委托给UnBonding和UnBonded状态的委托人。这样的设计是让验证人节点在出现异常时,还能接受到委托人的抵押。
如何利用漏洞
一个将股权委托给Bonded状态的委托人,可以找到Cosmos网络中的状态为UnBonded的验证人(这样的节点并不少),将股权转委托给它,然后再解绑,即可立即完成解绑。操作很简单,只用多耗费一点手续费便能让21天的锁定期形同虚设。
漏洞造成的影响
利用该漏洞本身不会造成资金的数量,但该漏洞的存在会让网络变得不稳定,更容易被攻击,最极端的情况的是共识失败,不再出块。Cosmos使用的BFT共识算法,最多能容忍三分之一的股权作恶。Cosmos期望atom总量的67%长期处于抵押状态,假设现在atom总量是1000,全网抵押的atom一共是670,作恶节点只拥有67,只占到10%,是不可能导致共识失败的。然后,作恶节点在交易所引起剧烈的价格波动,因为该漏洞的存在,委托人可以立刻解绑atom,转移至交易所交易。只要全网抵押的atom降到201以下,作恶节点的67个便超过了三分之一,最坏的可能便是宕机,由于Tendermint的最终一致性设计,只要作恶节点不上线,网络将不再出块,且目前没有很好的修复方法。先不论攻击者会不会有这样的企图(攻击成本和攻击收益),没有解绑锁定期,外部市场的价格波动必然会引起短期网络的稳定性,所以任何情况下都要确保解绑锁定期的有效。
漏洞修复
漏洞修复很简单,解绑时不再判断验证人节点的状态,无论怎样都要经过21天的解绑锁定期。
Cosmos热升级过程
Comos在漏洞造成严重影响前立即发布了修复后新版本,迅速联系各个验证人更新,上午大多数节点已经切换至新版本,出块也正常。由于Tendemrint的最终一致性,Cosmos Hub的新老版本在不兼容(某一个块高度后,新老版本的状态机数据不同)的情况下,部分验证人节点已经切换至新版本,部分仍使用老版本。如果热升级没有沟通好,在出现导致状态不一致的交易后,如果抵押股权中的三分之二的验证人已经升级到新版本,则共识以新版本的块为准,运行老版本的节点则会因为共识不一致停止出块。但如果三分之二的验证人仍使用老版本,共识以老版本为准,反而是新版本的节点停止共识。还有种情况则是两边都未达到三分之二,则都停止共识。这样热升级时,必须要协调大多数节点到位。
Polkadot因为有runtime机制的存在,将更新的代码写入区块,节点同步后实时更新运行逻辑,这样优雅的热更新机制,避免了共识失败的情况,节约了升级过程中协调验证人节点产生的成本。