github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/common/ccprovider/sigcdspackage.go (about) 1 /* 2 Copyright IBM Corp. 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 ccprovider 18 19 import ( 20 "fmt" 21 "io/ioutil" 22 "os" 23 24 "github.com/golang/protobuf/proto" 25 26 "bytes" 27 28 "github.com/hyperledger/fabric/bccsp" 29 "github.com/hyperledger/fabric/bccsp/factory" 30 "github.com/hyperledger/fabric/core/common/ccpackage" 31 "github.com/hyperledger/fabric/protos/common" 32 pb "github.com/hyperledger/fabric/protos/peer" 33 ) 34 35 //----- SignedCDSData ------ 36 37 //SignedCDSData is data stored in the LSCC on instantiation of a CC 38 //for SignedCDSPackage. This needs to be serialized for ChaincodeData 39 //hence the protobuf format 40 type SignedCDSData struct { 41 CodeHash []byte `protobuf:"bytes,1,opt,name=hash"` 42 MetaDataHash []byte `protobuf:"bytes,2,opt,name=metadatahash"` 43 SignatureHash []byte `protobuf:"bytes,3,opt,name=signaturehash"` 44 } 45 46 //----implement functions needed from proto.Message for proto's mar/unmarshal functions 47 48 //Reset resets 49 func (data *SignedCDSData) Reset() { *data = SignedCDSData{} } 50 51 //String convers to string 52 func (data *SignedCDSData) String() string { return proto.CompactTextString(data) } 53 54 //ProtoMessage just exists to make proto happy 55 func (*SignedCDSData) ProtoMessage() {} 56 57 //Equals data equals other 58 func (data *SignedCDSData) Equals(other *SignedCDSData) bool { 59 return other != nil && 60 bytes.Equal(data.CodeHash, other.CodeHash) && 61 bytes.Equal(data.MetaDataHash, other.MetaDataHash) && 62 bytes.Equal(data.SignatureHash, other.SignatureHash) 63 } 64 65 //-------- SignedCDSPackage --------- 66 67 //SignedCDSPackage encapsulates SignedChaincodeDeploymentSpec. 68 type SignedCDSPackage struct { 69 buf []byte 70 depSpec *pb.ChaincodeDeploymentSpec 71 sDepSpec *pb.SignedChaincodeDeploymentSpec 72 env *common.Envelope 73 data *SignedCDSData 74 datab []byte 75 id []byte 76 } 77 78 // resets data 79 func (ccpack *SignedCDSPackage) reset() { 80 *ccpack = SignedCDSPackage{} 81 } 82 83 // GetId gets the fingerprint of the chaincode based on package computation 84 func (ccpack *SignedCDSPackage) GetId() []byte { 85 //this has to be after creating a package and initializing it 86 //If those steps fail, GetId() should never be called 87 if ccpack.id == nil { 88 panic("GetId called on uninitialized package") 89 } 90 return ccpack.id 91 } 92 93 // GetDepSpec gets the ChaincodeDeploymentSpec from the package 94 func (ccpack *SignedCDSPackage) GetDepSpec() *pb.ChaincodeDeploymentSpec { 95 //this has to be after creating a package and initializing it 96 //If those steps fail, GetDepSpec() should never be called 97 if ccpack.depSpec == nil { 98 panic("GetDepSpec called on uninitialized package") 99 } 100 return ccpack.depSpec 101 } 102 103 // GetInstantiationPolicy gets the instantiation policy from the package 104 func (ccpack *SignedCDSPackage) GetInstantiationPolicy() []byte { 105 if ccpack.sDepSpec == nil { 106 panic("GetInstantiationPolicy called on uninitialized package") 107 } 108 return ccpack.sDepSpec.InstantiationPolicy 109 } 110 111 // GetDepSpecBytes gets the serialized ChaincodeDeploymentSpec from the package 112 func (ccpack *SignedCDSPackage) GetDepSpecBytes() []byte { 113 //this has to be after creating a package and initializing it 114 //If those steps fail, GetDepSpecBytes() should never be called 115 if ccpack.sDepSpec == nil || ccpack.sDepSpec.ChaincodeDeploymentSpec == nil { 116 panic("GetDepSpecBytes called on uninitialized package") 117 } 118 return ccpack.sDepSpec.ChaincodeDeploymentSpec 119 } 120 121 // GetPackageObject gets the ChaincodeDeploymentSpec as proto.Message 122 func (ccpack *SignedCDSPackage) GetPackageObject() proto.Message { 123 return ccpack.env 124 } 125 126 // GetChaincodeData gets the ChaincodeData 127 func (ccpack *SignedCDSPackage) GetChaincodeData() *ChaincodeData { 128 //this has to be after creating a package and initializing it 129 //If those steps fail, GetChaincodeData() should never be called 130 if ccpack.depSpec == nil || ccpack.datab == nil || ccpack.id == nil { 131 panic("GetChaincodeData called on uninitialized package") 132 } 133 return &ChaincodeData{Name: ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name, Version: ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version, Data: ccpack.datab, Id: ccpack.id} 134 } 135 136 func (ccpack *SignedCDSPackage) getCDSData(scds *pb.SignedChaincodeDeploymentSpec) ([]byte, []byte, *SignedCDSData, error) { 137 // check for nil argument. It is an assertion that getCDSData 138 // is never called on a package that did not go through/succeed 139 // package initialization. 140 if scds == nil { 141 panic("nil cds") 142 } 143 144 cds := &pb.ChaincodeDeploymentSpec{} 145 err := proto.Unmarshal(scds.ChaincodeDeploymentSpec, cds) 146 if err != nil { 147 return nil, nil, nil, err 148 } 149 150 if err = factory.InitFactories(nil); err != nil { 151 return nil, nil, nil, fmt.Errorf("Internal error, BCCSP could not be initialized : %s", err) 152 } 153 154 //get the hash object 155 hash, err := factory.GetDefault().GetHash(&bccsp.SHAOpts{}) 156 if err != nil { 157 return nil, nil, nil, err 158 } 159 160 scdsdata := &SignedCDSData{} 161 162 //get the code hash 163 scdsdata.CodeHash = hash.Sum(cds.CodePackage) 164 165 hash.Reset() 166 167 //get the metadata hash 168 hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Name)) 169 hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Version)) 170 171 scdsdata.MetaDataHash = hash.Sum(nil) 172 173 hash.Reset() 174 175 //get the signature hashes 176 if scds.InstantiationPolicy == nil { 177 return nil, nil, nil, fmt.Errorf("instantiation policy cannot be nil for chaincode (%s:%s)", cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version) 178 } 179 180 hash.Write(scds.InstantiationPolicy) 181 for _, o := range scds.OwnerEndorsements { 182 hash.Write(o.Endorser) 183 } 184 scdsdata.SignatureHash = hash.Sum(nil) 185 186 //marshall data 187 b, err := proto.Marshal(scdsdata) 188 if err != nil { 189 return nil, nil, nil, err 190 } 191 192 hash.Reset() 193 194 //compute the id 195 hash.Write(scdsdata.CodeHash) 196 hash.Write(scdsdata.MetaDataHash) 197 hash.Write(scdsdata.SignatureHash) 198 199 id := hash.Sum(nil) 200 201 return b, id, scdsdata, nil 202 } 203 204 // ValidateCC returns error if the chaincode is not found or if its not a 205 // ChaincodeDeploymentSpec 206 func (ccpack *SignedCDSPackage) ValidateCC(ccdata *ChaincodeData) error { 207 if ccpack.sDepSpec == nil { 208 return fmt.Errorf("uninitialized package") 209 } 210 211 if ccpack.sDepSpec.ChaincodeDeploymentSpec == nil { 212 return fmt.Errorf("signed chaincode deployment spec cannot be nil in a package") 213 } 214 215 if ccpack.depSpec == nil { 216 return fmt.Errorf("chaincode deployment spec cannot be nil in a package") 217 } 218 219 if ccdata.Name != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name || ccdata.Version != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version { 220 return fmt.Errorf("invalid chaincode data %v (%v)", ccdata, ccpack.depSpec.ChaincodeSpec.ChaincodeId) 221 } 222 223 otherdata := &SignedCDSData{} 224 err := proto.Unmarshal(ccdata.Data, otherdata) 225 if err != nil { 226 return err 227 } 228 229 if !ccpack.data.Equals(otherdata) { 230 return fmt.Errorf("data mismatch") 231 } 232 233 return nil 234 } 235 236 //InitFromBuffer sets the buffer if valid and returns ChaincodeData 237 func (ccpack *SignedCDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, error) { 238 //incase ccpack is reused 239 ccpack.reset() 240 241 env := &common.Envelope{} 242 err := proto.Unmarshal(buf, env) 243 if err != nil { 244 return nil, fmt.Errorf("failed to unmarshal envelope from bytes") 245 } 246 cHdr, sDepSpec, err := ccpackage.ExtractSignedCCDepSpec(env) 247 if err != nil { 248 return nil, err 249 } 250 if cHdr.Type != int32(common.HeaderType_CHAINCODE_PACKAGE) { 251 return nil, fmt.Errorf("invalid type of envelope for chaincode package") 252 } 253 254 depSpec := &pb.ChaincodeDeploymentSpec{} 255 err = proto.Unmarshal(sDepSpec.ChaincodeDeploymentSpec, depSpec) 256 if err != nil { 257 return nil, fmt.Errorf("error getting deployment spec") 258 } 259 260 databytes, id, data, err := ccpack.getCDSData(sDepSpec) 261 if err != nil { 262 return nil, err 263 } 264 265 ccpack.buf = buf 266 ccpack.sDepSpec = sDepSpec 267 ccpack.depSpec = depSpec 268 ccpack.env = env 269 ccpack.data = data 270 ccpack.datab = databytes 271 ccpack.id = id 272 273 return ccpack.GetChaincodeData(), nil 274 } 275 276 //InitFromFS returns the chaincode and its package from the file system 277 func (ccpack *SignedCDSPackage) InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) { 278 //incase ccpack is reused 279 ccpack.reset() 280 281 buf, err := GetChaincodePackage(ccname, ccversion) 282 if err != nil { 283 return nil, nil, err 284 } 285 286 if _, err = ccpack.InitFromBuffer(buf); err != nil { 287 return nil, nil, err 288 } 289 290 return ccpack.buf, ccpack.depSpec, nil 291 } 292 293 //PutChaincodeToFS - serializes chaincode to a package on the file system 294 func (ccpack *SignedCDSPackage) PutChaincodeToFS() error { 295 if ccpack.buf == nil { 296 return fmt.Errorf("uninitialized package") 297 } 298 299 if ccpack.id == nil { 300 return fmt.Errorf("id cannot be nil if buf is not nil") 301 } 302 303 if ccpack.sDepSpec == nil || ccpack.depSpec == nil { 304 return fmt.Errorf("depspec cannot be nil if buf is not nil") 305 } 306 307 if ccpack.env == nil { 308 return fmt.Errorf("env cannot be nil if buf and depspec are not nil") 309 } 310 311 if ccpack.data == nil { 312 return fmt.Errorf("nil data") 313 } 314 315 if ccpack.datab == nil { 316 return fmt.Errorf("nil data bytes") 317 } 318 319 ccname := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name 320 ccversion := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version 321 322 //return error if chaincode exists 323 path := fmt.Sprintf("%s/%s.%s", chaincodeInstallPath, ccname, ccversion) 324 if _, err := os.Stat(path); err == nil { 325 return fmt.Errorf("chaincode %s exists", path) 326 } 327 328 if err := ioutil.WriteFile(path, ccpack.buf, 0644); err != nil { 329 return err 330 } 331 332 return nil 333 }