@@ -61,7 +61,8 @@ type transactionContext struct {
61
61
// tracks open iterators used for range queries
62
62
queryIteratorMap map [string ]commonledger.ResultsIterator
63
63
64
- txsimulator ledger.TxSimulator
64
+ txsimulator ledger.TxSimulator
65
+ historyQueryExecutor ledger.HistoryQueryExecutor
65
66
}
66
67
67
68
type nextStateInfo struct {
@@ -194,6 +195,7 @@ func (handler *Handler) createTxContext(ctxt context.Context, chainID string, tx
194
195
queryIteratorMap : make (map [string ]commonledger.ResultsIterator )}
195
196
handler .txCtxs [txid ] = txctx
196
197
txctx .txsimulator = getTxSimulator (ctxt )
198
+ txctx .historyQueryExecutor = getHistoryQueryExecutor (ctxt )
197
199
198
200
return txctx , nil
199
201
}
@@ -417,6 +419,7 @@ func newChaincodeSupportHandler(chaincodeSupport *ChaincodeSupport, peerChatStre
417
419
{Name : pb .ChaincodeMessage_GET_STATE .String (), Src : []string {readystate }, Dst : readystate },
418
420
{Name : pb .ChaincodeMessage_GET_STATE_BY_RANGE .String (), Src : []string {readystate }, Dst : readystate },
419
421
{Name : pb .ChaincodeMessage_GET_QUERY_RESULT .String (), Src : []string {readystate }, Dst : readystate },
422
+ {Name : pb .ChaincodeMessage_GET_HISTORY_FOR_KEY .String (), Src : []string {readystate }, Dst : readystate },
420
423
{Name : pb .ChaincodeMessage_QUERY_STATE_NEXT .String (), Src : []string {readystate }, Dst : readystate },
421
424
{Name : pb .ChaincodeMessage_QUERY_STATE_CLOSE .String (), Src : []string {readystate }, Dst : readystate },
422
425
{Name : pb .ChaincodeMessage_ERROR .String (), Src : []string {readystate }, Dst : readystate },
@@ -425,19 +428,20 @@ func newChaincodeSupportHandler(chaincodeSupport *ChaincodeSupport, peerChatStre
425
428
{Name : pb .ChaincodeMessage_TRANSACTION .String (), Src : []string {readystate }, Dst : readystate },
426
429
},
427
430
fsm.Callbacks {
428
- "before_" + pb .ChaincodeMessage_REGISTER .String (): func (e * fsm.Event ) { v .beforeRegisterEvent (e , v .FSM .Current ()) },
429
- "before_" + pb .ChaincodeMessage_COMPLETED .String (): func (e * fsm.Event ) { v .beforeCompletedEvent (e , v .FSM .Current ()) },
430
- "after_" + pb .ChaincodeMessage_GET_STATE .String (): func (e * fsm.Event ) { v .afterGetState (e , v .FSM .Current ()) },
431
- "after_" + pb .ChaincodeMessage_GET_STATE_BY_RANGE .String (): func (e * fsm.Event ) { v .afterGetStateByRange (e , v .FSM .Current ()) },
432
- "after_" + pb .ChaincodeMessage_GET_QUERY_RESULT .String (): func (e * fsm.Event ) { v .afterGetQueryResult (e , v .FSM .Current ()) },
433
- "after_" + pb .ChaincodeMessage_QUERY_STATE_NEXT .String (): func (e * fsm.Event ) { v .afterQueryStateNext (e , v .FSM .Current ()) },
434
- "after_" + pb .ChaincodeMessage_QUERY_STATE_CLOSE .String (): func (e * fsm.Event ) { v .afterQueryStateClose (e , v .FSM .Current ()) },
435
- "after_" + pb .ChaincodeMessage_PUT_STATE .String (): func (e * fsm.Event ) { v .enterBusyState (e , v .FSM .Current ()) },
436
- "after_" + pb .ChaincodeMessage_DEL_STATE .String (): func (e * fsm.Event ) { v .enterBusyState (e , v .FSM .Current ()) },
437
- "after_" + pb .ChaincodeMessage_INVOKE_CHAINCODE .String (): func (e * fsm.Event ) { v .enterBusyState (e , v .FSM .Current ()) },
438
- "enter_" + establishedstate : func (e * fsm.Event ) { v .enterEstablishedState (e , v .FSM .Current ()) },
439
- "enter_" + readystate : func (e * fsm.Event ) { v .enterReadyState (e , v .FSM .Current ()) },
440
- "enter_" + endstate : func (e * fsm.Event ) { v .enterEndState (e , v .FSM .Current ()) },
431
+ "before_" + pb .ChaincodeMessage_REGISTER .String (): func (e * fsm.Event ) { v .beforeRegisterEvent (e , v .FSM .Current ()) },
432
+ "before_" + pb .ChaincodeMessage_COMPLETED .String (): func (e * fsm.Event ) { v .beforeCompletedEvent (e , v .FSM .Current ()) },
433
+ "after_" + pb .ChaincodeMessage_GET_STATE .String (): func (e * fsm.Event ) { v .afterGetState (e , v .FSM .Current ()) },
434
+ "after_" + pb .ChaincodeMessage_GET_STATE_BY_RANGE .String (): func (e * fsm.Event ) { v .afterGetStateByRange (e , v .FSM .Current ()) },
435
+ "after_" + pb .ChaincodeMessage_GET_QUERY_RESULT .String (): func (e * fsm.Event ) { v .afterGetQueryResult (e , v .FSM .Current ()) },
436
+ "after_" + pb .ChaincodeMessage_GET_HISTORY_FOR_KEY .String (): func (e * fsm.Event ) { v .afterGetHistoryForKey (e , v .FSM .Current ()) },
437
+ "after_" + pb .ChaincodeMessage_QUERY_STATE_NEXT .String (): func (e * fsm.Event ) { v .afterQueryStateNext (e , v .FSM .Current ()) },
438
+ "after_" + pb .ChaincodeMessage_QUERY_STATE_CLOSE .String (): func (e * fsm.Event ) { v .afterQueryStateClose (e , v .FSM .Current ()) },
439
+ "after_" + pb .ChaincodeMessage_PUT_STATE .String (): func (e * fsm.Event ) { v .enterBusyState (e , v .FSM .Current ()) },
440
+ "after_" + pb .ChaincodeMessage_DEL_STATE .String (): func (e * fsm.Event ) { v .enterBusyState (e , v .FSM .Current ()) },
441
+ "after_" + pb .ChaincodeMessage_INVOKE_CHAINCODE .String (): func (e * fsm.Event ) { v .enterBusyState (e , v .FSM .Current ()) },
442
+ "enter_" + establishedstate : func (e * fsm.Event ) { v .enterEstablishedState (e , v .FSM .Current ()) },
443
+ "enter_" + readystate : func (e * fsm.Event ) { v .enterReadyState (e , v .FSM .Current ()) },
444
+ "enter_" + endstate : func (e * fsm.Event ) { v .enterEndState (e , v .FSM .Current ()) },
441
445
},
442
446
)
443
447
@@ -968,7 +972,7 @@ func (handler *Handler) handleGetQueryResult(msg *pb.ChaincodeMessage) {
968
972
if err != nil {
969
973
// Send error msg back to chaincode. GetState will not trigger event
970
974
payload := []byte (err .Error ())
971
- chaincodeLogger .Errorf ("Failed to get ledger scan iterator. Sending %s" , pb .ChaincodeMessage_ERROR )
975
+ chaincodeLogger .Errorf ("Failed to get ledger query iterator. Sending %s" , pb .ChaincodeMessage_ERROR )
972
976
serialSendMsg = & pb.ChaincodeMessage {Type : pb .ChaincodeMessage_ERROR , Payload : payload , Txid : msg .Txid }
973
977
return
974
978
}
@@ -1017,6 +1021,118 @@ func (handler *Handler) handleGetQueryResult(msg *pb.ChaincodeMessage) {
1017
1021
}()
1018
1022
}
1019
1023
1024
+ const maxGetHistoryForKeyLimit = 100
1025
+
1026
+ // afterGetHistoryForKey handles a GET_HISTORY_FOR_KEY request from the chaincode.
1027
+ func (handler * Handler ) afterGetHistoryForKey (e * fsm.Event , state string ) {
1028
+ msg , ok := e .Args [0 ].(* pb.ChaincodeMessage )
1029
+ if ! ok {
1030
+ e .Cancel (fmt .Errorf ("Received unexpected message type" ))
1031
+ return
1032
+ }
1033
+ chaincodeLogger .Debugf ("Received %s, invoking get state from ledger" , pb .ChaincodeMessage_GET_HISTORY_FOR_KEY )
1034
+
1035
+ // Query ledger history db
1036
+ handler .handleGetHistoryForKey (msg )
1037
+ chaincodeLogger .Debug ("Exiting GET_HISTORY_FOR_KEY" )
1038
+ }
1039
+
1040
+ // Handles query to ledger history db
1041
+ func (handler * Handler ) handleGetHistoryForKey (msg * pb.ChaincodeMessage ) {
1042
+ // The defer followed by triggering a go routine dance is needed to ensure that the previous state transition
1043
+ // is completed before the next one is triggered. The previous state transition is deemed complete only when
1044
+ // the afterQueryState function is exited. Interesting bug fix!!
1045
+ go func () {
1046
+ // Check if this is the unique state request from this chaincode txid
1047
+ uniqueReq := handler .createTXIDEntry (msg .Txid )
1048
+ if ! uniqueReq {
1049
+ // Drop this request
1050
+ chaincodeLogger .Error ("Another state request pending for this Txid. Cannot process." )
1051
+ return
1052
+ }
1053
+
1054
+ var serialSendMsg * pb.ChaincodeMessage
1055
+
1056
+ defer func () {
1057
+ handler .deleteTXIDEntry (msg .Txid )
1058
+ chaincodeLogger .Debugf ("[%s]handleGetHistoryForKey serial send %s" , shorttxid (serialSendMsg .Txid ), serialSendMsg .Type )
1059
+ handler .serialSendAsync (serialSendMsg , nil )
1060
+ }()
1061
+
1062
+ getHistoryForKey := & pb.GetHistoryForKey {}
1063
+ unmarshalErr := proto .Unmarshal (msg .Payload , getHistoryForKey )
1064
+ if unmarshalErr != nil {
1065
+ payload := []byte (unmarshalErr .Error ())
1066
+ chaincodeLogger .Errorf ("Failed to unmarshall query request. Sending %s" , pb .ChaincodeMessage_ERROR )
1067
+ serialSendMsg = & pb.ChaincodeMessage {Type : pb .ChaincodeMessage_ERROR , Payload : payload , Txid : msg .Txid }
1068
+ return
1069
+ }
1070
+
1071
+ iterID := util .GenerateUUID ()
1072
+
1073
+ var txContext * transactionContext
1074
+
1075
+ txContext , serialSendMsg = handler .isValidTxSim (msg .Txid , "[%s]No ledger context for GetHistoryForKey. Sending %s" , shorttxid (msg .Txid ), pb .ChaincodeMessage_ERROR )
1076
+ if txContext == nil {
1077
+ return
1078
+ }
1079
+ chaincodeID := handler .getCCRootName ()
1080
+
1081
+ historyIter , err := txContext .historyQueryExecutor .GetHistoryForKey (chaincodeID , getHistoryForKey .Key )
1082
+ if err != nil {
1083
+ // Send error msg back to chaincode. GetState will not trigger event
1084
+ payload := []byte (err .Error ())
1085
+ chaincodeLogger .Errorf ("Failed to get ledger history iterator. Sending %s" , pb .ChaincodeMessage_ERROR )
1086
+ serialSendMsg = & pb.ChaincodeMessage {Type : pb .ChaincodeMessage_ERROR , Payload : payload , Txid : msg .Txid }
1087
+ return
1088
+ }
1089
+
1090
+ handler .putQueryIterator (txContext , iterID , historyIter )
1091
+
1092
+ // TODO QueryStateKeyValue can be re-used for now since history records have a string (TxID)
1093
+ // and value (value). But we'll need to use another structure if we add other fields like timestamp.
1094
+ var keysAndValues []* pb.QueryStateKeyValue
1095
+ var i = uint32 (0 )
1096
+ var qresult commonledger.QueryResult
1097
+ for ; i < maxGetHistoryForKeyLimit ; i ++ {
1098
+ qresult , err = historyIter .Next ()
1099
+ if err != nil {
1100
+ chaincodeLogger .Errorf ("Failed to get query result from iterator. Sending %s" , pb .ChaincodeMessage_ERROR )
1101
+ return
1102
+ }
1103
+ if qresult == nil {
1104
+ break
1105
+ }
1106
+ queryRecord := qresult .(* ledger.KeyModification )
1107
+ keyAndValue := pb.QueryStateKeyValue {Key : queryRecord .TxID , Value : queryRecord .Value }
1108
+ keysAndValues = append (keysAndValues , & keyAndValue )
1109
+ }
1110
+
1111
+ if qresult != nil {
1112
+ historyIter .Close ()
1113
+ handler .deleteQueryIterator (txContext , iterID )
1114
+ }
1115
+
1116
+ var payloadBytes []byte
1117
+ payload := & pb.QueryStateResponse {KeysAndValues : keysAndValues , HasMore : qresult != nil , Id : iterID }
1118
+ payloadBytes , err = proto .Marshal (payload )
1119
+ if err != nil {
1120
+ historyIter .Close ()
1121
+ handler .deleteQueryIterator (txContext , iterID )
1122
+
1123
+ // Send error msg back to chaincode. GetState will not trigger event
1124
+ payload := []byte (err .Error ())
1125
+ chaincodeLogger .Errorf ("Failed marshall resopnse. Sending %s" , pb .ChaincodeMessage_ERROR )
1126
+ serialSendMsg = & pb.ChaincodeMessage {Type : pb .ChaincodeMessage_ERROR , Payload : payload , Txid : msg .Txid }
1127
+ return
1128
+ }
1129
+
1130
+ chaincodeLogger .Debugf ("Got keys and values. Sending %s" , pb .ChaincodeMessage_RESPONSE )
1131
+ serialSendMsg = & pb.ChaincodeMessage {Type : pb .ChaincodeMessage_RESPONSE , Payload : payloadBytes , Txid : msg .Txid }
1132
+
1133
+ }()
1134
+ }
1135
+
1020
1136
// afterPutState handles a PUT_STATE request from the chaincode.
1021
1137
func (handler * Handler ) afterPutState (e * fsm.Event , state string ) {
1022
1138
_ , ok := e .Args [0 ].(* pb.ChaincodeMessage )
@@ -1141,6 +1257,7 @@ func (handler *Handler) enterBusyState(e *fsm.Event, state string) {
1141
1257
// We grab the called channel's ledger simulator to hold the new state
1142
1258
ctxt := context .Background ()
1143
1259
txsim := txContext .txsimulator
1260
+ historyQueryExecutor := txContext .historyQueryExecutor
1144
1261
if calledCcParts .suffix != txContext .chainID {
1145
1262
lgr := peer .GetLedger (calledCcParts .suffix )
1146
1263
if lgr == nil {
@@ -1159,6 +1276,7 @@ func (handler *Handler) enterBusyState(e *fsm.Event, state string) {
1159
1276
txsim = txsim2
1160
1277
}
1161
1278
ctxt = context .WithValue (ctxt , TXSimulatorKey , txsim )
1279
+ ctxt = context .WithValue (ctxt , HistoryQueryExecutorKey , historyQueryExecutor )
1162
1280
1163
1281
if chaincodeLogger .IsEnabledFor (logging .DEBUG ) {
1164
1282
chaincodeLogger .Debugf ("[%s] calling lccc to get chaincode data for %s on channel %s" ,
0 commit comments