diff --git a/bddtests/peer_basic.feature b/bddtests/peer_basic.feature index 0317a6fcc5f..35bf92bf4a2 100644 --- a/bddtests/peer_basic.feature +++ b/bddtests/peer_basic.feature @@ -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" @@ -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" diff --git a/bddtests/steps/peer_basic_impl.py b/bddtests/steps/peer_basic_impl.py index 1aa8951d14d..d0ca7e85ca3 100644 --- a/bddtests/steps/peer_basic_impl.py +++ b/bddtests/steps/peer_basic_impl.py @@ -20,6 +20,7 @@ import time import copy from datetime import datetime, timedelta +import base64 import sys, requests, json @@ -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}"') @@ -239,7 +239,8 @@ 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": { @@ -247,8 +248,7 @@ def createChaincodeSpec(context, chaincode): "name" : chaincode["name"] }, "ctorMsg": { - "function" : chaincode["constructor"], - "args" : chaincode["args"] + "args" : args }, } @@ -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) @@ -424,6 +422,7 @@ 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, @@ -431,7 +430,6 @@ def invokeMasterChaincode(context, devopsFunc, chaincodeName, functionName, cont "name" : chaincodeName }, "ctorMsg": { - "function" : functionName, "args" : args } } @@ -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) @@ -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)) @@ -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 diff --git a/bddtests/syschaincode/noop/chaincode.go b/bddtests/syschaincode/noop/chaincode.go index a4923615871..b1709d7552c 100644 --- a/bddtests/syschaincode/noop/chaincode.go +++ b/bddtests/syschaincode/noop/chaincode.go @@ -17,9 +17,8 @@ package noop import ( - "encoding/base64" + "bytes" "errors" - "fmt" "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/core/chaincode/shim" @@ -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") } diff --git a/bddtests/syschaincode/noop/chaincode_test.go b/bddtests/syschaincode/noop/chaincode_test.go index b9e51efdb00..7664329a6ac 100644 --- a/bddtests/syschaincode/noop/chaincode_test.go +++ b/bddtests/syschaincode/noop/chaincode_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/protos" ) @@ -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 } diff --git a/core/chaincode/chaincode_support.go b/core/chaincode/chaincode_support.go index 8c999def66f..0a081d71384 100644 --- a/core/chaincode/chaincode_support.go +++ b/core/chaincode/chaincode_support.go @@ -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 @@ -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 { @@ -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 { @@ -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{} @@ -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) diff --git a/core/chaincode/exectransaction_test.go b/core/chaincode/exectransaction_test.go index 9b5c312cc7f..bfd8705dbbc 100644 --- a/core/chaincode/exectransaction_test.go +++ b/core/chaincode/exectransaction_test.go @@ -28,6 +28,7 @@ import ( "path/filepath" + "github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/core/container" "github.com/hyperledger/fabric/core/container/ccintf" "github.com/hyperledger/fabric/core/crypto" @@ -338,8 +339,8 @@ func executeDeployTransaction(t *testing.T, url string) { var ctxt = context.Background() f := "init" - args := []string{"a", "100", "b", "200"} - spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Path: url}, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + args := shim.ToChaincodeArgs(f, "a", "100", "b", "200") + spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Path: url}, CtorMsg: &pb.ChaincodeInput{Args: args}} _, err = deploy(ctxt, spec) chaincodeID := spec.ChaincodeID.Name if err != nil { @@ -423,8 +424,8 @@ func checkFinalState(uuid string, chaincodeID string) error { func invokeExample02Transaction(ctxt context.Context, cID *pb.ChaincodeID, args []string, destroyImage bool) error { f := "init" - argsDeploy := []string{"a", "100", "b", "200"} - spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Function: f, Args: argsDeploy}} + argsDeploy := shim.ToChaincodeArgs(f, "a", "100", "b", "200") + spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: argsDeploy}} _, err := deploy(ctxt, spec) chaincodeID := spec.ChaincodeID.Name if err != nil { @@ -445,7 +446,8 @@ func invokeExample02Transaction(ctxt context.Context, cID *pb.ChaincodeID, args } f = "invoke" - spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + invokeArgs := append([]string{f}, args...) + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: shim.ToChaincodeArgs(invokeArgs...)}} _, uuid, _, err := invoke(ctxt, spec, pb.Transaction_CHAINCODE_INVOKE) if err != nil { return fmt.Errorf("Error invoking <%s>: %s", chaincodeID, err) @@ -458,8 +460,8 @@ func invokeExample02Transaction(ctxt context.Context, cID *pb.ChaincodeID, args // Test for delete state f = "delete" - delArgs := []string{"a"} - spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Function: f, Args: delArgs}} + delArgs := shim.ToChaincodeArgs(f, "a") + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: delArgs}} _, uuid, _, err = invoke(ctxt, spec, pb.Transaction_CHAINCODE_INVOKE) if err != nil { return fmt.Errorf("Error deleting state in <%s>: %s", chaincodeID, err) @@ -538,14 +540,14 @@ func exec(ctxt context.Context, chaincodeID string, numTrans int, numQueries int var spec *pb.ChaincodeSpec if typ == pb.Transaction_CHAINCODE_INVOKE { f := "invoke" - args := []string{"a", "b", "10"} + args := shim.ToChaincodeArgs(f, "a", "b", "10") - spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: chaincodeID}, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: chaincodeID}, CtorMsg: &pb.ChaincodeInput{Args: args}} } else { f := "query" - args := []string{"a"} + args := shim.ToChaincodeArgs(f, "a") - spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: chaincodeID}, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: chaincodeID}, CtorMsg: &pb.ChaincodeInput{Args: args}} } _, _, _, err := invoke(ctxt, spec, typ) @@ -613,9 +615,9 @@ func TestExecuteQuery(t *testing.T) { cID := &pb.ChaincodeID{Path: url} f := "init" - args := []string{"a", "100", "b", "200"} + args := shim.ToChaincodeArgs(f, "a", "100", "b", "200") - spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: args}} _, err = deploy(ctxt, spec) chaincodeID := spec.ChaincodeID.Name @@ -759,9 +761,9 @@ func TestExecuteInvalidQuery(t *testing.T) { cID := &pb.ChaincodeID{Path: url} f := "init" - args := []string{"a", "100"} + args := shim.ToChaincodeArgs(f, "a", "100") - spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: args}} _, err = deploy(ctxt, spec) chaincodeID := spec.ChaincodeID.Name @@ -776,9 +778,9 @@ func TestExecuteInvalidQuery(t *testing.T) { time.Sleep(time.Second) f = "query" - args = []string{"b", "200"} + args = shim.ToChaincodeArgs(f, "b", "200") - spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: args}} // This query should fail as it attempts to put state _, _, _, err = invoke(ctxt, spec, pb.Transaction_CHAINCODE_QUERY) @@ -832,9 +834,9 @@ func TestChaincodeInvokeChaincode(t *testing.T) { cID1 := &pb.ChaincodeID{Path: url1} f := "init" - args := []string{"a", "100", "b", "200"} + args := shim.ToChaincodeArgs(f, "a", "100", "b", "200") - spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Args: args}} _, err = deploy(ctxt, spec1) chaincodeID1 := spec1.ChaincodeID.Name @@ -853,9 +855,9 @@ func TestChaincodeInvokeChaincode(t *testing.T) { cID2 := &pb.ChaincodeID{Path: url2} f = "init" - args = []string{"e", "0"} + args = shim.ToChaincodeArgs(f, "e", "0") - spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}} _, err = deploy(ctxt, spec2) chaincodeID2 := spec2.ChaincodeID.Name @@ -872,9 +874,9 @@ func TestChaincodeInvokeChaincode(t *testing.T) { // Invoke second chaincode, which will inturn invoke the first chaincode f = "invoke" - args = []string{"e", "1"} + args = shim.ToChaincodeArgs(f, "e", "1") - spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}} // Invoke chaincode var uuid string _, uuid, _, err = invoke(ctxt, spec2, pb.Transaction_CHAINCODE_INVOKE) @@ -946,9 +948,9 @@ func TestChaincodeInvokeChaincodeErrorCase(t *testing.T) { cID1 := &pb.ChaincodeID{Path: url1} f := "init" - args := []string{"a", "100", "b", "200"} + args := shim.ToChaincodeArgs(f, "a", "100", "b", "200") - spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Args: args}} _, err = deploy(ctxt, spec1) chaincodeID1 := spec1.ChaincodeID.Name @@ -967,9 +969,9 @@ func TestChaincodeInvokeChaincodeErrorCase(t *testing.T) { cID2 := &pb.ChaincodeID{Path: url2} f = "init" - args = []string{""} + args = shim.ToChaincodeArgs(f) - spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}} _, err = deploy(ctxt, spec2) chaincodeID2 := spec2.ChaincodeID.Name @@ -986,9 +988,9 @@ func TestChaincodeInvokeChaincodeErrorCase(t *testing.T) { // Invoke second chaincode, which will inturn invoke the first chaincode but pass bad params f = chaincodeID1 - args = []string{"invoke", "a"} //expect {"invoke", "a","b","10"} + args = shim.ToChaincodeArgs(f, "invoke", "a") - spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}} // Invoke chaincode _, _, _, err = invoke(ctxt, spec2, pb.Transaction_CHAINCODE_INVOKE) @@ -1023,9 +1025,9 @@ func chaincodeQueryChaincode(user string) error { cID1 := &pb.ChaincodeID{Path: url1} f := "init" - args := []string{"a", "100", "b", "200"} + args := shim.ToChaincodeArgs(f, "a", "100", "b", "200") - spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}, SecureContext: user} + spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Args: args}, SecureContext: user} _, err := deploy(ctxt, spec1) chaincodeID1 := spec1.ChaincodeID.Name @@ -1041,9 +1043,9 @@ func chaincodeQueryChaincode(user string) error { cID2 := &pb.ChaincodeID{Path: url2} f = "init" - args = []string{"sum", "0"} + args = shim.ToChaincodeArgs(f, "sum", "0") - spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}, SecureContext: user} + spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}, SecureContext: user} _, err = deploy(ctxt, spec2) chaincodeID2 := spec2.ChaincodeID.Name @@ -1057,9 +1059,9 @@ func chaincodeQueryChaincode(user string) error { // Invoke second chaincode, which will inturn query the first chaincode f = "invoke" - args = []string{chaincodeID1, "sum"} + args = shim.ToChaincodeArgs(f, chaincodeID1, "sum") - spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}, SecureContext: user} + spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}, SecureContext: user} // Invoke chaincode var retVal []byte _, _, retVal, err = invoke(ctxt, spec2, pb.Transaction_CHAINCODE_INVOKE) @@ -1080,9 +1082,9 @@ func chaincodeQueryChaincode(user string) error { // Query second chaincode, which will inturn query the first chaincode f = "query" - args = []string{chaincodeID1, "sum"} + args = shim.ToChaincodeArgs(f, chaincodeID1, "sum") - spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}, SecureContext: user} + spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}, SecureContext: user} // Invoke chaincode _, _, retVal, err = invoke(ctxt, spec2, pb.Transaction_CHAINCODE_QUERY) @@ -1169,9 +1171,9 @@ func TestChaincodeQueryChaincodeErrorCase(t *testing.T) { cID1 := &pb.ChaincodeID{Path: url1} f := "init" - args := []string{"a", "100", "b", "200"} + args := shim.ToChaincodeArgs(f, "a", "100", "b", "200") - spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Args: args}} _, err = deploy(ctxt, spec1) chaincodeID1 := spec1.ChaincodeID.Name @@ -1190,9 +1192,9 @@ func TestChaincodeQueryChaincodeErrorCase(t *testing.T) { cID2 := &pb.ChaincodeID{Path: url2} f = "init" - args = []string{""} + args = shim.ToChaincodeArgs(f) - spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}} _, err = deploy(ctxt, spec2) chaincodeID2 := spec2.ChaincodeID.Name @@ -1209,9 +1211,9 @@ func TestChaincodeQueryChaincodeErrorCase(t *testing.T) { // Invoke second chaincode, which will inturn invoke the first chaincode but pass bad params f = chaincodeID1 - args = []string{"query", "c"} //expect {"query", "a"} + args = shim.ToChaincodeArgs(f, "query", "c") - spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}} // Invoke chaincode _, _, _, err = invoke(ctxt, spec2, pb.Transaction_CHAINCODE_QUERY) @@ -1332,10 +1334,10 @@ func TestRangeQuery(t *testing.T) { url := "github.com/hyperledger/fabric/examples/chaincode/go/map" cID := &pb.ChaincodeID{Path: url} - args := []string{} f := "init" + args := shim.ToChaincodeArgs(f) - spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: args}} _, err = deploy(ctxt, spec) chaincodeID := spec.ChaincodeID.Name @@ -1349,9 +1351,9 @@ func TestRangeQuery(t *testing.T) { // Invoke second chaincode, which will inturn invoke the first chaincode f = "keys" - args = []string{} + args = shim.ToChaincodeArgs(f) - spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: args}} _, _, _, err = invoke(ctxt, spec, pb.Transaction_CHAINCODE_QUERY) if err != nil { @@ -1403,7 +1405,8 @@ func TestGetEvent(t *testing.T) { url := "github.com/hyperledger/fabric/examples/chaincode/go/eventsender" cID := &pb.ChaincodeID{Path: url} - spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Function: "init", Args: []string{}}} + f := "init" + spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: shim.ToChaincodeArgs(f)}} _, err = deploy(ctxt, spec) chaincodeID := spec.ChaincodeID.Name @@ -1417,9 +1420,9 @@ func TestGetEvent(t *testing.T) { time.Sleep(time.Second) - args := []string{"i", "am", "satoshi"} + args := shim.ToChaincodeArgs("", "i", "am", "satoshi") - spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Function: "", Args: args}} + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: args}} var ccevt *pb.ChaincodeEvent ccevt, _, _, err = invoke(ctxt, spec, pb.Transaction_CHAINCODE_INVOKE) diff --git a/core/chaincode/handler.go b/core/chaincode/handler.go index a967f6f5695..52c66deeef1 100644 --- a/core/chaincode/handler.go +++ b/core/chaincode/handler.go @@ -1236,21 +1236,19 @@ func (handler *Handler) setChaincodeSecurityContext(tx *pb.Transaction, msg *pb. msg.SecurityContext.Binding = binding msg.SecurityContext.Metadata = tx.Metadata - if tx.Type == pb.Transaction_CHAINCODE_INVOKE || tx.Type == pb.Transaction_CHAINCODE_QUERY { - cis := &pb.ChaincodeInvocationSpec{} - if err := proto.Unmarshal(tx.Payload, cis); err != nil { - chaincodeLogger.Errorf("Failed getting payload [%s]", err) - return err - } - - ctorMsgRaw, err := proto.Marshal(cis.ChaincodeSpec.GetCtorMsg()) - if err != nil { - chaincodeLogger.Errorf("Failed getting ctorMsgRaw [%s]", err) - return err - } + cis := &pb.ChaincodeInvocationSpec{} + if err := proto.Unmarshal(tx.Payload, cis); err != nil { + chaincodeLogger.Errorf("Failed getting payload [%s]", err) + return err + } - msg.SecurityContext.Payload = ctorMsgRaw + ctorMsgRaw, err := proto.Marshal(cis.ChaincodeSpec.GetCtorMsg()) + if err != nil { + chaincodeLogger.Errorf("Failed getting ctorMsgRaw [%s]", err) + return err } + + msg.SecurityContext.Payload = ctorMsgRaw msg.SecurityContext.TxTimestamp = tx.Timestamp } return nil @@ -1258,7 +1256,7 @@ func (handler *Handler) setChaincodeSecurityContext(tx *pb.Transaction, msg *pb. //if initArgs is set (should be for "deploy" only) move to Init //else move to ready -func (handler *Handler) initOrReady(txid string, f *string, initArgs []string, tx *pb.Transaction, depTx *pb.Transaction) (chan *pb.ChaincodeMessage, error) { +func (handler *Handler) initOrReady(txid string, initArgs [][]byte, tx *pb.Transaction, depTx *pb.Transaction) (chan *pb.ChaincodeMessage, error) { var ccMsg *pb.ChaincodeMessage var send bool @@ -1269,13 +1267,9 @@ func (handler *Handler) initOrReady(txid string, f *string, initArgs []string, t notfy := txctx.responseNotifier - if f != nil || initArgs != nil { + if initArgs != nil { chaincodeLogger.Debug("sending INIT") - var f2 string - if f != nil { - f2 = *f - } - funcArgsMsg := &pb.ChaincodeInput{Function: f2, Args: initArgs} + funcArgsMsg := &pb.ChaincodeInput{Args: initArgs} var payload []byte if payload, funcErr = proto.Marshal(funcArgsMsg); funcErr != nil { handler.deleteTxContext(txid) diff --git a/core/chaincode/platforms/car/hash.go b/core/chaincode/platforms/car/hash.go index 2d3ff0d74d5..870d572320d 100644 --- a/core/chaincode/platforms/car/hash.go +++ b/core/chaincode/platforms/car/hash.go @@ -21,6 +21,7 @@ import ( "fmt" "io/ioutil" + "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/core/util" pb "github.com/hyperledger/fabric/protos" ) @@ -34,11 +35,14 @@ import ( func generateHashcode(spec *pb.ChaincodeSpec, path string) (string, error) { ctor := spec.CtorMsg - if ctor == nil || ctor.Function == "" { + if ctor == nil || len(ctor.Args) == 0 { return "", fmt.Errorf("Cannot generate hashcode from empty ctor") } - - hash := util.GenerateHashFromSignature(spec.ChaincodeID.Path, ctor.Function, ctor.Args) + ctorbytes, err := proto.Marshal(ctor) + if err != nil { + return "", fmt.Errorf("Error marshalling constructor: %s", err) + } + hash := util.GenerateHashFromSignature(spec.ChaincodeID.Path, ctorbytes) buf, err := ioutil.ReadFile(path) if err != nil { diff --git a/core/chaincode/platforms/car/test/car_test.go b/core/chaincode/platforms/car/test/car_test.go index 18cf00ef938..e39b199a520 100644 --- a/core/chaincode/platforms/car/test/car_test.go +++ b/core/chaincode/platforms/car/test/car_test.go @@ -20,6 +20,7 @@ import ( "os" "testing" + "github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/core/config" "github.com/hyperledger/fabric/core/container" pb "github.com/hyperledger/fabric/protos" @@ -46,7 +47,7 @@ func TestCar_BuildImage(t *testing.T) { } chaincodePath := cwd + "/org.hyperledger.chaincode.example02-0.1-SNAPSHOT.car" - spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_CAR, ChaincodeID: &pb.ChaincodeID{Path: chaincodePath}, CtorMsg: &pb.ChaincodeInput{Function: "f"}} + spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_CAR, ChaincodeID: &pb.ChaincodeID{Path: chaincodePath}, CtorMsg: &pb.ChaincodeInput{Args: shim.ToChaincodeArgs("f")}} if _, err := vm.BuildChaincodeContainer(spec); err != nil { t.Fail() t.Log(err) diff --git a/core/chaincode/platforms/golang/hash.go b/core/chaincode/platforms/golang/hash.go index d5fa1b4aec4..33eb8cc8847 100755 --- a/core/chaincode/platforms/golang/hash.go +++ b/core/chaincode/platforms/golang/hash.go @@ -29,6 +29,7 @@ import ( "strings" "time" + "github.com/golang/protobuf/proto" "github.com/op/go-logging" "github.com/spf13/viper" @@ -226,7 +227,7 @@ func generateHashcode(spec *pb.ChaincodeSpec, tw *tar.Writer) (string, error) { } ctor := spec.CtorMsg - if ctor == nil || ctor.Function == "" { + if ctor == nil || len(ctor.Args) == 0 { return "", fmt.Errorf("Cannot generate hashcode from empty ctor") } @@ -267,8 +268,11 @@ func generateHashcode(spec *pb.ChaincodeSpec, tw *tar.Writer) (string, error) { if err = isCodeExist(tmppath); err != nil { return "", fmt.Errorf("code does not exist %s", err) } - - hash := util.GenerateHashFromSignature(actualcodepath, ctor.Function, ctor.Args) + ctorbytes, err := proto.Marshal(ctor) + if err != nil { + return "", fmt.Errorf("Error marshalling constructor: %s", err) + } + hash := util.GenerateHashFromSignature(actualcodepath, ctorbytes) hash, err = hashFilesInDir(filepath.Join(codegopath, "src"), actualcodepath, hash, tw) if err != nil { diff --git a/core/chaincode/platforms/java/hash.go b/core/chaincode/platforms/java/hash.go index 6697598c04e..14abec13486 100644 --- a/core/chaincode/platforms/java/hash.go +++ b/core/chaincode/platforms/java/hash.go @@ -9,6 +9,7 @@ import ( "os" "strings" + "github.com/golang/protobuf/proto" cutil "github.com/hyperledger/fabric/core/container/util" "github.com/hyperledger/fabric/core/util" pb "github.com/hyperledger/fabric/protos" @@ -91,7 +92,7 @@ func generateHashcode(spec *pb.ChaincodeSpec, tw *tar.Writer) (string, error) { } ctor := spec.CtorMsg - if ctor == nil || ctor.Function == "" { + if ctor == nil || len(ctor.Args) == 0 { return "", fmt.Errorf("Cannot generate hashcode from empty ctor") } @@ -132,8 +133,11 @@ func generateHashcode(spec *pb.ChaincodeSpec, tw *tar.Writer) (string, error) { root = root[:len(root)-1] } root = root[:strings.LastIndex(root, "/")+1] - - hash := util.GenerateHashFromSignature(codepath, ctor.Function, ctor.Args) + ctorbytes, err := proto.Marshal(ctor) + if err != nil { + return "", fmt.Errorf("Error marshalling constructor: %s", err) + } + hash := util.GenerateHashFromSignature(codepath, ctorbytes) hash, err = hashFilesInDir(root, codepath, hash, tw) if err != nil { diff --git a/core/chaincode/platforms/java/test/java_test.go b/core/chaincode/platforms/java/test/java_test.go index 789542173fd..be3cdfc5734 100644 --- a/core/chaincode/platforms/java/test/java_test.go +++ b/core/chaincode/platforms/java/test/java_test.go @@ -20,6 +20,7 @@ import ( "os" "testing" + "github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/core/config" "github.com/hyperledger/fabric/core/container" pb "github.com/hyperledger/fabric/protos" @@ -41,7 +42,7 @@ func TestJava_BuildImage(t *testing.T) { chaincodePath := "../../../shim/java" //TODO find a better way to launch example java chaincode - spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_JAVA, ChaincodeID: &pb.ChaincodeID{Path: chaincodePath}, CtorMsg: &pb.ChaincodeInput{Function: "f"}} + spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_JAVA, ChaincodeID: &pb.ChaincodeID{Path: chaincodePath}, CtorMsg: &pb.ChaincodeInput{Args: shim.ToChaincodeArgs("f")}} if _, err := vm.BuildChaincodeContainer(spec); err != nil { t.Fail() t.Log(err) diff --git a/core/chaincode/shim/chaincode.go b/core/chaincode/shim/chaincode.go index 4753c0995c1..b4dc8eab670 100644 --- a/core/chaincode/shim/chaincode.go +++ b/core/chaincode/shim/chaincode.go @@ -69,6 +69,7 @@ type ChaincodeStub struct { UUID string securityContext *pb.ChaincodeSecurityContext chaincodeEvent *pb.ChaincodeEvent + args [][]byte } // Peer address derived from command line or env var @@ -244,9 +245,19 @@ func chatWithPeer(chaincodename string, stream PeerChaincodeStream, cc Chaincode } // -- init stub --- +// ChaincodeInvocation functionality + func (stub *ChaincodeStub) init(uuid string, secContext *pb.ChaincodeSecurityContext) { stub.UUID = uuid stub.securityContext = secContext + stub.args = [][]byte{} + newCI := pb.ChaincodeInput{} + err := proto.Unmarshal(secContext.Payload, &newCI) + if err == nil { + stub.args = newCI.Args + } else { + panic("Arguments cannot be unmarshalled.") + } } // --------- Security functions ---------- @@ -257,15 +268,15 @@ func (stub *ChaincodeStub) init(uuid string, secContext *pb.ChaincodeSecurityCon // InvokeChaincode locally calls the specified chaincode `Invoke` using the // same transaction context; that is, chaincode calling chaincode doesn't // create a new transaction message. -func (stub *ChaincodeStub) InvokeChaincode(chaincodeName string, function string, args []string) ([]byte, error) { - return handler.handleInvokeChaincode(chaincodeName, function, args, stub.UUID) +func (stub *ChaincodeStub) InvokeChaincode(chaincodeName string, args [][]byte) ([]byte, error) { + return handler.handleInvokeChaincode(chaincodeName, args, stub.UUID) } // QueryChaincode locally calls the specified chaincode `Query` using the // same transaction context; that is, chaincode calling chaincode doesn't // create a new transaction message. -func (stub *ChaincodeStub) QueryChaincode(chaincodeName string, function string, args []string) ([]byte, error) { - return handler.handleQueryChaincode(chaincodeName, function, args, stub.UUID) +func (stub *ChaincodeStub) QueryChaincode(chaincodeName string, args [][]byte) ([]byte, error) { + return handler.handleQueryChaincode(chaincodeName, args, stub.UUID) } // --------- State functions ---------- @@ -380,6 +391,19 @@ func (iter *StateRangeQueryIterator) Close() error { return err } +func (stub *ChaincodeStub) GetArgs() [][]byte { + return stub.args +} + +func (stub *ChaincodeStub) GetStringArgs() []string { + args := stub.GetArgs() + strargs := make([]string, 0, len(args)) + for _, barg := range args { + strargs = append(strargs, string(barg)) + } + return strargs +} + // TABLE FUNCTIONALITY // TODO More comments here with documentation @@ -1009,3 +1033,11 @@ func (c *ChaincodeLogger) Errorf(format string, args ...interface{}) { func (c *ChaincodeLogger) Criticalf(format string, args ...interface{}) { c.logger.Criticalf(format, args...) } + +func ToChaincodeArgs(args ...string) [][]byte { + bargs := make([][]byte, len(args)) + for i, arg := range args { + bargs[i] = []byte(arg) + } + return bargs +} diff --git a/core/chaincode/shim/handler.go b/core/chaincode/shim/handler.go index 05a3ce0f96f..4c9ef1b8ef9 100644 --- a/core/chaincode/shim/handler.go +++ b/core/chaincode/shim/handler.go @@ -223,7 +223,8 @@ func (handler *Handler) handleInit(msg *pb.ChaincodeMessage) { // Create the ChaincodeStub which the chaincode can use to callback stub := new(ChaincodeStub) stub.init(msg.Txid, msg.SecurityContext) - res, err := handler.cc.Init(stub, input.Function, input.Args) + function, params := getFunctionAndParams(stub) + res, err := handler.cc.Init(stub, function, params) // delete isTransaction entry handler.deleteIsTransaction(msg.Txid) @@ -290,7 +291,8 @@ func (handler *Handler) handleTransaction(msg *pb.ChaincodeMessage) { // Create the ChaincodeStub which the chaincode can use to callback stub := new(ChaincodeStub) stub.init(msg.Txid, msg.SecurityContext) - res, err := handler.cc.Invoke(stub, input.Function, input.Args) + function, params := getFunctionAndParams(stub) + res, err := handler.cc.Invoke(stub, function, params) // delete isTransaction entry handler.deleteIsTransaction(msg.Txid) @@ -337,7 +339,8 @@ func (handler *Handler) handleQuery(msg *pb.ChaincodeMessage) { // Create the ChaincodeStub which the chaincode can use to callback stub := new(ChaincodeStub) stub.init(msg.Txid, msg.SecurityContext) - res, err := handler.cc.Query(stub, input.Function, input.Args) + function, params := getFunctionAndParams(stub) + res, err := handler.cc.Query(stub, function, params) // delete isTransaction entry handler.deleteIsTransaction(msg.Txid) @@ -740,14 +743,14 @@ func (handler *Handler) handleRangeQueryStateClose(id, txid string) (*pb.RangeQu } // handleInvokeChaincode communicates with the validator to invoke another chaincode. -func (handler *Handler) handleInvokeChaincode(chaincodeName string, function string, args []string, txid string) ([]byte, error) { +func (handler *Handler) handleInvokeChaincode(chaincodeName string, args [][]byte, txid string) ([]byte, error) { // Check if this is a transaction if !handler.isTransaction[txid] { return nil, errors.New("Cannot invoke chaincode in query context") } chaincodeID := &pb.ChaincodeID{Name: chaincodeName} - input := &pb.ChaincodeInput{Function: function, Args: args} + input := &pb.ChaincodeInput{Args: args} payload := &pb.ChaincodeSpec{ChaincodeID: chaincodeID, CtorMsg: input} payloadBytes, err := proto.Marshal(payload) if err != nil { @@ -806,9 +809,9 @@ func (handler *Handler) handleInvokeChaincode(chaincodeName string, function str } // handleQueryChaincode communicates with the validator to query another chaincode. -func (handler *Handler) handleQueryChaincode(chaincodeName string, function string, args []string, txid string) ([]byte, error) { +func (handler *Handler) handleQueryChaincode(chaincodeName string, args [][]byte, txid string) ([]byte, error) { chaincodeID := &pb.ChaincodeID{Name: chaincodeName} - input := &pb.ChaincodeInput{Function: function, Args: args} + input := &pb.ChaincodeInput{Args: args} payload := &pb.ChaincodeSpec{ChaincodeID: chaincodeID, CtorMsg: input} payloadBytes, err := proto.Marshal(payload) if err != nil { @@ -904,3 +907,14 @@ func filterError(errFromFSMEvent error) error { } return nil } + +func getFunctionAndParams(stub *ChaincodeStub) (function string, params []string) { + allargs := stub.GetStringArgs() + function = "" + params = []string{} + if len(allargs) >= 1 { + function = allargs[0] + params = allargs[1:] + } + return +} diff --git a/core/chaincode/shim/java/src/main/java/example/LinkExample.java b/core/chaincode/shim/java/src/main/java/example/LinkExample.java index c9468b10987..9eec17898f8 100644 --- a/core/chaincode/shim/java/src/main/java/example/LinkExample.java +++ b/core/chaincode/shim/java/src/main/java/example/LinkExample.java @@ -1,62 +1,74 @@ -/* -Copyright DTCC 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package example; - -import org.hyperledger.java.shim.ChaincodeBase; -import org.hyperledger.java.shim.ChaincodeStub; - -public class LinkExample extends ChaincodeBase { - - //Default name for map chaincode in dev mode - //Can be set to a hash location via init or setMap - private String mapChaincode = "map"; - - @Override - public String run(ChaincodeStub stub, String function, String[] args) { - switch (function) { - case "init": - case "setMap": - mapChaincode = args[0]; - break; - case "put": - stub.invokeChaincode(mapChaincode, function, args); - default: - break; - } - return null; - } - - @Override - public String query(ChaincodeStub stub, String function, String[] args) { - String tmp = stub.queryChaincode("map", function, args); - if (tmp.isEmpty()) tmp = "NULL"; - else tmp = "\"" + tmp + "\""; - tmp += " (queried from map chaincode)"; - return tmp; - } - - public static void main(String[] args) throws Exception { - new LinkExample().start(args); - //new Example().start(); - } - - @Override - public String getChaincodeID() { - return "link"; - } - -} +/* +Copyright DTCC 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package example; + +import com.google.protobuf.ByteString; +import org.hyperledger.java.shim.ChaincodeBase; +import org.hyperledger.java.shim.ChaincodeStub; + +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; + +public class LinkExample extends ChaincodeBase { + + //Default name for map chaincode in dev mode + //Can be set to a hash location via init or setMap + private String mapChaincode = "map"; + + @Override + public String run(ChaincodeStub stub, String function, String[] args) { + switch (function) { + case "init": + case "setMap": + mapChaincode = args[0]; + break; + case "put": + stub.invokeChaincode(mapChaincode, function, toByteStringList(args)); + default: + break; + } + return null; + } + + @Override + public String query(ChaincodeStub stub, String function, String[] args) { + String tmp = stub.queryChaincode("map", function, toByteStringList(args)); + if (tmp.isEmpty()) tmp = "NULL"; + else tmp = "\"" + tmp + "\""; + tmp += " (queried from map chaincode)"; + return tmp; + } + + public static void main(String[] args) throws Exception { + new LinkExample().start(args); + //new Example().start(); + } + + @Override + public String getChaincodeID() { + return "link"; + } + + private List toByteStringList(String[] args) { + LinkedList result = new LinkedList(); + for (int i=0; i args) { return handler.handleInvokeChaincode(chaincodeName, function, args, uuid).toStringUtf8(); } @@ -96,7 +98,7 @@ public String invokeChaincode(String chaincodeName, String function, String[] ar * @param args * @return */ - public String queryChaincode(String chaincodeName, String function, String[] args) { + public String queryChaincode(String chaincodeName, String function, List args) { return handler.handleQueryChaincode(chaincodeName, function, args, uuid).toStringUtf8(); } @@ -138,7 +140,7 @@ public void putRawState(String key, ByteString value) { * @param args * @return */ - public ByteString queryRawChaincode(String chaincodeName, String function, String[] args) { + public ByteString queryRawChaincode(String chaincodeName, String function, List args) { return handler.handleQueryChaincode(chaincodeName, function, args, uuid); } @@ -150,7 +152,7 @@ public ByteString queryRawChaincode(String chaincodeName, String function, Strin * @param args the arguments to be provided in the chaincode call * @return the value returned by the chaincode call */ - public ByteString invokeRawChaincode(String chaincodeName, String function, String[] args) { + public ByteString invokeRawChaincode(String chaincodeName, String function, List args) { return handler.handleInvokeChaincode(chaincodeName, function, args, uuid); } @@ -572,6 +574,4 @@ public void createTable(String name) { // } // // return true, nil - - } diff --git a/core/chaincode/shim/java/src/main/java/org/hyperledger/java/shim/Handler.java b/core/chaincode/shim/java/src/main/java/org/hyperledger/java/shim/Handler.java index babbcce6676..95b1094314a 100644 --- a/core/chaincode/shim/java/src/main/java/org/hyperledger/java/shim/Handler.java +++ b/core/chaincode/shim/java/src/main/java/org/hyperledger/java/shim/Handler.java @@ -38,11 +38,10 @@ Licensed to the Apache Software Foundation (ASF) under one import static protos.Chaincode.ChaincodeMessage.Type.RESPONSE; import static protos.Chaincode.ChaincodeMessage.Type.TRANSACTION; -import java.util.Arrays; import java.util.HashMap; +import java.util.List; import com.google.protobuf.ByteString; -import com.google.protobuf.ProtocolStringList; import org.hyperledger.java.fsm.CBDesc; import org.hyperledger.java.fsm.Event; @@ -233,7 +232,7 @@ public void handleInit(ChaincodeMessage message) { // Call chaincode's Run ByteString result; try { - result = chaincode.runHelper(stub, input.getFunction(), arrayHelper(input.getArgsList())); + result = chaincode.runHelper(stub, getFunction(input.getArgsList()), getParameters(input.getArgsList())); } catch (Exception e) { // Send ERROR message to chaincode support and change state logger.debug(String.format("[%s]Init failed. Sending %s", shortID(message), ERROR)); @@ -270,11 +269,17 @@ public void handleInit(ChaincodeMessage message) { new Thread(task).start(); } + private String getFunction(List args) { + return (args.size() > 0) ? args.get(0).toStringUtf8() : ""; + } - private String[] arrayHelper(ProtocolStringList argsList) { - String[] array = new String[argsList.size()]; - argsList.toArray(array); - return array; + private String[] getParameters(List args) { + int size = (args.size() == 0) ? 0 : args.size() - 1; + String[] strArgs = new String[size]; + for(int i = 1; i < args.size(); ++i) { + strArgs[i-1] = args.get(i).toStringUtf8(); + } + return strArgs; } // enterInitState will initialize the chaincode if entering init from established. @@ -326,7 +331,7 @@ public void handleTransaction(ChaincodeMessage message) { // Call chaincode's Run ByteString response; try { - response = chaincode.runHelper(stub, input.getFunction(), arrayHelper(input.getArgsList())); + response = chaincode.runHelper(stub, getFunction(input.getArgsList()), getParameters(input.getArgsList())); } catch (Exception e) { e.printStackTrace(); System.err.flush(); @@ -392,7 +397,7 @@ public void handleQuery(ChaincodeMessage message) { ByteString response; try { - response = chaincode.queryHelper(stub, input.getFunction(), arrayHelper(input.getArgsList())); + response = chaincode.queryHelper(stub, getFunction(input.getArgsList()), getParameters(input.getArgsList())); } catch (Exception e) { // Send ERROR message to chaincode support and change state logger.debug(String.format("[%s]Query execution failed. Sending %s", @@ -762,7 +767,7 @@ public void handleDeleteState(String key, String uuid) { // } // } - public ByteString handleInvokeChaincode(String chaincodeName, String function, String[] args, String uuid) { + public ByteString handleInvokeChaincode(String chaincodeName, String function, List args, String uuid) { // Check if this is a transaction if (!isTransaction.containsKey(uuid)) { throw new RuntimeException("Cannot invoke chaincode in query context"); @@ -771,8 +776,8 @@ public ByteString handleInvokeChaincode(String chaincodeName, String function, S ChaincodeID id = ChaincodeID.newBuilder() .setName(chaincodeName).build(); ChaincodeInput input = ChaincodeInput.newBuilder() - .setFunction(function) - .addAllArgs(Arrays.asList(args)) + .addArgs(ByteString.copyFromUtf8(function)) + .addAllArgs(args) .build(); ChaincodeSpec payload = ChaincodeSpec.newBuilder() .setChaincodeID(id) @@ -837,11 +842,11 @@ public ByteString handleInvokeChaincode(String chaincodeName, String function, S } } - public ByteString handleQueryChaincode(String chaincodeName, String function, String[] args, String uuid) { + public ByteString handleQueryChaincode(String chaincodeName, String function, List args, String uuid) { ChaincodeID id = ChaincodeID.newBuilder().setName(chaincodeName).build(); ChaincodeInput input = ChaincodeInput.newBuilder() - .setFunction(function) - .addAllArgs(Arrays.asList(args)) + .addArgs(ByteString.copyFromUtf8(function)) + .addAllArgs(args) .build(); ChaincodeSpec payload = ChaincodeSpec.newBuilder() .setChaincodeID(id) diff --git a/core/chaincode/shim/java/src/main/proto/chaincode.proto b/core/chaincode/shim/java/src/main/proto/chaincode.proto index efb80a31c71..b66d89290c2 100644 --- a/core/chaincode/shim/java/src/main/proto/chaincode.proto +++ b/core/chaincode/shim/java/src/main/proto/chaincode.proto @@ -47,10 +47,7 @@ message ChaincodeID { // Carries the chaincode function and its arguments. message ChaincodeInput { - - string function = 1; - repeated string args = 2; - + repeated bytes args = 2; } // Carries the chaincode specification. This is the actual metadata required for diff --git a/core/container/vm_test.go b/core/container/vm_test.go index 7f75248d202..a01aaac1570 100644 --- a/core/container/vm_test.go +++ b/core/container/vm_test.go @@ -24,6 +24,7 @@ import ( "os" "testing" + "github.com/hyperledger/fabric/core/chaincode/shim" cutil "github.com/hyperledger/fabric/core/container/util" pb "github.com/hyperledger/fabric/protos" "golang.org/x/net/context" @@ -73,7 +74,7 @@ func TestVM_BuildImage_ChaincodeLocal(t *testing.T) { } // Build the spec chaincodePath := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01" - spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeID: &pb.ChaincodeID{Path: chaincodePath}, CtorMsg: &pb.ChaincodeInput{Function: "f"}} + spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeID: &pb.ChaincodeID{Path: chaincodePath}, CtorMsg: &pb.ChaincodeInput{Args: shim.ToChaincodeArgs("f")}} if _, err := vm.BuildChaincodeContainer(spec); err != nil { t.Fail() t.Log(err) @@ -90,7 +91,7 @@ func TestVM_BuildImage_ChaincodeRemote(t *testing.T) { } // Build the spec chaincodePath := "https://github.com/prjayach/chaincode_examples/chaincode_example02" - spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeID: &pb.ChaincodeID{Path: chaincodePath}, CtorMsg: &pb.ChaincodeInput{Function: "f"}} + spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeID: &pb.ChaincodeID{Path: chaincodePath}, CtorMsg: &pb.ChaincodeInput{Args: shim.ToChaincodeArgs("f")}} if _, err := vm.BuildChaincodeContainer(spec); err != nil { t.Fail() t.Log(err) diff --git a/core/devops.go b/core/devops.go index 16660fc92aa..894e10828dd 100644 --- a/core/devops.go +++ b/core/devops.go @@ -213,7 +213,11 @@ func (d *Devops) invokeOrQuery(ctx context.Context, chaincodeInvocationSpec *pb. var customIDgenAlg = strings.ToLower(chaincodeInvocationSpec.IdGenerationAlg) var id string var generr error - id, generr = util.GenerateIDWithAlg(customIDgenAlg, chaincodeInvocationSpec.ChaincodeSpec.CtorMsg.Args) + ctorbytes, merr := proto.Marshal(chaincodeInvocationSpec.ChaincodeSpec.CtorMsg) + if merr != nil { + return nil, fmt.Errorf("Error marshalling constructor: %s", merr) + } + id, generr = util.GenerateIDWithAlg(customIDgenAlg, ctorbytes) if generr != nil { return nil, generr } @@ -444,7 +448,11 @@ func (d *Devops) EXP_ExecuteWithBinding(ctx context.Context, executeWithBinding return &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(err.Error())}, nil } - tid, generr := util.GenerateIDWithAlg("", executeWithBinding.ChaincodeInvocationSpec.ChaincodeSpec.CtorMsg.Args) + ctorbytes, merr := proto.Marshal(executeWithBinding.ChaincodeInvocationSpec.ChaincodeSpec.CtorMsg) + if merr != nil { + return nil, fmt.Errorf("Error marshalling constructor: %s", err) + } + tid, generr := util.GenerateIDWithAlg("", ctorbytes) if generr != nil { return nil, fmt.Errorf("Error: cannot generate TX ID (executing with binding)") } diff --git a/core/ledger/blockchain_test.go b/core/ledger/blockchain_test.go index 5cd8623e1a5..8d114fabd85 100644 --- a/core/ledger/blockchain_test.go +++ b/core/ledger/blockchain_test.go @@ -20,6 +20,7 @@ import ( "testing" "time" + "github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/core/ledger/testutil" "github.com/hyperledger/fabric/core/util" "github.com/hyperledger/fabric/protos" @@ -58,7 +59,7 @@ func TestBlockChain_SingleBlock(t *testing.T) { // Create the Chaincode specification chaincodeSpec := &protos.ChaincodeSpec{Type: protos.ChaincodeSpec_GOLANG, ChaincodeID: &protos.ChaincodeID{Path: "Contracts"}, - CtorMsg: &protos.ChaincodeInput{Function: "Initialize", Args: []string{"param1"}}} + CtorMsg: &protos.ChaincodeInput{Args: shim.ToChaincodeArgs("Initialize", "param1")}} chaincodeDeploymentSepc := &protos.ChaincodeDeploymentSpec{ChaincodeSpec: chaincodeSpec} uuid := testutil.GenerateID(t) newChaincodeTx, err := protos.NewChaincodeDeployTransaction(chaincodeDeploymentSepc, uuid) diff --git a/core/rest/rest_api.go b/core/rest/rest_api.go index 2390428c773..e6836764b6c 100644 --- a/core/rest/rest_api.go +++ b/core/rest/rest_api.go @@ -788,7 +788,7 @@ func (s *ServerOpenchainREST) Deploy(rw web.ResponseWriter, req *web.Request) { } // Check that the CtorMsg is not left blank. - if (spec.CtorMsg == nil) || (spec.CtorMsg.Function == "") { + if (spec.CtorMsg == nil) || (len(spec.CtorMsg.Args) == 0) { rw.WriteHeader(http.StatusBadRequest) fmt.Fprintf(rw, "{\"Error\": \"Payload must contain a CtorMsg with a Chaincode function name.\"}") restLogger.Error("{\"Error\": \"Payload must contain a CtorMsg with a Chaincode function name.\"}") @@ -929,7 +929,7 @@ func (s *ServerOpenchainREST) Invoke(rw web.ResponseWriter, req *web.Request) { } // Check that the CtorMsg is not left blank. - if (spec.ChaincodeSpec.CtorMsg == nil) || (spec.ChaincodeSpec.CtorMsg.Function == "") { + if (spec.ChaincodeSpec.CtorMsg == nil) || (len(spec.ChaincodeSpec.CtorMsg.Args) == 0) { rw.WriteHeader(http.StatusBadRequest) fmt.Fprintf(rw, "{\"Error\": \"Payload must contain a CtorMsg with a Chaincode function name.\"}") restLogger.Error("{\"Error\": \"Payload must contain a CtorMsg with a Chaincode function name.\"}") @@ -1071,7 +1071,7 @@ func (s *ServerOpenchainREST) Query(rw web.ResponseWriter, req *web.Request) { } // Check that the CtorMsg is not left blank. - if (spec.ChaincodeSpec.CtorMsg == nil) || (spec.ChaincodeSpec.CtorMsg.Function == "") { + if (spec.ChaincodeSpec.CtorMsg == nil) || (len(spec.ChaincodeSpec.CtorMsg.Args) == 0) { rw.WriteHeader(http.StatusBadRequest) fmt.Fprintf(rw, "{\"Error\": \"Payload must contain a CtorMsg with a Chaincode function name.\"}") restLogger.Error("{\"Error\": \"Payload must contain a CtorMsg with a Chaincode function name.\"}") @@ -1400,7 +1400,7 @@ func (s *ServerOpenchainREST) processChaincodeDeploy(spec *pb.ChaincodeSpec) rpc } // Check that the CtorMsg is not left blank. - if (spec.CtorMsg == nil) || (spec.CtorMsg.Function == "") { + if (spec.CtorMsg == nil) || (len(spec.CtorMsg.Args) == 0) { // Format the error appropriately for further processing error := formatRPCError(InvalidParams.Code, InvalidParams.Message, "Payload must contain a CtorMsg with a Chaincode function name.") restLogger.Error("Payload must contain a CtorMsg with a Chaincode function name.") @@ -1524,7 +1524,7 @@ func (s *ServerOpenchainREST) processChaincodeInvokeOrQuery(method string, spec } // Check that the CtorMsg is not left blank. - if (spec.ChaincodeSpec.CtorMsg == nil) || (spec.ChaincodeSpec.CtorMsg.Function == "") { + if (spec.ChaincodeSpec.CtorMsg == nil) || (len(spec.ChaincodeSpec.CtorMsg.Args) == 0) { // Format the error appropriately for further processing error := formatRPCError(InvalidParams.Code, InvalidParams.Message, "Payload must contain a CtorMsg with a Chaincode function name.") restLogger.Error("Payload must contain a CtorMsg with a Chaincode function name.") diff --git a/core/rest/rest_api.json b/core/rest/rest_api.json index e6ed9c5c53b..d82e763b1a6 100644 --- a/core/rest/rest_api.json +++ b/core/rest/rest_api.json @@ -630,10 +630,6 @@ "ChaincodeInput": { "type": "object", "properties": { - "function": { - "type": "string", - "description": "Function to execute within the Chaincode." - }, "args": { "type": "array", "items": { diff --git a/core/rest/rest_api_test.go b/core/rest/rest_api_test.go index 9f1af52a854..c6816f7b68b 100644 --- a/core/rest/rest_api_test.go +++ b/core/rest/rest_api_test.go @@ -18,6 +18,7 @@ package rest import ( "bytes" + "encoding/base64" "encoding/json" "fmt" "io/ioutil" @@ -33,6 +34,11 @@ import ( "github.com/hyperledger/fabric/protos" ) +var failb64 string = base64.StdEncoding.EncodeToString([]byte("fail")) +var initb64 string = base64.StdEncoding.EncodeToString([]byte("Init")) +var change_ownerb64 string = base64.StdEncoding.EncodeToString([]byte("change_owner")) +var get_ownerb64 string = base64.StdEncoding.EncodeToString([]byte("get_owner")) + func performHTTPGet(t *testing.T, url string) []byte { response, err := http.Get(url) if err != nil { @@ -117,7 +123,10 @@ func (d *mockDevops) Deploy(c context.Context, spec *protos.ChaincodeSpec) (*pro } func (d *mockDevops) Invoke(c context.Context, cis *protos.ChaincodeInvocationSpec) (*protos.Response, error) { - switch cis.ChaincodeSpec.CtorMsg.Function { + if len(cis.ChaincodeSpec.CtorMsg.Args) == 0 { + return nil, fmt.Errorf("No function invoked") + } + switch string(cis.ChaincodeSpec.CtorMsg.Args[0]) { case "fail": return nil, fmt.Errorf("Invoke failure") case "change_owner": @@ -127,7 +136,10 @@ func (d *mockDevops) Invoke(c context.Context, cis *protos.ChaincodeInvocationSp } func (d *mockDevops) Query(c context.Context, cis *protos.ChaincodeInvocationSpec) (*protos.Response, error) { - switch cis.ChaincodeSpec.CtorMsg.Function { + if len(cis.ChaincodeSpec.CtorMsg.Args) == 0 { + return nil, fmt.Errorf("No function invoked") + } + switch string(cis.ChaincodeSpec.CtorMsg.Args[0]) { case "fail": return nil, fmt.Errorf("Query failure with special-\" chars") case "get_owner": @@ -581,8 +593,9 @@ func TestServerOpenchainREST_API_Chaincode_Deploy(t *testing.T) { "path": "non-existing" }, "ctorMsg": { - "function": "Init", - "args": [] + "args": ["` + + initb64 + + `"] }, "secureContext": "myuser" } @@ -607,8 +620,9 @@ func TestServerOpenchainREST_API_Chaincode_Deploy(t *testing.T) { "path": "github.com/hyperledger/fabric/core/rest/test_chaincode" }, "ctorMsg": { - "function": "Init", - "args": [] + "args": ["` + + initb64 + + `"] } } }` @@ -629,8 +643,9 @@ func TestServerOpenchainREST_API_Chaincode_Deploy(t *testing.T) { "path": "github.com/hyperledger/fabric/core/rest/test_chaincode" }, "ctorMsg": { - "function": "Init", - "args": [] + "args": ["` + + initb64 + + `"] }, "secureContext": "myuser" } @@ -676,7 +691,7 @@ func TestServerOpenchainREST_API_Chaincode_Invoke(t *testing.T) { performHTTPPost(t, httpServer.URL+"/registrar", []byte(`{"enrollId":"myuser","enrollSecret":"password"}`)) // Test invoke with "fail" function - httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"invoke","params":{"type":1,"chaincodeID":{"name":"dummy"},"ctorMsg":{"function":"fail","args":[]},"secureContext":"myuser"}}`)) + httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"invoke","params":{"type":1,"chaincodeID":{"name":"dummy"},"ctorMsg":{"args":["`+failb64+`"]},"secureContext":"myuser"}}`)) if httpResponse.StatusCode != http.StatusOK { t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode) } @@ -686,7 +701,7 @@ func TestServerOpenchainREST_API_Chaincode_Invoke(t *testing.T) { } // Test invoke with "change_owner" function - httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"invoke","params":{"type":1,"chaincodeID":{"name":"dummy"},"ctorMsg":{"function":"change_owner","args":[]},"secureContext":"myuser"}}`)) + httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"invoke","params":{"type":1,"chaincodeID":{"name":"dummy"},"ctorMsg":{"args":["`+change_ownerb64+`"]},"secureContext":"myuser"}}`)) if httpResponse.StatusCode != http.StatusOK { t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode) } @@ -727,7 +742,7 @@ func TestServerOpenchainREST_API_Chaincode_Query(t *testing.T) { performHTTPPost(t, httpServer.URL+"/registrar", []byte(`{"enrollId":"myuser","enrollSecret":"password"}`)) // Test query with non-existing chaincode name - httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"query","params":{"type":1,"chaincodeID":{"name":"non-existing"},"ctorMsg":{"function":"Init","args":[]},"secureContext":"myuser"}}`)) + httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"query","params":{"type":1,"chaincodeID":{"name":"non-existing"},"ctorMsg":{"args":["`+initb64+`"]},"secureContext":"myuser"}}`)) if httpResponse.StatusCode != http.StatusOK { t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode) } @@ -737,7 +752,7 @@ func TestServerOpenchainREST_API_Chaincode_Query(t *testing.T) { } // Test query with fail function - httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"query","params":{"type":1,"chaincodeID":{"name":"dummy"},"ctorMsg":{"function":"fail","args":[]},"secureContext":"myuser"}}`)) + httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"query","params":{"type":1,"chaincodeID":{"name":"dummy"},"ctorMsg":{"args":["`+failb64+`"]},"secureContext":"myuser"}}`)) if httpResponse.StatusCode != http.StatusOK { t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode) } @@ -750,7 +765,7 @@ func TestServerOpenchainREST_API_Chaincode_Query(t *testing.T) { } // Test query with get_owner function - httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"query","params":{"type":1,"chaincodeID":{"name":"dummy"},"ctorMsg":{"function":"get_owner","args":[]},"secureContext":"myuser"}}`)) + httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"query","params":{"type":1,"chaincodeID":{"name":"dummy"},"ctorMsg":{"args":["`+get_ownerb64+`"]},"secureContext":"myuser"}}`)) if httpResponse.StatusCode != http.StatusOK { t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode) } diff --git a/core/system_chaincode/api/sysccapi.go b/core/system_chaincode/api/sysccapi.go index 6b98ec86ead..d8ebc553e95 100644 --- a/core/system_chaincode/api/sysccapi.go +++ b/core/system_chaincode/api/sysccapi.go @@ -47,7 +47,7 @@ type SystemChaincode struct { Path string //InitArgs initialization arguments to startup the system chaincode - InitArgs []string + InitArgs [][]byte // Chaincode is the actual chaincode object Chaincode shim.Chaincode diff --git a/core/system_chaincode/importsysccs.go b/core/system_chaincode/importsysccs.go index 06bca7e9a96..c99ed746250 100644 --- a/core/system_chaincode/importsysccs.go +++ b/core/system_chaincode/importsysccs.go @@ -28,7 +28,7 @@ var systemChaincodes = []*api.SystemChaincode{ Enabled: true, Name: "noop", Path: "github.com/hyperledger/fabric/bddtests/syschaincode/noop", - InitArgs: []string{}, + InitArgs: [][]byte{}, Chaincode: &noop.SystemChaincode{}, }} diff --git a/core/system_chaincode/systemchaincode_test.go b/core/system_chaincode/systemchaincode_test.go index 36b6f2c7695..b47d060c1be 100644 --- a/core/system_chaincode/systemchaincode_test.go +++ b/core/system_chaincode/systemchaincode_test.go @@ -24,6 +24,7 @@ import ( "time" "github.com/hyperledger/fabric/core/chaincode" + "github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/core/db" "github.com/hyperledger/fabric/core/ledger" "github.com/hyperledger/fabric/core/system_chaincode/api" @@ -110,7 +111,7 @@ func TestExecuteDeploySysChaincode(t *testing.T) { Enabled: true, Name: "sample_syscc", Path: "github.com/hyperledger/fabric/core/system_chaincode/samplesyscc", - InitArgs: []string{}, + InitArgs: [][]byte{}, Chaincode: &samplesyscc.SampleSysCC{}, }, } @@ -121,9 +122,9 @@ func TestExecuteDeploySysChaincode(t *testing.T) { url := "github.com/hyperledger/fabric/core/system_chaincode/sample_syscc" f := "putval" - args := []string{"greeting", "hey there"} + args := shim.ToChaincodeArgs(f, "greeting", "hey there") - spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "sample_syscc", Path: url}, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "sample_syscc", Path: url}, CtorMsg: &pb.ChaincodeInput{Args: args}} _, _, _, err = invoke(ctxt, spec, pb.Transaction_CHAINCODE_INVOKE) if err != nil { closeListenerAndSleep(lis) @@ -133,8 +134,8 @@ func TestExecuteDeploySysChaincode(t *testing.T) { } f = "getval" - args = []string{"greeting"} - spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "sample_syscc", Path: url}, CtorMsg: &pb.ChaincodeInput{Function: f, Args: args}} + args = shim.ToChaincodeArgs(f, "greeting") + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "sample_syscc", Path: url}, CtorMsg: &pb.ChaincodeInput{Args: args}} _, _, _, err = invoke(ctxt, spec, pb.Transaction_CHAINCODE_QUERY) if err != nil { closeListenerAndSleep(lis) diff --git a/core/util/utils.go b/core/util/utils.go index 056a616e527..af4caad1026 100644 --- a/core/util/utils.go +++ b/core/util/utils.go @@ -31,7 +31,7 @@ import ( ) type alg struct { - hashFun func([]string) string + hashFun func([]byte) string } const defaultAlg = "sha256" @@ -86,39 +86,23 @@ func CreateUtcTimestamp() *gp.Timestamp { } //GenerateHashFromSignature returns a hash of the combined parameters -func GenerateHashFromSignature(path string, ctor string, args []string) []byte { - fargs := ctor - if args != nil { - for _, str := range args { - fargs = fargs + str - } - } - cbytes := []byte(path + fargs) - - b := make([]byte, len(cbytes)) - copy(b, cbytes) - hash := ComputeCryptoHash(b) - return hash +func GenerateHashFromSignature(path string, args []byte) []byte { + return ComputeCryptoHash(args) } // GenerateIDfromTxSHAHash generates SHA256 hash using Tx payload -func GenerateIDfromTxSHAHash(payload []string) string { - h := sha256.New() - for _, part := range payload { - utf8bytes := []byte(part) - h.Write(utf8bytes) - } - return fmt.Sprintf("%x", h.Sum([]byte{})) +func GenerateIDfromTxSHAHash(payload []byte) string { + return fmt.Sprintf("%x", sha256.Sum256(payload)) } // GenerateIDWithAlg generates an ID using a custom algorithm -func GenerateIDWithAlg(customIDgenAlg string, strPayload []string) (string, error) { +func GenerateIDWithAlg(customIDgenAlg string, payload []byte) (string, error) { if customIDgenAlg == "" { customIDgenAlg = defaultAlg } var alg = availableIDgenAlgs[customIDgenAlg] if alg.hashFun != nil { - return alg.hashFun(strPayload), nil + return alg.hashFun(payload), nil } return "", fmt.Errorf("Wrong ID generation algorithm was given: %s", customIDgenAlg) } diff --git a/core/util/utils_test.go b/core/util/utils_test.go index 97c0896124c..5be086f0e95 100644 --- a/core/util/utils_test.go +++ b/core/util/utils_test.go @@ -59,12 +59,12 @@ func TestTimestamp(t *testing.T) { } func TestGenerateHashFromSignature(t *testing.T) { - if bytes.Compare(GenerateHashFromSignature("aPath", "aCtor", []string{"1", "2"}), - GenerateHashFromSignature("aPath", "aCtor", []string{"1", "2"})) != 0 { + if bytes.Compare(GenerateHashFromSignature("aPath", []byte("aCtor12")), + GenerateHashFromSignature("aPath", []byte("aCtor12"))) != 0 { t.Fatalf("Expected hashes to match, but they did not match") } - if bytes.Compare(GenerateHashFromSignature("aPath", "aCtor", []string{"1", "2"}), - GenerateHashFromSignature("bPath", "bCtor", []string{"3", "4"})) == 0 { + if bytes.Compare(GenerateHashFromSignature("aPath", []byte("aCtor12")), + GenerateHashFromSignature("bPath", []byte("bCtor34"))) == 0 { t.Fatalf("Expected hashes to be different, but they match") } } diff --git a/examples/chaincode/go/chaincode_example04/chaincode_example04.go b/examples/chaincode/go/chaincode_example04/chaincode_example04.go index fc483ed8aaf..28a1b6451a5 100644 --- a/examples/chaincode/go/chaincode_example04/chaincode_example04.go +++ b/examples/chaincode/go/chaincode_example04/chaincode_example04.go @@ -33,8 +33,7 @@ type SimpleChaincode struct { func (t *SimpleChaincode) getChaincodeToCall(stub *shim.ChaincodeStub) (string, error) { //This is the hashcode for github.com/hyperledger/fabric/core/example/chaincode/chaincode_example02 //if the example is modifed this hashcode will change!! - chainCodeToCall := "a5389f7dfb9efae379900a41db1503fea2199fe400272b61ac5fe7bd0c6b97cf10ce3aa8dd00cd7626ce02f18accc7e5f2059dae6eb0786838042958352b89fb" //with SHA3 - + chainCodeToCall := "9578ffde22fede358d6390d6a3f81bee6e690e210ad7c544e93d567f55e9290369df30822cd771acc0ca233fb32c7948c257599e0412b9b4f2d1eae5721486ce" return chainCodeToCall, nil } @@ -92,8 +91,8 @@ func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args } f := "invoke" - invokeArgs := []string{"a", "b", "10"} - response, err := stub.InvokeChaincode(chainCodeToCall, f, invokeArgs) + invokeArgs := shim.ToChaincodeArgs(f, "a", "b", "10") + response, err := stub.InvokeChaincode(chainCodeToCall, invokeArgs) if err != nil { errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error()) fmt.Printf(errStr) diff --git a/examples/chaincode/go/chaincode_example05/chaincode_example05.go b/examples/chaincode/go/chaincode_example05/chaincode_example05.go index 4bc7801eafa..820f4e94dc7 100644 --- a/examples/chaincode/go/chaincode_example05/chaincode_example05.go +++ b/examples/chaincode/go/chaincode_example05/chaincode_example05.go @@ -73,8 +73,8 @@ func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args // Query chaincode_example02 f := "query" - queryArgs := []string{"a"} - response, err := stub.QueryChaincode(chaincodeURL, f, queryArgs) + queryArgs := shim.ToChaincodeArgs(f, "a") + response, err := stub.QueryChaincode(chaincodeURL, queryArgs) if err != nil { errStr := fmt.Sprintf("Failed to query chaincode. Got error: %s", err.Error()) fmt.Printf(errStr) @@ -87,8 +87,8 @@ func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args return nil, errors.New(errStr) } - queryArgs = []string{"b"} - response, err = stub.QueryChaincode(chaincodeURL, f, queryArgs) + queryArgs = shim.ToChaincodeArgs(f, "b") + response, err = stub.QueryChaincode(chaincodeURL, queryArgs) if err != nil { errStr := fmt.Sprintf("Failed to query chaincode. Got error: %s", err.Error()) fmt.Printf(errStr) @@ -133,8 +133,8 @@ func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args // Query chaincode_example02 f := "query" - queryArgs := []string{"a"} - response, err := stub.QueryChaincode(chaincodeURL, f, queryArgs) + queryArgs := shim.ToChaincodeArgs(f, "a") + response, err := stub.QueryChaincode(chaincodeURL, queryArgs) if err != nil { errStr := fmt.Sprintf("Failed to query chaincode. Got error: %s", err.Error()) fmt.Printf(errStr) @@ -147,8 +147,8 @@ func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args return nil, errors.New(errStr) } - queryArgs = []string{"b"} - response, err = stub.QueryChaincode(chaincodeURL, f, queryArgs) + queryArgs = shim.ToChaincodeArgs(f, "b") + response, err = stub.QueryChaincode(chaincodeURL, queryArgs) if err != nil { errStr := fmt.Sprintf("Failed to query chaincode. Got error: %s", err.Error()) fmt.Printf(errStr) diff --git a/examples/chaincode/go/passthru/passthru.go b/examples/chaincode/go/passthru/passthru.go index 5d481c9ff6c..27dbb15ba2c 100644 --- a/examples/chaincode/go/passthru/passthru.go +++ b/examples/chaincode/go/passthru/passthru.go @@ -47,17 +47,10 @@ func (p *PassthruChaincode) iq(invoke bool, stub *shim.ChaincodeStub, function s } chaincodeID := function - var f string - var cargs []string - if len(args) > 0 { - f = args[0] - cargs = args[1:] - } - if invoke { - return stub.InvokeChaincode(chaincodeID, f, cargs) + return stub.InvokeChaincode(chaincodeID, shim.ToChaincodeArgs(args...)) } - return stub.QueryChaincode(chaincodeID, f, cargs) + return stub.QueryChaincode(chaincodeID, shim.ToChaincodeArgs(args...)) } // Invoke passes through the invoke call diff --git a/protos/chaincode.pb.go b/protos/chaincode.pb.go index acbfe93a20a..771373199bd 100644 --- a/protos/chaincode.pb.go +++ b/protos/chaincode.pb.go @@ -187,8 +187,7 @@ func (*ChaincodeID) ProtoMessage() {} // Carries the chaincode function and its arguments. type ChaincodeInput struct { - Function string `protobuf:"bytes,1,opt,name=function" json:"function,omitempty"` - Args []string `protobuf:"bytes,2,rep,name=args" json:"args,omitempty"` + Args [][]byte `protobuf:"bytes,2,rep,name=args,proto3" json:"args,omitempty"` } func (m *ChaincodeInput) Reset() { *m = ChaincodeInput{} } diff --git a/protos/chaincode.proto b/protos/chaincode.proto index efb80a31c71..495817d56bd 100644 --- a/protos/chaincode.proto +++ b/protos/chaincode.proto @@ -47,10 +47,7 @@ message ChaincodeID { // Carries the chaincode function and its arguments. message ChaincodeInput { - - string function = 1; - repeated string args = 2; - + repeated bytes args = 1; } // Carries the chaincode specification. This is the actual metadata required for