github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/core/common/ccprovider/cdspackage.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 pb "github.com/hyperledger/fabric/protos/peer" 31 ) 32 33 //----- CDSData ------ 34 35 //CDSData is data stored in the LSCC on instantiation of a CC 36 //for CDSPackage. This needs to be serialized for ChaincodeData 37 //hence the protobuf format 38 type CDSData struct { 39 //CodeHash hash of CodePackage from ChaincodeDeploymentSpec 40 CodeHash []byte `protobuf:"bytes,1,opt,name=codehash,proto3"` 41 42 //MetaDataHash hash of Name and Version from ChaincodeDeploymentSpec 43 MetaDataHash []byte `protobuf:"bytes,2,opt,name=metadatahash,proto3"` 44 } 45 46 //----implement functions needed from proto.Message for proto's mar/unmarshal functions 47 48 //Reset resets 49 func (data *CDSData) Reset() { *data = CDSData{} } 50 51 //String converts to string 52 func (data *CDSData) String() string { return proto.CompactTextString(data) } 53 54 //ProtoMessage just exists to make proto happy 55 func (*CDSData) ProtoMessage() {} 56 57 //Equals data equals other 58 func (data *CDSData) Equals(other *CDSData) bool { 59 return other != nil && bytes.Equal(data.CodeHash, other.CodeHash) && bytes.Equal(data.MetaDataHash, other.MetaDataHash) 60 } 61 62 //--------- CDSPackage ------------ 63 64 //CDSPackage encapsulates ChaincodeDeploymentSpec. 65 type CDSPackage struct { 66 buf []byte 67 depSpec *pb.ChaincodeDeploymentSpec 68 data *CDSData 69 datab []byte 70 id []byte 71 } 72 73 // resets data 74 func (ccpack *CDSPackage) reset() { 75 *ccpack = CDSPackage{} 76 } 77 78 // GetId gets the fingerprint of the chaincode based on package computation 79 func (ccpack *CDSPackage) GetId() []byte { 80 //this has to be after creating a package and initializing it 81 //If those steps fail, GetId() should never be called 82 if ccpack.id == nil { 83 panic("GetId called on uninitialized package") 84 } 85 return ccpack.id 86 } 87 88 // GetDepSpec gets the ChaincodeDeploymentSpec from the package 89 func (ccpack *CDSPackage) GetDepSpec() *pb.ChaincodeDeploymentSpec { 90 //this has to be after creating a package and initializing it 91 //If those steps fail, GetDepSpec() should never be called 92 if ccpack.depSpec == nil { 93 panic("GetDepSpec called on uninitialized package") 94 } 95 return ccpack.depSpec 96 } 97 98 // GetDepSpecBytes gets the serialized ChaincodeDeploymentSpec from the package 99 func (ccpack *CDSPackage) GetDepSpecBytes() []byte { 100 //this has to be after creating a package and initializing it 101 //If those steps fail, GetDepSpecBytes() should never be called 102 if ccpack.buf == nil { 103 panic("GetDepSpecBytes called on uninitialized package") 104 } 105 return ccpack.buf 106 } 107 108 // GetPackageObject gets the ChaincodeDeploymentSpec as proto.Message 109 func (ccpack *CDSPackage) GetPackageObject() proto.Message { 110 return ccpack.depSpec 111 } 112 113 // GetChaincodeData gets the ChaincodeData 114 func (ccpack *CDSPackage) GetChaincodeData() *ChaincodeData { 115 //this has to be after creating a package and initializing it 116 //If those steps fail, GetChaincodeData() should never be called 117 if ccpack.depSpec == nil || ccpack.datab == nil || ccpack.id == nil { 118 panic("GetChaincodeData called on uninitialized package") 119 } 120 return &ChaincodeData{Name: ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name, Version: ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version, Data: ccpack.datab, Id: ccpack.id} 121 } 122 123 func (ccpack *CDSPackage) getCDSData(cds *pb.ChaincodeDeploymentSpec) ([]byte, []byte, *CDSData, error) { 124 // check for nil argument. It is an assertion that getCDSData 125 // is never called on a package that did not go through/succeed 126 // package initialization. 127 if cds == nil { 128 panic("nil cds") 129 } 130 131 b, err := proto.Marshal(cds) 132 if err != nil { 133 return nil, nil, nil, err 134 } 135 136 if err = factory.InitFactories(nil); err != nil { 137 return nil, nil, nil, fmt.Errorf("Internal error, BCCSP could not be initialized : %s", err) 138 } 139 140 //compute hashes now 141 hash, err := factory.GetDefault().GetHash(&bccsp.SHAOpts{}) 142 if err != nil { 143 return nil, nil, nil, err 144 } 145 146 cdsdata := &CDSData{} 147 148 //code hash 149 hash.Write(cds.CodePackage) 150 cdsdata.CodeHash = hash.Sum(nil) 151 152 hash.Reset() 153 154 //metadata hash 155 hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Name)) 156 hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Version)) 157 158 cdsdata.MetaDataHash = hash.Sum(nil) 159 160 b, err = proto.Marshal(cdsdata) 161 if err != nil { 162 return nil, nil, nil, err 163 } 164 165 hash.Reset() 166 167 //compute the id 168 hash.Write(cdsdata.CodeHash) 169 hash.Write(cdsdata.MetaDataHash) 170 171 id := hash.Sum(nil) 172 173 return b, id, cdsdata, nil 174 } 175 176 // ValidateCC returns error if the chaincode is not found or if its not a 177 // ChaincodeDeploymentSpec 178 func (ccpack *CDSPackage) ValidateCC(ccdata *ChaincodeData) error { 179 if ccpack.depSpec == nil { 180 return fmt.Errorf("uninitialized package") 181 } 182 183 if ccpack.data == nil { 184 return fmt.Errorf("nil data") 185 } 186 187 if ccdata.Name != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name || ccdata.Version != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version { 188 return fmt.Errorf("invalid chaincode data %v (%v)", ccdata, ccpack.depSpec.ChaincodeSpec.ChaincodeId) 189 } 190 191 otherdata := &CDSData{} 192 err := proto.Unmarshal(ccdata.Data, otherdata) 193 if err != nil { 194 return err 195 } 196 197 if !ccpack.data.Equals(otherdata) { 198 return fmt.Errorf("data mismatch") 199 } 200 201 return nil 202 } 203 204 //InitFromBuffer sets the buffer if valid and returns ChaincodeData 205 func (ccpack *CDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, error) { 206 //incase ccpack is reused 207 ccpack.reset() 208 209 depSpec := &pb.ChaincodeDeploymentSpec{} 210 err := proto.Unmarshal(buf, depSpec) 211 if err != nil { 212 return nil, fmt.Errorf("failed to unmarshal deployment spec from bytes") 213 } 214 215 databytes, id, data, err := ccpack.getCDSData(depSpec) 216 if err != nil { 217 return nil, err 218 } 219 220 ccpack.buf = buf 221 ccpack.depSpec = depSpec 222 ccpack.data = data 223 ccpack.datab = databytes 224 ccpack.id = id 225 226 return ccpack.GetChaincodeData(), nil 227 } 228 229 //InitFromFS returns the chaincode and its package from the file system 230 func (ccpack *CDSPackage) InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) { 231 //incase ccpack is reused 232 ccpack.reset() 233 234 buf, err := GetChaincodePackage(ccname, ccversion) 235 if err != nil { 236 return nil, nil, err 237 } 238 239 if _, err = ccpack.InitFromBuffer(buf); err != nil { 240 return nil, nil, err 241 } 242 243 return ccpack.buf, ccpack.depSpec, nil 244 } 245 246 //PutChaincodeToFS - serializes chaincode to a package on the file system 247 func (ccpack *CDSPackage) PutChaincodeToFS() error { 248 if ccpack.buf == nil { 249 return fmt.Errorf("uninitialized package") 250 } 251 252 if ccpack.id == nil { 253 return fmt.Errorf("id cannot be nil if buf is not nil") 254 } 255 256 if ccpack.depSpec == nil { 257 return fmt.Errorf("depspec cannot be nil if buf is not nil") 258 } 259 260 if ccpack.data == nil { 261 return fmt.Errorf("nil data") 262 } 263 264 if ccpack.datab == nil { 265 return fmt.Errorf("nil data bytes") 266 } 267 268 ccname := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name 269 ccversion := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version 270 271 //return error if chaincode exists 272 path := fmt.Sprintf("%s/%s.%s", chaincodeInstallPath, ccname, ccversion) 273 if _, err := os.Stat(path); err == nil { 274 return fmt.Errorf("chaincode %s exists", path) 275 } 276 277 if err := ioutil.WriteFile(path, ccpack.buf, 0644); err != nil { 278 return err 279 } 280 281 return nil 282 }