github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/integration/nwo/deploy.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package nwo 8 9 import ( 10 "encoding/json" 11 "fmt" 12 "io/ioutil" 13 "os" 14 "os/exec" 15 "strconv" 16 "strings" 17 18 "github.com/golang/protobuf/proto" 19 "github.com/hechain20/hechain/common/util" 20 "github.com/hechain20/hechain/integration/nwo/commands" 21 "github.com/hechain20/hechain/protoutil" 22 "github.com/hyperledger/fabric-protos-go/common" 23 "github.com/hyperledger/fabric-protos-go/peer/lifecycle" 24 "github.com/onsi/ginkgo" 25 . "github.com/onsi/gomega" 26 "github.com/onsi/gomega/gbytes" 27 "github.com/onsi/gomega/gexec" 28 "github.com/onsi/gomega/gstruct" 29 ) 30 31 type Chaincode struct { 32 Name string 33 Version string 34 Path string 35 Ctor string 36 Policy string // only used for legacy lifecycle. For new lifecycle use SignaturePolicy 37 Lang string 38 CollectionsConfig string // optional 39 PackageFile string 40 PackageID string // if unspecified, chaincode won't be executable. Can use SetPackageIDFromPackageFile() to set. 41 CodeFiles map[string]string // map from paths on the filesystem to code.tar.gz paths 42 Sequence string 43 EndorsementPlugin string 44 ValidationPlugin string 45 InitRequired bool 46 Label string 47 SignaturePolicy string 48 ChannelConfigPolicy string 49 } 50 51 func (c *Chaincode) SetPackageIDFromPackageFile() { 52 fileBytes, err := ioutil.ReadFile(c.PackageFile) 53 Expect(err).NotTo(HaveOccurred()) 54 hashStr := fmt.Sprintf("%x", util.ComputeSHA256(fileBytes)) 55 c.PackageID = c.Label + ":" + hashStr 56 } 57 58 // DeployChaincode is a helper that will install chaincode to all peers that 59 // are connected to the specified channel, approve the chaincode on one of the 60 // peers of each organization in the network, commit the chaincode definition 61 // on the channel using one of the peers, and wait for the chaincode commit to 62 // complete on all of the peers. It uses the _lifecycle implementation. 63 // NOTE V2_0 capabilities must be enabled for this functionality to work. 64 func DeployChaincode(n *Network, channel string, orderer *Orderer, chaincode Chaincode, peers ...*Peer) { 65 if len(peers) == 0 { 66 peers = n.PeersWithChannel(channel) 67 } 68 if len(peers) == 0 { 69 return 70 } 71 72 PackageAndInstallChaincode(n, chaincode, peers...) 73 74 // approve for each org 75 ApproveChaincodeForMyOrg(n, channel, orderer, chaincode, peers...) 76 77 // commit definition 78 CheckCommitReadinessUntilReady(n, channel, chaincode, n.PeerOrgs(), peers...) 79 CommitChaincode(n, channel, orderer, chaincode, peers[0], peers...) 80 81 // init the chaincode, if required 82 if chaincode.InitRequired { 83 InitChaincode(n, channel, orderer, chaincode, peers...) 84 } 85 } 86 87 // DeployChaincodeLegacy is a helper that will install chaincode to all peers 88 // that are connected to the specified channel, instantiate the chaincode on 89 // one of the peers, and wait for the instantiation to complete on all of the 90 // peers. It uses the legacy lifecycle (lscc) implementation. 91 // 92 // NOTE: This helper should not be used to deploy the same chaincode on 93 // multiple channels as the install will fail on subsequent calls. Instead, 94 // simply use InstantiateChaincode(). 95 func DeployChaincodeLegacy(n *Network, channel string, orderer *Orderer, chaincode Chaincode, peers ...*Peer) { 96 if len(peers) == 0 { 97 peers = n.PeersWithChannel(channel) 98 } 99 if len(peers) == 0 { 100 return 101 } 102 103 // create temp file for chaincode package if not provided 104 if chaincode.PackageFile == "" { 105 tempFile, err := ioutil.TempFile("", "chaincode-package") 106 Expect(err).NotTo(HaveOccurred()) 107 tempFile.Close() 108 defer os.Remove(tempFile.Name()) 109 chaincode.PackageFile = tempFile.Name() 110 } 111 112 // only create chaincode package if it doesn't already exist 113 if fi, err := os.Stat(chaincode.PackageFile); os.IsNotExist(err) || fi.Size() == 0 { 114 PackageChaincodeLegacy(n, chaincode, peers[0]) 115 } 116 117 // install on all peers 118 InstallChaincodeLegacy(n, chaincode, peers...) 119 120 // instantiate on the first peer 121 InstantiateChaincodeLegacy(n, channel, orderer, chaincode, peers[0], peers...) 122 } 123 124 func PackageAndInstallChaincode(n *Network, chaincode Chaincode, peers ...*Peer) { 125 // create temp file for chaincode package if not provided 126 if chaincode.PackageFile == "" { 127 tempFile, err := ioutil.TempFile("", "chaincode-package") 128 Expect(err).NotTo(HaveOccurred()) 129 tempFile.Close() 130 defer os.Remove(tempFile.Name()) 131 chaincode.PackageFile = tempFile.Name() 132 } 133 134 // only create chaincode package if it doesn't already exist 135 if _, err := os.Stat(chaincode.PackageFile); os.IsNotExist(err) { 136 switch chaincode.Lang { 137 case "binary", "ccaas": 138 PackageChaincodeBinary(chaincode) 139 default: 140 PackageChaincode(n, chaincode, peers[0]) 141 } 142 } 143 144 // install on all peers 145 InstallChaincode(n, chaincode, peers...) 146 } 147 148 func PackageChaincode(n *Network, chaincode Chaincode, peer *Peer) { 149 sess, err := n.PeerAdminSession(peer, commands.ChaincodePackage{ 150 Path: chaincode.Path, 151 Lang: chaincode.Lang, 152 Label: chaincode.Label, 153 OutputFile: chaincode.PackageFile, 154 ClientAuth: n.ClientAuthRequired, 155 }) 156 Expect(err).NotTo(HaveOccurred()) 157 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 158 } 159 160 func PackageChaincodeLegacy(n *Network, chaincode Chaincode, peer *Peer) { 161 sess, err := n.PeerAdminSession(peer, commands.ChaincodePackageLegacy{ 162 Name: chaincode.Name, 163 Version: chaincode.Version, 164 Path: chaincode.Path, 165 Lang: chaincode.Lang, 166 OutputFile: chaincode.PackageFile, 167 ClientAuth: n.ClientAuthRequired, 168 }) 169 Expect(err).NotTo(HaveOccurred()) 170 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 171 } 172 173 func CheckPackageID(n *Network, packageFile string, packageID string, peer *Peer) { 174 sess, err := n.PeerAdminSession(peer, commands.ChaincodeCalculatePackageID{ 175 PackageFile: packageFile, 176 ClientAuth: n.ClientAuthRequired, 177 }) 178 Expect(err).NotTo(HaveOccurred()) 179 Eventually(sess, n.EventuallyTimeout).Should(gbytes.Say(fmt.Sprintf(`\Q%s\E`, packageID))) 180 } 181 182 func InstallChaincode(n *Network, chaincode Chaincode, peers ...*Peer) { 183 // Ensure 'jq' exists in path, because we need it to build chaincode 184 if _, err := exec.LookPath("jq"); err != nil { 185 ginkgo.Fail("'jq' is needed to build chaincode but it wasn't found in the PATH") 186 } 187 188 if chaincode.PackageID == "" { 189 chaincode.SetPackageIDFromPackageFile() 190 } 191 192 for _, p := range peers { 193 sess, err := n.PeerAdminSession(p, commands.ChaincodeInstall{ 194 PackageFile: chaincode.PackageFile, 195 ClientAuth: n.ClientAuthRequired, 196 }) 197 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 198 EventuallyWithOffset(1, sess, n.EventuallyTimeout).Should(gexec.Exit()) 199 200 EnsureInstalled(n, chaincode.Label, chaincode.PackageID, p) 201 CheckPackageID(n, chaincode.PackageFile, chaincode.PackageID, p) 202 } 203 } 204 205 func InstallChaincodeLegacy(n *Network, chaincode Chaincode, peers ...*Peer) { 206 // Ensure 'jq' exists in path, because we need it to build chaincode 207 if _, err := exec.LookPath("jq"); err != nil { 208 ginkgo.Fail("'jq' is needed to build chaincode but it wasn't found in the PATH") 209 } 210 211 for _, p := range peers { 212 sess, err := n.PeerAdminSession(p, commands.ChaincodeInstallLegacy{ 213 Name: chaincode.Name, 214 Version: chaincode.Version, 215 Path: chaincode.Path, 216 Lang: chaincode.Lang, 217 PackageFile: chaincode.PackageFile, 218 ClientAuth: n.ClientAuthRequired, 219 }) 220 Expect(err).NotTo(HaveOccurred()) 221 EventuallyWithOffset(1, sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 222 223 sess, err = n.PeerAdminSession(p, commands.ChaincodeListInstalledLegacy{ 224 ClientAuth: n.ClientAuthRequired, 225 }) 226 Expect(err).NotTo(HaveOccurred()) 227 EventuallyWithOffset(1, sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 228 ExpectWithOffset(1, sess).To(gbytes.Say(fmt.Sprintf("Name: %s, Version: %s,", chaincode.Name, chaincode.Version))) 229 } 230 } 231 232 func ApproveChaincodeForMyOrg(n *Network, channel string, orderer *Orderer, chaincode Chaincode, peers ...*Peer) { 233 if chaincode.PackageID == "" { 234 chaincode.SetPackageIDFromPackageFile() 235 } 236 237 // used to ensure we only approve once per org 238 approvedOrgs := map[string]bool{} 239 for _, p := range peers { 240 if _, ok := approvedOrgs[p.Organization]; !ok { 241 sess, err := n.PeerAdminSession(p, commands.ChaincodeApproveForMyOrg{ 242 ChannelID: channel, 243 Orderer: n.OrdererAddress(orderer, ListenPort), 244 Name: chaincode.Name, 245 Version: chaincode.Version, 246 PackageID: chaincode.PackageID, 247 Sequence: chaincode.Sequence, 248 EndorsementPlugin: chaincode.EndorsementPlugin, 249 ValidationPlugin: chaincode.ValidationPlugin, 250 SignaturePolicy: chaincode.SignaturePolicy, 251 ChannelConfigPolicy: chaincode.ChannelConfigPolicy, 252 InitRequired: chaincode.InitRequired, 253 CollectionsConfig: chaincode.CollectionsConfig, 254 ClientAuth: n.ClientAuthRequired, 255 }) 256 Expect(err).NotTo(HaveOccurred()) 257 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 258 approvedOrgs[p.Organization] = true 259 Eventually(sess.Err, n.EventuallyTimeout).Should(gbytes.Say(fmt.Sprintf(`\Qcommitted with status (VALID) at %s\E`, n.PeerAddress(p, ListenPort)))) 260 } 261 } 262 } 263 264 func EnsureChaincodeApproved(n *Network, peer *Peer, channel, name, sequence string) { 265 sequenceInt, err := strconv.ParseInt(sequence, 10, 64) 266 Expect(err).NotTo(HaveOccurred()) 267 Eventually(queryApproved(n, peer, channel, name, sequence), n.EventuallyTimeout).Should( 268 gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{ 269 "Sequence": Equal(sequenceInt), 270 }), 271 ) 272 } 273 274 func CheckCommitReadinessUntilReady(n *Network, channel string, chaincode Chaincode, checkOrgs []*Organization, peers ...*Peer) { 275 for _, p := range peers { 276 keys := gstruct.Keys{} 277 for _, org := range checkOrgs { 278 keys[org.MSPID] = BeTrue() 279 } 280 Eventually(checkCommitReadiness(n, p, channel, chaincode), n.EventuallyTimeout).Should( 281 gstruct.MatchKeys(gstruct.IgnoreExtras, keys), 282 ) 283 } 284 } 285 286 func CommitChaincode(n *Network, channel string, orderer *Orderer, chaincode Chaincode, peer *Peer, checkPeers ...*Peer) { 287 // commit using one peer per org 288 commitOrgs := map[string]bool{} 289 var peerAddresses []string 290 for _, p := range checkPeers { 291 if exists := commitOrgs[p.Organization]; !exists { 292 peerAddresses = append(peerAddresses, n.PeerAddress(p, ListenPort)) 293 commitOrgs[p.Organization] = true 294 } 295 } 296 297 sess, err := n.PeerAdminSession(peer, commands.ChaincodeCommit{ 298 ChannelID: channel, 299 Orderer: n.OrdererAddress(orderer, ListenPort), 300 Name: chaincode.Name, 301 Version: chaincode.Version, 302 Sequence: chaincode.Sequence, 303 EndorsementPlugin: chaincode.EndorsementPlugin, 304 ValidationPlugin: chaincode.ValidationPlugin, 305 SignaturePolicy: chaincode.SignaturePolicy, 306 ChannelConfigPolicy: chaincode.ChannelConfigPolicy, 307 InitRequired: chaincode.InitRequired, 308 CollectionsConfig: chaincode.CollectionsConfig, 309 PeerAddresses: peerAddresses, 310 ClientAuth: n.ClientAuthRequired, 311 }) 312 Expect(err).NotTo(HaveOccurred()) 313 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 314 for i := 0; i < len(peerAddresses); i++ { 315 Eventually(sess.Err, n.EventuallyTimeout).Should(gbytes.Say(`\Qcommitted with status (VALID)\E`)) 316 } 317 checkOrgs := []*Organization{} 318 for org := range commitOrgs { 319 checkOrgs = append(checkOrgs, n.Organization(org)) 320 } 321 EnsureChaincodeCommitted(n, channel, chaincode.Name, chaincode.Version, chaincode.Sequence, checkOrgs, checkPeers...) 322 } 323 324 // EnsureChaincodeCommitted polls each supplied peer until the chaincode definition 325 // has been committed to the peer's ledger. 326 func EnsureChaincodeCommitted(n *Network, channel, name, version, sequence string, checkOrgs []*Organization, peers ...*Peer) { 327 for _, p := range peers { 328 sequenceInt, err := strconv.ParseInt(sequence, 10, 64) 329 Expect(err).NotTo(HaveOccurred()) 330 approvedKeys := gstruct.Keys{} 331 for _, org := range checkOrgs { 332 approvedKeys[org.MSPID] = BeTrue() 333 } 334 Eventually(listCommitted(n, p, channel, name), n.EventuallyTimeout).Should( 335 gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{ 336 "Version": Equal(version), 337 "Sequence": Equal(sequenceInt), 338 "Approvals": gstruct.MatchKeys(gstruct.IgnoreExtras, approvedKeys), 339 }), 340 ) 341 } 342 } 343 344 func InitChaincode(n *Network, channel string, orderer *Orderer, chaincode Chaincode, peers ...*Peer) { 345 // init using one peer per org 346 initOrgs := map[string]bool{} 347 var peerAddresses []string 348 for _, p := range peers { 349 if exists := initOrgs[p.Organization]; !exists { 350 peerAddresses = append(peerAddresses, n.PeerAddress(p, ListenPort)) 351 initOrgs[p.Organization] = true 352 } 353 } 354 355 sess, err := n.PeerUserSession(peers[0], "User1", commands.ChaincodeInvoke{ 356 ChannelID: channel, 357 Orderer: n.OrdererAddress(orderer, ListenPort), 358 Name: chaincode.Name, 359 Ctor: chaincode.Ctor, 360 PeerAddresses: peerAddresses, 361 WaitForEvent: true, 362 IsInit: true, 363 ClientAuth: n.ClientAuthRequired, 364 }) 365 Expect(err).NotTo(HaveOccurred()) 366 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 367 for i := 0; i < len(peerAddresses); i++ { 368 Eventually(sess.Err, n.EventuallyTimeout).Should(gbytes.Say(`\Qcommitted with status (VALID)\E`)) 369 } 370 Expect(sess.Err).To(gbytes.Say("Chaincode invoke successful. result: status:200")) 371 } 372 373 func InstantiateChaincodeLegacy(n *Network, channel string, orderer *Orderer, chaincode Chaincode, peer *Peer, checkPeers ...*Peer) { 374 sess, err := n.PeerAdminSession(peer, commands.ChaincodeInstantiateLegacy{ 375 ChannelID: channel, 376 Orderer: n.OrdererAddress(orderer, ListenPort), 377 Name: chaincode.Name, 378 Version: chaincode.Version, 379 Ctor: chaincode.Ctor, 380 Policy: chaincode.Policy, 381 Lang: chaincode.Lang, 382 CollectionsConfig: chaincode.CollectionsConfig, 383 ClientAuth: n.ClientAuthRequired, 384 }) 385 Expect(err).NotTo(HaveOccurred()) 386 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 387 388 EnsureInstantiatedLegacy(n, channel, chaincode.Name, chaincode.Version, checkPeers...) 389 } 390 391 func EnsureInstantiatedLegacy(n *Network, channel, name, version string, peers ...*Peer) { 392 for _, p := range peers { 393 Eventually(listInstantiatedLegacy(n, p, channel), n.EventuallyTimeout).Should( 394 gbytes.Say(fmt.Sprintf("Name: %s, Version: %s,", name, version)), 395 ) 396 } 397 } 398 399 func UpgradeChaincodeLegacy(n *Network, channel string, orderer *Orderer, chaincode Chaincode, peers ...*Peer) { 400 if len(peers) == 0 { 401 peers = n.PeersWithChannel(channel) 402 } 403 if len(peers) == 0 { 404 return 405 } 406 407 // install on all peers 408 InstallChaincodeLegacy(n, chaincode, peers...) 409 410 // upgrade from the first peer 411 sess, err := n.PeerAdminSession(peers[0], commands.ChaincodeUpgradeLegacy{ 412 ChannelID: channel, 413 Orderer: n.OrdererAddress(orderer, ListenPort), 414 Name: chaincode.Name, 415 Version: chaincode.Version, 416 Ctor: chaincode.Ctor, 417 Policy: chaincode.Policy, 418 CollectionsConfig: chaincode.CollectionsConfig, 419 ClientAuth: n.ClientAuthRequired, 420 }) 421 Expect(err).NotTo(HaveOccurred()) 422 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 423 424 EnsureInstantiatedLegacy(n, channel, chaincode.Name, chaincode.Version, peers...) 425 } 426 427 func EnsureInstalled(n *Network, label, packageID string, peers ...*Peer) { 428 for _, p := range peers { 429 Eventually(QueryInstalled(n, p), n.EventuallyTimeout).Should( 430 ContainElement(gstruct.MatchFields(gstruct.IgnoreExtras, 431 gstruct.Fields{ 432 "Label": Equal(label), 433 "PackageId": Equal(packageID), 434 }, 435 )), 436 ) 437 } 438 } 439 440 func QueryInstalledReferences(n *Network, channel, label, packageID string, checkPeer *Peer, nameVersions ...[]string) { 441 chaincodes := make([]*lifecycle.QueryInstalledChaincodesResult_Chaincode, len(nameVersions)) 442 for i, nameVersion := range nameVersions { 443 chaincodes[i] = &lifecycle.QueryInstalledChaincodesResult_Chaincode{ 444 Name: nameVersion[0], 445 Version: nameVersion[1], 446 } 447 } 448 449 Expect(QueryInstalled(n, checkPeer)()).To( 450 ContainElement(gstruct.MatchFields(gstruct.IgnoreExtras, 451 gstruct.Fields{ 452 "Label": Equal(label), 453 "PackageId": Equal(packageID), 454 "References": HaveKeyWithValue(channel, gstruct.PointTo(gstruct.MatchFields(gstruct.IgnoreExtras, 455 gstruct.Fields{ 456 "Chaincodes": ConsistOf(chaincodes), 457 }, 458 ))), 459 }, 460 )), 461 ) 462 } 463 464 type queryInstalledOutput struct { 465 InstalledChaincodes []lifecycle.QueryInstalledChaincodesResult_InstalledChaincode `json:"installed_chaincodes"` 466 } 467 468 func QueryInstalled(n *Network, peer *Peer) func() []lifecycle.QueryInstalledChaincodesResult_InstalledChaincode { 469 return func() []lifecycle.QueryInstalledChaincodesResult_InstalledChaincode { 470 sess, err := n.PeerAdminSession(peer, commands.ChaincodeQueryInstalled{ 471 ClientAuth: n.ClientAuthRequired, 472 }) 473 Expect(err).NotTo(HaveOccurred()) 474 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 475 output := &queryInstalledOutput{} 476 err = json.Unmarshal(sess.Out.Contents(), output) 477 Expect(err).NotTo(HaveOccurred()) 478 return output.InstalledChaincodes 479 } 480 } 481 482 type checkCommitReadinessOutput struct { 483 Approvals map[string]bool `json:"approvals"` 484 } 485 486 func checkCommitReadiness(n *Network, peer *Peer, channel string, chaincode Chaincode) func() map[string]bool { 487 return func() map[string]bool { 488 sess, err := n.PeerAdminSession(peer, commands.ChaincodeCheckCommitReadiness{ 489 ChannelID: channel, 490 Name: chaincode.Name, 491 Version: chaincode.Version, 492 Sequence: chaincode.Sequence, 493 EndorsementPlugin: chaincode.EndorsementPlugin, 494 ValidationPlugin: chaincode.ValidationPlugin, 495 SignaturePolicy: chaincode.SignaturePolicy, 496 ChannelConfigPolicy: chaincode.ChannelConfigPolicy, 497 InitRequired: chaincode.InitRequired, 498 CollectionsConfig: chaincode.CollectionsConfig, 499 ClientAuth: n.ClientAuthRequired, 500 }) 501 Expect(err).NotTo(HaveOccurred()) 502 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 503 output := &checkCommitReadinessOutput{} 504 err = json.Unmarshal(sess.Out.Contents(), output) 505 Expect(err).NotTo(HaveOccurred()) 506 return output.Approvals 507 } 508 } 509 510 type queryApprovedOutput struct { 511 Sequence int64 `json:"sequence"` 512 } 513 514 // queryApproved returns the result of the queryApproved command. 515 // If the command fails for any reason, it will return an empty output object. 516 func queryApproved(n *Network, peer *Peer, channel, name, sequence string) func() queryApprovedOutput { 517 return func() queryApprovedOutput { 518 sess, err := n.PeerAdminSession(peer, commands.ChaincodeQueryApproved{ 519 ChannelID: channel, 520 Name: name, 521 Sequence: sequence, 522 PeerAddresses: []string{n.PeerAddress(peer, ListenPort)}, 523 ClientAuth: n.ClientAuthRequired, 524 }) 525 Expect(err).NotTo(HaveOccurred()) 526 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit()) 527 output := &queryApprovedOutput{} 528 if sess.ExitCode() == 1 { 529 // don't try to unmarshal the output as JSON if the query failed 530 return *output 531 } 532 err = json.Unmarshal(sess.Out.Contents(), output) 533 Expect(err).NotTo(HaveOccurred()) 534 return *output 535 } 536 } 537 538 type queryCommittedOutput struct { 539 Sequence int64 `json:"sequence"` 540 Version string `json:"version"` 541 Approvals map[string]bool `json:"approvals"` 542 } 543 544 // listCommitted returns the result of the queryCommitted command. 545 // If the command fails for any reason (e.g. namespace not defined 546 // or a database access issue), it will return an empty output object. 547 func listCommitted(n *Network, peer *Peer, channel, name string) func() queryCommittedOutput { 548 return func() queryCommittedOutput { 549 sess, err := n.PeerAdminSession(peer, commands.ChaincodeListCommitted{ 550 ChannelID: channel, 551 Name: name, 552 ClientAuth: n.ClientAuthRequired, 553 }) 554 Expect(err).NotTo(HaveOccurred()) 555 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit()) 556 output := &queryCommittedOutput{} 557 if sess.ExitCode() == 1 { 558 // don't try to unmarshal the output as JSON if the query failed 559 return *output 560 } 561 err = json.Unmarshal(sess.Out.Contents(), output) 562 Expect(err).NotTo(HaveOccurred()) 563 return *output 564 } 565 } 566 567 func listInstantiatedLegacy(n *Network, peer *Peer, channel string) func() *gbytes.Buffer { 568 return func() *gbytes.Buffer { 569 sess, err := n.PeerAdminSession(peer, commands.ChaincodeListInstantiatedLegacy{ 570 ChannelID: channel, 571 ClientAuth: n.ClientAuthRequired, 572 }) 573 Expect(err).NotTo(HaveOccurred()) 574 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 575 return sess.Buffer() 576 } 577 } 578 579 // EnableCapabilities enables a specific capabilities flag for a running network. 580 // It generates the config update using the first peer, signs the configuration 581 // with the subsequent peers, and then submits the config update using the 582 // first peer. 583 func EnableCapabilities(network *Network, channel, capabilitiesGroup, capabilitiesVersion string, orderer *Orderer, peers ...*Peer) { 584 if len(peers) == 0 { 585 return 586 } 587 588 config := GetConfig(network, peers[0], orderer, channel) 589 updatedConfig := proto.Clone(config).(*common.Config) 590 591 updatedConfig.ChannelGroup.Groups[capabilitiesGroup].Values["Capabilities"] = &common.ConfigValue{ 592 ModPolicy: "Admins", 593 Value: protoutil.MarshalOrPanic( 594 &common.Capabilities{ 595 Capabilities: map[string]*common.Capability{ 596 capabilitiesVersion: {}, 597 }, 598 }, 599 ), 600 } 601 602 UpdateConfig(network, orderer, channel, config, updatedConfig, false, peers[0], peers...) 603 } 604 605 // WaitUntilEqualLedgerHeight waits until all specified peers have the 606 // provided ledger height on a channel 607 func WaitUntilEqualLedgerHeight(n *Network, channel string, height int, peers ...*Peer) { 608 for _, peer := range peers { 609 Eventually(func() int { 610 return GetLedgerHeight(n, peer, channel) 611 }, n.EventuallyTimeout).Should(Equal(height)) 612 } 613 } 614 615 // GetLedgerHeight returns the current ledger height for a peer on 616 // a channel 617 func GetLedgerHeight(n *Network, peer *Peer, channel string) int { 618 sess, err := n.PeerUserSession(peer, "User1", commands.ChannelInfo{ 619 ChannelID: channel, 620 ClientAuth: n.ClientAuthRequired, 621 }) 622 Expect(err).NotTo(HaveOccurred()) 623 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit()) 624 625 if sess.ExitCode() == 1 { 626 // if org is not yet member of channel, peer will return error 627 return -1 628 } 629 630 channelInfoStr := strings.TrimPrefix(string(sess.Buffer().Contents()[:]), "Blockchain info:") 631 channelInfo := common.BlockchainInfo{} 632 json.Unmarshal([]byte(channelInfoStr), &channelInfo) 633 return int(channelInfo.Height) 634 } 635 636 // GetMaxLedgerHeight returns the maximum ledger height for the 637 // peers on a channel 638 func GetMaxLedgerHeight(n *Network, channel string, peers ...*Peer) int { 639 var maxHeight int 640 for _, peer := range peers { 641 peerHeight := GetLedgerHeight(n, peer, channel) 642 if peerHeight > maxHeight { 643 maxHeight = peerHeight 644 } 645 } 646 return maxHeight 647 }