@@ -18,6 +18,10 @@ const (
18
18
created state = "created" // start state
19
19
established state = "established" // connection established
20
20
ready state = "ready" // ready for requests
21
+
22
+ defaultMaxSizePutStateBatch = 100
23
+ prefixMetaData = "m"
24
+ prefixStateData = "s"
21
25
)
22
26
23
27
// PeerChaincodeStream is the common stream interface for Peer - chaincode communication.
@@ -46,6 +50,11 @@ type Handler struct {
46
50
cc Chaincode
47
51
// state holds the current state of this handler.
48
52
state state
53
+ // if you can send the changes in batches.
54
+ usePutStateBatch bool
55
+ maxSizePutStateBatch uint32
56
+ stateDataMutex sync.RWMutex
57
+ stateData map [string ]map [string ]* peer.StateKV
49
58
50
59
// Multiple queries (and one transaction) with different txids can be executing in parallel for this chaincode
51
60
// responseChannels is the channel on which responses are communicated by the shim to the chaincodeStub.
@@ -150,6 +159,7 @@ func newChaincodeHandler(peerChatStream PeerChaincodeStream, chaincode Chaincode
150
159
cc : chaincode ,
151
160
responseChannels : map [string ]chan * peer.ChaincodeMessage {},
152
161
state : created ,
162
+ stateData : map [string ]map [string ]* peer.StateKV {},
153
163
}
154
164
}
155
165
@@ -188,6 +198,11 @@ func (h *Handler) handleInit(msg *peer.ChaincodeMessage) (*peer.ChaincodeMessage
188
198
return nil , fmt .Errorf ("failed to marshal response: %s" , err )
189
199
}
190
200
201
+ err = h .sendBatch (msg .ChannelId , msg .Txid )
202
+ if err != nil {
203
+ return nil , fmt .Errorf ("failed send batch: %s" , err )
204
+ }
205
+
191
206
return & peer.ChaincodeMessage {Type : peer .ChaincodeMessage_COMPLETED , Payload : resBytes , Txid : msg .Txid , ChaincodeEvent : stub .chaincodeEvent , ChannelId : stub .ChannelID }, nil
192
207
}
193
208
@@ -214,6 +229,11 @@ func (h *Handler) handleTransaction(msg *peer.ChaincodeMessage) (*peer.Chaincode
214
229
return nil , fmt .Errorf ("failed to marshal response: %s" , err )
215
230
}
216
231
232
+ err = h .sendBatch (msg .ChannelId , msg .Txid )
233
+ if err != nil {
234
+ return nil , fmt .Errorf ("failed send batch: %s" , err )
235
+ }
236
+
217
237
return & peer.ChaincodeMessage {Type : peer .ChaincodeMessage_COMPLETED , Payload : resBytes , Txid : msg .Txid , ChaincodeEvent : stub .chaincodeEvent , ChannelId : stub .ChannelID }, nil
218
238
}
219
239
@@ -312,6 +332,17 @@ func (h *Handler) handleGetStateMetadata(collection string, key string, channelI
312
332
313
333
// handlePutState communicates with the peer to put state information into the ledger.
314
334
func (h * Handler ) handlePutState (collection string , key string , value []byte , channelID string , txid string ) error {
335
+ if h .usePutStateBatch {
336
+ st := h .stateDataByID (channelID , txid )
337
+ st [prefixStateData + collection + key ] = & peer.StateKV {
338
+ Key : key ,
339
+ Value : value ,
340
+ Collection : collection ,
341
+ Type : peer .StateKV_PUT_STATE ,
342
+ }
343
+ return nil
344
+ }
345
+
315
346
// Construct payload for PUT_STATE
316
347
payloadBytes := marshalOrPanic (& peer.PutState {Collection : collection , Key : key , Value : value })
317
348
@@ -340,6 +371,19 @@ func (h *Handler) handlePutState(collection string, key string, value []byte, ch
340
371
func (h * Handler ) handlePutStateMetadataEntry (collection string , key string , metakey string , metadata []byte , channelID string , txID string ) error {
341
372
// Construct payload for PUT_STATE_METADATA
342
373
md := & peer.StateMetadata {Metakey : metakey , Value : metadata }
374
+
375
+ if h .usePutStateBatch {
376
+ st := h .stateDataByID (channelID , txID )
377
+ st [prefixMetaData + collection + key ] = & peer.StateKV {
378
+ Key : key ,
379
+ Collection : collection ,
380
+ Metadata : md ,
381
+ Type : peer .StateKV_PUT_STATE_METADATA ,
382
+ }
383
+
384
+ return nil
385
+ }
386
+
343
387
payloadBytes := marshalOrPanic (& peer.PutStateMetadata {Collection : collection , Key : key , Metadata : md })
344
388
345
389
msg := & peer.ChaincodeMessage {Type : peer .ChaincodeMessage_PUT_STATE_METADATA , Payload : payloadBytes , Txid : txID , ChannelId : channelID }
@@ -365,6 +409,16 @@ func (h *Handler) handlePutStateMetadataEntry(collection string, key string, met
365
409
366
410
// handleDelState communicates with the peer to delete a key from the state in the ledger.
367
411
func (h * Handler ) handleDelState (collection string , key string , channelID string , txid string ) error {
412
+ if h .usePutStateBatch {
413
+ st := h .stateDataByID (channelID , txid )
414
+ st [prefixStateData + collection + key ] = & peer.StateKV {
415
+ Key : key ,
416
+ Collection : collection ,
417
+ Type : peer .StateKV_DEL_STATE ,
418
+ }
419
+ return nil
420
+ }
421
+
368
422
payloadBytes := marshalOrPanic (& peer.DelState {Collection : collection , Key : key })
369
423
msg := & peer.ChaincodeMessage {Type : peer .ChaincodeMessage_DEL_STATE , Payload : payloadBytes , Txid : txid , ChannelId : channelID }
370
424
// Execute the request and get response
@@ -388,6 +442,16 @@ func (h *Handler) handleDelState(collection string, key string, channelID string
388
442
389
443
// handlePurgeState communicates with the peer to purge a state from private data
390
444
func (h * Handler ) handlePurgeState (collection string , key string , channelID string , txid string ) error {
445
+ if h .usePutStateBatch {
446
+ st := h .stateDataByID (channelID , txid )
447
+ st [prefixStateData + collection + key ] = & peer.StateKV {
448
+ Key : key ,
449
+ Collection : collection ,
450
+ Type : peer .StateKV_PURGE_PRIVATE_DATA ,
451
+ }
452
+ return nil
453
+ }
454
+
391
455
payloadBytes := marshalOrPanic (& peer.DelState {Collection : collection , Key : key })
392
456
msg := & peer.ChaincodeMessage {Type : peer .ChaincodeMessage_PURGE_PRIVATE_DATA , Payload : payloadBytes , Txid : txid , ChannelId : channelID }
393
457
// Execute the request and get response
@@ -409,6 +473,69 @@ func (h *Handler) handlePurgeState(collection string, key string, channelID stri
409
473
return fmt .Errorf ("[%s] incorrect chaincode message %s received. Expecting %s or %s" , shorttxid (responseMsg .Txid ), responseMsg .Type , peer .ChaincodeMessage_RESPONSE , peer .ChaincodeMessage_ERROR )
410
474
}
411
475
476
+ // handlePutStateBatch communicates with the peer to put state as batch all changes information into the ledger.
477
+ func (h * Handler ) handlePutStateBatch (batch * peer.PutStateBatch , channelID string , txid string ) error {
478
+ // Construct payload for PUT_STATE_BATCH
479
+ payloadBytes := marshalOrPanic (batch )
480
+
481
+ msg := & peer.ChaincodeMessage {Type : peer .ChaincodeMessage_PUT_STATE_BATCH , Payload : payloadBytes , Txid : txid , ChannelId : channelID }
482
+
483
+ // Execute the request and get response
484
+ responseMsg , err := h .callPeerWithChaincodeMsg (msg , channelID , txid )
485
+ if err != nil {
486
+ return fmt .Errorf ("[%s] error sending %s: %s" , msg .Txid , peer .ChaincodeMessage_PUT_STATE_BATCH , err )
487
+ }
488
+
489
+ if responseMsg .Type == peer .ChaincodeMessage_RESPONSE {
490
+ // Success response
491
+ return nil
492
+ }
493
+
494
+ if responseMsg .Type == peer .ChaincodeMessage_ERROR {
495
+ // Error response
496
+ return fmt .Errorf ("%s" , responseMsg .Payload [:])
497
+ }
498
+
499
+ // Incorrect chaincode message received
500
+ return fmt .Errorf ("[%s] incorrect chaincode message %s received. Expecting %s or %s" , shorttxid (responseMsg .Txid ), responseMsg .Type , peer .ChaincodeMessage_RESPONSE , peer .ChaincodeMessage_ERROR )
501
+ }
502
+
503
+ func (h * Handler ) sendBatch (channelID string , txid string ) error {
504
+ if ! h .usePutStateBatch {
505
+ return nil
506
+ }
507
+
508
+ st := h .stateDataByID (channelID , txid )
509
+ txCtxID := transactionContextID (channelID , txid )
510
+
511
+ defer func () {
512
+ h .stateDataMutex .Lock ()
513
+ delete (h .stateData , txCtxID )
514
+ h .stateDataMutex .Unlock ()
515
+ }()
516
+
517
+ batch := & peer.PutStateBatch {}
518
+ for _ , kv := range st {
519
+ batch .Kvs = append (batch .Kvs , kv )
520
+ if len (batch .Kvs ) >= int (h .maxSizePutStateBatch ) {
521
+ err := h .handlePutStateBatch (batch , channelID , txid )
522
+ if err != nil {
523
+ return fmt .Errorf ("failed send state batch: %s" , err )
524
+ }
525
+ batch .Kvs = batch .Kvs [:0 ]
526
+ }
527
+ }
528
+
529
+ if len (batch .Kvs ) != 0 {
530
+ err := h .handlePutStateBatch (batch , channelID , txid )
531
+ if err != nil {
532
+ return fmt .Errorf ("failed send state batch: %s" , err )
533
+ }
534
+ }
535
+
536
+ return nil
537
+ }
538
+
412
539
func (h * Handler ) handleGetStateByRange (collection , startKey , endKey string , metadata []byte ,
413
540
channelID string , txid string ) (* peer.QueryResponse , error ) {
414
541
// Send GET_STATE_BY_RANGE message to peer chaincode support
@@ -655,6 +782,23 @@ func (h *Handler) handleEstablished(msg *peer.ChaincodeMessage) error {
655
782
}
656
783
657
784
h .state = ready
785
+ if len (msg .Payload ) == 0 {
786
+ return nil
787
+ }
788
+
789
+ ccAdditionalParams := & peer.ChaincodeAdditionalParams {}
790
+ err := proto .Unmarshal (msg .Payload , ccAdditionalParams )
791
+ if err != nil {
792
+ return nil
793
+ }
794
+
795
+ h .usePutStateBatch = ccAdditionalParams .UsePutStateBatch
796
+ h .maxSizePutStateBatch = ccAdditionalParams .MaxSizePutStateBatch
797
+
798
+ if h .usePutStateBatch && h .maxSizePutStateBatch < defaultMaxSizePutStateBatch {
799
+ h .maxSizePutStateBatch = defaultMaxSizePutStateBatch
800
+ }
801
+
658
802
return nil
659
803
}
660
804
@@ -697,6 +841,28 @@ func (h *Handler) handleMessage(msg *peer.ChaincodeMessage, errc chan error) err
697
841
return nil
698
842
}
699
843
844
+ func (h * Handler ) stateDataByID (channelID string , txID string ) map [string ]* peer.StateKV {
845
+ txCtxID := transactionContextID (channelID , txID )
846
+
847
+ h .stateDataMutex .RLock ()
848
+ st , ok := h .stateData [txCtxID ]
849
+ h .stateDataMutex .RUnlock ()
850
+ if ok {
851
+ return st
852
+ }
853
+
854
+ h .stateDataMutex .Lock ()
855
+ defer h .stateDataMutex .Unlock ()
856
+ st , ok = h .stateData [txCtxID ]
857
+ if ok {
858
+ return st
859
+ }
860
+
861
+ st = make (map [string ]* peer.StateKV )
862
+ h .stateData [txCtxID ] = st
863
+ return st
864
+ }
865
+
700
866
// marshalOrPanic attempts to marshal the provided protobbuf message but will panic
701
867
// when marshaling fails instead of returning an error.
702
868
func marshalOrPanic (msg proto.Message ) []byte {
0 commit comments