diff --git a/peer/chaincode/resources.go b/peer/chaincode/resources.go index cdbc062600b..05ede3ec695 100644 --- a/peer/chaincode/resources.go +++ b/peer/chaincode/resources.go @@ -9,11 +9,10 @@ package chaincode import ( "bytes" "fmt" - "strings" - "time" - "io/ioutil" "os" + "strings" + "time" "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/common/cauthdsl" @@ -37,6 +36,8 @@ const ( v11 ) +const defaultEndorsementPolicy = "/Channel/Application/Writers" + // SignatureSupport creates signature headers, signs messages, // and also serializes its identity to bytes type SignatureSupport interface { @@ -184,6 +185,7 @@ func fetchResourceConfig(ec peer.EndorserClient, ss SignatureSupport, channel st func ccGroup(ccName string, version string, validation string, endorsement string, hash []byte, modpolicies map[string]string, policy *common.SignaturePolicyEnvelope) *common.ConfigGroup { logger.Infof("creating ccGroup using %s and %s", validation, endorsement) var vsccArg []byte + appendConfigPolicy := true if validation == "" { validation = "vscc" } @@ -191,25 +193,23 @@ func ccGroup(ccName string, version string, validation string, endorsement strin endorsement = "escc" } if validation == "static-endorsement-policy" { - vsccArg = utils.MarshalOrPanic(&peer.VSCCArgs{ - EndorsementPolicyRef: fmt.Sprintf("/Resources/Chaincodes/%s/Endorsement", ccName), - }) + if policy == nil { + appendConfigPolicy = false + logger.Info("Policy not specified, defaulting to", defaultEndorsementPolicy) + vsccArg = utils.MarshalOrPanic(&peer.VSCCArgs{ + EndorsementPolicyRef: defaultEndorsementPolicy, + }) + } else { + vsccArg = utils.MarshalOrPanic(&peer.VSCCArgs{ + EndorsementPolicyRef: fmt.Sprintf("/Resources/Chaincodes/%s/Endorsement", ccName), + }) + } } if validation == "vscc" { logger.Infof("Setting VSCC arg to simple policy, using %s and %s", validation, endorsement) vsccArg = utils.MarshalOrPanic(policy) } - return &common.ConfigGroup{ - Policies: map[string]*common.ConfigPolicy{ - // TODO: make a constant in some other package - "Endorsement": { - ModPolicy: modpolicies["[Policy] Endorsement"], - Policy: &common.Policy{ - Type: int32(common.Policy_SIGNATURE), - Value: utils.MarshalOrPanic(policy), - }, - }, - }, + cfgGrp := &common.ConfigGroup{ ModPolicy: modpolicies["Base"], Values: map[string]*common.ConfigValue{ // TODO: make a constant in some other package @@ -237,6 +237,19 @@ func ccGroup(ccName string, version string, validation string, endorsement strin }, }, } + if appendConfigPolicy { + cfgGrp.Policies = map[string]*common.ConfigPolicy{ + // TODO: make a constant in some other package + "Endorsement": { + ModPolicy: modpolicies["[Policy] Endorsement"], + Policy: &common.Policy{ + Type: int32(common.Policy_SIGNATURE), + Value: utils.MarshalOrPanic(policy), + }, + }, + } + } + return cfgGrp } func (update ccUpdate) addChaincode() { @@ -338,13 +351,18 @@ func configBasedLifecycleUpdate(ss *sigSupport, cf *ChaincodeCmdFactory, config if err != nil { return err } - if policy == "" { - return errors.New("empty policy") + var pol *common.SignaturePolicyEnvelope + if policy != "" { + pol, err = cauthdsl.FromString(policy) + if err != nil { + return err + } } - pol, err := cauthdsl.FromString(policy) - if err != nil { - return err + + if policy == "" && (vscc == "vscc" || vscc == "") { + return errors.New("policy must be specified when vscc flag is set to 'vscc' or missing") } + update := ccUpdate{ policy: pol, computeDelta: update2.Compute, diff --git a/peer/chaincode/resources_test.go b/peer/chaincode/resources_test.go index fd1f470e0d1..394574826a4 100644 --- a/peer/chaincode/resources_test.go +++ b/peer/chaincode/resources_test.go @@ -279,7 +279,7 @@ func TestDeployResource(t *testing.T) { Groups: map[string]*common.ConfigGroup{ resourcesconfig.ChaincodesGroupKey: { Groups: map[string]*common.ConfigGroup{ - "example02": ccGroup("example02", "1.0", "vscc", "escc", []byte("hash"), nil, pol), + "example01": ccGroup("example01", "1.0", "vscc", "escc", []byte("hash"), nil, pol), }, }, }, @@ -360,6 +360,7 @@ func TestDeployResource(t *testing.T) { assert.NoError(t, err) assert.True(t, broadcastEvent.wasSent(), "Config update was not sent to ordering, but shouldn't have") assert.Equal(t, 2, broadcastEvent.signatureCount(), "Expected 2 signatures in config update") + resourceEnvelopeLoadPath = "" // Bad path: peer returns the config but the chaincodes it returns don't have the wanted name chaincodeName = "example03" @@ -380,6 +381,62 @@ func TestDeployResource(t *testing.T) { assert.Error(t, err) assert.Equal(t, "failed probing channel version: endorsement failed", err.Error()) + // Bad path: vscc is empty and policy is missing + policy = "" + chaincodeName = "example02" + cmd, broadcastEvent = newTestCase(creatorBytes) + err = chaincodeDeploy(cmd, noopInit) + assert.Error(t, err) + assert.Equal(t, "policy must be specified when vscc flag is set to 'vscc' or missing", err.Error()) + + // Bad path: vscc is 'vscc' and policy is missing + vscc = "vscc" + cmd, broadcastEvent = newTestCase(creatorBytes) + err = chaincodeDeploy(cmd, noopInit) + assert.Error(t, err) + assert.Equal(t, "policy must be specified when vscc flag is set to 'vscc' or missing", err.Error()) + + extractVSCCArgAndCheckPoliciesPresent := func(env *common.ConfigUpdateEnvelope) (*peer.VSCCArgs, bool) { + cu := &common.ConfigUpdate{} + proto.Unmarshal(env.ConfigUpdate, cu) + ccVal := &peer.ChaincodeValidation{} + ccGrp := cu.WriteSet.Groups["Chaincodes"].Groups[chaincodeName] + proto.Unmarshal(ccGrp.Values["ChaincodeValidation"].Value, ccVal) + vsccArg := &peer.VSCCArgs{} + proto.Unmarshal(ccVal.Argument, vsccArg) + return vsccArg, ccGrp.Policies != nil + } + // Good path: vscc is set to 'static-endorsement-policy'. + // We make sure that if no policy is specified, the config update sets the endorsement policy + // to be "/Channel/Application/Writers" (default) + vscc = "static-endorsement-policy" + resourceEnvelopeSavePath = fmt.Sprintf("/tmp/%d.pb", os.Getpid()) + defer os.Remove(resourceEnvelopeSavePath) + cmd, broadcastEvent = newTestCase(creatorBytes) + err = chaincodeDeploy(cmd, noopInit) + assert.NoError(t, err) + env, err := loadEnvelope(resourceEnvelopeSavePath) + assert.NoError(t, err) + vsccArg, policiesPresent := extractVSCCArgAndCheckPoliciesPresent(env) + assert.Equal(t, "/Channel/Application/Writers", vsccArg.EndorsementPolicyRef) + // If static policy is employed and policy is nil, then no policies should have been defined + assert.False(t, policiesPresent) + + // Good path: vscc is set to 'static-endorsement-policy', but this time the policy exists. + // We make sure that the Policies are now initialized, and that the EndorsementPolicyRef is set + // to the policies of the chaincode group + policy = "AND ('Org1MSP.member','Org2MSP.member')" + resourceEnvelopeSavePath = fmt.Sprintf("/tmp/%d.pb", os.Getpid()) + defer os.Remove(resourceEnvelopeSavePath) + cmd, broadcastEvent = newTestCase(creatorBytes) + err = chaincodeDeploy(cmd, noopInit) + assert.NoError(t, err) + env, err = loadEnvelope(resourceEnvelopeSavePath) + assert.NoError(t, err) + vsccArg, policiesPresent = extractVSCCArgAndCheckPoliciesPresent(env) + assert.Equal(t, "/Resources/Chaincodes/example02/Endorsement", vsccArg.EndorsementPolicyRef) + // If static policy is employed and policy is nil, then no policies should have been defined + assert.True(t, policiesPresent) } type mockSigningIdentity struct {