Skip to content

Commit 17219e2

Browse files
author
Srinivasan Muralidharan
committed
FAB-2767 expose chaincode timeout as a property
https://jira.hyperledger.org/browse/FAB-2767 The new property "chaincode.executetimeout" (CORE_CHAINCODE_EXECUTETIMEOUT) can be used override the default value of 30000ms (30 secs) for Init and Invoke methods to wait. The value should be at least 1000ms This was tested by setting CORE_CHAINCODE_EXECUTETIMEOUT=1000 and using "sleeper" chaincode to sleep for less than and greater than 1000ms with expected results of success and failure respectively. Change-Id: Icc02d4c83c1e389283dd57a7d35a694085e38f56 Signed-off-by: Srinivasan Muralidharan <[email protected]>
1 parent b096016 commit 17219e2

File tree

4 files changed

+142
-5
lines changed

4 files changed

+142
-5
lines changed

core/chaincode/chaincode_support.go

+12
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,17 @@ func NewChaincodeSupport(getPeerEndpoint func() (*pb.PeerEndpoint, error), userr
168168
theChaincodeSupport.keepalive = time.Duration(t) * time.Second
169169
}
170170

171+
//default chaincode execute timeout is 30000ms (30 secs)
172+
execto := 30000
173+
if eto := viper.GetInt("chaincode.executetimeout"); eto <= 1000 {
174+
chaincodeLogger.Errorf("Invalid execute timeout value %d (should be at least 1000ms) defaulting to %d ms", eto, execto)
175+
} else {
176+
chaincodeLogger.Debugf("Setting execute timeout value to %d ms", eto)
177+
execto = eto
178+
}
179+
180+
theChaincodeSupport.executetimeout = time.Duration(execto) * time.Millisecond
181+
171182
viper.SetEnvPrefix("CORE")
172183
viper.AutomaticEnv()
173184
replacer := strings.NewReplacer(".", "_")
@@ -208,6 +219,7 @@ type ChaincodeSupport struct {
208219
keepalive time.Duration
209220
chaincodeLogLevel string
210221
logFormat string
222+
executetimeout time.Duration
211223
}
212224

213225
// DuplicateChaincodeHandlerError returned if attempt to register same chaincodeID while a stream already exists.

core/chaincode/exectransaction.go

+1-5
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package chaincode
1919
import (
2020
"errors"
2121
"fmt"
22-
"time"
2322

2423
"github.com/golang/protobuf/proto"
2524
"golang.org/x/net/context"
@@ -57,9 +56,6 @@ func Execute(ctxt context.Context, cccid *ccprovider.CCContext, spec interface{}
5756
return nil, nil, fmt.Errorf("Failed to stablish stream to container %s", chaincode)
5857
}
5958

60-
// TODO: Need to comment next line and uncomment call to getTimeout, when transaction blocks are being created
61-
timeout := time.Duration(30000) * time.Millisecond
62-
6359
if err != nil {
6460
return nil, nil, fmt.Errorf("Failed to retrieve chaincode spec(%s)", err)
6561
}
@@ -70,7 +66,7 @@ func Execute(ctxt context.Context, cccid *ccprovider.CCContext, spec interface{}
7066
return nil, nil, fmt.Errorf("Failed to transaction message(%s)", err)
7167
}
7268

73-
resp, err := theChaincodeSupport.Execute(ctxt, cccid, ccMsg, timeout)
69+
resp, err := theChaincodeSupport.Execute(ctxt, cccid, ccMsg, theChaincodeSupport.executetimeout)
7470
if err != nil {
7571
// Rollback transaction
7672
return nil, nil, fmt.Errorf("Failed to execute transaction (%s)", err)
+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
Copyright IBM Corp. 2016 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package main
18+
19+
// Sleeper chaincode sleeps and works with one state variable
20+
// Init - 1 param, a sleep time in millisecs
21+
// Invoke - 4 or 3 params, "put" or "get", value to set and sleep time in millisecs
22+
//
23+
// Sleeper can be used to test the "chaincode.executetimeout" property
24+
25+
import (
26+
"fmt"
27+
"strconv"
28+
"time"
29+
30+
"github.com/hyperledger/fabric/core/chaincode/shim"
31+
pb "github.com/hyperledger/fabric/protos/peer"
32+
)
33+
34+
// SleeperChaincode example simple Chaincode implementation
35+
type SleeperChaincode struct {
36+
}
37+
38+
func (t *SleeperChaincode) sleep(sleepTime string) {
39+
st, _ := strconv.Atoi(sleepTime)
40+
if st >= 0 {
41+
time.Sleep(time.Duration(st) * time.Millisecond)
42+
}
43+
}
44+
45+
// Init initializes chaincode...all it does is sleep a bi
46+
func (t *SleeperChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
47+
args := stub.GetStringArgs()
48+
49+
if len(args) != 1 {
50+
return shim.Error("Incorrect number of arguments. Expecting 1")
51+
}
52+
53+
sleepTime := args[0]
54+
55+
t.sleep(sleepTime)
56+
57+
return shim.Success(nil)
58+
}
59+
60+
// Invoke sets key/value and sleeps a bit
61+
func (t *SleeperChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
62+
function, args := stub.GetFunctionAndParameters()
63+
if function == "put" {
64+
if len(args) != 3 {
65+
return shim.Error("Incorrect number of arguments. Expecting 3")
66+
}
67+
68+
// Make payment of X units from A to B
69+
return t.invoke(stub, args)
70+
} else if function == "get" {
71+
if len(args) != 2 {
72+
return shim.Error("Incorrect number of arguments. Expecting 2")
73+
}
74+
75+
// the old "Query" is now implemtned in invoke
76+
return t.query(stub, args)
77+
}
78+
79+
return shim.Error("Invalid invoke function name. Expecting \"put\" or \"get\"")
80+
}
81+
82+
// Transaction makes payment of X units from A to B
83+
func (t *SleeperChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
84+
// set state
85+
key := args[0]
86+
val := args[1]
87+
88+
err := stub.PutState(key, []byte(val))
89+
if err != nil {
90+
return shim.Error(err.Error())
91+
}
92+
93+
sleepTime := args[2]
94+
95+
//sleep for a bit
96+
t.sleep(sleepTime)
97+
98+
return shim.Success([]byte("OK"))
99+
}
100+
101+
// query callback representing the query of a chaincode
102+
func (t *SleeperChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
103+
key := args[0]
104+
105+
// Get the state from the ledger
106+
val, err := stub.GetState(key)
107+
if err != nil {
108+
return shim.Error(err.Error())
109+
}
110+
111+
sleepTime := args[1]
112+
113+
//sleep for a bit
114+
t.sleep(sleepTime)
115+
116+
return shim.Success(val)
117+
}
118+
119+
func main() {
120+
err := shim.Start(new(SleeperChaincode))
121+
if err != nil {
122+
fmt.Printf("Error starting Sleeper chaincode: %s", err)
123+
}
124+
}

peer/core.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,11 @@ chaincode:
323323
# to come through. 1sec should be plenty for chaincode unit tests
324324
startuptimeout: 300000
325325

326+
# timeout in millisecs for invokes and initialize commands
327+
# this timeout is used by all chaincodes in all the channels including
328+
# system chaincodes. Default is 30000ms (30 seconds)
329+
executetimeout: 30000
330+
326331
#timeout in millisecs for deploying chaincode from a remote repository.
327332
deploytimeout: 30000
328333

0 commit comments

Comments
 (0)