How to Query Transaction By ID in Hyperledger Fabric 2.0

Querying transaction content out from a blockchain network is a common practice used by common scenarios like exploring the blockchain history or verifying the blockchain transaction content from a known ID. In Hyperledger Fabric, the transaction can be queried using a special system chaincode QSCC (Query System Chaincode) which is for ledger and other Fabric-related queries. For querying transaction by its ID, we can query/invoke the GetTransactionByID function from QSCC.

This tutorial assumes you have just finished installing Hyperledger Fabric 2.0 in Ubuntu 18.04 and we introduce the steps using the test-network.

Change the working directory and set up the environment

First change the working directory to the test-network directory from the fabric-samples repository which was pulled by the installation script during installing Hyperledger Fabric 2.0 following the tutorial mentioned above.

$ cd $GOPATH/src/github.com/hyperledger/fabric-samples/test-network

Set up the environment variables correctly so that the peer command can work correctly.

$ export FABRIC_CFG_PATH=../config/
$ source scripts/envVar.sh 
$ setGlobals 1
$ parsePeerConnectionParameters 1 2

Here, parsePeerConnectionParameters 1 2 sets the variables, especially $PEER_CONN_PARMS, so that endorsement requests for the invocation will be sent to both organization 1 and 2.

Invoke a chaincode

Now let’s invoke the fabcar chaincode to generate one transaction and its ID so that we can query the transaction out.

$ peer chaincode invoke \
-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA \
$PEER_CONN_PARMS \
-C mychannel -n fabcar \
-c '{"function":"CreateCar","Args":["abc", "makeM", "modelX", "red", "ownerO"]}' \
--waitForEvent

It will show output as follows. The txid field contains the transaction ID for the new transaction.

2020-04-08 12:58:38.703 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [fa0f757bc278fdf6a32d00975602eb853e23a86a156781588d99ddef5b80720f] committed with status (VALID) at localhost:7051
2020-04-08 12:58:38.713 UTC [chaincodeCmd] ClientWait -> INFO 002 txid [fa0f757bc278fdf6a32d00975602eb853e23a86a156781588d99ddef5b80720f] committed with status (VALID) at localhost:9051
2020-04-08 12:58:38.713 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 003 Chaincode invoke successful. result: status:200 

Query the transaction out by transaction ID

Now let’s query it out. For query, we only need to query from one organization 1. So set the environment variable again.

$ parsePeerConnectionParameters 1

Now we are ready to invoke qscc chaincode’s GetTransactionByID function with the channel ID and transaction ID as the arguments:

$ peer chaincode invoke \
-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA \
$PEER_CONN_PARMS \
-C mychannel -n qscc \
-c '{"function":"GetTransactionByID","Args":["mychannel", "fa0f757bc278fdf6a32d00975602eb853e23a86a156781588d99ddef5b80720f"]}'

It will return the transaction payload out as a very long string.

