@@ -7,11 +7,13 @@ SPDX-License-Identifier: Apache-2.0
77package chaincode
88
99import (
10+ "bytes"
1011 "context"
1112 "encoding/base64"
1213 "strconv"
1314 "strings"
1415 "sync"
16+ "time"
1517
1618 peer2 "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/core/generic/peer"
1719 "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/core/generic/transaction"
@@ -44,6 +46,9 @@ type Invoke struct {
4446 DiscoveredEndorsersByEndpoints []string
4547 Function string
4648 Args []interface {}
49+ MatchEndorsementPolicy bool
50+ NumRetries int
51+ RetrySleep time.Duration
4752}
4853
4954func NewInvoke (chaincode * Chaincode , function string , args ... interface {}) * Invoke {
@@ -55,10 +60,27 @@ func NewInvoke(chaincode *Chaincode, function string, args ...interface{}) *Invo
5560 ChaincodeName : chaincode .name ,
5661 Function : function ,
5762 Args : args ,
63+ NumRetries : int (chaincode .NumRetries ),
64+ RetrySleep : chaincode .RetrySleep ,
5865 }
5966}
6067
6168func (i * Invoke ) Endorse () (driver.Envelope , error ) {
69+ for j := 0 ; j < i .NumRetries ; j ++ {
70+ res , err := i .endorse ()
71+ if err != nil {
72+ if j + 1 >= i .NumRetries {
73+ return nil , err
74+ }
75+ time .Sleep (i .RetrySleep )
76+ continue
77+ }
78+ return res , nil
79+ }
80+ return nil , errors .Errorf ("failed to perform endorse" )
81+ }
82+
83+ func (i * Invoke ) endorse () (driver.Envelope , error ) {
6284 _ , prop , responses , signer , err := i .prepare (false )
6385 if err != nil {
6486 return nil , err
@@ -79,21 +101,74 @@ func (i *Invoke) Endorse() (driver.Envelope, error) {
79101}
80102
81103func (i * Invoke ) Query () ([]byte , error ) {
82- _ , _ , responses , _ , err := i .prepare (true )
104+ for j := 0 ; j < i .NumRetries ; j ++ {
105+ res , err := i .query ()
106+ if err != nil {
107+ if j + 1 >= i .NumRetries {
108+ return nil , err
109+ }
110+ time .Sleep (i .RetrySleep )
111+ continue
112+ }
113+ return res , nil
114+ }
115+ return nil , errors .Errorf ("failed to perform query" )
116+ }
117+
118+ func (i * Invoke ) query () ([]byte , error ) {
119+ _ , _ , responses , _ , err := i .prepare (! i .MatchEndorsementPolicy )
83120 if err != nil {
84121 return nil , err
85122 }
86- proposalResp := responses [0 ]
87- if proposalResp == nil {
123+
124+ // check all responses match
125+ resp := responses [0 ]
126+ if resp == nil {
88127 return nil , errors .New ("error during query: received nil proposal response" )
89128 }
90- if proposalResp .Endorsement == nil {
91- return nil , errors .Errorf ("endorsement failure during query. response: %v" , proposalResp .Response )
129+ if resp .Endorsement == nil {
130+ return nil , errors .Errorf ("endorsement failure during query. endorsement is nil: [%v]" , resp .Response )
131+ }
132+ if resp .Response == nil {
133+ return nil , errors .Errorf ("endorsement failure during query. response is nil: [%v]" , resp .Endorsement )
134+ }
135+ for i := 1 ; i < len (responses ); i ++ {
136+ if responses [i ].Endorsement == nil {
137+ return nil , errors .Errorf ("endorsement failure during query. endorsement is nil: [%v]" , resp .Response )
138+ }
139+ if responses [i ].Response == nil {
140+ return nil , errors .Errorf ("endorsement failure during query. response is nil: [%v]" , resp .Endorsement )
141+ }
142+ if ! bytes .Equal (responses [i ].Response .Payload , resp .Response .Payload ) {
143+ return nil , errors .Errorf ("endorsement failure during query. response payload does not match" )
144+ }
145+ if responses [i ].Response .Status != resp .Response .Status {
146+ return nil , errors .Errorf ("endorsement failure during query. response status does not match" )
147+ }
148+ if responses [i ].Response .Message != resp .Response .Message {
149+ return nil , errors .Errorf ("endorsement failure during query. response message does not match" )
150+ }
92151 }
93- return proposalResp .Response .Payload , nil
152+
153+ return resp .Response .Payload , nil
94154}
95155
96156func (i * Invoke ) Submit () (string , []byte , error ) {
157+ for j := 0 ; j < i .NumRetries ; j ++ {
158+ txID , res , err := i .submit ()
159+ if err != nil {
160+ if j + 1 >= i .NumRetries {
161+ return "" , nil , err
162+ }
163+ time .Sleep (i .RetrySleep )
164+ continue
165+ }
166+ return txID , res , nil
167+ }
168+ return "" , nil , errors .Errorf ("failed to perform submit" )
169+ }
170+
171+ func (i * Invoke ) submit () (string , []byte , error ) {
97172 txID , prop , responses , signer , err := i .prepare (false )
98173 if err != nil {
99174 return "" , nil , err
@@ -148,6 +223,11 @@ func (i *Invoke) WithDiscoveredEndorsersByEndpoints(endpoints ...string) driver.
148223 return i
149224}
150225
226+ func (i * Invoke ) WithMatchEndorsementPolicy () driver.ChaincodeInvocation {
227+ i .MatchEndorsementPolicy = true
228+ return i
229+ }
230+
151231func (i * Invoke ) WithSignerIdentity (id view.Identity ) driver.ChaincodeInvocation {
152232 i .SignerIdentity = id
153233 return i
@@ -168,6 +248,16 @@ func (i *Invoke) WithTxID(id driver.TxID) driver.ChaincodeInvocation {
168248 return i
169249}
170250
251+ func (i * Invoke ) WithNumRetries (numRetries uint ) driver.ChaincodeInvocation {
252+ i .NumRetries = int (numRetries )
253+ return i
254+ }
255+
256+ func (i * Invoke ) WithRetrySleep (duration time.Duration ) driver.ChaincodeInvocation {
257+ i .RetrySleep = duration
258+ return i
259+ }
260+
171261func (i * Invoke ) prepare (query bool ) (string , * pb.Proposal , []* pb.ProposalResponse , driver.SigningIdentity , error ) {
172262 // TODO: improve by providing grpc connection pool
173263 var peerClients []peer2.Client
0 commit comments