Hyperledger Fabric 入门笔记(十四)Fabric V2.5 总结补充——交易流程中的消息结构


前言

入门笔记(二)中,介绍了Fabric的交易流程,其中涉及“交易提案”、“提案响应”、“交易信封”等概念,它们到底包含了什么内容?它们之间又有什么关系?深入探索其中的细节将对Fabric的交易流程有一个全新的认知。本节的参考内容如下:
《区块链原理、设计与应用》第一版(电子书)
《区块链原理、设计与应用》第二版
《深度探索区块链:Hyperledger技术与应用》


一、消息结构介绍

Fabric中大量采用了gRPC消息在不同组件之间进行通信交互,在交易流程的第一阶段中,涉及如下三个消息结构:

  • SignedProposal:发送给背书节点的交易提案;
  • ProposalResponse:背书节点返回的提案响应;
  • Envelope:提交给排序者的交易信封。

1.1. 交易提案

消息结构SignedProposal定义在fabric-protos-go项目的peer/proposal.pb.go文件中。它包含两个字段:ProposalBytes和Signature。

ProposalBytes使用的是Proposal结构,包含三个字段:Header、Payload和Extension。Signature则携带了调用者的签名信息。

在这里插入图片描述

  • Header
    Header包含了ChannelHeader(通道头)和SignatureHeader(签名头)。
    • ChannelHeader描述与通道和交易相关的信息,包括:
      • Type:消息结构的类型,根据类型的不同,Proposal结构中的Payload可以解码为不同的结构。对于SignedProposal,Type只能是ENDORSER_TRANSACTION或CONFIG。
      • Version:消息协议的版本,一般为0。
      • Timestamp:消息创建的时间戳。
      • ChannelID:消息所关联的通道ID。
      • TxID:交易的ID,由交易发起者创建。
      • Epoch:所属的世代,指定为所属区块的高度。
      • Extension(可选):扩展域。当Type是ENDORSER_TRANSACTION时,这里的Extension使用的是ChaincodeHeaderExtension结构,包括:
        • PayloadVisibility:ProposalBytes中的Payload在最终交易和账本中的可见程度。
        • ChaincodeID:调用的链码ID,由Path、Name、Version指定。
    • SignatureHeader描述签名者的信息,包括:
      • Nonce:随机数,用于防止重放攻击。
      • Creator:调用者的身份证书,用于验证签名是否有效。
  • Payload
    Payload使用的是ChaincodeProposalPayload结构,包含了TransientMap和Input。
    • TransientMap:用于私有数据的瞬态字段。
    • Input:输入,使用的是ChaincodeInvocationSpec结构,携带了调用的链码ID和输入参数等信息。
  • Extension

背书节点收到交易提案后,会验证调用者的签名信息是否有效。包括以下步骤:

  1. 预验证调用者证书的有效性:从SignatureHeader(签名头)的Creator字段中解码证书,过滤掉证书过期的情况。
  2. 验证证书是否可信(即,证书是否由受信任的CA签名)。
  3. 使用证书中的公钥验证Signature中的用户签名是否有效。
  4. 使用SignatureHeader(签名头)的nonce字段检测重放攻击。

1.2. 提案响应

消息结构ProposalResponse定义在fabric-protos-go项目的peer/proposal.pb.go文件中。它包含五个字段:Version、Timestamp、Payload、Response和Endorsement。

在这里插入图片描述

  • Payload
    Payload使用的ProposalResponsePayload结构,包含了ProposalHash和Extension。
    • ProposalHash:记录背书提案的哈希值,该字段将交易提案和提案响应两者对应起来,实现异步系统的记账功能和安全诉求。
    • Extension:这里的Extension使用的是ChaincodeAction结构,包括:
      • Results:使用的TxRwSet结构,代表调用链码产生的读写集。
      • Events:使用的ChaincodeEvent结构,代表调用链码产生的事件。
      • Response:调用链码的结果,记录了背书操作是否成功。包含Status(比如200代表正常)、Message和Payload。
      • ChaincodeID:调用的链码ID。
  • Response
    调用链码的结果,与Payload中的Response相同。
  • Endorsement
    Endorsement包含了背书节点的证书和签名等信息。

1.3. 交易信封

消息结构Envelope定义在fabric-protos-go项目的common/common.pb.go文件中。它包含两个字段:Payload和Signature。

Payload包含两个字段:Header和Data。Signature同样携带了调用者的签名信息。

在这里插入图片描述

  • Header
    这里的Header与交易提案中的Header一致,包含了ChannelHeader(通道头)和SignatureHeader(签名头)。ChannelHeader描述与通道和交易相关的信息,SignatureHeader描述签名者的信息。

注:交易信封是Fabric中最基本的消息结构,与交易提案和提案响应不同,它的使用范围更多样,因此其Payload中的Header.ChannelHeader.Type的可选项比SignedProposal更多。

  • Data
    同样的,对交易信封而言,其Payload中的Data根据使用情况的不同,有多种不同的结构可选,包括:Transaction、ConfigEnvelope和ConfigUpdateEnvelope。在这里,使用的是Transaction结构,它包含了一个列表TransactionAction:
    • TransactionAction:其中的每一个元素都包含:
      • Header:使用的是SignatureHeader结构,与上面的SignatureHeader一致,描述签名者的信息。
      • Payload:使用的ChaincodeActionPayload结构,记录了交易的核心信息。包括:
        • ChaincodeProposalPayload:与交易提案中的同名结构一致,包含了TransientMap和Input。不同的是,TransientMap强制设置为nil,目的是避免在区块中出现一些敏感信息(即,私有数据)。
        • Action:使用的是ChaincodeEndorsedAction结构,其中又包括:
          • Payload:ProposalResponsePayload结构,与提案响应中的同名结构一致,包含了ProposalHash、TxRwSet等内容。
          • Endorsement:与交易响应中的同名结构一致,包含了背书节点的证书和签名等信息。不同的是,这里是一个列表,代表多个背书节点的背书。

二、对应关系

它们的对应关系如下,相同颜色代表完全相同的内容,除了Envelope中的Endorsement部分变成了数组,代表多个背书节点的背书签名。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


附录:交易流程中的完整消息结构示意

交易提案

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
}

提案响应

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
    }
}

交易信封

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
}

  • 26
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值