根据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. Solon2 开发之IoC,五、Bean 扫描的三种方式

    1.启动时扫描 package org.example.demo; public class DemoApp{ public static void main(String[] args){ // / ...

  2. 拒绝了对对象 ‘GetTips‘ (数据库 ‘vipsoft‘,架构 ‘dbo‘)的 EXECUTE 权限

    SQL Server 2016 安装 数据库-属性-权限-选择用户或角色-勾选执行权限即可.

  3. 无法访问Docker 里的 mysql, redis

    [root@centos-linux jimmy]# firewall-cmd --state not running [root@centos-linux jimmy]# sysctl net.ip ...

  4. 非洲 AI 不发达,看看这份PPT,受益匪浅

    非洲 AI 不发达,看看这份PPT,受益匪浅 非洲有大量的工程+机器学习人才,他们渴望学习.努力工作和进步. 大家好,我是老章 看到我关注的一位博主在首届非洲 @LangChainAI 聚会上的一个演 ...

  5. 【JAVA基础】List处理

    List处理 List使用Lists.partition()分片 public static <T> List<List<T>> partition(List< ...

  6. SpringBoot多模块项目搭建以及搭建基础模板

    多模块项目搭建 目录 多模块项目搭建 1.父项目pom文件编辑 2.创建子模块 1.父项目pom文件编辑 <!--1.父工程 添加pom格式--> <packaging>pom ...

  7. 技术文档丨 OpenSCA技术原理之npm依赖解析

    本文主要介绍基于npm包管理器的组件成分解析原理. npm介绍 npm(全称Node Package Manager)是Node.js标准的软件包管理器. npm的依赖管理文件是package.jso ...

  8. mysql 字段逗号分割行转列操作

    一.需求 某字段的值为 7654,7698,7782,7788 期望的效果:  二.实现语句 SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('7654,7698,778 ...

  9. 一、redis单例安装(linux)

    系列导航 一.redis单例安装(linux) 二.redis主从环境搭建 三.redis集群搭建 四.redis增加密码验证 五.java操作redis 环境:centos7.5需要的安装包: re ...

  10. 小白学标准库之 mux

    本文介绍第三方库 gorilla/mux,相比于 Go 自带的 net/http 它能提供更为强大的路由处理功能. mux 表示 HTTP request multiplexer (HTTP 请求多路 ...