2020-04-08 13:06:46.297 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 payload:"\n\232\037\n\317\036\n\301\007\ni\010\003\032\014\010\374\224\267\364\005\020\245\214\347\256\002\"\tmychannel*@fa0f757bc278fdf6a32d00975602eb853e23a86a156781588d99ddef5b80720f:\n\022\010\022\006fabcar\022\323\006\n\266\006\n\007Org2MSP\022\252\006-----BEGIN CERTIFICATE-----\nMIICKTCCAdCgAwIBAgIRANB520WsRCPUtHxGxXAF/zQwCgYIKoZIzj0EAwIwczEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzIuZXhhbXBsZS5jb20wHhcNMjAwNDA4MTAxMDAwWhcNMzAwNDA2MTAxMDAw\nWjBrMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN\nU2FuIEZyYW5jaXNjbzEOMAwGA1UECxMFYWRtaW4xHzAdBgNVBAMMFkFkbWluQG9y\nZzIuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT87rGWke+T\nMcPm5IWJ2Z345AgSSMyYM56oCAQw5pU6HiSzkIX2SYyfM3qhgxXuDKtDLRl+6oAQ\nH9TkdJXiuDwIo00wSzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADArBgNV\nHSMEJDAigCB3CtCiWYUiHns2+BB5oaDbGmkpCFLgi/AHVgS1ZQHvzzAKBggqhkjO\nPQQDAgNHADBEAiA4+SsMgSJY1iMyBaqmqhUWCAdPeiFgjZcoPwxP6mXxigIgWDU2\nNLpKgqSXz0Qkv4f560F2HmjDcE2OiXH2RnSn/DU=\n-----END CERTIFICATE-----\n\022\030\337\033\362\341\3530\362 \243\357\316i\257\247\244y0D\246\274\241\240\013\267\022\210\027\n\205\027\n\323\006\n\266\006\n\007Org2MSP\022\252\006-----BEGIN CERTIFICATE-----\nMIICKTCCAdCgAwIBAgIRANB520WsRCPUtHxGxXAF/zQwCgYIKoZIzj0EAwIwczEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzIuZXhhbXBsZS5jb20wHhcNMjAwNDA4MTAxMDAwWhcNMzAwNDA2MTAxMDAw\nWjBrMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN\nU2FuIEZyYW5jaXNjbzEOMAwGA1UECxMFYWRtaW4xHzAdBgNVBAMMFkFkbWluQG9y\nZzIuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT87rGWke+T\nMcPm5IWJ2Z345AgSSMyYM56oCAQw5pU6HiSzkIX2SYyfM3qhgxXuDKtDLRl+6oAQ\nH9TkdJXiuDwIo00wSzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADArBgNV\nHSMEJDAigCB3CtCiWYUiHns2+BB5oaDbGmkpCFLgi/AHVgS1ZQHvzzAKBggqhkjO\nPQQDAgNHADBEAiA4+SsMgSJY1iMyBaqmqhUWCAdPeiFgjZcoPwxP6mXxigIgWDU2\nNLpKgqSXz0Qkv4f560F2HmjDcE2OiXH2RnSn/DU=\n-----END CERTIFICATE-----\n\022\030\337\033\362\341\3530\362 \243\357\316i\257\247\244y0D\246\274\241\240\013\267\022\254\020\n>\n<\n:\010\001\022\010\022\006fabcar\032,\n\tCreateCar\n\003abc\n\005makeM\n\006modelX\n\003red\n\006ownerO\022\351\017\n\341\001\n \224\316G\014Piw[C\356\342\241\223\360\314\026+\317\370\271\2405\207\202r\242\361\253\270\207\275\271\022\274\001\n\247\001\0227\n\n_lifecycle\022)\n'\n!namespaces/fields/fabcar/Sequence\022\002\010\005\022l\n\006fabcar\022b\n\026\n\020\000\364\217\277\277initialized\022\002\010\006\032H\n\003abc\032A{\"make\":\"makeM\",\"model\":\"modelX\",\"colour\":\"red\",\"owner\":\"ownerO\"}\032\003\010\310\001\"\013\022\006fabcar\032\0011\022\375\006\n\262\006\n\007Org2MSP\022\246\006-----BEGIN CERTIFICATE-----\nMIICJjCCAc2gAwIBAgIPT1M5v/RIw2pFGFV43bRcMAoGCCqGSM49BAMCMHMxCzAJ\nBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJh\nbmNpc2NvMRkwFwYDVQQKExBvcmcyLmV4YW1wbGUuY29tMRwwGgYDVQQDExNjYS5v\ncmcyLmV4YW1wbGUuY29tMB4XDTIwMDQwODEwMTAwMFoXDTMwMDQwNjEwMTAwMFow\najELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xDTALBgNVBAsTBHBlZXIxHzAdBgNVBAMTFnBlZXIwLm9yZzIu\nZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATED9XSksxuJut0\nFMoFakmzA6T3xWg5ktg720SDBjaKX03YOT+c+d4gIyWt+OoVp1CgSrGDZD1+P/BH\ntc4OY7uio00wSzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADArBgNVHSME\nJDAigCB3CtCiWYUiHns2+BB5oaDbGmkpCFLgi/AHVgS1ZQHvzzAKBggqhkjOPQQD\nAgNHADBEAiAofLpGCn75/iezwWRutN7O8YMDiji2i8+gwPItfaRLzwIgFvgqbGCY\nWzJOKtfwoDVWamWpMWlMWNFqDrD37IEeGs8=\n-----END CERTIFICATE-----\n\022F0D\002 _2\220B\327]\306\2522ZDa\224\211\231\257\320\313\306\026\254\307\307\344\330+\352\006\001\3752\003\002 *3\250\214lfK\353\267\235\233\333`0\241\2102\033\202F>\207|p\352\330\341\271\264\2453\033\022\202\007\n\266\006\n\007Org1MSP\022\252\006-----BEGIN CERTIFICATE-----\nMIICKDCCAc+gAwIBAgIRAONRdxDRTUieH3V5HwUgOnUwCgYIKoZIzj0EAwIwczEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAwNDA4MTAxMDAwWhcNMzAwNDA2MTAxMDAw\nWjBqMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN\nU2FuIEZyYW5jaXNjbzENMAsGA1UECxMEcGVlcjEfMB0GA1UEAxMWcGVlcjAub3Jn\nMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBjL6HrhcvoK\n/pWpiQlGG2Y+gbz/norGp+M8ep+8J4pop4qAU+tu2rm46AZBwkn7o76zRWcbDfRp\n9hf8jBlETRijTTBLMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1Ud\nIwQkMCKAIP1CJqu24vSd4ZMQUFEHS2d5USD8U5gYAjbHPxnhZpjRMAoGCCqGSM49\nBAMCA0cAMEQCIBR7lI1wwY4641P9Kg4n7Nq3trhc5ztQeQxadcwybBG/AiBE7M4d\n8LTCTMksf4d4QN50oSTussem8HmilE6Wt7iYCQ==\n-----END CERTIFICATE-----\n\022G0E\002!\000\263x.O\360G\315\276b\325\377\272]$\177@Z\375B^\017K\036\222\251\001lwS%\202v\002 \034\333%\214\023s\202\270?\270>\212:M\274\360\275O\"s\317\210\267\375F\363\316K\202\370PN\022F0D\002 M/7\005\276\312:\337\361Z\033\272a.\326\017\314\006Ov\244\374V\271W\341\034\336[\314@\245\002 \005\216i\345 \304\222\306C\330\370A\301\236etb\005P\361\242\2731[\330u\225l#\271\022\r" 

Now we get the serialized transaction content in the payload part of the response. From the beginning part, we can find the mychannel*@fa0f757bc278fdf6a32d00975602eb853e23a86a156781588d99ddef5b80720f string which contains the channel ID and the transaction ID.

Deserialize the transaction

From the GetTransactionByID query implementation, the chaincode calls func (l *kvLedger) GetTransactionByID(txID string) (*peer.ProcessedTransaction, error) and marshals the returned peer.ProcessedTransaction struct for the response.

The peer.ProcessedTransaction struct is a protobuf struct defined in peer/transaction.proto and the generated Go struct is defined in the peer/transaction.pb.go file.

If you would like to deserizlie the transaction, you may parse it into a peer.ProcessedTransaction struct using any programming language that can unmarshal the marshalled protobuf struct.

Eric Ma

Eric is a systems guy. Eric is interested in building high-performance and scalable distributed systems and related technologies. The views or opinions expressed here are solely Eric's own and do not necessarily represent those of any third parties.

2 comments:

  1. Well explained! Is there a way to query transaction history using the key in fabric 2.0? I don’t see any such function in the QSCC.

Leave a Reply

Your email address will not be published. Required fields are marked *