流程和数据设计

受众:架构师,应用程序和智能合约开发者,业务专家

本文主要讨论 PaperNet 中商业票据流程的设计方法以及该流程的相关数据结构。我们在分析这篇文章中已经强调过,使用状态和交易对 PaperNet 网络进行建模能够准确呈现商业票据的交易流程。接下来我们将详细讲解两个关联性很高的概念,从而为我们后续设计 PaperNet 智能合约和应用程序提供帮助。

生命周期

正如我们所见,在处理商业票据时有两个重要的概念:状态交易。实际上,所有区块链用例都是如此;一些以状态为模型的概念性价值对象的生命周期转换是通过交易来描述的。要想成功实施商业票据流程,必须先对状态和交易进行有效分析。

我们可以用以下状态转移图来展示商业票据的生命周期:

develop.statetransition 以上是商业票据的状态转移图。商业票据通过发行购买兑换交易在 issued(已发行), trading(交易中)redeemed(已兑换) 状态之间进行转换。

对照上图,观察商业票据的状态变化,看特定交易是如何控制商业票据生命周期转换的。在 Hypledger Fabric 中,智能合约实现了商业票据不同生命周期转换的交易逻辑。实际上商业票据状态被储存在账本世界状态中,接下来我们就深入了解一下这些概念。

账本状态

回想一下商业票据的结构:

develop.paperstructure 我们可以用一组属性来代表商业票据,其中每个属性都对应一个值。通常,这些属性的组合会为每个票据提供一个独一无二的键。

观察上图可知,商业票据的 Paper 属性的值是00001Face value 属性的值是 5M USD。更重要的是 Current state 属性,它体现了商业票据的具体状态(issuedtrading 或者 redeemed)。将以上所有属性结合起来就构成了一个商业票据的状态,而将所有这些商业票据的状态集合起来就构成了账本的世界状态

所有账本世界状态的形式皆是如此:每个状态中包含一系列属性,各属性的值都不一样。账本的这种多属性特征十分有用,我们可以把Fabric的状态看作是一个矢量而不是简单的标量。在此基础上我们可以用独立的状态来代表一个对象的全部事实信息,这些状态后续将会经历由交易逻辑控制的状态转换。Fabric 中的状态是作为键值对来实现的,其中值是以一种捕获了指定对象多个属性的格式来编码对象属性的,通常是 JSON 格式。账本数据库支持根据上述属性进行高级查询操作,这对于复杂的对象索取十分有帮助。

下图将 MagnetoCorp 的商业票据 00001 呈现为一个根据不同交易进行转换的状态矢量:

develop.paperstates 不同交易导致的结果是产生或转换商业票据状态。Hyperledger Fabric 状态拥有多个属性,所以它们是向量而不是标量。

观察上图可发现,各票据的起始状态皆为空,从技术上来说这是票据的 nil 状态,即票据不存在!发行交易生成了票据 00001 ,随后购买兑换交易使得票据状态发生改变。

观察上图可发现,各状态的每个属性都有一个名字和一个值。虽然目前所有商业票据的属性都相同,但这并非表示属性相同是必要条件,比如 Hyperledger Fabric 就支持不同的状态拥有不同的属性。这就使得相同的账本世界状态能够包含同一资产的不同形式以及不同形式的资产。同时这也使得更新状态结构成为可能;试想一下如果出现新规定要求必须有一个额外的数据字段,那么更新状态结构就十分有益。灵活的状态属性可满足数据演化的基本需求。

状态的键

在绝大多数实际应用程序中,每个状态都包含一系列独特属性,这些属性可以在指定情形下描述该状态,我们把这种状态称之为。将 PaperNet 商业票据的 Issuerpaper 属性拼接起来就形成了它的键,也就是说MagnetoCorp 第一个票据的键是 MagnetoCorp00001

通过一个状态的键我们就可以描述一张票据;票据的形成是 发行 交易的结果,后续过程中,购买兑换交易将对票据进行更新。Hyperledger Fabric 要求账本中每个状态都有一个独特的键。

当现有属性无法形成一个独特的键时,系统将指定应用程序生成的独特建来作为更新票据状态的交易的输入。应用程序生成的键通常是UUID形式,虽然可读性不强,但却是一种标准做法。账本中的所有状态都必须拥有一个独特的键,这一点很重要。

注意:不要在键中使用 U+0000 (nil 字节) 。

多种状态

从上文中我们了解到,PaperNet 中的商业票据作为状态向量被存储在账本中。从账本中查询不同的商业票据是合理需求;比如,查询所有由 MagnetoCorp 发行的的票据,或者查询所有由 MagnetoCorp 发行且处在 redeemed 状态的票据。

要想实现不同类型的查询操作,需要将所有相关票据组合起来放在一个逻辑列表中。PaperNet 的设计中就包含了商业票据列表的思想,该列表是一个逻辑容器,每当发行商业票据或更新商业票据的状态时,该逻辑容器就会发生更新。

逻辑描述

设想所有的 PaperNet 商业票据都位于同一个商业票据列表中,这样有助于我们理解:

develop.paperlist MagnetoCorp 新创建的票据 00004 被添加到现有票据的列表中。

通过发行交易将新票据添加到上述列表中,列表中已有的票据会因购买兑换交易而发生状态更新。观察可得,该列表有一个描述性的名称 org.papernet.papers。使用这种DNS 名称有诸多优势,因为准确的命名可以使得区块链设计变得简便易懂,这和智能合约的命名空间是一个道理。

物理描述

设想 PaperNet 中存在一个单独的票据列表org.papernet.papers 是没有问题的,但是最好将该列表作为一组单独的 Fabric 状态来实现,这些状态的复合键将各状态与其列表关联起来。这样一来,每个状态的复合键都是唯一的,并且可以支持高效的列表查询操作。

develop.paperlist 如上图,用一组互不相同的 Hyperledger Fabric 状态来代表一个 PaperNet 商业票据列表

观察上图可知,列表中的每张票据都被用一个向量状态来表示,每个状态都包含一个由 org.papernet.paperIssuerPaper 属性连接而成的复合键。这种结构具有以下两种优势:

  • 支持用户检查账本中的任意状态向量以判定其所在列表,无需查询其他列表。这就好比观察体育比赛的粉丝:通过所穿队服颜色就能知道粉丝支持的是哪支队伍。无需罗列粉丝名单,因为粉丝们自己就表达了各自支持的队伍。
  • Hyperlegder Fabric 内部使用了一个并发控制机制来更新账本,保证各票据处于不同的状态向量中,大大降低了出现相同状态冲突的概率。出现这种碰撞使得交易需要重新提交,应用程序设计变得复杂,系统性能大打折扣。

上述第二点是 Hyperledger Fabric 的关键点;状态向量的物理设计对于优化性能和行为至关重要。所以,一定要保证你的网络中不会出现相同票据状态的情况!

信任关系

本文中我们探讨了网络中不同角色确定交易签署者的相关规则,其中包括发行者、交易者或评级机构,以及各种商业利益等。在 Fabric 中,上述规则包含在背书策略中。这些规则可以在链码层面设置,也可以针对单个状态键来设置。

这意味着在 PaperNet 中,我们可以为整个命名空间设置一个规则,以确定哪些组织可以发行新票据。然后,我们可以针对单个票据来设置和更新这些规则,从而体现购买和兑换交易之间的信任关系。

在下一篇文章中,我们将讲解如何把这些设计概念结合起来实现 PaperNet 商业票据智能合约,然后让应用程序来使用它!