github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/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 converts 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 134 var instPolicy []byte 135 if ccpack.sDepSpec != nil { 136 instPolicy = ccpack.sDepSpec.InstantiationPolicy 137 } 138 139 return &ChaincodeData{ 140 Name: ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name, 141 Version: ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version, 142 Data: ccpack.datab, 143 Id: ccpack.id, 144 InstantiationPolicy: instPolicy, 145 } 146 } 147 148 func (ccpack *SignedCDSPackage) getCDSData(scds *pb.SignedChaincodeDeploymentSpec) ([]byte, []byte, *SignedCDSData, error) { 149 // check for nil argument. It is an assertion that getCDSData 150 // is never called on a package that did not go through/succeed 151 // package initialization. 152 if scds == nil { 153 panic("nil cds") 154 } 155 156 cds := &pb.ChaincodeDeploymentSpec{} 157 err := proto.Unmarshal(scds.ChaincodeDeploymentSpec, cds) 158 if err != nil { 159 return nil, nil, nil, err 160 } 161 162 if err = factory.InitFactories(nil); err != nil { 163 return nil, nil, nil, fmt.Errorf("Internal error, BCCSP could not be initialized : %s", err) 164 } 165 166 //get the hash object 167 hash, err := factory.GetDefault().GetHash(&bccsp.SHAOpts{}) 168 if err != nil { 169 return nil, nil, nil, err 170 } 171 172 scdsdata := &SignedCDSData{} 173 174 //get the code hash 175 hash.Write(cds.CodePackage) 176 scdsdata.CodeHash = hash.Sum(nil) 177 178 hash.Reset() 179 180 //get the metadata hash 181 hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Name)) 182 hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Version)) 183 184 scdsdata.MetaDataHash = hash.Sum(nil) 185 186 hash.Reset() 187 188 //get the signature hashes 189 if scds.InstantiationPolicy == nil { 190 return nil, nil, nil, fmt.Errorf("instantiation policy cannot be nil for chaincode (%s:%s)", cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version) 191 } 192 193 hash.Write(scds.InstantiationPolicy) 194 for _, o := range scds.OwnerEndorsements { 195 hash.Write(o.Endorser) 196 } 197 scdsdata.SignatureHash = hash.Sum(nil) 198 199 //marshall data 200 b, err := proto.Marshal(scdsdata) 201 if err != nil { 202 return nil, nil, nil, err 203 } 204 205 hash.Reset() 206 207 //compute the id 208 hash.Write(scdsdata.CodeHash) 209 hash.Write(scdsdata.MetaDataHash) 210 hash.Write(scdsdata.SignatureHash) 211 212 id := hash.Sum(nil) 213 214 return b, id, scdsdata, nil 215 } 216 217 // ValidateCC returns error if the chaincode is not found or if its not a 218 // ChaincodeDeploymentSpec 219 func (ccpack *SignedCDSPackage) ValidateCC(ccdata *ChaincodeData) error { 220 if ccpack.sDepSpec == nil { 221 return fmt.Errorf("uninitialized package") 222 } 223 224 if ccpack.sDepSpec.ChaincodeDeploymentSpec == nil { 225 return fmt.Errorf("signed chaincode deployment spec cannot be nil in a package") 226 } 227 228 if ccpack.depSpec == nil { 229 return fmt.Errorf("chaincode deployment spec cannot be nil in a package") 230 } 231 232 if ccdata.Name != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name || ccdata.Version != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version { 233 return fmt.Errorf("invalid chaincode data %v (%v)", ccdata, ccpack.depSpec.ChaincodeSpec.ChaincodeId) 234 } 235 236 otherdata := &SignedCDSData{} 237 err := proto.Unmarshal(ccdata.Data, otherdata) 238 if err != nil { 239 return err 240 } 241 242 if !ccpack.data.Equals(otherdata) { 243 return fmt.Errorf("data mismatch") 244 } 245 246 return nil 247 } 248 249 //InitFromBuffer sets the buffer if valid and returns ChaincodeData 250 func (ccpack *SignedCDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, error) { 251 //incase ccpack is reused 252 ccpack.reset() 253 254 env := &common.Envelope{} 255 err := proto.Unmarshal(buf, env) 256 if err != nil { 257 return nil, fmt.Errorf("failed to unmarshal envelope from bytes") 258 } 259 cHdr, sDepSpec, err := ccpackage.ExtractSignedCCDepSpec(env) 260 if err != nil { 261 return nil, err 262 } 263 if cHdr.Type != int32(common.HeaderType_CHAINCODE_PACKAGE) { 264 return nil, fmt.Errorf("invalid type of envelope for chaincode package") 265 } 266 267 depSpec := &pb.ChaincodeDeploymentSpec{} 268 err = proto.Unmarshal(sDepSpec.ChaincodeDeploymentSpec, depSpec) 269 if err != nil { 270 return nil, fmt.Errorf("error getting deployment spec") 271 } 272 273 databytes, id, data, err := ccpack.getCDSData(sDepSpec) 274 if err != nil { 275 return nil, err 276 } 277 278 ccpack.buf = buf 279 ccpack.sDepSpec = sDepSpec 280 ccpack.depSpec = depSpec 281 ccpack.env = env 282 ccpack.data = data 283 ccpack.datab = databytes 284 ccpack.id = id 285 286 return ccpack.GetChaincodeData(), nil 287 } 288 289 //InitFromFS returns the chaincode and its package from the file system 290 func (ccpack *SignedCDSPackage) InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) { 291 //incase ccpack is reused 292 ccpack.reset() 293 294 buf, err := GetChaincodePackage(ccname, ccversion) 295 if err != nil { 296 return nil, nil, err 297 } 298 299 if _, err = ccpack.InitFromBuffer(buf); err != nil { 300 return nil, nil, err 301 } 302 303 return ccpack.buf, ccpack.depSpec, nil 304 } 305 306 //PutChaincodeToFS - serializes chaincode to a package on the file system 307 func (ccpack *SignedCDSPackage) PutChaincodeToFS() error { 308 if ccpack.buf == nil { 309 return fmt.Errorf("uninitialized package") 310 } 311 312 if ccpack.id == nil { 313 return fmt.Errorf("id cannot be nil if buf is not nil") 314 } 315 316 if ccpack.sDepSpec == nil || ccpack.depSpec == nil { 317 return fmt.Errorf("depspec cannot be nil if buf is not nil") 318 } 319 320 if ccpack.env == nil { 321 return fmt.Errorf("env cannot be nil if buf and depspec are not nil") 322 } 323 324 if ccpack.data == nil { 325 return fmt.Errorf("nil data") 326 } 327 328 if ccpack.datab == nil { 329 return fmt.Errorf("nil data bytes") 330 } 331 332 ccname := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name 333 ccversion := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version 334 335 //return error if chaincode exists 336 path := fmt.Sprintf("%s/%s.%s", chaincodeInstallPath, ccname, ccversion) 337 if _, err := os.Stat(path); err == nil { 338 return fmt.Errorf("chaincode %s exists", path) 339 } 340 341 if err := ioutil.WriteFile(path, ccpack.buf, 0644); err != nil { 342 return err 343 } 344 345 return nil 346 }