github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/common/ccpackage/ccpackage.go (about) 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 // ExtractSignedCCDepSpec extracts the messages from the envelope 32 func ExtractSignedCCDepSpec(env *common.Envelope) (*common.ChannelHeader, *peer.SignedChaincodeDeploymentSpec, error) { 33 p := &common.Payload{} 34 err := proto.Unmarshal(env.Payload, p) 35 if err != nil { 36 return nil, nil, err 37 } 38 ch := &common.ChannelHeader{} 39 err = proto.Unmarshal(p.Header.ChannelHeader, ch) 40 if err != nil { 41 return nil, nil, err 42 } 43 44 sp := &peer.SignedChaincodeDeploymentSpec{} 45 err = proto.Unmarshal(p.Data, sp) 46 if err != nil { 47 return nil, nil, err 48 } 49 50 return ch, sp, nil 51 } 52 53 // This file provides functions for helping with the chaincode install 54 // package workflow. In particular 55 // OwnerCreateSignedCCDepSpec - each owner creates signs the package using the same deploy 56 // CreateSignedCCDepSpecForInstall - an admin or owner creates the package to be installed 57 // using the packages from OwnerCreateSignedCCDepSpec 58 59 // ValidateCip validate the endorsed package against the base package 60 func ValidateCip(baseCip, otherCip *peer.SignedChaincodeDeploymentSpec) error { 61 if baseCip == nil || otherCip == nil { 62 panic("do not call with nil parameters") 63 } 64 65 if (baseCip.OwnerEndorsements == nil && otherCip.OwnerEndorsements != nil) || (baseCip.OwnerEndorsements != nil && otherCip.OwnerEndorsements == nil) { 66 return fmt.Errorf("endorsements should either be both nil or not nil") 67 } 68 69 bN := len(baseCip.OwnerEndorsements) 70 oN := len(otherCip.OwnerEndorsements) 71 if bN > 1 || oN > 1 { 72 return fmt.Errorf("expect utmost 1 endorsement from a owner") 73 } 74 75 if bN != oN { 76 return fmt.Errorf("Rule-all packages should be endorsed or none should be endorsed failed for (%d, %d)", bN, oN) 77 } 78 79 if !bytes.Equal(baseCip.ChaincodeDeploymentSpec, otherCip.ChaincodeDeploymentSpec) { 80 return fmt.Errorf("Rule-all deployment specs should match(%d, %d)", len(baseCip.ChaincodeDeploymentSpec), len(otherCip.ChaincodeDeploymentSpec)) 81 } 82 83 if !bytes.Equal(baseCip.InstantiationPolicy, otherCip.InstantiationPolicy) { 84 return fmt.Errorf("Rule-all instantiation policies should match(%d, %d)", len(baseCip.InstantiationPolicy), len(otherCip.InstantiationPolicy)) 85 } 86 87 return nil 88 } 89 90 func createSignedCCDepSpec(cdsbytes []byte, instpolicybytes []byte, endorsements []*peer.Endorsement) (*common.Envelope, error) { 91 if cdsbytes == nil { 92 return nil, fmt.Errorf("nil chaincode deployment spec") 93 } 94 95 if instpolicybytes == nil { 96 return nil, fmt.Errorf("nil instantiation policy") 97 } 98 99 // create SignedChaincodeDeploymentSpec... 100 cip := &peer.SignedChaincodeDeploymentSpec{ChaincodeDeploymentSpec: cdsbytes, InstantiationPolicy: instpolicybytes, OwnerEndorsements: endorsements} 101 102 //...and marshal it 103 cipbytes := utils.MarshalOrPanic(cip) 104 105 //use defaults (this is definitely ok for install package) 106 msgVersion := int32(0) 107 epoch := uint64(0) 108 chdr := utils.MakeChannelHeader(common.HeaderType_CHAINCODE_PACKAGE, msgVersion, "", epoch) 109 110 // create the payload 111 payl := &common.Payload{Header: &common.Header{ChannelHeader: utils.MarshalOrPanic(chdr)}, Data: cipbytes} 112 paylBytes, err := utils.GetBytesPayload(payl) 113 if err != nil { 114 return nil, err 115 } 116 117 // here's the unsigned envelope. The install package is endorsed if signingEntity != nil 118 return &common.Envelope{Payload: paylBytes}, nil 119 } 120 121 // CreateSignedCCDepSpecForInstall creates the final package from a set of packages signed by 122 // owners. This is similar to how the SDK assembles a TX from various proposal 123 // responses from the signatures. 124 func CreateSignedCCDepSpecForInstall(pack []*common.Envelope) (*common.Envelope, error) { 125 if len(pack) == 0 { 126 return nil, errors.New("no packages provided to collate") 127 } 128 129 //rules... 130 // all packages must be endorsed or all packages should not be endorsed 131 // the chaincode deployment spec should be same 132 var baseCip *peer.SignedChaincodeDeploymentSpec 133 var err error 134 var endorsementExists bool 135 var endorsements []*peer.Endorsement 136 for n, r := range pack { 137 p := &common.Payload{} 138 if err = proto.Unmarshal(r.Payload, p); err != nil { 139 return nil, err 140 } 141 142 cip := &peer.SignedChaincodeDeploymentSpec{} 143 if err = proto.Unmarshal(p.Data, cip); err != nil { 144 return nil, err 145 } 146 147 //if its the first element, check if it has endorsement so we can 148 //enforce endorsement rules 149 if n == 0 { 150 baseCip = cip 151 //if it has endorsement, all other owners should have signed too 152 if len(cip.OwnerEndorsements) > 0 { 153 endorsements = make([]*peer.Endorsement, len(pack)) 154 } 155 156 } else if err = ValidateCip(baseCip, cip); err != nil { 157 return nil, err 158 } 159 160 if endorsementExists { 161 endorsements[n] = cip.OwnerEndorsements[0] 162 } 163 } 164 165 return createSignedCCDepSpec(baseCip.ChaincodeDeploymentSpec, baseCip.InstantiationPolicy, endorsements) 166 } 167 168 // OwnerCreateSignedCCDepSpec creates a package from a ChaincodeDeploymentSpec and 169 // optionally endorses it 170 func OwnerCreateSignedCCDepSpec(cds *peer.ChaincodeDeploymentSpec, instPolicy *common.SignaturePolicyEnvelope, owner msp.SigningIdentity) (*common.Envelope, error) { 171 if cds == nil { 172 return nil, fmt.Errorf("invalid chaincode deployment spec") 173 } 174 175 if instPolicy == nil { 176 return nil, fmt.Errorf("must provide an instantiation policy") 177 } 178 179 cdsbytes := utils.MarshalOrPanic(cds) 180 181 instpolicybytes := utils.MarshalOrPanic(instPolicy) 182 183 var endorsements []*peer.Endorsement 184 //it is not mandatory (at this utils level) to have a signature 185 //this is especially convenient during dev/test 186 //it may be necessary to enforce it via a policy at a higher level 187 if owner != nil { 188 // serialize the signing identity 189 endorser, err := owner.Serialize() 190 if err != nil { 191 return nil, fmt.Errorf("Could not serialize the signing identity for %s, err %s", owner.GetIdentifier(), err) 192 } 193 194 // sign the concatenation of cds, instpolicy and the serialized endorser identity with this endorser's key 195 signature, err := owner.Sign(append(cdsbytes, append(instpolicybytes, endorser...)...)) 196 if err != nil { 197 return nil, fmt.Errorf("Could not sign the ccpackage, err %s", err) 198 } 199 200 // each owner starts off the endorsements with one element. All such endorsed 201 // packages will be collected in a final package by CreateSignedCCDepSpecForInstall 202 // when endorsements will have all the entries 203 endorsements = make([]*peer.Endorsement, 1) 204 205 endorsements[0] = &peer.Endorsement{Signature: signature, Endorser: endorser} 206 } 207 208 return createSignedCCDepSpec(cdsbytes, instpolicybytes, endorsements) 209 } 210 211 // SignExistingPackage adds a signature to a signed package. 212 func SignExistingPackage(env *common.Envelope, owner msp.SigningIdentity) (*common.Envelope, error) { 213 if owner == nil { 214 return nil, fmt.Errorf("owner not provided") 215 } 216 217 ch, sdepspec, err := ExtractSignedCCDepSpec(env) 218 if err != nil { 219 return nil, err 220 } 221 222 if ch == nil { 223 return nil, fmt.Errorf("channel header not found in the envelope") 224 } 225 226 if sdepspec == nil || sdepspec.ChaincodeDeploymentSpec == nil || sdepspec.InstantiationPolicy == nil || sdepspec.OwnerEndorsements == nil { 227 return nil, fmt.Errorf("invalid signed deployment spec") 228 } 229 230 // serialize the signing identity 231 endorser, err := owner.Serialize() 232 if err != nil { 233 return nil, fmt.Errorf("Could not serialize the signing identity for %s, err %s", owner.GetIdentifier(), err) 234 } 235 236 // sign the concatenation of cds, instpolicy and the serialized endorser identity with this endorser's key 237 signature, err := owner.Sign(append(sdepspec.ChaincodeDeploymentSpec, append(sdepspec.InstantiationPolicy, endorser...)...)) 238 if err != nil { 239 return nil, fmt.Errorf("Could not sign the ccpackage, err %s", err) 240 } 241 242 endorsements := append(sdepspec.OwnerEndorsements, &peer.Endorsement{Signature: signature, Endorser: endorser}) 243 244 return createSignedCCDepSpec(sdepspec.ChaincodeDeploymentSpec, sdepspec.InstantiationPolicy, endorsements) 245 }