Skip to content

Commit fd498d2

Browse files
committed
Use repeated bytes instead of repeated string for chaincode call args
This allows applications to easily pass arbitrary blobs without having to serialize them to strings. At the same time, we also consolidate the function argument to be part of the repeated bytes args. For convenience and to simplify porting of existing chaincode to the new argument format, we introduce helper functions in the shim which cast between ([][]byte) and (string, []string). Change-Id: I67562523a208727157c4767e86e1ef437e997f13 Signed-off-by: Gabor Hosszu <[email protected]>
1 parent c950903 commit fd498d2

34 files changed

+361
-298
lines changed

bddtests/peer_basic.feature

+3-4
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,7 @@ Feature: Network of Peers
349349

350350
# @doNotDecompose
351351
# @wip
352-
# Arg[0] = a, base64 = 'YQ=='
353-
# sha256 = 'acfb280369a87a57b1954210081d78943f1a0adb5368184984e8852a42c14df8'
352+
# sha256 = '53a54f606b9cc14ae2825cc50736b183cf8d6fd0131b9d3176997efcf77d775f'
354353
# calculated using all the args
355354
Scenario: chaincode map single peer content generated ID
356355
Given we compose "docker-compose-1.yml"
@@ -364,10 +363,10 @@ Feature: Network of Peers
364363

365364
When I invoke chaincode "map" function name "put" on "vp0" with "sha256"
366365
| arg1 |arg2|
367-
| YQ== | 10 |
366+
| a | 10 |
368367
Then I should have received a transactionID
369368
Then I wait up to "25" seconds for transaction to be committed to all peers
370-
Then I check the transaction ID if it is "acfb280369a87a57b1954210081d78943f1a0adb5368184984e8852a42c14df8"
369+
Then I check the transaction ID if it is "cbe63379a50f0c9d798951e5ccdf70a5c341acda508d7fa1345841d977825f71"
371370

372371
Scenario: chaincode example 01 single peer rejection message
373372
Given we compose "docker-compose-1-exp.yml"

bddtests/steps/peer_basic_impl.py

+16-11
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import time
2121
import copy
2222
from datetime import datetime, timedelta
23+
import base64
2324

2425
import sys, requests, json
2526

@@ -194,7 +195,6 @@ def getArgsFromContext(context):
194195
if 'table' in context:
195196
# There is ctor arguments
196197
args = context.table[0].cells
197-
198198
return args
199199

200200
@when(u'I deploy chaincode "{chaincodePath}" with ctor "{ctor}" to "{containerName}"')
@@ -239,16 +239,16 @@ def deployChainCodeToContainer(context, chaincode, containerName):
239239

240240
def createChaincodeSpec(context, chaincode):
241241
chaincode = validateChaincodeDictionary(chaincode)
242-
242+
args = to_bytes(prepend(chaincode["constructor"], chaincode["args"]))
243+
# Create a ChaincodeSpec structure
243244
chaincodeSpec = {
244245
"type": getChaincodeTypeValue(chaincode["language"]),
245246
"chaincodeID": {
246247
"path" : chaincode["path"],
247248
"name" : chaincode["name"]
248249
},
249250
"ctorMsg": {
250-
"function" : chaincode["constructor"],
251-
"args" : chaincode["args"]
251+
"args" : args
252252
},
253253
}
254254

