众所周知,区块链具有不可篡改的特性。每一次智能合约部署都会重新生成一个新的合约地址,就已经是一个全新的合约了。但在实际的软件开发和业务发展,其实我们都是有着「升级」的诉求的。而要实现合约的升级通常需要实现:业务逻辑的修改 和 存储数据的修改。下文就由浅到深的顺序讨论每个升级方案的差异
合约参数写入
最简单的实现「升级」和修改合约的办法其实就是把一些关键的因子变成参数。智能合约虽然部署到链上之后代码就不能修改了,但里面代码如果开放了一些外部调用方法的话,是可以通过这些方法修改一些内部运行用到的数据的。
通过合理的调用接口放开,是可以实现对合约运行过程的干预。比如下面这个例子就开放了 approve 和 decreaseAllowance 的调用
代理合约
如果业务上的诉求不是简单的修改参数就能实现,必须对业务代码进行修改,上面的方案就不适用了。最基础的智能合约架构大概像下面一样:Dapp调用合约的接口
如果在 DApp 和 合约中间加入一个代理合约,由代理合约来调用真正的逻辑合约。当逻辑合约A需要升级时,部署新的逻辑合约B,并把代理合约的调用对象改成逻辑合约B即可
得益于 solidity 的 delegatecall 语法,代理合约调用逻辑合约时,逻辑合约收到的 msg.sender 和 msg.value 还是用户(DApp)
存储和逻辑分离
代理合约实现了智能合约逻辑的可升级,但应用中除了业务逻辑,智能合约里面还有数据。上面的方案还需要完成数据从合约A到合约B的迁移,比较麻烦,这个时候我们可以考虑把合约拆分成逻辑合约和数据合约。数据合约只做数据相关的增删改查,这样一来就可以在合约A升级到合约B之后不需要做数据迁移
总结
以上就是目前智能合约升级的常用思路。当然也不是每一个合约都会用最后一种升级方式,升级越方便,其实对项目本身的公信力是有一定程度的伤害的。区块链能获得大众的信任和认可,很大一部分原因还是它不可篡改的特性。在技术选型和接口设计时除了需要考虑开发的便利也需要考虑是否会影响用户的信任