github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/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 convers 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 cdsdata.CodeHash = hash.Sum(cds.CodePackage) 150 151 hash.Reset() 152 153 //metadata hash 154 hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Name)) 155 hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Version)) 156 157 cdsdata.MetaDataHash = hash.Sum(nil) 158 159 b, err = proto.Marshal(cdsdata) 160 if err != nil { 161 return nil, nil, nil, err 162 } 163 164 hash.Reset() 165 166 //compute the id 167 hash.Write(cdsdata.CodeHash) 168 hash.Write(cdsdata.MetaDataHash) 169 170 id := hash.Sum(nil) 171 172 return b, id, cdsdata, nil 173 } 174 175 // ValidateCC returns error if the chaincode is not found or if its not a 176 // ChaincodeDeploymentSpec 177 func (ccpack *CDSPackage) ValidateCC(ccdata *ChaincodeData) error { 178 if ccpack.depSpec == nil { 179 return fmt.Errorf("uninitialized package") 180 } 181 182 if ccpack.data == nil { 183 return fmt.Errorf("nil data") 184 } 185 186 if ccdata.Name != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name || ccdata.Version != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version { 187 return fmt.Errorf("invalid chaincode data %v (%v)", ccdata, ccpack.depSpec.ChaincodeSpec.ChaincodeId) 188 } 189 190 otherdata := &CDSData{} 191 err := proto.Unmarshal(ccdata.Data, otherdata) 192 if err != nil { 193 return err 194 } 195 196 if !ccpack.data.Equals(otherdata) { 197 return fmt.Errorf("data mismatch") 198 } 199 200 return nil 201 } 202 203 //InitFromBuffer sets the buffer if valid and returns ChaincodeData 204 func (ccpack *CDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, error) { 205 //incase ccpack is reused 206 ccpack.reset() 207 208 depSpec := &pb.ChaincodeDeploymentSpec{} 209 err := proto.Unmarshal(buf, depSpec) 210 if err != nil { 211 return nil, fmt.Errorf("failed to unmarshal deployment spec from bytes") 212 } 213 214 databytes, id, data, err := ccpack.getCDSData(depSpec) 215 if err != nil { 216 return nil, err 217 } 218 219 ccpack.buf = buf 220 ccpack.depSpec = depSpec 221 ccpack.data = data 222 ccpack.datab = databytes 223 ccpack.id = id 224 225 return ccpack.GetChaincodeData(), nil 226 } 227 228 //InitFromFS returns the chaincode and its package from the file system 229 func (ccpack *CDSPackage) InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) { 230 //incase ccpack is reused 231 ccpack.reset() 232 233 buf, err := GetChaincodePackage(ccname, ccversion) 234 if err != nil { 235 return nil, nil, err 236 } 237 238 if _, err = ccpack.InitFromBuffer(buf); err != nil { 239 return nil, nil, err 240 } 241 242 return ccpack.buf, ccpack.depSpec, nil 243 } 244 245 //PutChaincodeToFS - serializes chaincode to a package on the file system 246 func (ccpack *CDSPackage) PutChaincodeToFS() error { 247 if ccpack.buf == nil { 248 return fmt.Errorf("uninitialized package") 249 } 250 251 if ccpack.id == nil { 252 return fmt.Errorf("id cannot be nil if buf is not nil") 253 } 254 255 if ccpack.depSpec == nil { 256 return fmt.Errorf("depspec cannot be nil if buf is not nil") 257 } 258 259 if ccpack.data == nil { 260 return fmt.Errorf("nil data") 261 } 262 263 if ccpack.datab == nil { 264 return fmt.Errorf("nil data bytes") 265 } 266 267 ccname := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name 268 ccversion := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version 269 270 //return error if chaincode exists 271 path := fmt.Sprintf("%s/%s.%s", chaincodeInstallPath, ccname, ccversion) 272 if _, err := os.Stat(path); err == nil { 273 return fmt.Errorf("chaincode %s exists", path) 274 } 275 276 if err := ioutil.WriteFile(path, ccpack.buf, 0644); err != nil { 277 return err 278 } 279 280 return nil 281 }