@@ -365,14 +365,12 @@ def invokeChaincode(context, devopsFunc, functionName, containerName, idGenAlg=N
365365
if 'table' in context:
366366
# There is ctor arguments
367367
args = context.table[0].cells
368-
368+
args = to_bytes(prepend(functionName, args))
369369
for idx, attr in enumerate(attributes):
370370
attributes[idx] = attr.strip()
371371

372-
context.chaincodeSpec['ctorMsg']['function'] = functionName
373372
context.chaincodeSpec['ctorMsg']['args'] = args
374373
context.chaincodeSpec['attributes'] = attributes
375-
376374
#If idGenAlg is passed then, we still using the deprecated devops API because this parameter can't be passed in the new API.
377375
if idGenAlg != None:
378376
invokeUsingDevopsService(context, devopsFunc, functionName, containerName, idGenAlg)
@@ -424,14 +422,14 @@ def invokeMasterChaincode(context, devopsFunc, chaincodeName, functionName, cont
424422
args = []
425423
if 'table' in context:
426424
args = context.table[0].cells
425+
args = to_bytes(prepend(functionName, args))
427426
typeGolang = 1
428427
chaincodeSpec = {
429428
"type": typeGolang,
430429
"chaincodeID": {
431430
"name" : chaincodeName
432431
},
433432
"ctorMsg": {
434-
"function" : functionName,
435433
"args" : args
436434
}
437435
}
@@ -646,7 +644,7 @@ def step_impl(context, chaincodeName, functionName):
646644
if 'table' in context:
647645
# There is ctor arguments
648646
args = context.table[0].cells
649-
context.chaincodeSpec['ctorMsg']['function'] = functionName
647+
args = to_bytes(prepend(functionName, args))
650648
context.chaincodeSpec['ctorMsg']['args'] = args #context.table[0].cells if ('table' in context) else []
651649
# Invoke the POST
652650
chaincodeOpPayload = createChaincodeOpPayload("query", context.chaincodeSpec)
@@ -678,8 +676,7 @@ def query_common(context, chaincodeName, functionName, value, failOnError):
678676
containerDataList = bdd_test_util.getContainerDataValuesFromContext(context, aliases, lambda containerData: containerData)
679677

680678
# Update the chaincodeSpec ctorMsg for invoke
681-
context.chaincodeSpec['ctorMsg']['function'] = functionName
682-
context.chaincodeSpec['ctorMsg']['args'] = [value]
679+
context.chaincodeSpec['ctorMsg']['args'] = to_bytes([functionName, value])
683680
# Invoke the POST
684681
# Make deep copy of chaincodeSpec as we will be changing the SecurityContext per call.
685682
chaincodeOpPayload = createChaincodeOpPayload("query", copy.deepcopy(context.chaincodeSpec))
@@ -819,3 +816,11 @@ def compose_op(context, op):
819816
else:
820817
parseComposeOutput(context)
821818
print("After {0}ing, the container service list is = {1}".format(op, [containerData.composeService for containerData in context.compose_containers]))
819+
820+
def to_bytes(strlist):
821+
return [base64.standard_b64encode(s.encode('ascii')) for s in strlist]
822+
823+
def prepend(elem, l):
824+
if l is None or l == "":
825+
return [elem]
826+
return [elem] + l

bddtests/syschaincode/noop/chaincode.go

+3-8
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717
package noop
1818

1919
import (
20-
"encoding/base64"
20+
"bytes"
2121
"errors"
22-
"fmt"
2322

2423
"github.com/golang/protobuf/proto"
2524
"github.com/hyperledger/fabric/core/chaincode/shim"
@@ -95,12 +94,8 @@ func (t *SystemChaincode) Query(stub *shim.ChaincodeStub, function string, args
9594
if nil != merr {
9695
return nil, merr
9796
}
98-
var data = newCCIS.ChaincodeSpec.CtorMsg.Args[0]
99-
var dataInByteForm, b64err = base64.StdEncoding.DecodeString(data)
100-
if b64err != nil {
101-
return nil, fmt.Errorf("Error in decoding from Base64: %s", b64err)
102-
}
103-
return dataInByteForm, nil
97+
var dataInByteForm = newCCIS.ChaincodeSpec.CtorMsg.Args
98+
return bytes.Join(dataInByteForm, []byte{}), nil
10499
default:
105100
return nil, errors.New("Unsupported operation")
106101
}

bddtests/syschaincode/noop/chaincode_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"testing"
2222

2323
"github.com/golang/protobuf/proto"
24+
"github.com/hyperledger/fabric/core/chaincode/shim"
2425
"github.com/hyperledger/fabric/protos"
2526
)
2627

@@ -115,7 +116,7 @@ func (ml mockLedger) GetTransactionByID(txID string) (*protos.Transaction, error
115116
if txID == "noSuchTX" {
116117
return nil, fmt.Errorf("Some error")
117118
}
118-
newCCIS := &protos.ChaincodeInvocationSpec{ChaincodeSpec: &protos.ChaincodeSpec{CtorMsg: &protos.ChaincodeInput{Function: "execute", Args: []string{something}}}}
119+
newCCIS := &protos.ChaincodeInvocationSpec{ChaincodeSpec: &protos.ChaincodeSpec{CtorMsg: &protos.ChaincodeInput{Args: shim.ToChaincodeArgs("execute", something)}}}
119120
pl, _ := proto.Marshal(newCCIS)
120121
return &protos.Transaction{Payload: pl}, nil
121122
}

core/chaincode/chaincode_support.go

+5-7
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ func (chaincodeSupport *ChaincodeSupport) deregisterHandler(chaincodehandler *Ha
243243
}
244244

245245
// Based on state of chaincode send either init or ready to move to ready state
246-
func (chaincodeSupport *ChaincodeSupport) sendInitOrReady(context context.Context, txid string, chaincode string, f *string, initArgs []string, timeout time.Duration, tx *pb.Transaction, depTx *pb.Transaction) error {
246+
func (chaincodeSupport *ChaincodeSupport) sendInitOrReady(context context.Context, txid string, chaincode string, initArgs [][]byte, timeout time.Duration, tx *pb.Transaction, depTx *pb.Transaction) error {
247247
chaincodeSupport.runningChaincodes.Lock()
248248
//if its in the map, there must be a connected stream...nothing to do
249249
var chrte *chaincodeRTEnv
@@ -257,7 +257,7 @@ func (chaincodeSupport *ChaincodeSupport) sendInitOrReady(context context.Contex
257257

258258
var notfy chan *pb.ChaincodeMessage
259259
var err error
260-
if notfy, err = chrte.handler.initOrReady(txid, f, initArgs, tx, depTx); err != nil {
260+
if notfy, err = chrte.handler.initOrReady(txid, initArgs, tx, depTx); err != nil {
261261
return fmt.Errorf("Error sending %s: %s", pb.ChaincodeMessage_INIT, err)
262262
}
263263
if notfy != nil {
@@ -411,9 +411,8 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, t *pb.
411411
//build the chaincode
412412
var cID *pb.ChaincodeID
413413
var cMsg *pb.ChaincodeInput
414-
var f *string
415414
var cLang pb.ChaincodeSpec_Type
416-
var initargs []string
415+
var initargs [][]byte
417416

418417
cds := &pb.ChaincodeDeploymentSpec{}
419418
if t.Type == pb.Transaction_CHAINCODE_DEPLOY {
@@ -424,7 +423,6 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, t *pb.
424423
cID = cds.ChaincodeSpec.ChaincodeID
425424
cMsg = cds.ChaincodeSpec.CtorMsg
426425
cLang = cds.ChaincodeSpec.Type
427-
f = &cMsg.Function
428426
initargs = cMsg.Args
429427
} else if t.Type == pb.Transaction_CHAINCODE_INVOKE || t.Type == pb.Transaction_CHAINCODE_QUERY {
430428
ci := &pb.ChaincodeInvocationSpec{}
@@ -522,8 +520,8 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, t *pb.
522520
}
523521

524522
if err == nil {
525-
//send init (if (f,args)) and wait for ready state
526-
err = chaincodeSupport.sendInitOrReady(context, t.Txid, chaincode, f, initargs, chaincodeSupport.ccStartupTimeout, t, depTx)
523+
//send init (if (args)) and wait for ready state
524+
err = chaincodeSupport.sendInitOrReady(context, t.Txid, chaincode, initargs, chaincodeSupport.ccStartupTimeout, t, depTx)
527525
if err != nil {
528526
chaincodeLogger.Errorf("sending init failed(%s)", err)
529527
err = fmt.Errorf("Failed to init chaincode(%s)", err)

0 commit comments

Comments
 (0)