图3-4所示为Hyperledger Fabric 1.0典型的交易流程图。

图3-4 交易流程总图

从上一节的网络节点架构中,我们已经了解到基于Hyperledger Fabric 1.0的区块链应用中涉及几个节点角色:应用程序、背书节点、排序服务节点和主节点。在图3-4中,假定各节点已经提前颁发好证书,且已正常启动,并加入 已经创建好的通道。后面的步骤介绍在已经实例化了的链码通道上从发起一个调用交易到最终记账的全过程。

3.3.1 创建交易提案并发送给背书节点

使用应用程序构造交易提案,SignedProposal的结构如下所示:加 入 会 员 微 信 dedao555


SignedProposal: {
   ProposalBytes(Proposal): {
       Header: {
           ChannelHeader: {
               Type: "HeaderType_ENDORSER_TRANSACTION",
               TxId: TxId,
               Timestamp: Timestamp,
               ChannelId: ChannelId,
               Extension(ChaincodeHeaderExtension): {
                   PayloadVisibility: PayloadVisibility,
                   ChaincodeId: {
                       Path: Path,
                       Name: Name,
                       Version: Version
                   }
               },
               Epoch: Epoch
           },
           SignatureHeader: {
               Creator: Creator,
               Nonce: Nonce
           }
       },
       Payload: {
           ChaincodeProposalPayload: {
               Input(ChaincodeInvocationSpec): {
                   ChaincodeSpec: {
                       Type: Type,
                       ChaincodeId: {
                           Name: Name
                       },
                       Input(ChaincodeInput): {
                           Args: []
                       }
                   }
               },
               TransientMap: TransientMap
           }
       }
   },
   Signature: Signature
}


我们来看看上面的结构,SignedProposal是封装了Proposal的结构,添加了调用者的签名信息。背书节点会根据签名信息验证其是否是一个有效的消息。Proposal由两个部分组成:消息头和消息结构。消息结构详细的解释参考后面的章节。这里简单讲一下消息头。

消息头(Header)也包含两项内容。

1)通道头(ChannelHeader):通道头包含了与通道和链码调用相关的信息,比如在哪个通道上调用哪个版本的链码。TxId是应用程序本地生成的交易号,跟调用者的身份证书相关,可以避免交易号的冲突,背书节点和记账节点都会校验是否存在重复交易。

2)签名头(SignatureHeader):签名头包含了调用者的身份证书和一个随机数,用于消息的有效性校验。

应用程序构造好交易提案请求后,选择背书节点执行并进行背书签名。背书节点是链码背书策略里指定的节点。有一些背 书节点是离线的,其他的背书节点可以拒绝对交易进行背书,也可以不背书。应用程序可以尝试使用其他可用的背书节点来满足策略。应用程序以何种顺序给背书节 点发送背书请求是没有关系的,正常情况下背书节点执行后的结果是一致的,只有背书节点对结果的签名不一样。

3.3.2 背书节点模拟交易并生成背书签名

背书节点在收到交易提案后会进行一些验证,包括:

·交易提案的格式是否正确;

·交易是否提交过(重复攻击保护);

·交易签名有效(通过MSP);

·交易提案的提交者在当前通道上是否已授权有写权限。

验证通过后,背书节点会根据当前账本数据模拟执行链码中的业务逻辑并生成读写集(RwSet),其中包含响应值、读写集等。在模拟执行时账本数据不会更新。而后背书节点对这些读写集进行签名成为提案响应(Proposal Response),然后返回给应用程序。ProposalResponse的结构如下:


ProposalResponse: {
   Version: Version,
   Timestamp: Timestamp,
   Response: {
       Status: Status,
       Message: Message,
       Payload: Payload
   },
   Payload(ProposalResponsePayload): {
       ProposalHash: ProposalHash,
       Extension(ChaincodeAction): {
           Results(TxRwSet): {
               NsRwSets(NsRwSet): [
                   NameSpace: NameSpace,
                   KvRwSet: {
                       Reads(KVRead): [
                           Key: Key,
                           Version: {
                               BlockNum: BlockNum,
                               TxNum: TxNum
                           }
                       ],
                       RangeQueriesInfo(RangeQueryInfo): [
                           StartKey: StartKey,
                           EndKey: EndKey,
                           ItrExhausted: ItrExhausted,
                           ReadsInfo: ReadsInfo
                       ],
                       Writes(KVWrite): [
                           Key: Key,
                           IsDelete: IsDelete,
                           Value: Value
                       ]
                   }
               ]
           },
           Events(ChaincodeEvent): {
               ChaincodeId: ChaincodeId,
               TxId: TxId,
               EventName: EventName,
               Payload: Payload
           }
           Response: {
               Status: Status,
               Message: Message,
               Payload: Payload
           },
           ChaincodeId: ChaincodeId
       }
   },
   Endorsement: {
       Endorser: Endorser,
       Signature: Signature
   }
}


返回的ProposalResponse中包含了读写集、背书节点签名以及通道名称等信息,更多字段的详细解释参考3.4节。

背书节点接收消息后执行的详细过程请参考第9章的相关内容。

3.3.3 收集交易的背书

应用程序收到ProposalResponse后会对背书节点签名进行验证,所有节点接收到任何消息后都是需要先 验证消息合法性的。如果链码只进行账本查询,应用程序会检查查询响应,但不会将交易提交给排序服务节点。如果链码对账本进行Invoke操作,则须提交交 易给排序服务进行账本更新,应用程序会在提交交易前判断背书策略是否满足。如果应用程序没有收集到足够的背书就提交交易了,记账节点在提交验证阶段会发现 交易不能满足背书策略,标记为无效交易。

如何选择背书节点呢?目前fabric-sdk-go默认的实现是把配置文件选项 channels.mychannel.peers(其中的mychannel需要替换成实际的通道名称)里的节点全部添加为背书节点,需要等待所有背书 节点的背书签名。应用程序等待每个背书节点执行的超时时间是通过配置文件选项client.peer.timeout.connection设置的,配置 文件的示例给出的是3秒,根据实际情况调整,如果没有设置就是5秒的默认值。

3.3.4 构造交易请求并发送给排序服务节点

应用程序接收到所有的背书节点签名后,根据背书签名调用SDK生成交易,广播给排序服务节点。生成交易的过程比较简单,确认所有的背书节点的执行结果完全一致,再将交易提案、提案响应和背书签名打包生成交易。交易的结构如下:


Envelope: {
   Payload: {
       Header: {
           ChannelHeader: {
               Type: "HeaderType_ENDORSER_TRANSACTION",
               TxId: TxId,
               Timestamp: Timestamp,
               ChannelId: ChannelId,
               Extension(ChaincodeHeaderExtension): {
                   PayloadVisibility: PayloadVisibility,
                   ChaincodeId: {
                       Path: Path,
                       Name: Name,
                       Version: Version
                   }
               },
               Epoch: Epoch
           },
           SignatureHeader: {
               Creator: Creator,
               Nonce: Nonce
           }
       },
       Data(Transaction): {
           TransactionAction: [
               Header(SignatureHeader): {
                   Creator: Creator,
                   Nonce: Nonce
               },
               Payload(ChaincodeActionPayload): {
                   ChaincodeProposalPayload: {
                       Input(ChaincodeInvocationSpec): {
                           ChaincodeSpec: {
                               Type: Type,
                               ChaincodeId: {
                                   Name: Name
                               },
                               Input(ChaincodeInput): {
                                   Args: []
                               }
                           }
                       },
                       TransientMap: nil
                   },
                   Action(ChaincodeEndorsedAction): {
                       Payload(ProposalResponsePayload): {
                           ProposalHash: ProposalHash,
                           Extension(ChaincodeAction): {
                               Results(TxRwSet): {
                                   NsRwSets(NsRwSet): [
                                       NameSpace: NameSpace,
                                       KvRwSet: {
                                           Reads(KVRead): [
                                               Key: Key,
                                               Version: {
                                                   BlockNum: BlockNum,
                                                   TxNum: TxNum
                                               }
                                           ],
                                           RangeQueriesInfo(RangeQueryInfo): [
                                               StartKey: StartKey,
                                               EndKey: EndKey,
                                               ItrExhausted: ItrExhausted,
                                               ReadsInfo: ReadsInfo
                                           ],
                                           Writes(KVWrite): [
                                               Key: Key,
                                               IsDelete: IsDelete,
                                               Value: Value
                                           ]
                                       }
                                   ]
                               },
                               Events(ChaincodeEvent): {
                                   ChaincodeId: ChaincodeId,
                                   TxId: TxId,
                                   EventName: EventName,
                                   Payload: Payload
                               }
                               Response: {
                                   Status: Status,
                                   Message: Message,
                                   Payload: Payload
                               },
                               ChaincodeId: ChaincodeId
                           }
                       },
                       Endorsement: [
                           Endorser: Endorser,
                           Signature: Signature
                       ]
                   }
               }
           ]
       }
   },
   Signature: Signature
}


