Skip to content

Commit

Permalink
Use repeated bytes instead of repeated string for chaincode call args
Browse files Browse the repository at this point in the history
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 <gabor@digitalasset.com>
  • Loading branch information
gaborh-da committed Aug 10, 2016
1 parent c950903 commit fd498d2
Show file tree
Hide file tree
Showing 34 changed files with 361 additions and 298 deletions.
7 changes: 3 additions & 4 deletions bddtests/peer_basic.feature
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,7 @@ Feature: Network of Peers

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

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

Scenario: chaincode example 01 single peer rejection message
Given we compose "docker-compose-1-exp.yml"
Expand Down
27 changes: 16 additions & 11 deletions bddtests/steps/peer_basic_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import time
import copy
from datetime import datetime, timedelta
import base64

import sys, requests, json

Expand Down Expand Up @@ -194,7 +195,6 @@ def getArgsFromContext(context):
if 'table' in context:
# There is ctor arguments
args = context.table[0].cells

return args

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

def createChaincodeSpec(context, chaincode):
chaincode = validateChaincodeDictionary(chaincode)

args = to_bytes(prepend(chaincode["constructor"], chaincode["args"]))
# Create a ChaincodeSpec structure
chaincodeSpec = {
"type": getChaincodeTypeValue(chaincode["language"]),
"chaincodeID": {
"path" : chaincode["path"],
"name" : chaincode["name"]
},
"ctorMsg": {
"function" : chaincode["constructor"],
"args" : chaincode["args"]
"args" : args
},
}

