根据TxID获取上链信息

前段时间应甲方爸爸的要求,需要在现有的业务系统中新增一个根据TxID来查询上链信息的接口。搜了一圈发现相关的信息很少,最后只能祭出终极大招:Read Source Code

本文主要记录我实现这一功能的过程。

1、获取交易信息

首先要做的就是拿到交易信息,我这里是通过fabric-sdk-go提供的接口ledger.Client.QueryTransaction(transactionID fab.TransactionID, options ...RequestOption) (*pb.ProcessedTransaction, error)来获取交易信息;交易信息就包含在ProcessedTransaction结构中。

1.1、ProcessedTransaction

ProcessedTransaction定义如下:

type ProcessedTransaction struct {
// 封装了所有的交易信息
TransactionEnvelope *common.Envelope `protobuf:"bytes,1,opt,name=transactionEnvelope,proto3" json:"transactionEnvelope,omitempty"`
// 标识交易是否通过验证
ValidationCode int32 `protobuf:"varint,2,opt,name=validationCode,proto3" json:"validationCode,omitempty"`
}

2、解析TransactionEnvelope

交易信息全都封装在common.Envelope结构中:

// Envelope wraps a Payload with a signature so that the message may be authenticated
type Envelope struct {
// 编码后的交易信息,是common.Payload编码后的
Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
// 交易发起人的签名
Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
}

2.1、common.Payload

common.Payload定义如下:

// Payload is the message contents (and header to allow for signing)
type Payload struct {
// Header is included to provide identity and prevent replay
Header *Header `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
// 编码后的peer.Transaction,该结构保存交易信息
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
}

2.2、peer.Transaction

peer.Transaction结构中包含了该交易的所有活动:

type Transaction struct {
// The payload is an array of TransactionAction. An array is necessary to
// accommodate multiple actions per transaction
Actions []*TransactionAction `protobuf:"bytes,1,rep,name=actions,proto3" json:"actions,omitempty"`
}

这个结构就是整个接口的核心,说白了就是要解析TransactionAction结构。

3、解析peer.TransactionAction

peer.TransactionAction定义如下:

type TransactionAction struct {
// The header of the proposal action, which is the proposal header
Header []byte `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
// bytes格式的ChaincodeActionPayload
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
}

其中Payload中包含着我们想要的信息。

3.1、peer.ChaincodeActionPayload

peer.ChaincodeActionPayload定义如下:

type ChaincodeActionPayload struct {
ChaincodeProposalPayload []byte `protobuf:"bytes,1,opt,name=chaincode_proposal_payload,json=chaincodeProposalPayload,proto3" json:"chaincode_proposal_payload,omitempty"`
// 在账本中执行的操作
Action *ChaincodeEndorsedAction `protobuf:"bytes,2,opt,name=action,proto3" json:"action,omitempty"`
}

其中的我们要找的信息就在这个Action里。

3.2、peer.ChaincodeEndorsedAction

peer.ChaincodeEndorsedAction定义如下:

type ChaincodeEndorsedAction struct {
// This is the bytes of the ProposalResponsePayload message signed by the
// endorsers. Recall that for the CHAINCODE type, the
// ProposalResponsePayload's extenstion field carries a ChaincodeAction
ProposalResponsePayload []byte `protobuf:"bytes,1,opt,name=proposal_response_payload,json=proposalResponsePayload,proto3" json:"proposal_response_payload,omitempty"`
Endorsements []*Endorsement `protobuf:"bytes,2,rep,name=endorsements,proto3" json:"endorsements,omitempty"`
}

ProposalResponsePayload字段解出peer.ProposalResponsePayload结构:

type ProposalResponsePayload struct {
ProposalHash []byte `protobuf:"bytes,1,opt,name=proposal_hash,json=proposalHash,proto3" json:"proposal_hash,omitempty"`
// 对chaincode来说, Extension保存ChaincodeAction信息
Extension []byte `protobuf:"bytes,2,opt,name=extension,proto3" json:"extension,omitempty"`
}

接下来就是解Extension

3.3、peer.ChaincodeAction

peer.ChaincodeAction定义如下:

