智能合约的设计模式

概述

由于区块链运行机制的原因,智能合约的运行即使是异常运行都会在所有区块链节点上独立重复运行。因此,无论是在公有链还是联盟链运行智能合约都是非常昂贵(运算资源、存储资源)的操作。

另外,智能合约与传统应用程序有一个不同的地方在于智能合约一经发布于区块链上就无法篡改,即使智能合约中有Bug需要修复或者业务逻辑变更,它也不能直接在原有的合约上直接修改再重新发布。因此在设计之初就需要结合业务场景考虑合理的升级机制。

总而言之,智能合约实现上要达到的目标是

  • 完备的业务功能
  • 精悍的代码逻辑
  • 良好的模块抽象
  • 清晰的合约结构
  • 合理的安全检查
  • 完备的升级方案

智能合约的生命周期主要有设计、开发、部署、运行、升级、销毁。在下文中主要是基于目标在设计阶段、升级阶段的一些梳理总结。

CD模式

从业务视角来看,智能合约只需要做两件事,其一是如何定义数据的结构和读写方式,其二是如何处理数据并对外提供服务接口。

为了更好的做好模块抽象和合约结构分层,将这两件事分开,既是将业务控制逻辑和数据从合约代码层面就做好分离,这样的处理在复杂业务逻辑场景中经过实践是当前被认为最佳的模式。

这个模式简称为CD(Controller-Data)模式。将合约分为两类:控制器合约(Controller Contract)与数据合约(Data Contract)。

CD-model.png
控制器合约

通过访问数据合约获得数据,并对数据做逻辑处理,然后写回数据合约。它专注于对数据的逻辑处理和对外提供服务。

根据处理逻辑的不同,常见的有命名空间控制器合约、代理控制器合约、业务控制器合约、工厂控制器合约等。一般情况下,控制器合约不需要存储任何数据,它完全依赖外部的输入来决定对数据合约的访问。特殊情况下,控制器合约可以存储某个固定的数据合约的地址或者命名空间(通过命名空间在运行时获得合约地址)。

数据合约

专注于数据结构定义与所存储数据的读写裸接口。为了达到数据统一访问管理和数据访问权限控制的目的,最好是将数据读写接口只暴露给对应的控制器合约。禁止其他方式的读写访问。

命名控制器合约

面向链上合约,提供命名空间服务,提供了命名空间到合约地址的映射。使得链上合约可以在运行时根据命名获得实际的合约地址。

