根據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)
使用的key和value。
宣告:本作品採用署名-非商業性使用-相同方式共享 4.0 國際 (CC BY-NC-SA 4.0)進行許可,使用時請註明出處。
Author: MengBin