type ChaincodeAction struct {
// chaincode执行影响到的读写集
Results []byte `protobuf:"bytes,1,opt,name=results,proto3" json:"results,omitempty"`
// This field contains the events generated by the chaincode executing this
// invocation.
Events []byte `protobuf:"bytes,2,opt,name=events,proto3" json:"events,omitempty"`
// chaincode调用结果
Response *Response `protobuf:"bytes,3,opt,name=response,proto3" json:"response,omitempty"`
// 调用的chaincode的信息
ChaincodeId *ChaincodeID `protobuf:"bytes,4,opt,name=chaincode_id,json=chaincodeId,proto3" json:"chaincode_id,omitempty"`
// This field contains the token expectation generated by the chaincode
// executing this invocation
TokenExpectation *token.TokenExpectation `protobuf:"bytes,5,opt,name=token_expectation,json=tokenExpectation,proto3" json:"token_expectation,omitempty"`
}

至此,我们才算拿到我们真正想要的东西 --- 没错,就是这个Results

4、解析TxReadWriteSet

rwset.TxReadWriteSet结构定义如下:

type TxReadWriteSet struct {
DataModel TxReadWriteSet_DataModel `protobuf:"varint,1,opt,name=data_model,json=dataModel,proto3,enum=rwset.TxReadWriteSet_DataModel" json:"data_model,omitempty"`
NsRwset []*NsReadWriteSet `protobuf:"bytes,2,rep,name=ns_rwset,json=nsRwset,proto3" json:"ns_rwset,omitempty"`
}

NsReadWriteSet定义:

type NsReadWriteSet struct {
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
Rwset []byte `protobuf:"bytes,2,opt,name=rwset,proto3" json:"rwset,omitempty"`
CollectionHashedRwset []*CollectionHashedReadWriteSet `protobuf:"bytes,3,rep,name=collection_hashed_rwset,json=collectionHashedRwset,proto3" json:"collection_hashed_rwset,omitempty"`
}

其中这个Rwset就是我们的目标,它是kvrwset.KVRWSet编码后得到的。

4.1、kvrwset.KVRWSet

kvrwset.KVRWSet定义如下:

type KVRWSet struct {
Reads []*KVRead `protobuf:"bytes,1,rep,name=reads,proto3" json:"reads,omitempty"`
RangeQueriesInfo []*RangeQueryInfo `protobuf:"bytes,2,rep,name=range_queries_info,json=rangeQueriesInfo,proto3" json:"range_queries_info,omitempty"`
Writes []*KVWrite `protobuf:"bytes,3,rep,name=writes,proto3" json:"writes,omitempty"`
MetadataWrites []*KVMetadataWrite `protobuf:"bytes,4,rep,name=metadata_writes,json=metadataWrites,proto3" json:"metadata_writes,omitempty"`
}

之后通过解析Writes就能获取到上链的数据,即调用shim.PutState(key string, value []byte)使用的keyvalue


声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。

Author: MengBin


