Skip to content

Commit 7415b02

Browse files
authored
chaincode configuration (#440)
Signed-off-by: Angelo De Caro <[email protected]>
1 parent 1e8a007 commit 7415b02

File tree

19 files changed

+405
-101
lines changed

19 files changed

+405
-101
lines changed

docs/core-fabric.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ fabric:
304304
# whether this is the default channel or not
305305
# TBD: What is the meaning of a default channel ?
306306
default: true
307+
numRetries: 3 # number of retries on a chaincode operation failure
308+
retrySleep: 1s # waiting time before retry again a failed chaincode operation
307309
chaincodes:
308310
# chaincode id
309311
- name: mychaincode

integration/fabric/atsa/chaincode/views/assets.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package views
88

99
import (
1010
"encoding/json"
11+
"time"
1112

1213
"github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/chaincode"
1314
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/assert"
@@ -33,7 +34,7 @@ func (c *CreateAssetView) Call(context view.Context) (interface{}, error) {
3334
"CreateAsset",
3435
c.AssetProperties.ID,
3536
c.PublicDescription,
36-
).WithTransientEntry("asset_properties", apRaw).WithEndorsersFromMyOrg(),
37+
).WithTransientEntry("asset_properties", apRaw).WithEndorsersFromMyOrg().WithNumRetries(2).WithRetrySleep(2 * time.Second),
3738
)
3839
assert.NoError(err, "failed creating asset")
3940

@@ -58,7 +59,10 @@ type ReadAssetView struct {
5859
}
5960

6061
func (r *ReadAssetView) Call(context view.Context) (interface{}, error) {
61-
res, err := context.RunView(chaincode.NewQueryView("asset_transfer", "ReadAsset", r.ID).WithEndorsersFromMyOrg())
62+
res, err := context.RunView(
63+
chaincode.NewQueryView(
64+
"asset_transfer", "ReadAsset", r.ID,
65+
).WithEndorsersFromMyOrg().WithNumRetries(2).WithRetrySleep(2 * time.Second).WithMatchEndorsementPolicy())
6266
assert.NoError(err, "failed reading asset")
6367
return res, nil
6468
}

integration/fabric/fpc/echo/views/echo.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package views
88

99
import (
1010
"encoding/json"
11+
"time"
1112

1213
"github.com/hyperledger-labs/fabric-smart-client/platform/fabric"
1314
"github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/chaincode"
@@ -100,7 +101,7 @@ func (e *EchoView) Call(context view.Context) (interface{}, error) {
100101
fpc.StringsToArgs(e.Args)...,
101102
).WithSignerIdentity(
102103
fabric.GetDefaultFNS(context).LocalMembership().AnonymousIdentity(),
103-
).Endorse(context)
104+
).WithNumRetries(4).WithRetrySleep(2 * time.Second).Endorse(context)
104105
assert.NoError(err, "failed endorsing echo")
105106
assert.Equal(e.Function, string(res))
106107
assert.NoError(fabric.GetDefaultFNS(context).Ordering().Broadcast(envelope))

integration/nwo/fabric/topology/core_template.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ fabric:
298298
channels: {{ range .Channels }}
299299
- name: {{ .Name }}
300300
default: {{ .Default }}
301+
numRetries: 3
302+
retrySleep: 1s
301303
chaincodes: {{range Chaincodes .Name }}
302304
- name: {{ .Chaincode.Name }}
303305
private: {{ .Private }}

platform/fabric/chaincode.go

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package fabric
88

99
import (
1010
"encoding/json"
11+
"time"
1112

1213
"github.com/hyperledger-labs/fabric-smart-client/platform/fabric/driver"
1314
"github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
@@ -82,7 +83,7 @@ func (c *Chaincode) Query(function string, args ...interface{}) *ChaincodeQuery
8283
}
8384

8485
func (c *Chaincode) Endorse(function string, args ...interface{}) *ChaincodeEndorse {
85-
ci := &ChaincodeEndorse{ci: c.chaincode.NewInvocation(function, args...)}
86+
ci := &ChaincodeEndorse{ChaincodeInvocation: c.chaincode.NewInvocation(function, args...)}
8687
ci.WithInvokerIdentity(c.fns.LocalMembership().DefaultIdentity())
8788
return ci
8889
}
@@ -163,6 +164,18 @@ func (i *ChaincodeInvocation) WithInvokerIdentity(id view.Identity) *ChaincodeIn
163164
return i
164165
}
165166

167+
// WithNumRetries sets the number of times the chaincode operation should be retried before returning a failure
168+
func (i *ChaincodeInvocation) WithNumRetries(numRetries uint) *ChaincodeInvocation {
169+
i.ChaincodeInvocation.WithNumRetries(numRetries)
170+
return i
171+
}
172+
173+
// WithRetrySleep sets the time interval between each retry
174+
func (i *ChaincodeInvocation) WithRetrySleep(duration time.Duration) *ChaincodeInvocation {
175+
i.ChaincodeInvocation.WithRetrySleep(duration)
176+
return i
177+
}
178+
166179
type ChaincodeQuery struct {
167180
driver.ChaincodeInvocation
168181
}
@@ -206,47 +219,78 @@ func (i *ChaincodeQuery) WithTxID(id TxID) *ChaincodeQuery {
206219
return i
207220
}
208221

