How to Query Transaction By ID in Hyperledger Fabric 2.0

Posted on In Blockchain, Systems, Tutorial

Querying transaction content out from a blockchain network is a common practice used by common scenarios like exploring the 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:"n232 37n317 36n301 07ni 10 03 32 14 10374224267364 05 20245214347256 02"tmychannel*@fa0f757bc278fdf6a32d00975602eb853e23a86a156781588d99ddef5b80720f:n 22 10 22 06fabcar 22323 06n266 06n 07Org2MSP 22252 06-----BEGIN CERTIFICATE-----nMIICKTCCAdCgAwIBAgIRANB520WsRCPUtHxGxXAF/zQwCgYIKoZIzj0EAwIwczELnMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGncmFuY2lzY28xGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2NhnLm9yZzIuZXhhbXBsZS5jb20wHhcNMjAwNDA4MTAxMDAwWhcNMzAwNDA2MTAxMDAwnWjBrMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNnU2FuIEZyYW5jaXNjbzEOMAwGA1UECxMFYWRtaW4xHzAdBgNVBAMMFkFkbWluQG9ynZzIuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT87rGWke+TnMcPm5IWJ2Z345AgSSMyYM56oCAQw5pU6HiSzkIX2SYyfM3qhgxXuDKtDLRl+6oAQnH9TkdJXiuDwIo00wSzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADArBgNVnHSMEJDAigCB3CtCiWYUiHns2+BB5oaDbGmkpCFLgi/AHVgS1ZQHvzzAKBggqhkjOnPQQDAgNHADBEAiA4+SsMgSJY1iMyBaqmqhUWCAdPeiFgjZcoPwxP6mXxigIgWDU2nNLpKgqSXz0Qkv4f560F2HmjDcE2OiXH2RnSn/DU=n-----END CERTIFICATE-----n 22 30337 333623413530362 243357316i257247244y0D246274241240 13267 22210 27n205 27n323 06n266 06n 07Org2MSP 22252 06-----BEGIN CERTIFICATE-----nMIICKTCCAdCgAwIBAgIRANB520WsRCPUtHxGxXAF/zQwCgYIKoZIzj0EAwIwczELnMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGncmFuY2lzY28xGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2NhnLm9yZzIuZXhhbXBsZS5jb20wHhcNMjAwNDA4MTAxMDAwWhcNMzAwNDA2MTAxMDAwnWjBrMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNnU2FuIEZyYW5jaXNjbzEOMAwGA1UECxMFYWRtaW4xHzAdBgNVBAMMFkFkbWluQG9ynZzIuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT87rGWke+TnMcPm5IWJ2Z345AgSSMyYM56oCAQw5pU6HiSzkIX2SYyfM3qhgxXuDKtDLRl+6oAQnH9TkdJXiuDwIo00wSzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADArBgNVnHSMEJDAigCB3CtCiWYUiHns2+BB5oaDbGmkpCFLgi/AHVgS1ZQHvzzAKBggqhkjOnPQQDAgNHADBEAiA4+SsMgSJY1iMyBaqmqhUWCAdPeiFgjZcoPwxP6mXxigIgWDU2nNLpKgqSXz0Qkv4f560F2HmjDcE2OiXH2RnSn/DU=n-----END CERTIFICATE-----n 22 30337 333623413530362 243357316i257247244y0D246274241240 13267 22254 20n>n207|p3523303412712642453 33 22202 07n266 06n 07Org1MSP 22252 06-----BEGIN CERTIFICATE-----nMIICKDCCAc+gAwIBAgIRAONRdxDRTUieH3V5HwUgOnUwCgYIKoZIzj0EAwIwczELnMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGncmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2NhnLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAwNDA4MTAxMDAwWhcNMzAwNDA2MTAxMDAwnWjBqMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNnU2FuIEZyYW5jaXNjbzENMAsGA1UECxMEcGVlcjEfMB0GA1UEAxMWcGVlcjAub3JnnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBjL6HrhcvoKn/pWpiQlGG2Y+gbz/norGp+M8ep+8J4pop4qAU+tu2rm46AZBwkn7o76zRWcbDfRpn9hf8jBlETRijTTBLMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdnIwQkMCKAIP1CJqu24vSd4ZMQUFEHS2d5USD8U5gYAjbHPxnhZpjRMAoGCCqGSM49nBAMCA0cAMEQCIBR7lI1wwY4641P9Kg4n7Nq3trhc5ztQeQxadcwybBG/AiBE7M4dn8LTCTMksf4d4QN50oSTussem8HmilE6Wt7iYCQ==n-----END CERTIFICATE-----n 22G0E 02! 00263x.O360G315276b325377272]$177@Z375B^ 17K 36222251 01lwS%202v 02  34333%214 23s202270?270>212:M274360275O"s317210267375F363316K202370PN 22F0D 02 M/7 05276312:337361Z 33272a.326 17314 06Ov244374V271W341 34336[314@245 02  05216i345 304222306C330370A301236etb 05P3612422731[330u225l#271 22r" 

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.