根据TxID获取上链数据的更多相关文章

  1. C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据

    我曾经在系列文章中的<C#开发微信门户及应用(11)--微信菜单的多种表现方式介绍>中介绍了微信菜单里面的重定向操作,通过这个重定向操作,我们可以获取一个code值,然后获取用户的open ...

  2. jdbc java数据库连接 7)获取插入数据的自增长值

    我们创建一个sql表,里面的数据往往都会有自增长值. 那么,我们用jdbc插入数据的时候,要想同时获得这个增长值. 代码: /** * * 这是插入一条数据的同时,获取该数据的则增长列的值(该例子的自 ...

  3. 室内定位系列(二)——仿真获取RSS数据

    很多情况下大家都采用实际测量的数据进行定位算法的性能分析和验证,但是实际测量的工作量太大.数据不全面.灵活性较小,采用仿真的方法获取RSS数据是另一种可供选择的方式.本文介绍射线跟踪技术的基本原理,以 ...

  4. asp.net三层架构 及其中使用泛型获取实体数据介绍

    asp.net中使用泛型获取实体数据可以发挥更高的效率,代码简洁方便,本例采用三层架构.首先在model层中定义StuInfo实体,然后在 DAL层的SQLHelper数据操作类中定义list< ...

  5. android 从服务器获取新闻数据并显示在客户端

    新闻客户端案例 第一次进入新闻客户端需要请求服务器获取新闻数据,做listview的展示, 为了第二次再次打开新闻客户端时能快速显示新闻,需要将数据缓存到数据库中,下次打开可以直接去数据库中获取新闻直 ...

  6. 对 griview获取的数据添加方法 6月

    <asp:TemplateField HeaderText="日期">                            <HeaderStyle CssCl ...

  7. 速战速决 (6) - PHP: 获取 http 请求数据, 获取 get 数据 和 post 数据, json 字符串与对象之间的相互转换

    [源码下载] 速战速决 (6) - PHP: 获取 http 请求数据, 获取 get 数据 和 post 数据, json 字符串与对象之间的相互转换 作者:webabcd 介绍速战速决 之 PHP ...

  8. 【Spring】获取资源文件+从File+从InputStream对象获取正文数据

    1.获取资源文件或者获取文本文件等,可以通过Spring的Resource的方式获取 2.仅有File对象即可获取正文数据 3.仅有InputStream即可获取正文数据 package com.sx ...

  9. java URL实现调用其他系统发送报文并获取返回数据

    模拟本系统通过Url方式发送报文到目标服务器,并获取返回数据:(实现类) import java.io.BufferedOutputStream; import java.io.BufferedRea ...

  10. ajax请求获取的数据无法赋值给全局变量问题总结

    一.总结: 1.问题描述: 今天做项目遇到在用表单显示详细信息的过程中ajax请求获取的数据无法赋值给全局变量的情况,从列表页面进入详情页,在详情页面被渲染了之后就会调用js文件里的接口向服务器请求数 ...

随机推荐

  1. LAS Spark+云原生:数据分析全新解决方案

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 随着数据规模的迅速增长和数据处理需求的不断演进,云原生架构和湖仓分析成为了现代数据处理的重要趋势.在这个数字化时代 ...

  2. cmd 7z 文件压缩

    7z压缩测试 为了方便,将7z的安装目录,添加到环境变量中 # 不加环境变量的话,需要带上全路径 C:\Users\vipsoft>"C:\\Program Files\\7-Zip\ ...

  3. 以 Golang 为例详解 AST 抽象语法树

    前言 各位同行有没有想过一件事,一个程序文件,比如 hello.go 是如何被编译器理解的,平常在编写程序时,IDE 又是如何提供代码提示的.在这奥妙无穷的背后, AST(Abstract Synta ...

  4. Linux day3:⽹络不通排查流程 linux重要数据文件 系统优化相关 上传下载 文件权限 所属用户及用户组

    目录 ⽹络不通排查流程 linux重要数据文件 etc⽬录下重要的数据⽂件 usr⽬录下重要的数据⽂件 var⽬录下重要的数据⽂件 proc⽬录重要的数据⽂件 系统优化相关 环境变量 下载软件优化操作 ...

  5. NBA赛事直播超清画质背后:阿里云视频云「窄带高清2.0」技术深度解读

    在半月前结束的NBA总决赛中,百视TV作为全网唯一采用"主播陪你看NBA"模式的直播平台,以"陪看型"赛事解说来面对内容差异化竞争.与此同时,百视TV还运用了& ...

  6. acwing算法提高课程笔记—数字三角形模型,最长上升子序列模型

    转自自网络,仅作为学习使用 1015摘花生 /*Hello Kitty想摘点花生送给她喜欢的米老鼠. 她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来. 地里每个道路的交叉点上都 ...

  7. 【每日一题】39. Contest(树状数组 / 容斥分治)

    补题链接:Here 算法涉及:树状数组.CDQ分治 n支队伍一共参加了三场比赛. 一支队伍x认为自己比另一支队伍y强当且仅当x在至少一场比赛中比y的排名高. 求有多少组(x,y),使得x自己觉得比y强 ...

  8. AISing Programming Contest 2021(AtCoder Beginner Contest 202) 简单题解记录

    补题链接:Here A - Three Dice 水题,问给定三次摇色子的正面,请问3次结果以后相对面的点数和 cout << (21 - a - b - c) << &quo ...

  9. 面试通过,拿到offer了,不去了会怎么样?

    接受了offer但不去,其实没啥事,但这属于诚信问题. 这里有个概念,给了offer但不接受,这没事. 给了offer,也接受了,但在入职前一周(或在其它约定的时间范围内)说不去,同时姿态放低些打招呼 ...

  10. ngix反向代理服务器

    Nginx ("engine x") 是一个高性能的HTTP 和反向代理 服务器,在大负载的情况下表现十分优秀. 1.正向代理 正向代理也是大家最常接触的到的代理模式.正向代理最大 ...