222+
// WithMatchEndorsementPolicy enforces that the query is perfomed against a set of peers that satisfy the
223+
// endorsement policy of the chaincode
224+
func (i *ChaincodeQuery) WithMatchEndorsementPolicy() *ChaincodeQuery {
225+
i.ChaincodeInvocation.WithMatchEndorsementPolicy()
226+
return i
227+
}
228+
229+
// WithNumRetries sets the number of times the chaincode operation should be retried before returning a failure
230+
func (i *ChaincodeQuery) WithNumRetries(numRetries uint) *ChaincodeQuery {
231+
i.ChaincodeInvocation.WithNumRetries(numRetries)
232+
return i
233+
}
234+
235+
// WithRetrySleep sets the time interval between each retry
236+
func (i *ChaincodeQuery) WithRetrySleep(duration time.Duration) *ChaincodeQuery {
237+
i.ChaincodeInvocation.WithRetrySleep(duration)
238+
return i
239+
}
240+
209241
type ChaincodeEndorse struct {
210-
ci driver.ChaincodeInvocation
242+
ChaincodeInvocation driver.ChaincodeInvocation
211243
}
212244

213245
func (i *ChaincodeEndorse) Call() (*Envelope, error) {
214-
env, err := i.ci.Endorse()
246+
env, err := i.ChaincodeInvocation.Endorse()
215247
if err != nil {
216248
return nil, err
217249
}
218250
return &Envelope{e: env}, nil
219251
}
220252

221253
func (i *ChaincodeEndorse) WithTransientEntry(k string, v interface{}) *ChaincodeEndorse {
222-
i.ci.WithTransientEntry(k, v)
254+
i.ChaincodeInvocation.WithTransientEntry(k, v)
223255
return i
224256
}
225257

226258
func (i *ChaincodeEndorse) WithEndorsersByMSPIDs(mspIDs ...string) *ChaincodeEndorse {
227-
i.ci.WithEndorsersByMSPIDs(mspIDs...)
259+
i.ChaincodeInvocation.WithEndorsersByMSPIDs(mspIDs...)
228260
return i
229261
}
230262

231263
func (i *ChaincodeEndorse) WithEndorsersFromMyOrg() *ChaincodeEndorse {
232-
i.ci.WithEndorsersFromMyOrg()
264+
i.ChaincodeInvocation.WithEndorsersFromMyOrg()
233265
return i
234266
}
235267

236268
func (i *ChaincodeEndorse) WithInvokerIdentity(id view.Identity) *ChaincodeEndorse {
237-
i.ci.WithSignerIdentity(id)
269+
i.ChaincodeInvocation.WithSignerIdentity(id)
238270
return i
239271
}
240272

241273
func (i *ChaincodeEndorse) WithTxID(id TxID) *ChaincodeEndorse {
242-
i.ci.WithTxID(driver.TxID{
274+
i.ChaincodeInvocation.WithTxID(driver.TxID{
243275
Nonce: id.Nonce,
244276
Creator: id.Creator,
245277
})
246278
return i
247279
}
248280

249281
func (i *ChaincodeEndorse) WithImplicitCollections(mspIDs ...string) *ChaincodeEndorse {
250-
i.ci.WithImplicitCollections(mspIDs...)
282+
i.ChaincodeInvocation.WithImplicitCollections(mspIDs...)
283+
return i
284+
}
285+
286+
// WithNumRetries sets the number of times the chaincode operation should be retried before returning a failure
287+
func (i *ChaincodeEndorse) WithNumRetries(numRetries uint) *ChaincodeEndorse {
288+
i.ChaincodeInvocation.WithNumRetries(numRetries)
289+
return i
290+
}
291+
292+
// WithRetrySleep sets the time interval between each retry
293+
func (i *ChaincodeEndorse) WithRetrySleep(duration time.Duration) *ChaincodeEndorse {
294+
i.ChaincodeInvocation.WithRetrySleep(duration)
251295
return i
252296
}

platform/fabric/core/generic/chaincode/chaincode.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,35 @@ package chaincode
88

99
import (
1010
"sync"
11+
"time"
1112

1213
"github.com/ReneKroon/ttlcache/v2"
1314
"github.com/hyperledger-labs/fabric-smart-client/platform/fabric/driver"
1415
"github.com/hyperledger-labs/fabric-smart-client/platform/view"
1516
)
1617

1718
type Chaincode struct {
18-
name string
19-
sp view.ServiceProvider
20-
network Network
21-
channel Channel
19+
name string
20+
sp view.ServiceProvider
21+
network Network
22+
channel Channel
23+
NumRetries uint
24+
RetrySleep time.Duration
2225

2326
discoveryResultsCacheLock sync.RWMutex
2427
discoveryResultsCache ttlcache.SimpleCache
2528
}
2629

2730
func NewChaincode(name string, sp view.ServiceProvider, network Network, channel Channel) *Chaincode {
2831
return &Chaincode{
29-
name: name,
30-
sp: sp,
31-
network: network,
32-
channel: channel,
33-
discoveryResultsCache: ttlcache.NewCache(),
32+
name: name,
33+
sp: sp,
34+
network: network,
35+
channel: channel,
36+
NumRetries: channel.Config().NumRetries,
37+
RetrySleep: channel.Config().RetrySleep,
38+
discoveryResultsCacheLock: sync.RWMutex{},
39+
discoveryResultsCache: ttlcache.NewCache(),
3440
}
3541
}
3642

platform/fabric/core/generic/chaincode/invoke.go

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ SPDX-License-Identifier: Apache-2.0
77
package chaincode
88

99
import (
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

4954
func 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

6168
func (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

81103
func (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

96156
func (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+
151231
func (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+
171261
func (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

Comments
 (0)