1. 程式人生 > 實用技巧 >根據TxID獲取上鍊資料

根據TxID獲取上鍊資料

根據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