例如,A银行控制器合约向命名控制器合约请求(“BankA-Data"),可以获得A银行数据合约地址,使得A银行控制器合约可以在运行时访问A银行数据合约。它与代理控制器合约的主要不同在于服务对象的不同,代理控制器合约面向Dapp,命名控制器合约面向链上合约。另外,命名控制器合约包含有版本控制的设计(下文第3.2节介绍),可以根据需要配合灰度策略的实施。

升级

在CD模式下,在业务逻辑变更需要升级合约的情况下,根据控制器合约与数据合约的升级关系来划分,可以归纳为以下三种情况:

控制器合约升级,数据合约不升级

银行业务控制器合约从V1升级到V2,而其他的合约和接口都是不需要更新的,假设V2版本相对V1版本只是升级withdraw这个接口。

此时,V2版本的银行业务控制器合约需要做的事情是:

  1. 继承V1版本的银行业务控制器合约。
  2. 增加一个指向V1版本的链上合约地址的成员变量。
  3. 增加一个withdraw开关接口,允许外部账户通过普通交易来操作V2版本合约的启停灰度策略。
  4. 重载withdraw接口。升级对应的接口逻辑。并且在业务逻辑真正开始执行之前,自定义实现灰度策略(譬如灰度特定用户,或者一定比例用户或者其他策略)。并且需要注意的是在打开灰度开关的情况下,如果请求没有命中灰度策略,则直接透传参数调用V1版本的合约接口,V2版本的withdraw接口不做任何额外工作。

完成V2版本的合约工作之后,即可发布一个普通交易,交易中的逻辑是,先部署V2版本的银行业务控制器合约,再将其地址更新到代理控制器合约中,使得将“Bank”映射到V2版本的合约地址上。这样控制器合约即升级完成。

如果需要回退版本,只需要发布一个普通交易,将代理控制器合约的“Bank”映射到V1版本的合约地址上即可。

以上是单链场景的升级方法。如果是多链场景,只需根据业务的需要来判断链与链之间的灰度策略,重复单链场景的升级即可。如果是跨链场景,需要根据跨链两端的具体情况来制定升级方法。

控制器合约不升级,数据合约升级

A银行数据合约从V1升级到V2。而其他的合约和接口都是不需要更新,假设V2版本相对V1版本只是增加新的数据字段loan,并假设银行业务控制器合约原本就能支持到V2版本的A银行数据合约

V2版本的A银行数据合约需要做的事情是:

  1. 继承V1版本的银行数据合约。
  2. 增加一个新字段loan。并实现loan相关的数据接口。

需要注意的是,命名控制器合约有如下重要的设计:

  1. 命名控制器合约是通过访问命名数据合约来存储和访问数据的(为了方便描述,图中并没有画出来),因此命令控制器合约是可以参考3.1节的方法来升级的。
  2. 命名数据合约保存了name=>mapping(version=>address)的映射表。
  3. 命名数据合约保存了name=>当前有效的version的映射表。
  4. 命名控制器合约提供了对命名数据合约的name进行遍历的接口。
  5. 命名控制器合约提供了对命名数据合约的映射表的变更接口。

因此,完成V2版本的数据合约之后,即可发布一个普通交易,交易中的逻辑是,先部署V2版本的A银行数据合约,并完成V1版本数据合约到V2版本数据合约的数据迁移(数据迁移方法第4节会描述),接着将V2版本数据合约地址注册到命名控制器合约,并更新BankA-Data所映射的当前有效verison=V2。此时已完成了A银行数据合约的V2版本升级。

有些特殊场景下,需要对所有的历史旧版本数据合约进行升级,这时可以利用命名控制器合约的遍历功能,对所有数据合约进行类似的升级。而对于新加入的C银行,它可以直接使用最新版本V2的数据合约,按照正常流程完成部署与注册,无任何额外操作。

控制器合约升级,数据合约升级

此种情况下,实质是3.1与3.2 两种情况的混搭。

因此根据具体情况,拆解成参考3.1和3.2场景方法来执行即可。

数据迁移

在数据合约升级的场景,某些情况需要处理历史数据在新旧合约之间的迁移。迁移的方法有如下三种,各有特点。

硬编码迁移法

硬编码迁移法指的是,新版本的数据合约中保存一个指向旧版本数据合约的合约地址,新版本数据合约保存的是增量的数据内容。

这样相当于新版本合约保留了一份旧版本数据的指针,当新版本需要使用旧数据的时候,直接调用旧数据合约地址对应数据接口即可。这样,新旧版本数据合约可以并存,即使是在异常情况下,数据被误写到了旧版本合约上,它依然可以被新版本所访问到。

这个方法的优点是:新旧合约可以同时并存,不增加区块链存储压力,简单灵活,较强的升级容错能力。缺点:持续不断的版本升级会导致形成较长的链式逻辑关系,维护成本较高。

硬拷贝迁移法

硬拷贝迁移法指的是,新版本和旧版本之间切断逻辑关系,利用外部迁移工具,将旧版本数据逐步拷贝到链下,再从链下重新存储到新版本合约的过程。

这个方法的优点是:无历史包袱。缺点是:大幅度增加区块链存储压力;数据迁移工具需要适配不同的数据合约,开发成本较高;迁移过程需要停止服务,否则容易出现脏数据;数据量大时,耗时长,操作复杂,容易出错,基本无法实操。

默克尔树迁移法

默克尔数迁移法要点如下:

  1. 利用智能合约语言的面向对象的继承特性,使得新版本合约存储结构完全兼容旧版本合约存储结构。
  2. 利用智能合约在区块链上的storage树原理,使得新版本合约的storeage树直接从旧版本合约上衍生。无需显式的迁移过程。
  3. 利用区块链交易的原子性,使得新版本合约的部署、数据迁移、升级,原子完成。

这个方法拥有前面两个方法的所有优点,且简单高效,安全,实操性强。缺点:需要区块链底层功能特性的支持。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • 智能合约的升级 目前智能合约不支持传统的migration方式,链上的数据与合约的地址紧密地绑定在一起。 这种方式...
    bradyjoestar阅读 1,134评论 0 0
  • 原文:Smart contracts 正如我们在[intro]中看到的那样,以太坊中有两种不同类型的帐户:外部拥有...
    Jisen阅读 4,925评论 1 7
  • 爬山虎是一种常见的植物。 春暖花开之时,嫩芽露出藤蔓,淡绿的小叶子不停地摇曳着。散发出勃勃生机。叶子...
    泽楷0927阅读 309评论 0 0
  • 可能摧毁爱情对于我来说,没有最直接的方式。
    不动情的咳嗽阅读 108评论 0 0