我们来看交易信封的几个对应关系:

·Envelope.Payload.Header同交易提案SignedProposal.Proposal.Header;

·Envelope.Payload.Data.TransactionAction.Header是交易提案的 提交者的身份信息,同SignedProposal.Proposal.Header.SignatureHeader和 Envelope.Payload.Header.SignatureHeader是冗余的;

·Envelope.Payload.Data.TransactionAction.Payload.ChaincodeProposalPayload 同交易提案的SignedProposal.Proposal.Payload.ChaincodeProposalPayload,唯一不同的 是,TransientMap强制设置为nil,目的是避免在区块中出现一些敏感信息;

·Envelope.Payload.Data.TransactionAction.Payload.Action.Payload结构,其实和Proposal Response.Payload结构完全一样;

·Envelope.Payload.Data.TransactionAction.Payload.Action.Endorsement变成了数组,代表多个背书节点的背书签名。

整个信封Envelope的Signature是交易提交者对整个Envelope.Payload的签名。应用程序可以把生成的交易信封内容发送给任意选择的几个排序服务节点。

3.3.5 排序服务节点以对交易进行排序并生成区块

排序服务不读取交易的内容,如果在生成交易信封内容的时候伪造了交易模拟执行的结果,排序服务节点也不会发现,但 会在最终的交易验证阶段校验出来并标记为无效交易。排序服务要做得很简单,先是接收网络中所有通道发出的交易信息,读取交易信封的 Envelope.Payload.Header.ChannelHeader.ChannelId以获取通道名称,按各个通道上交易的接收时间顺序对交 易信息进行排序,生成区块,详细的流程请参考第6章。

3.3.6 排序服务节点以广播给组织的主节点

排序服务节点生成区块以后会广播给通道上不同组织的主节点,详细的流程请参考第4章。

3.3.7 记账节点验证区块内容并写入区块

背书节点是动态角色,只要参与交易的背书就是背书节点,哪些交易选择哪些节点作为背书节点是由应用程序选择的,这 需要满足背书策略才能生效。所有的背书节点都属于记账节点。所有的Peer节点都是记账节点,记录的是节点已加入通道的账本数据。记账节点接收到的是排序 服务节点生成的区块,验证区块交易的有效性,提交到本地账本后再产生一个生成区块的事件,监听区块事件的应用程序可以进行后续的处理。如果接收到的区块是 配置区块,则会更新缓存的配置信息。记账节点的处理流程如图3-5所示。

图3-5 记账节点的流程图

1.交易数据的验证

区块数据的验证是以交易验证为单位的,每次对区块进行验证时都会生成一个交易号的位图 TxValidationFlags,它记录每个交易号的交易验证状态,只有状态为TxValidationCode_VALID才是有效的。位图也会写 入到区块的元数据BlockMetadataIndex_TRANSACTIONS_FILTER中。交易验证的时候会检查以下内容:

·是否为合法的交易:交易格式是否正确,是否有合法的签名,交易内容是否被篡改;

·记账节点是否加入了这个通道。

基本的验证通过以后会提交给VSCC进行背书策略的验证。

2.记账节点与VSCC

链码的交易是隔离的,每个交易的模拟执行结果读写集TxRwSet都包含了交易所属的链码。为了避免错误地更新链码交易数据,在交易提交给系统链码VSCC验证交易内容之前,还会对链码进行校验。下面这些交易都是非法的:

·链码的名称或者版本为空;

·交易消息头里的链码名称 Envelope.Payload.Header.ChannelHeader.Extension.ChaincodeId.Name和交易数据里的链 码名称 Envelope.Payload.Data.TransactionAction.Payload.ChaincodeProposalPayload.Input.ChaincodeSpec.ChaincodeId.Name 不一致;

·链码更新当前链码数据时,生成读写集的链码版本不是LSCC记录的最新版本;

·应用程序链码更新了LSCC(生命周期管理系统链码)的数据;

·应用程序链码更新了不可被外部调用的系统链码的数据;

·应用程序链码更新了不可被其他链码调用的系统链码的数据;

·调用了不可被外部调用的系统链码。

更多系统链码的介绍,请参考9.3节。

3.基于状态数据的验证和MVCC检查

交易通过VSCC检查以后,就进入记账流程。kvledger还会对读写集TxRwSet进行MVCC(Multi-Version Concurrency Control)检查。

kvledger实现的是基于键值对(key-value)的状态数据模型。对状态数据的键有3种操作:

·读状态数据;

·写状态数据;

·删除状态数据。

对状态数据的读操作有两种形式:

·基于单一键的读取;

·基于键范围的读取。

MVCC检查只对读数据进行校验,基本逻辑是对模拟执行时状态数据的版本和提交交易时状态数据的版本进行比较。如 果数据版本发生变化或者某个键的范围数据发生变化,就说明这段时间之内有别的交易改变了状态数据,当前交易基于原有状态的处理就是有问题的。由于交易提交 是并行的,所以在交易未打包生成区块之前,并不能确定最终的执行顺序。如果交易执行的顺序存在依赖,在MVCC检查的时候就会出现依赖的状态发生了变化, 实际上是数据出现了冲突。图3-6所示为基于状态的数据验证的流程图。

写集合本身包含了写和删除的数据,有一个状态位标识是否删除数据。为了提升效率,状态数据库的提交是批处理的,整 个区块交易的状态数据同时提交,这也保证了整个区块的状态数据要么都提交成功,要么都提交失败。这时只会出现记录的账本数据和状态数据库不一致,不会出现 区块的状态数据不一致的情况。当账本数据和状态数据库不一致时,可以通过状态数据库的检查点来标记。

图3-6 基于状态的数据验证的流程图

4.无效交易的处理

伪造的交易会导致无效交易,正常的交易也可能出现无效交易。MVCC检查的是背书节点在模拟执行的时候,环境是否 和记账节点提交交易时的环境一致,这里的环境是指状态数据库里数据的三元组(key、value、version)是否完全一致。如果正常提交的交易在这 个过程中涉及的数据发生了变化,那么也会出现检查失败从而导致无效交易。在这种情况下,需要在上层的应用程序有一些补偿措施,比如调整交易打包的配置,重 新提交失败的交易等。

在目前版本的实现中,无效交易也会保留在区块中,可以通过区块记录的元数据确定哪些是无效交易。无效交易的读写集不会提交到状态数据库中,不会导致状态数据库发生变化,只是会占用区块的大小,占用记账节点的硬盘空间。后续的版本会实现账本的精简,过滤掉无效交易。

3.3.8 在组织内部同步最新的区块

主节点在组织内部同步区块的过程详见第4章的相关内容。

来源:我是码农,转载请保留出处和链接!

本文链接:http://www.54manong.com/?id=1084

'); (window.slotbydup = window.slotbydup || []).push({ id: "u3646208", container: s }); })(); '); (window.slotbydup = window.slotbydup || []).push({ id: "u3646147", container: s }); })();

