github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/core/scc/lccc/lccc.go (about) 1 /* 2 Copyright IBM Corp. 2016 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 lccc 18 19 import ( 20 "fmt" 21 "strconv" 22 "strings" 23 24 "github.com/golang/protobuf/proto" 25 "github.com/hyperledger/fabric/common/cauthdsl" 26 "github.com/hyperledger/fabric/core/chaincode/shim" 27 "github.com/hyperledger/fabric/core/common/ccprovider" 28 "github.com/hyperledger/fabric/core/common/sysccprovider" 29 pb "github.com/hyperledger/fabric/protos/peer" 30 "github.com/hyperledger/fabric/protos/utils" 31 "github.com/op/go-logging" 32 ) 33 34 //The life cycle system chaincode manages chaincodes deployed 35 //on this peer. It manages chaincodes via Invoke proposals. 36 // "Args":["deploy",<ChaincodeDeploymentSpec>] 37 // "Args":["upgrade",<ChaincodeDeploymentSpec>] 38 // "Args":["stop",<ChaincodeInvocationSpec>] 39 // "Args":["start",<ChaincodeInvocationSpec>] 40 41 var logger = logging.MustGetLogger("lccc") 42 43 const ( 44 //CHAINCODETABLE prefix for chaincode tables 45 CHAINCODETABLE = "chaincodes" 46 47 //chaincode lifecyle commands 48 49 //INSTALL install command 50 INSTALL = "install" 51 52 //DEPLOY deploy command 53 DEPLOY = "deploy" 54 55 //UPGRADE upgrade chaincode 56 UPGRADE = "upgrade" 57 58 //GETCCINFO get chaincode 59 GETCCINFO = "getid" 60 61 //GETDEPSPEC get ChaincodeDeploymentSpec 62 GETDEPSPEC = "getdepspec" 63 64 //GETCCDATA get ChaincodeData 65 GETCCDATA = "getccdata" 66 67 //GETCHAINCODES gets the instantiated chaincodes on a channel 68 GETCHAINCODES = "getchaincodes" 69 70 //GETINSTALLEDCHAINCODES gets the installed chaincodes on a peer 71 GETINSTALLEDCHAINCODES = "getinstalledchaincodes" 72 73 //characters used in chaincodenamespace 74 specialChars = "/:[]${}" 75 ) 76 77 //---------- the LCCC ----------------- 78 79 // LifeCycleSysCC implements chaincode lifecycle and policies aroud it 80 type LifeCycleSysCC struct { 81 // sccprovider is the interface with which we call 82 // methods of the system chaincode package without 83 // import cycles 84 sccprovider sysccprovider.SystemChaincodeProvider 85 } 86 87 //----------------errors--------------- 88 89 //AlreadyRegisteredErr Already registered error 90 type AlreadyRegisteredErr string 91 92 func (f AlreadyRegisteredErr) Error() string { 93 return fmt.Sprintf("%s already registered", string(f)) 94 } 95 96 //InvalidFunctionErr invalid function error 97 type InvalidFunctionErr string 98 99 func (f InvalidFunctionErr) Error() string { 100 return fmt.Sprintf("invalid function to lccc %s", string(f)) 101 } 102 103 //InvalidArgsLenErr invalid arguments length error 104 type InvalidArgsLenErr int 105 106 func (i InvalidArgsLenErr) Error() string { 107 return fmt.Sprintf("invalid number of argument to lccc %d", int(i)) 108 } 109 110 //InvalidArgsErr invalid arguments error 111 type InvalidArgsErr int 112 113 func (i InvalidArgsErr) Error() string { 114 return fmt.Sprintf("invalid argument (%d) to lccc", int(i)) 115 } 116 117 //TXExistsErr transaction exists error 118 type TXExistsErr string 119 120 func (t TXExistsErr) Error() string { 121 return fmt.Sprintf("transaction exists %s", string(t)) 122 } 123 124 //TXNotFoundErr transaction not found error 125 type TXNotFoundErr string 126 127 func (t TXNotFoundErr) Error() string { 128 return fmt.Sprintf("transaction not found %s", string(t)) 129 } 130 131 //InvalidDeploymentSpecErr invalide chaincode deployment spec error 132 type InvalidDeploymentSpecErr string 133 134 func (f InvalidDeploymentSpecErr) Error() string { 135 return fmt.Sprintf("Invalid deployment spec : %s", string(f)) 136 } 137 138 //ExistsErr chaincode exists error 139 type ExistsErr string 140 141 func (t ExistsErr) Error() string { 142 return fmt.Sprintf("Chaincode exists %s", string(t)) 143 } 144 145 //NotFoundErr chaincode not registered with LCCC error 146 type NotFoundErr string 147 148 func (t NotFoundErr) Error() string { 149 return fmt.Sprintf("chaincode not found %s", string(t)) 150 } 151 152 //InvalidChainNameErr invalid chain name error 153 type InvalidChainNameErr string 154 155 func (f InvalidChainNameErr) Error() string { 156 return fmt.Sprintf("invalid chain name %s", string(f)) 157 } 158 159 //InvalidChaincodeNameErr invalid chaincode name error 160 type InvalidChaincodeNameErr string 161 162 func (f InvalidChaincodeNameErr) Error() string { 163 return fmt.Sprintf("invalid chain code name %s", string(f)) 164 } 165 166 //MarshallErr error marshaling/unmarshalling 167 type MarshallErr string 168 169 func (m MarshallErr) Error() string { 170 return fmt.Sprintf("error while marshalling %s", string(m)) 171 } 172 173 //IdenticalVersionErr trying to upgrade to same version of Chaincode 174 type IdenticalVersionErr string 175 176 func (f IdenticalVersionErr) Error() string { 177 return fmt.Sprintf("chain code with the same version exists %s", string(f)) 178 } 179 180 //InvalidVersionErr trying to upgrade to same version of Chaincode 181 type InvalidVersionErr string 182 183 func (f InvalidVersionErr) Error() string { 184 return fmt.Sprintf("invalid version %s", string(f)) 185 } 186 187 //EmptyVersionErr trying to upgrade to same version of Chaincode 188 type EmptyVersionErr string 189 190 func (f EmptyVersionErr) Error() string { 191 return fmt.Sprintf("version not provided for chaincode %s", string(f)) 192 } 193 194 //-------------- helper functions ------------------ 195 //create the chaincode on the given chain 196 func (lccc *LifeCycleSysCC) createChaincode(stub shim.ChaincodeStubInterface, chainname string, ccname string, version string, cccode []byte, policy []byte, escc []byte, vscc []byte) (*ccprovider.ChaincodeData, error) { 197 return lccc.putChaincodeData(stub, chainname, ccname, version, cccode, policy, escc, vscc) 198 } 199 200 //upgrade the chaincode on the given chain 201 func (lccc *LifeCycleSysCC) upgradeChaincode(stub shim.ChaincodeStubInterface, chainname string, ccname string, version string, cccode []byte, policy []byte, escc []byte, vscc []byte) (*ccprovider.ChaincodeData, error) { 202 return lccc.putChaincodeData(stub, chainname, ccname, version, cccode, policy, escc, vscc) 203 } 204 205 //create the chaincode on the given chain 206 func (lccc *LifeCycleSysCC) putChaincodeData(stub shim.ChaincodeStubInterface, chainname string, ccname string, version string, cccode []byte, policy []byte, escc []byte, vscc []byte) (*ccprovider.ChaincodeData, error) { 207 // check that escc and vscc are real system chaincodes 208 if !lccc.sccprovider.IsSysCC(string(escc)) { 209 return nil, fmt.Errorf("%s is not a valid endorsement system chaincode", string(escc)) 210 } 211 if !lccc.sccprovider.IsSysCC(string(vscc)) { 212 return nil, fmt.Errorf("%s is not a valid validation system chaincode", string(vscc)) 213 } 214 215 cd := &ccprovider.ChaincodeData{Name: ccname, Version: version, DepSpec: cccode, Policy: policy, Escc: string(escc), Vscc: string(vscc)} 216 cdbytes, err := proto.Marshal(cd) 217 if err != nil { 218 return nil, err 219 } 220 221 if cdbytes == nil { 222 return nil, MarshallErr(ccname) 223 } 224 225 err = stub.PutState(ccname, cdbytes) 226 227 return cd, err 228 } 229 230 //checks for existence of chaincode on the given chain 231 func (lccc *LifeCycleSysCC) getChaincode(stub shim.ChaincodeStubInterface, ccname string, checkFS bool) (*ccprovider.ChaincodeData, []byte, error) { 232 cdbytes, err := stub.GetState(ccname) 233 if err != nil { 234 return nil, nil, err 235 } 236 237 if cdbytes != nil { 238 cd := &ccprovider.ChaincodeData{} 239 err = proto.Unmarshal(cdbytes, cd) 240 if err != nil { 241 return nil, nil, MarshallErr(ccname) 242 } 243 244 if checkFS { 245 cd.DepSpec, _, err = ccprovider.GetChaincodeFromFS(ccname, cd.Version) 246 if err != nil { 247 return cd, nil, InvalidDeploymentSpecErr(err.Error()) 248 } 249 } 250 251 return cd, cdbytes, nil 252 } 253 254 return nil, nil, NotFoundErr(ccname) 255 } 256 257 // getChaincodes returns all chaincodes instantiated on this LCCC's channel 258 func (lccc *LifeCycleSysCC) getChaincodes(stub shim.ChaincodeStubInterface) pb.Response { 259 // get all rows from LCCC 260 itr, err := stub.GetStateByRange("", "") 261 262 if err != nil { 263 return shim.Error(err.Error()) 264 } 265 defer itr.Close() 266 267 // array to store metadata for all chaincode entries from LCCC 268 var ccInfoArray []*pb.ChaincodeInfo 269 270 for itr.HasNext() { 271 _, value, err := itr.Next() 272 if err != nil { 273 return shim.Error(err.Error()) 274 } 275 276 ccdata := &ccprovider.ChaincodeData{} 277 if err = proto.Unmarshal(value, ccdata); err != nil { 278 return shim.Error(err.Error()) 279 } 280 281 ccdepspec := &pb.ChaincodeDeploymentSpec{} 282 if err = proto.Unmarshal(ccdata.DepSpec, ccdepspec); err != nil { 283 return shim.Error(err.Error()) 284 } 285 286 path := ccdepspec.GetChaincodeSpec().ChaincodeId.Path 287 input := ccdepspec.GetChaincodeSpec().Input.String() 288 289 ccInfo := &pb.ChaincodeInfo{Name: ccdata.Name, Version: ccdata.Version, Path: path, Input: input, Escc: ccdata.Escc, Vscc: ccdata.Vscc} 290 291 // add this specific chaincode's metadata to the array of all chaincodes 292 ccInfoArray = append(ccInfoArray, ccInfo) 293 } 294 // add array with info about all instantiated chaincodes to the query 295 // response proto 296 cqr := &pb.ChaincodeQueryResponse{Chaincodes: ccInfoArray} 297 298 cqrbytes, err := proto.Marshal(cqr) 299 if err != nil { 300 return shim.Error(err.Error()) 301 } 302 303 return shim.Success(cqrbytes) 304 } 305 306 // getInstalledChaincodes returns all chaincodes installed on the peer 307 func (lccc *LifeCycleSysCC) getInstalledChaincodes() pb.Response { 308 // get chaincode query response proto which contains information about all 309 // installed chaincodes 310 cqr, err := ccprovider.GetInstalledChaincodes() 311 if err != nil { 312 return shim.Error(err.Error()) 313 } 314 315 cqrbytes, err := proto.Marshal(cqr) 316 if err != nil { 317 return shim.Error(err.Error()) 318 } 319 320 return shim.Success(cqrbytes) 321 } 322 323 //do access control 324 func (lccc *LifeCycleSysCC) acl(stub shim.ChaincodeStubInterface, chainname string, cds *pb.ChaincodeDeploymentSpec) error { 325 return nil 326 } 327 328 //check validity of chain name 329 func (lccc *LifeCycleSysCC) isValidChainName(chainname string) bool { 330 //TODO we probably need more checks 331 if chainname == "" { 332 return false 333 } 334 return true 335 } 336 337 //check validity of chaincode name 338 func (lccc *LifeCycleSysCC) isValidChaincodeName(chaincodename string) bool { 339 //TODO we probably need more checks 340 if chaincodename == "" { 341 return false 342 } 343 344 //do not allow special characters in chaincode name 345 if strings.ContainsAny(chaincodename, specialChars) { 346 return false 347 } 348 349 return true 350 } 351 352 //this implements "install" Invoke transaction 353 func (lccc *LifeCycleSysCC) executeInstall(stub shim.ChaincodeStubInterface, depSpec []byte) error { 354 cds, err := utils.GetChaincodeDeploymentSpec(depSpec) 355 356 if err != nil { 357 return err 358 } 359 360 if !lccc.isValidChaincodeName(cds.ChaincodeSpec.ChaincodeId.Name) { 361 return InvalidChaincodeNameErr(cds.ChaincodeSpec.ChaincodeId.Name) 362 } 363 364 if cds.ChaincodeSpec.ChaincodeId.Version == "" { 365 return EmptyVersionErr(cds.ChaincodeSpec.ChaincodeId.Name) 366 } 367 368 if err = ccprovider.PutChaincodeIntoFS(cds); err != nil { 369 return fmt.Errorf("Error installing chaincode code %s:%s(%s)", cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version, err) 370 } 371 372 return err 373 } 374 375 //this implements "deploy" Invoke transaction 376 func (lccc *LifeCycleSysCC) executeDeploy(stub shim.ChaincodeStubInterface, chainname string, depSpec []byte, policy []byte, escc []byte, vscc []byte) error { 377 cds, err := utils.GetChaincodeDeploymentSpec(depSpec) 378 379 if err != nil { 380 return err 381 } 382 383 if !lccc.isValidChaincodeName(cds.ChaincodeSpec.ChaincodeId.Name) { 384 return InvalidChaincodeNameErr(cds.ChaincodeSpec.ChaincodeId.Name) 385 } 386 387 if err = lccc.acl(stub, chainname, cds); err != nil { 388 return err 389 } 390 391 cd, _, err := lccc.getChaincode(stub, cds.ChaincodeSpec.ChaincodeId.Name, true) 392 if cd != nil { 393 return ExistsErr(cds.ChaincodeSpec.ChaincodeId.Name) 394 } 395 396 if cds.ChaincodeSpec.ChaincodeId.Version == "" { 397 return EmptyVersionErr(cds.ChaincodeSpec.ChaincodeId.Name) 398 } 399 400 _, err = lccc.createChaincode(stub, chainname, cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version, depSpec, policy, escc, vscc) 401 402 return err 403 } 404 405 func (lccc *LifeCycleSysCC) getUpgradeVersion(cd *ccprovider.ChaincodeData, cds *pb.ChaincodeDeploymentSpec) (string, error) { 406 if cd.Version == cds.ChaincodeSpec.ChaincodeId.Version { 407 return "", IdenticalVersionErr(cds.ChaincodeSpec.ChaincodeId.Name) 408 } 409 410 if cds.ChaincodeSpec.ChaincodeId.Version != "" { 411 return cds.ChaincodeSpec.ChaincodeId.Version, nil 412 } 413 414 //user did not specifcy Version. the previous version better be a number 415 v, err := strconv.ParseInt(cd.Version, 10, 32) 416 417 //This should never happen as long we don't expose version as version is computed internally 418 //so panic till we find a need to relax 419 if err != nil { 420 return "", InvalidVersionErr(cd.Version) 421 } 422 423 // replace the ChaincodeDeploymentSpec using the next version 424 newVersion := fmt.Sprintf("%d", (v + 1)) 425 426 return newVersion, nil 427 } 428 429 //this implements "upgrade" Invoke transaction 430 func (lccc *LifeCycleSysCC) executeUpgrade(stub shim.ChaincodeStubInterface, chainName string, depSpec []byte, policy []byte, escc []byte, vscc []byte) ([]byte, error) { 431 cds, err := utils.GetChaincodeDeploymentSpec(depSpec) 432 if err != nil { 433 return nil, err 434 } 435 436 if err = lccc.acl(stub, chainName, cds); err != nil { 437 return nil, err 438 } 439 440 chaincodeName := cds.ChaincodeSpec.ChaincodeId.Name 441 if !lccc.isValidChaincodeName(chaincodeName) { 442 return nil, InvalidChaincodeNameErr(chaincodeName) 443 } 444 445 // check for existence of chaincode 446 cd, _, err := lccc.getChaincode(stub, chaincodeName, true) 447 if cd == nil { 448 return nil, NotFoundErr(chainName) 449 } 450 451 ver, err := lccc.getUpgradeVersion(cd, cds) 452 if err != nil { 453 return nil, err 454 } 455 456 newCD, err := lccc.upgradeChaincode(stub, chainName, chaincodeName, ver, depSpec, policy, escc, vscc) 457 if err != nil { 458 return nil, err 459 } 460 461 return []byte(newCD.Version), nil 462 } 463 464 //-------------- the chaincode stub interface implementation ---------- 465 466 //Init only initializes the system chaincode provider 467 func (lccc *LifeCycleSysCC) Init(stub shim.ChaincodeStubInterface) pb.Response { 468 lccc.sccprovider = sysccprovider.GetSystemChaincodeProvider() 469 return shim.Success(nil) 470 } 471 472 // Invoke implements lifecycle functions "deploy", "start", "stop", "upgrade". 473 // Deploy's arguments - {[]byte("deploy"), []byte(<chainname>), <unmarshalled pb.ChaincodeDeploymentSpec>} 474 // 475 // Invoke also implements some query-like functions 476 // Get chaincode arguments - {[]byte("getid"), []byte(<chainname>), []byte(<chaincodename>)} 477 func (lccc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 478 args := stub.GetArgs() 479 if len(args) < 1 { 480 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 481 } 482 483 function := string(args[0]) 484 485 switch function { 486 case INSTALL: 487 if len(args) < 2 { 488 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 489 } 490 491 depSpec := args[1] 492 493 err := lccc.executeInstall(stub, depSpec) 494 if err != nil { 495 return shim.Error(err.Error()) 496 } 497 return shim.Success([]byte("OK")) 498 case DEPLOY: 499 if len(args) < 3 || len(args) > 6 { 500 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 501 } 502 503 //chain the chaincode shoud be associated with. It 504 //should be created with a register call 505 chainname := string(args[1]) 506 507 if !lccc.isValidChainName(chainname) { 508 return shim.Error(InvalidChainNameErr(chainname).Error()) 509 } 510 511 depSpec := args[2] 512 513 // optional arguments here (they can each be nil and may or may not be present) 514 // args[3] is a marshalled SignaturePolicyEnvelope representing the endorsement policy 515 // args[4] is the name of escc 516 // args[5] is the name of vscc 517 var policy []byte 518 if len(args) > 3 && args[3] != nil { 519 policy = args[3] 520 } else { 521 // FIXME: temporary workaround until all SDKs provide a policy 522 policy = utils.MarshalOrPanic(cauthdsl.SignedByMspMember("DEFAULT")) 523 } 524 525 var escc []byte 526 if len(args) > 4 && args[4] != nil { 527 escc = args[4] 528 } else { 529 escc = []byte("escc") 530 } 531 532 var vscc []byte 533 if len(args) > 5 && args[5] != nil { 534 vscc = args[5] 535 } else { 536 vscc = []byte("vscc") 537 } 538 539 err := lccc.executeDeploy(stub, chainname, depSpec, policy, escc, vscc) 540 if err != nil { 541 return shim.Error(err.Error()) 542 } 543 return shim.Success(nil) 544 case UPGRADE: 545 if len(args) < 3 || len(args) > 6 { 546 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 547 } 548 549 chainname := string(args[1]) 550 if !lccc.isValidChainName(chainname) { 551 return shim.Error(InvalidChainNameErr(chainname).Error()) 552 } 553 554 depSpec := args[2] 555 556 // optional arguments here (they can each be nil and may or may not be present) 557 // args[3] is a marshalled SignaturePolicyEnvelope representing the endorsement policy 558 // args[4] is the name of escc 559 // args[5] is the name of vscc 560 var policy []byte 561 if len(args) > 3 && args[3] != nil { 562 policy = args[3] 563 } else { 564 // FIXME: temporary workaround until all SDKs provide a policy 565 policy = utils.MarshalOrPanic(cauthdsl.SignedByMspMember("DEFAULT")) 566 } 567 568 var escc []byte 569 if len(args) > 4 && args[4] != nil { 570 escc = args[4] 571 } else { 572 escc = []byte("escc") 573 } 574 575 var vscc []byte 576 if len(args) > 5 && args[5] != nil { 577 vscc = args[5] 578 } else { 579 vscc = []byte("vscc") 580 } 581 582 verBytes, err := lccc.executeUpgrade(stub, chainname, depSpec, policy, escc, vscc) 583 if err != nil { 584 return shim.Error(err.Error()) 585 } 586 return shim.Success(verBytes) 587 case GETCCINFO, GETDEPSPEC, GETCCDATA: 588 if len(args) != 3 { 589 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 590 } 591 592 chain := string(args[1]) 593 ccname := string(args[2]) 594 595 //check the FS only for deployment spec 596 //other calls are looking for LCCC entries only 597 checkFS := false 598 if function == GETDEPSPEC { 599 checkFS = true 600 } 601 cd, cdbytes, err := lccc.getChaincode(stub, ccname, checkFS) 602 if cd == nil || cdbytes == nil { 603 logger.Errorf("ChaincodeId: %s does not exist on channel: %s(err:%s)", ccname, chain, err) 604 return shim.Error(TXNotFoundErr(ccname + "/" + chain).Error()) 605 } 606 607 switch function { 608 case GETCCINFO: 609 return shim.Success([]byte(cd.Name)) 610 case GETCCDATA: 611 return shim.Success(cdbytes) 612 default: 613 return shim.Success(cd.DepSpec) 614 } 615 case GETCHAINCODES: 616 if len(args) != 1 { 617 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 618 } 619 return lccc.getChaincodes(stub) 620 case GETINSTALLEDCHAINCODES: 621 if len(args) != 1 { 622 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 623 } 624 return lccc.getInstalledChaincodes() 625 } 626 627 return shim.Error(InvalidFunctionErr(function).Error()) 628 }