如有翻译不当之处烦请指出,我不确定的地方都给出了原文
超级账本是Linux基金会发起的项目,意在提供一套企业级区块链应用框架,便于大家开发基于区块链技术的应用。
Fabric的基本概念
- 世界状态
世界状态代表了所有账本状态当前的值。这个世界状态非常有用,因为程序通常需要某个账本的当前状态值,并且总是很容易就能获取到。你不需要遍历整个区块链去计算账本当前的状态的值(余额),你可以直接从世界状态获取。
图中有一个账本状态key=CAR1,value=Audi。还有一个账本状态key=CAR2,value={model:BMW, color=red, owner=Jane}。两个账本version都是0。
账本状态用来记录需要通过区块链分享的应用程序信息。图中显示了两辆车的账本状态,CAR1和CAR2。你可以发现状态信息包含一个key和一个value。你的应用程序调用链码,链码通过API访问这些状态。他们通过状态的key来存,取,删除状态。注意状态值什么时候可以简单(如同Audi),什么时候可以复杂(如同BMW)。
物理上,世界状态是一个数据库实现。这样做有很大的好处,因为数据库可以提供丰富的操作,更有效的存储及状态回滚功能。后面我们将会看到Fabric中针对应用程序的需要,配置不同的数据库,不同的状态值类型及存取模式,比如复杂的查询操作所需要的配置。
交易改变着世界状态,正如你所想的,交易有生命周期。他们被应用程序创建,在被提交到区块账本中时结束。整个生命周期的具体描述参见这里。但是Fabric设计的关键点是只有背书组织背书过的交易才能改变世界状态。如果交易被有被足够多的背书节点背书,那么验证将会失败,不会影响世界状态。
你也会注意到世界状态有一个版本号,CAR1状态和CAR2状态都在起始版本号,0。这个版本号在世界状态被修改是会自增。也可以检测版本号与交易创建时的版本号是否相同来判断世界状态是否更新过。这种检测保证了版本号从我们预期的相同的值变成了交易创建时预期相同的值。
最后,账本最初创建时,世界状态为空。因为任何一笔对世界状态有改变的交易都被记录在区块链上,这意味着世界状态可以通过区块链在任意时间重新生成。这是非常便利的,举个栗子,当一个peer启动时,世界状态会自动生成。而且,如果一个peer异常关闭,世界状态可以在peer重新启动后,交易被接收前重新生成。
- 区块链
区块链是一个交易记录的集合,由相连的区块构成,每个区块中包含一些列有序交易,每笔交易都可以当做对世界状态的一次查询或者更新。交易的排序机制在这个网页中有详细的讨论,重点就是区块的顺序,区块中的交易的顺序是在区块被创建之初就定了。
每个区块的区块头中都包含区块中所有交易的一个哈希值,同时也包含前一个区块头的哈希值。这样,账本中的交易都是有序的,加密的链接在一起。哈希和链接使得账本数据很安全。即使一个peer上的账本被篡改了,它也不能说服其他peer它自己拥有正确的账本,因为账本是分布式存储在网络中独立的节点上的。
物理上,区块链通常由文件存储方式来实现的,对于世界状态而言则相反,用的是数据库。这是一个明智设计,因为区块链的数据结构庞大,而且倾向于少量的简单操作。在区块链尾部添加区块是主要的操作,查询是相对较少的操作。
让我们稍稍进一步看看区块的细节
图中的区块链B包含B0~B3四个区块,B0是第一个区块,也就是创世块。
我们可以看到区块B2含有区块数据D2,D2中有T5,T6,T7三笔交易。
最重要的是,B2有区块头H2,H2包含D2中所有交易的哈希值,也包含前一个区块B1的所有交易的哈希值。这样,区块就永久不可分的链接在一起。
最后,你可以看到第一个区块叫创世块。这是账本的起点,它不包含任何用户的交易,取而代之的是包含Channel初始状态的配置的交易。我们会在讨论区块链网络和Channel时详细讨论创始区块。
- 区块
区块由三部分组成
区块头
区块头中有三个部分,区块号,当前区块哈希,上一个区块哈希。区块号最初为0,也就是创世块,有新区块被添加进来后,这个数值增加1。当前区块哈希是当前区块中所有交易生成的哈希。上一个区块哈希就是上一个区块的哈希值。
图中区块B2的区块头H2包含区块号2,当前区块数据D2的哈希值CH2和上一个区块的哈希值PH1
区块数据
这个部分包含排好序的交易,当区块生成时这些交易被打包进区块。这些交易的数据结构字段多,但很简单。
区块元数据
这个部分包含区块的创造时间,证书,公钥和生成区块者的签名。然后,区块提交者也会在区块中每笔交易里添加有效和无效的标签,但这些信息在计算哈希值时被忽略了。区块生成时便也生成了这些元数据。
- 交易
正如我们所了解的,交易记录了对世界状态的改变。现在我们来细致了解下交易的结构。
我们可以看到,区块B1里的数据D1中包含了交易T4,T4包含交易头部H4,交易签名S4,交易提议P4,交易响应R4和背书节点列表E4。
交易头部
图中交易头部H4包含了必不可少的元数据,比如相关链码的名字和版本。
交易签名
图中交易签名S4包含了一个加密的数字签名,由客户端应用程序创建。这个字段用来检测数据是否被篡改,因为生成签名必须要应用程序的私钥。
交易提议
图中的交易提议P4是将应用程序提供的创建交易提议的参数编码后的结果。当链码执行后,提议会提供一系列的输入参数,包含当前世界状态,这决定着新世界状态。
响应
图中的响应R4包含世界状态改变前,后的值,也就是读写集。响应是链码的输出结果,如果交易成功生效,它将会被应用到账本中并改变世界状态。
背书
图中的E4包含达到背书策略规定的足够多的组织背书的签名过的交易响应。你可能会注意到,只有一个交易响应包含在交易中,但它有很多背书节点。这是因为每个背书节点都有效的将交易响应编码了,这意味着没有必要包含不满足背书节点要求的响应,也就是无效响应,不会更新世界状态的响应。
这一节讨论了交易中主要的一些字段,此外还有其它字段,但我们提到的字段是必备的,你需要对账本数据结构有清晰扎实的了解。
- 世界状态数据库选项
为了提供简单有效的存储,可回溯的账本状态,世界状态采用数据库的实现方式。如我们所见到的,世界状态可以很简单,也可以很复杂,为了容纳这些简单或复杂的世界状态,世界状态数据库的实现方式可以有所差异,可以用高效的方式来实现这些数值的存储。当前世界状态数据库有两个选项,LevelDB和CouchDB。
LevelDB是默认选项,当世界状态是key-value键值对的时候,很适合使用LevelDB。LevelDB和网络中的节点结合紧密,它是嵌入到操作系统中的。
CouchDB适合在世界状态值是结构化数据时使用,例如Json数据,因为CouchDB支持丰富的查询操作及商业交易中的多数据更新。CouchDB在另一个操作系统中运行,但保持与网络中节点数量1:1的关系。这些对于链码来说是透明的。了解更多关于CouchDB信息可以点击查看。
我们可以看到,对于LevelDB和CouchDB在Fabric中重要的特点是插件化。世界状态数据库可以是关系型数据库,图表信息存储或者是传统数据库。这提供了Fabric很强的类型灵活性,以有效应对不同类型的问题。
- 账本例子:fabcar
在结束账本的话题之前,我们看一个账本的例子,fabcar。如果你运行过超级账本示例程序,那么它会创建这样一个账本。
fabcar的应用程序创建了10种车,包括不同颜色,不用厂商,不同型号及不同的拥有者。图中表示了前4种车被添加进账本后的情况。
账本L构成了世界状态W和区块链B。W包含了4个状态,它们的key分别是CAR0,CAR1,CAR2,CAR3。B包含两个区块,0和1,区块1包含4笔交易,T1,T2,T3,T4。
我们可以看到世界状态包含CAR0~3对应的状态。CAR0的值指明了这是一辆蓝色Toyota Prius,所有者是Tomoko,我们可以看到其它车辆类似的状态值。并且,我们可以看到所有车辆状态版本号都是0,表明这是他们的起始版本号,从被创建到现在没被改变过。
例子中的区块链包含两个区块,Block0是创始区块,它并没有包含任何与车辆相关的交易。Block1包含了交易T1 ~ T4,对应着CAR0 ~ 3的初始化世界状态。我们可以看到Block1是链接到Block0的。