3.3 典型交易流程相关推荐

  1. 深度探索Hyperledger技术与应用之超级账本的典型交易流程

    上一篇分享了超级账本的系统逻辑架构和网络节点架构,本篇主要分享超级账本的典型交易流程. 1 典型交易流程 下图所示为Hyperledger Fabric 1.0典型的交易流程图. 从上一节的网络节点架 ...

  2. DiscuzNT 商品交易插件设计之[线下交易流程]

    在上一篇文章中,大略说明了一个商品的添加编辑和删除操作.本文会继承其支付流程来展示如何购 买商品以及系统设计. 首先打开一个有效的商品,在商品显示页面中单击"立刻购买"按钮,如下: ...

  3. 【以太坊】javascript控制台完整交易流程

    一.前言 在前面几章,我们简单的在本地搭建了以太坊的测试网络.需要的小伙伴们可以看一下之前的那篇:搭建测试网络之ubuntu系统安装geth客户端以及同步区块数据,现在的问题是搭建完之后,该如何进行操 ...

  4. 架构设计 | 基于电商交易流程,图解TCC事务分段提交

    本文源码:GitHub·点这里 || GitEE·点这里 一.场景案例简介 1.场景描述 分布式事务在业务系统中是十分常见的,最经典的场景就是电商架构中的交易业务,如图: 客户端通过请求订单服务,执行 ...

  5. 区块链架构与交易流程(fabric1.0)

    区块链架构与交易流程 区块链系统架构 节点 网络拓扑 交易流程 1. 提交交易提案 2. 模拟执行提案并签名 3. 返回模拟执行结果 4. 提交交易 5. 交易排序并结块 6. 广播区块 7. 保存区 ...

  6. hyperledger fabric交易流程

    首先,先简单看看上面这个交易流程图吧,下面就这个图详细的说明一下整个fabric整个交易流程: 1.区块链客户端把交易请求发给之前约定好的所有背书节点(endorsing peer).这里说明一下en ...

  7. Fabric 节点类型&交易流程

    0x00 节点类型 在Fabric中,尽管所有对等节点都是相同的,但它们可以根据网络的配置方式承担多个角色:(①②是主要的节点类型) 1.提交节点: 通道中的每个对等节点都是一个提交节点.它们接收生成 ...

  8. 区块链Fabric 技术架构和交易流程

    Fabric 架构 总体架构核心部分由成员管理(Membership services).共识服务(Consensus services)和智能合约(Chain-code Services)三部分, ...

  9. 联盟链--3Fabric 1.0交易流程

    Fabric 1.0交易流程 fabric中的所有交易都是通过chaincode执行 1.应用程序客户端通过SDK调用证书服务(CA)服务,进行注册和登记,并获取身份证书. 2.应用程序客户端通过SD ...

最新文章

  1. 吴恩达神经网络和深度学习——第四周笔记
  2. 09-dispatch_source
  3. 算法导论Java实现-构建MaxHeap
  4. Task03:青少年软件编程(Scratch)等级考试模拟卷(一级)
  5. 口袋无人机DOBBY:我的“人脸识别”已上线
  6. [Java开发之路]Java字符串
  7. 优化安卓应用内存的神奇方法以及背后的原理,一般人我不告诉他
  8. 线程方法destroy()和stop(Throwable)在JDK 11中删除
  9. RUNOOB python练习题29
  10. leetcode面试题 16.19. 水域大小(深度优先搜索)
  11. setsockopt设置socket状态
  12. 阿坝县人民医院管理系统软件硬件配置参数
  13. RecycleView获取所有的ViewHolder
  14. Binder机制原理
  15. 2021年电工(初级)考试及电工(初级)考试题
  16. 华为智慧园区解决方案 -重新定位园区
  17. 工具说明书 - FTDI芯片的USB转UART串口线
  18. 地对地导弹地对地导弹地对地导弹
  19. word的链接到前一节消失
  20. React-Redux 学习,转载

热门文章

  1. Java 数字金额,字符串格式化
  2. 第2章第27节:英文排版技巧:大间距与大行距的应用 [PowerPoint精美幻灯片实战教程]
  3. 概率图模型(6)马尔科夫随机场
  4. 人际关系——做事要周全
  5. CSDN知名安卓博主
  6. 微信小程序用什么编写
  7. UVC(USB Video Class)协议讲解
  8. 多线程、并发/并行、自定义线程类、线程安全、守护线程、定时器、线程状态、线程池
  9. [TJOI2013]松鼠聚会【切比雪夫距离转换曼哈顿距离】
  10. 带问题重读ijkPlayer