Skip to content

Commit 8a37f5b

Browse files
author
Srinivasan Muralidharan
committed
FAB-2925 proto defn. for ChaincodeInstallPackage
https://jira.hyperledger.org/browse/FAB-2925 This the first of CRs for "Chaincode Install Packaging" story (FAB-2859). Key changes below. Note that these core definitions are not used in the fabric (which still uses raw ChaincodeDeploymentSpec). Future CRs will incrementally use them. protos/peer/chaincodepackage.proto ---------------------------------- Defines ChaincodeInstallPackage with ChaincodeDeploymentSpec and endorsements (owners) over it. Key observation- owner signs (CDS+instantiationpolicy+ownerid) protos/common/common.proto -------------------------- introduce CHAINCODE_PACKAGE header type core/common/ccpackage/ccpackage.go ---------------------------------- Defines two packaging functions - one for a owner and another for installer. Change-Id: Ie4b9ebb4aa08957f30c72dd576c90b119e4ea912 Signed-off-by: Srinivasan Muralidharan <[email protected]>
1 parent d778d0a commit 8a37f5b

8 files changed

+600
-66
lines changed

core/common/ccpackage/ccpackage.go

+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
Copyright IBM Corp. 2016-2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package ccpackage
18+
19+
import (
20+
"bytes"
21+
"errors"
22+
"fmt"
23+
24+
"github.com/golang/protobuf/proto"
25+
"github.com/hyperledger/fabric/msp"
26+
"github.com/hyperledger/fabric/protos/common"
27+
"github.com/hyperledger/fabric/protos/peer"
28+
"github.com/hyperledger/fabric/protos/utils"
29+
)
30+
31+
// This file provides functions for helping with the chaincode install
32+
// package workflow. In particular
33+
// OwnerCreateSignedCCDepSpec - each owner creates signs the package using the same deploy
34+
// CreateSignedCCDepSpecForInstall - an admin or owner creates the package to be installed
35+
// using the packages from OwnerCreateSignedCCDepSpec
36+
37+
// ValidateCip validate the endorsed package against the base package
38+
func ValidateCip(baseCip, otherCip *peer.SignedChaincodeDeploymentSpec) error {
39+
if baseCip == nil || otherCip == nil {
40+
panic("do not call with nil parameters")
41+
}
42+
43+
if (baseCip.OwnerEndorsements == nil && otherCip.OwnerEndorsements != nil) || (baseCip.OwnerEndorsements != nil && otherCip.OwnerEndorsements == nil) {
44+
return fmt.Errorf("endorsements should either be both nil or not nil")
45+
}
46+
47+
bN := len(baseCip.OwnerEndorsements)
48+
oN := len(otherCip.OwnerEndorsements)
49+
if bN > 1 || oN > 1 {
50+
return fmt.Errorf("expect utmost 1 endorsement from a owner")
51+
}
52+
53+
if bN != oN {
54+
return fmt.Errorf("Rule-all packages should be endorsed or none should be endorsed failed for (%d, %d)", bN, oN)
55+
}
56+
57+
if !bytes.Equal(baseCip.ChaincodeDeploymentSpec, otherCip.ChaincodeDeploymentSpec) {
58+
return fmt.Errorf("Rule-all deployment specs should match(%d, %d)", len(baseCip.ChaincodeDeploymentSpec), len(otherCip.ChaincodeDeploymentSpec))
59+
}
60+
61+
if !bytes.Equal(baseCip.InstantiationPolicy, otherCip.InstantiationPolicy) {
62+
return fmt.Errorf("Rule-all instantiation policies should match(%d, %d)", len(baseCip.InstantiationPolicy), len(otherCip.InstantiationPolicy))
63+
}
64+
65+
return nil
66+
}
67+
68+
func createSignedCCDepSpec(cdsbytes []byte, instpolicybytes []byte, endorsements []*peer.Endorsement) (*common.Envelope, error) {
69+
if cdsbytes == nil {
70+
return nil, fmt.Errorf("nil chaincode deployment spec")
71+
}
72+
73+
if instpolicybytes == nil {
74+
return nil, fmt.Errorf("nil instantiation policy")
75+
}
76+
77+
// create SignedChaincodeDeploymentSpec...
78+
cip := &peer.SignedChaincodeDeploymentSpec{ChaincodeDeploymentSpec: cdsbytes, InstantiationPolicy: instpolicybytes, OwnerEndorsements: endorsements}
79+
80+
//...and marshal it
81+
cipbytes := utils.MarshalOrPanic(cip)
82+
83+
//use defaults (this is definitely ok for install package)
84+
msgVersion := int32(0)
85+
epoch := uint64(0)
86+
chdr := utils.MakeChannelHeader(common.HeaderType_CHAINCODE_PACKAGE, msgVersion, "", epoch)
87+
88+
// create the payload
89+
payl := &common.Payload{Header: &common.Header{ChannelHeader: utils.MarshalOrPanic(chdr)}, Data: cipbytes}
90+
paylBytes, err := utils.GetBytesPayload(payl)
91+
if err != nil {
92+
return nil, err
93+
}
94+
95+
// here's the unsigned envelope. The install package is endorsed if signingEntity != nil
96+
return &common.Envelope{Payload: paylBytes}, nil
97+
}
98+
99+
// CreateSignedCCDepSpecForInstall creates the final package from a set of packages signed by
100+
// owners. This is similar to how the SDK assembles a TX from various proposal
101+
// responses from the signatures.
102+
func CreateSignedCCDepSpecForInstall(pack []*common.Envelope) (*common.Envelope, error) {
103+
if len(pack) == 0 {
104+
return nil, errors.New("no packages provided to collate")
105+
}
106+
107+
//rules...
108+
// all packages must be endorsed or all packages should not be endorsed
109+
// the chaincode deployment spec should be same
110+
var baseCip *peer.SignedChaincodeDeploymentSpec
111+
var err error
112+
var endorsementExists bool
113+
var endorsements []*peer.Endorsement
114+
for n, r := range pack {
115+
p := &common.Payload{}
116+
if err = proto.Unmarshal(r.Payload, p); err != nil {
117+
return nil, err
118+
}
119+
120+
cip := &peer.SignedChaincodeDeploymentSpec{}
121+
if err = proto.Unmarshal(p.Data, cip); err != nil {
122+
return nil, err
123+
}
124+
125+
//if its the first element, check if it has endorsement so we can
126+
//enforce endorsement rules
127+
if n == 0 {
128+
baseCip = cip
129+
//if it has endorsement, all other owners should have signed too
130+
if len(cip.OwnerEndorsements) > 0 {
131+
endorsements = make([]*peer.Endorsement, len(pack))
132+
}
133+
134+
} else if err = ValidateCip(baseCip, cip); err != nil {
135+
return nil, err
136+
}
137+
138+
if endorsementExists {
139+
endorsements[n] = cip.OwnerEndorsements[0]
140+
}
141+
}
142+
143+
return createSignedCCDepSpec(baseCip.ChaincodeDeploymentSpec, baseCip.InstantiationPolicy, endorsements)
144+
}
145+
146+
// OwnerCreateSignedCCDepSpec creates a package from a ChaincodeDeploymentSpec and
147+
// optionally endorses it
148+
func OwnerCreateSignedCCDepSpec(cds *peer.ChaincodeDeploymentSpec, instPolicy *common.SignaturePolicyEnvelope, owner msp.SigningIdentity) (*common.Envelope, error) {
149+
if cds == nil {
150+
return nil, fmt.Errorf("invalid chaincode deployment spec")
151+
}
152+
153+
if instPolicy == nil {
154+
return nil, fmt.Errorf("must provide an instantiation policy")
155+
}
156+
157+
cdsbytes := utils.MarshalOrPanic(cds)
158+
159+
instpolicybytes := utils.MarshalOrPanic(instPolicy)
160+
161+
var endorsements []*peer.Endorsement
162+
//it is not mandatory (at this utils level) to have a signature
163+
//this is especially convenient during dev/test
164+
//it may be necessary to enforce it via a policy at a higher level
165+
if owner != nil {
166+
// serialize the signing identity
167+
endorser, err := owner.Serialize()
168+
if err != nil {
169+
return nil, fmt.Errorf("Could not serialize the signing identity for %s, err %s", owner.GetIdentifier(), err)
170+
}
171+
172+
// sign the concatenation of cds, instpolicy and the serialized endorser identity with this endorser's key
173+
signature, err := owner.Sign(append(cdsbytes, append(instpolicybytes, endorser...)...))
174+
if err != nil {
175+
return nil, fmt.Errorf("Could not sign the ccpackage, err %s", err)
176+
}
177+
178+
// each owner starts off the endorsements with one element. All such endorsed
179+
// packages will be collected in a final package by CreateSignedCCDepSpecForInstall
180+
// when endorsements will have all the entries
181+
endorsements = make([]*peer.Endorsement, 1)
182+
183+
endorsements[0] = &peer.Endorsement{Signature: signature, Endorser: endorser}
184+
}
185+
186+
return createSignedCCDepSpec(cdsbytes, instpolicybytes, endorsements)
187+
}

0 commit comments

Comments
 (0)