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