Expand Down Expand Up @@ -365,14 +365,12 @@ def invokeChaincode(context, devopsFunc, functionName, containerName, idGenAlg=N
if 'table' in context:
# There is ctor arguments
args = context.table[0].cells

args = to_bytes(prepend(functionName, args))
for idx, attr in enumerate(attributes):
attributes[idx] = attr.strip()

context.chaincodeSpec['ctorMsg']['function'] = functionName
context.chaincodeSpec['ctorMsg']['args'] = args
context.chaincodeSpec['attributes'] = attributes

#If idGenAlg is passed then, we still using the deprecated devops API because this parameter can't be passed in the new API.
if idGenAlg != None:
invokeUsingDevopsService(context, devopsFunc, functionName, containerName, idGenAlg)
Expand Down Expand Up @@ -424,14 +422,14 @@ def invokeMasterChaincode(context, devopsFunc, chaincodeName, functionName, cont
args = []
if 'table' in context:
args = context.table[0].cells
args = to_bytes(prepend(functionName, args))
typeGolang = 1
chaincodeSpec = {
"type": typeGolang,
"chaincodeID": {
"name" : chaincodeName
},
"ctorMsg": {
"function" : functionName,
"args" : args
}
}
Expand Down Expand Up @@ -646,7 +644,7 @@ def step_impl(context, chaincodeName, functionName):
if 'table' in context:
# There is ctor arguments
args = context.table[0].cells
context.chaincodeSpec['ctorMsg']['function'] = functionName
args = to_bytes(prepend(functionName, args))
context.chaincodeSpec['ctorMsg']['args'] = args #context.table[0].cells if ('table' in context) else []
# Invoke the POST
chaincodeOpPayload = createChaincodeOpPayload("query", context.chaincodeSpec)
Expand Down Expand Up @@ -678,8 +676,7 @@ def query_common(context, chaincodeName, functionName, value, failOnError):
containerDataList = bdd_test_util.getContainerDataValuesFromContext(context, aliases, lambda containerData: containerData)

# Update the chaincodeSpec ctorMsg for invoke
context.chaincodeSpec['ctorMsg']['function'] = functionName
context.chaincodeSpec['ctorMsg']['args'] = [value]
context.chaincodeSpec['ctorMsg']['args'] = to_bytes([functionName, value])
# Invoke the POST
# Make deep copy of chaincodeSpec as we will be changing the SecurityContext per call.
chaincodeOpPayload = createChaincodeOpPayload("query", copy.deepcopy(context.chaincodeSpec))
Expand Down Expand Up @@ -819,3 +816,11 @@ def compose_op(context, op):
else:
parseComposeOutput(context)
print("After {0}ing, the container service list is = {1}".format(op, [containerData.composeService for containerData in context.compose_containers]))

def to_bytes(strlist):
return [base64.standard_b64encode(s.encode('ascii')) for s in strlist]

def prepend(elem, l):
if l is None or l == "":
return [elem]
return [elem] + l
11 changes: 3 additions & 8 deletions bddtests/syschaincode/noop/chaincode.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@
package noop

import (
"encoding/base64"
"bytes"
"errors"
"fmt"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/core/chaincode/shim"
Expand Down Expand Up @@ -95,12 +94,8 @@ func (t *SystemChaincode) Query(stub *shim.ChaincodeStub, function string, args
if nil != merr {
return nil, merr
}
var data = newCCIS.ChaincodeSpec.CtorMsg.Args[0]
var dataInByteForm, b64err = base64.StdEncoding.DecodeString(data)
if b64err != nil {
return nil, fmt.Errorf("Error in decoding from Base64: %s", b64err)
}
return dataInByteForm, nil
var dataInByteForm = newCCIS.ChaincodeSpec.CtorMsg.Args
return bytes.Join(dataInByteForm, []byte{}), nil
default:
return nil, errors.New("Unsupported operation")
}
Expand Down
3 changes: 2 additions & 1 deletion bddtests/syschaincode/noop/chaincode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"testing"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos"
)

Expand Down Expand Up @@ -115,7 +116,7 @@ func (ml mockLedger) GetTransactionByID(txID string) (*protos.Transaction, error
if txID == "noSuchTX" {
return nil, fmt.Errorf("Some error")
}
newCCIS := &protos.ChaincodeInvocationSpec{ChaincodeSpec: &protos.ChaincodeSpec{CtorMsg: &protos.ChaincodeInput{Function: "execute", Args: []string{something}}}}
newCCIS := &protos.ChaincodeInvocationSpec{ChaincodeSpec: &protos.ChaincodeSpec{CtorMsg: &protos.ChaincodeInput{Args: shim.ToChaincodeArgs("execute", something)}}}
pl, _ := proto.Marshal(newCCIS)
return &protos.Transaction{Payload: pl}, nil
}
12 changes: 5 additions & 7 deletions core/chaincode/chaincode_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ func (chaincodeSupport *ChaincodeSupport) deregisterHandler(chaincodehandler *Ha
}

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

var notfy chan *pb.ChaincodeMessage
var err error
if notfy, err = chrte.handler.initOrReady(txid, f, initArgs, tx, depTx); err != nil {
if notfy, err = chrte.handler.initOrReady(txid, initArgs, tx, depTx); err != nil {
return fmt.Errorf("Error sending %s: %s", pb.ChaincodeMessage_INIT, err)
}
if notfy != nil {
Expand Down Expand Up @@ -411,9 +411,8 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, t *pb.
//build the chaincode
var cID *pb.ChaincodeID
var cMsg *pb.ChaincodeInput
var f *string
var cLang pb.ChaincodeSpec_Type
var initargs []string
var initargs [][]byte

cds := &pb.ChaincodeDeploymentSpec{}
if t.Type == pb.Transaction_CHAINCODE_DEPLOY {
Expand All @@ -424,7 +423,6 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, t *pb.
cID = cds.ChaincodeSpec.ChaincodeID
cMsg = cds.ChaincodeSpec.CtorMsg
cLang = cds.ChaincodeSpec.Type
f = &cMsg.Function
initargs = cMsg.Args
} else if t.Type == pb.Transaction_CHAINCODE_INVOKE || t.Type == pb.Transaction_CHAINCODE_QUERY {
ci := &pb.ChaincodeInvocationSpec{}
Expand Down Expand Up @@ -522,8 +520,8 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, t *pb.
}

if err == nil {
//send init (if (f,args)) and wait for ready state
err = chaincodeSupport.sendInitOrReady(context, t.Txid, chaincode, f, initargs, chaincodeSupport.ccStartupTimeout, t, depTx)
//send init (if (args)) and wait for ready state
err = chaincodeSupport.sendInitOrReady(context, t.Txid, chaincode, initargs, chaincodeSupport.ccStartupTimeout, t, depTx)
if err != nil {
chaincodeLogger.Errorf("sending init failed(%s)", err)
err = fmt.Errorf("Failed to init chaincode(%s)", err)
Expand Down

0 comments on commit fd498d2

Please sign in to comment.