github.com/kaituanwang/hyperledger@v2.0.1+incompatible/integration/lifecycle/lifecycle_test.go (about)

     1  /*
     2  Copyright IBM Corp All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lifecycle
     8  
     9  import (
    10  	"bytes"
    11  	"io/ioutil"
    12  	"os"
    13  	"path/filepath"
    14  	"syscall"
    15  
    16  	docker "github.com/fsouza/go-dockerclient"
    17  	"github.com/golang/protobuf/proto"
    18  	"github.com/hyperledger/fabric-protos-go/common"
    19  	"github.com/hyperledger/fabric/common/tools/protolator"
    20  	"github.com/hyperledger/fabric/common/tools/protolator/protoext/ordererext"
    21  	"github.com/hyperledger/fabric/integration/nwo"
    22  	"github.com/hyperledger/fabric/integration/nwo/commands"
    23  	"github.com/hyperledger/fabric/integration/nwo/fabricconfig"
    24  	"github.com/hyperledger/fabric/integration/runner"
    25  	"github.com/onsi/gomega/gbytes"
    26  	"github.com/onsi/gomega/gexec"
    27  	"github.com/tedsuo/ifrit"
    28  
    29  	. "github.com/onsi/ginkgo"
    30  	. "github.com/onsi/gomega"
    31  	. "github.com/onsi/gomega/gstruct"
    32  )
    33  
    34  var _ = Describe("Lifecycle", func() {
    35  	var (
    36  		client    *docker.Client
    37  		testDir   string
    38  		network   *nwo.Network
    39  		processes = map[string]ifrit.Process{}
    40  		termFiles []string
    41  	)
    42  
    43  	BeforeEach(func() {
    44  		var err error
    45  		testDir, err = ioutil.TempDir("", "lifecycle")
    46  		Expect(err).NotTo(HaveOccurred())
    47  
    48  		client, err = docker.NewClientFromEnv()
    49  		Expect(err).NotTo(HaveOccurred())
    50  
    51  		network = nwo.New(nwo.BasicSolo(), testDir, client, StartPort(), components)
    52  
    53  		// Generate config
    54  		network.GenerateConfigTree()
    55  
    56  		// configure only one of four peers (Org1, peer0) to use couchdb.
    57  		// Note that we do not support a channel with mixed DBs.
    58  		// However, for testing, it would be fine to use couchdb for one
    59  		// peer. We're using couchdb here to ensure all supported character
    60  		// classes in chaincode names/versions work on the supported db types.
    61  		couchDB := &runner.CouchDB{}
    62  		couchProcess := ifrit.Invoke(couchDB)
    63  		Eventually(couchProcess.Ready(), runner.DefaultStartTimeout).Should(BeClosed())
    64  		Consistently(couchProcess.Wait()).ShouldNot(Receive())
    65  		couchAddr := couchDB.Address()
    66  		peer := network.Peer("Org1", "peer0")
    67  		core := network.ReadPeerConfig(peer)
    68  		core.Ledger.State.StateDatabase = "CouchDB"
    69  		core.Ledger.State.CouchDBConfig.CouchDBAddress = couchAddr
    70  		processes[couchDB.Name] = couchProcess
    71  		setTermFileEnvForBinaryExternalBuilder := func(envKey, termFile string, externalBuilders []*fabricconfig.ExternalBuilder) {
    72  			os.Setenv(envKey, termFile)
    73  			for _, e := range externalBuilders {
    74  				if e.Name == "binary" {
    75  					e.EnvironmentWhitelist = append(e.EnvironmentWhitelist, envKey)
    76  				}
    77  			}
    78  		}
    79  		org1TermFile := filepath.Join(testDir, "org1-term-file")
    80  		setTermFileEnvForBinaryExternalBuilder("ORG1_TERM_FILE", org1TermFile, core.Chaincode.ExternalBuilders)
    81  		network.WritePeerConfig(peer, core)
    82  
    83  		peer = network.Peer("Org2", "peer0")
    84  		core = network.ReadPeerConfig(peer)
    85  		org2TermFile := filepath.Join(testDir, "org2-term-file")
    86  		setTermFileEnvForBinaryExternalBuilder("ORG2_TERM_FILE", org2TermFile, core.Chaincode.ExternalBuilders)
    87  		network.WritePeerConfig(peer, core)
    88  
    89  		termFiles = []string{org1TermFile, org2TermFile}
    90  
    91  		// bootstrap the network
    92  		network.Bootstrap()
    93  
    94  		for _, o := range network.Orderers {
    95  			or := network.OrdererRunner(o)
    96  			p := ifrit.Invoke(or)
    97  			processes[o.ID()] = p
    98  			Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed())
    99  		}
   100  
   101  		for _, peer := range network.Peers {
   102  			pr := network.PeerRunner(peer)
   103  			p := ifrit.Invoke(pr)
   104  			processes[peer.ID()] = p
   105  			Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed())
   106  		}
   107  	})
   108  
   109  	AfterEach(func() {
   110  		// Shutdown processes and cleanup
   111  		for _, p := range processes {
   112  			p.Signal(syscall.SIGTERM)
   113  			Eventually(p.Wait(), network.EventuallyTimeout).Should(Receive())
   114  		}
   115  		network.Cleanup()
   116  
   117  		os.RemoveAll(testDir)
   118  	})
   119  
   120  	It("deploys and executes chaincode using _lifecycle and upgrades it", func() {
   121  		orderer := network.Orderer("orderer")
   122  		testPeers := network.PeersWithChannel("testchannel")
   123  		org1peer0 := network.Peer("Org1", "peer0")
   124  
   125  		chaincodePath := components.Build("github.com/hyperledger/fabric/integration/chaincode/module")
   126  		chaincode := nwo.Chaincode{
   127  			Name:                "My_1st-Chaincode",
   128  			Version:             "Version-0.0",
   129  			Path:                chaincodePath,
   130  			Lang:                "binary",
   131  			PackageFile:         filepath.Join(testDir, "modulecc.tar.gz"),
   132  			Ctor:                `{"Args":["init","a","100","b","200"]}`,
   133  			ChannelConfigPolicy: "/Channel/Application/Endorsement",
   134  			Sequence:            "1",
   135  			InitRequired:        true,
   136  			Label:               "my_simple_chaincode",
   137  		}
   138  
   139  		By("setting up the channel")
   140  		network.CreateAndJoinChannels(orderer)
   141  		network.UpdateChannelAnchors(orderer, "testchannel")
   142  		network.VerifyMembership(network.PeersWithChannel("testchannel"), "testchannel")
   143  		nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, network.Peer("Org1", "peer0"), network.Peer("Org2", "peer0"))
   144  
   145  		By("deploying the chaincode")
   146  		nwo.PackageChaincodeBinary(chaincode)
   147  		chaincode.SetPackageIDFromPackageFile()
   148  
   149  		nwo.InstallChaincode(network, chaincode, testPeers...)
   150  
   151  		By("verifying the installed chaincode package matches the one that was submitted")
   152  		sess, err := network.PeerAdminSession(testPeers[0], commands.ChaincodeGetInstalledPackage{
   153  			PackageID:       chaincode.PackageID,
   154  			OutputDirectory: testDir,
   155  		})
   156  		Expect(err).NotTo(HaveOccurred())
   157  		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
   158  		fileBytes, err := ioutil.ReadFile(chaincode.PackageFile)
   159  		Expect(err).NotTo(HaveOccurred())
   160  		fileBytesFromPeer, err := ioutil.ReadFile(filepath.Join(network.RootDir, chaincode.PackageID+".tar.gz"))
   161  		Expect(err).NotTo(HaveOccurred())
   162  		Expect(fileBytesFromPeer).To(Equal(fileBytes))
   163  
   164  		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, testPeers...)
   165  
   166  		nwo.CheckCommitReadinessUntilReady(network, "testchannel", chaincode, network.PeerOrgs(), testPeers...)
   167  		nwo.CommitChaincode(network, "testchannel", orderer, chaincode, testPeers[0], testPeers...)
   168  		nwo.InitChaincode(network, "testchannel", orderer, chaincode, testPeers...)
   169  
   170  		By("ensuring the chaincode can be invoked and queried")
   171  		endorsers := []*nwo.Peer{
   172  			network.Peer("Org1", "peer0"),
   173  			network.Peer("Org2", "peer0"),
   174  		}
   175  		RunQueryInvokeQuery(network, orderer, "My_1st-Chaincode", 100, endorsers...)
   176  
   177  		By("setting a bad package ID to temporarily disable endorsements on org1")
   178  		savedPackageID := chaincode.PackageID
   179  		// note that in theory it should be sufficient to set it to an
   180  		// empty string, but the ApproveChaincodeForMyOrg
   181  		// function fills the packageID field if empty
   182  		chaincode.PackageID = "bad"
   183  		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, org1peer0)
   184  
   185  		By("querying the chaincode and expecting the invocation to fail")
   186  		sess, err = network.PeerUserSession(org1peer0, "User1", commands.ChaincodeQuery{
   187  			ChannelID: "testchannel",
   188  			Name:      "My_1st-Chaincode",
   189  			Ctor:      `{"Args":["query","a"]}`,
   190  		})
   191  		Expect(err).NotTo(HaveOccurred())
   192  		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1))
   193  		Expect(sess.Err).To(gbytes.Say("Error: endorsement failure during query. response: status:500 " +
   194  			"message:\"make sure the chaincode My_1st-Chaincode has been successfully defined on channel testchannel and try " +
   195  			"again: chaincode definition for 'My_1st-Chaincode' exists, but chaincode is not installed\""))
   196  
   197  		By("setting the correct package ID to restore the chaincode")
   198  		chaincode.PackageID = savedPackageID
   199  		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, org1peer0)
   200  
   201  		By("querying the chaincode and expecting the invocation to succeed")
   202  		sess, err = network.PeerUserSession(org1peer0, "User1", commands.ChaincodeQuery{
   203  			ChannelID: "testchannel",
   204  			Name:      "My_1st-Chaincode",
   205  			Ctor:      `{"Args":["query","a"]}`,
   206  		})
   207  		Expect(err).NotTo(HaveOccurred())
   208  		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
   209  		Expect(sess).To(gbytes.Say("90"))
   210  
   211  		By("upgrading the chaincode to sequence 2 using a new chaincode package")
   212  		previousLabel := chaincode.Label
   213  		previousPackageID := chaincode.PackageID
   214  		chaincode.Label = "my_simple_chaincode_updated"
   215  		chaincode.PackageFile = filepath.Join(testDir, "modulecc-updated.tar.gz")
   216  		chaincode.Sequence = "2"
   217  		nwo.PackageChaincodeBinary(chaincode)
   218  		chaincode.SetPackageIDFromPackageFile()
   219  		nwo.InstallChaincode(network, chaincode, testPeers...)
   220  
   221  		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, testPeers...)
   222  
   223  		nwo.CheckCommitReadinessUntilReady(network, "testchannel", chaincode, network.PeerOrgs(), testPeers...)
   224  		nwo.CommitChaincode(network, "testchannel", orderer, chaincode, testPeers[0], testPeers...)
   225  
   226  		By("listing the installed chaincodes and verifying the channel/chaincode definitions that are using the chaincode package")
   227  		nwo.QueryInstalledReferences(network, "testchannel", chaincode.Label, chaincode.PackageID, network.Peer("Org2", "peer0"), []string{"My_1st-Chaincode", "Version-0.0"})
   228  
   229  		By("checking for term files that are written when the chaincode is stopped via SIGTERM")
   230  		for _, termFile := range termFiles {
   231  			Expect(termFile).To(BeARegularFile())
   232  		}
   233  
   234  		By("ensuring the previous chaincode package is no longer referenced by a chaincode definition on the channel")
   235  		Expect(nwo.QueryInstalled(network, network.Peer("Org2", "peer0"))()).To(
   236  			ContainElement(MatchFields(IgnoreExtras,
   237  				Fields{
   238  					"Label":      Equal(previousLabel),
   239  					"PackageId":  Equal(previousPackageID),
   240  					"References": Not(HaveKey("testchannel")),
   241  				},
   242  			)),
   243  		)
   244  
   245  		By("ensuring the chaincode can still be invoked and queried")
   246  		RunQueryInvokeQuery(network, orderer, "My_1st-Chaincode", 90, endorsers...)
   247  
   248  		By("deploying another chaincode using the same chaincode package")
   249  		anotherChaincode := nwo.Chaincode{
   250  			Name:                "Your_Chaincode",
   251  			Version:             "Version+0_0",
   252  			Path:                chaincodePath,
   253  			Lang:                "binary",
   254  			PackageFile:         filepath.Join(testDir, "modulecc.tar.gz"),
   255  			Ctor:                `{"Args":["init","a","100","b","200"]}`,
   256  			ChannelConfigPolicy: "/Channel/Application/Endorsement",
   257  			Sequence:            "1",
   258  			InitRequired:        true,
   259  			Label:               "my_simple_chaincode",
   260  		}
   261  		nwo.DeployChaincode(network, "testchannel", orderer, anotherChaincode)
   262  
   263  		By("listing the installed chaincodes and verifying the channel/chaincode definitions that are using the chaincode package")
   264  		anotherChaincode.SetPackageIDFromPackageFile()
   265  		nwo.QueryInstalledReferences(network, "testchannel", anotherChaincode.Label, anotherChaincode.PackageID, network.Peer("Org2", "peer0"), []string{"Your_Chaincode", "Version+0_0"})
   266  
   267  		By("adding a new org")
   268  		org3 := &nwo.Organization{
   269  			MSPID:         "Org3MSP",
   270  			Name:          "Org3",
   271  			Domain:        "org3.example.com",
   272  			EnableNodeOUs: true,
   273  			Users:         2,
   274  			CA: &nwo.CA{
   275  				Hostname: "ca",
   276  			},
   277  		}
   278  
   279  		org3peer0 := &nwo.Peer{
   280  			Name:         "peer0",
   281  			Organization: "Org3",
   282  			Channels:     testPeers[0].Channels,
   283  		}
   284  
   285  		network.AddOrg(org3, org3peer0)
   286  		GenerateOrgUpdateMaterials(network, org3peer0)
   287  
   288  		By("starting the org3 peer")
   289  		pr := network.PeerRunner(org3peer0)
   290  		org3Process := ifrit.Invoke(pr)
   291  		processes[org3peer0.ID()] = org3Process
   292  		Eventually(org3Process.Ready(), network.EventuallyTimeout).Should(BeClosed())
   293  
   294  		By("updating the channel config to include org3")
   295  		// get the current channel config
   296  		currentConfig := nwo.GetConfig(network, testPeers[0], orderer, "testchannel")
   297  		updatedConfig := proto.Clone(currentConfig).(*common.Config)
   298  
   299  		// get the configtx info for org3
   300  		sess, err = network.ConfigTxGen(commands.PrintOrg{
   301  			ConfigPath: network.RootDir,
   302  			PrintOrg:   "Org3",
   303  		})
   304  		Expect(err).NotTo(HaveOccurred())
   305  		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
   306  		org3Group := &ordererext.DynamicOrdererOrgGroup{ConfigGroup: &common.ConfigGroup{}}
   307  		err = protolator.DeepUnmarshalJSON(bytes.NewBuffer(sess.Out.Contents()), org3Group)
   308  		Expect(err).NotTo(HaveOccurred())
   309  
   310  		// update the channel config to include org3
   311  		updatedConfig.ChannelGroup.Groups["Application"].Groups["Org3"] = org3Group.ConfigGroup
   312  		nwo.UpdateConfig(network, orderer, "testchannel", currentConfig, updatedConfig, true, testPeers[0], testPeers...)
   313  
   314  		By("joining the org3 peers to the channel")
   315  		network.JoinChannel("testchannel", orderer, org3peer0)
   316  
   317  		// update testPeers now that org3 has joined
   318  		testPeers = network.PeersWithChannel("testchannel")
   319  
   320  		// wait until all peers, particularly those in org3, have received the block
   321  		// containing the updated config
   322  		maxLedgerHeight := nwo.GetMaxLedgerHeight(network, "testchannel", testPeers...)
   323  		nwo.WaitUntilEqualLedgerHeight(network, "testchannel", maxLedgerHeight, testPeers...)
   324  
   325  		By("querying definitions by org3 before performing any chaincode actions")
   326  		sess, err = network.PeerAdminSession(network.Peer("Org2", "peer0"), commands.ChaincodeListCommitted{
   327  			ChannelID: "testchannel",
   328  		})
   329  		Expect(err).NotTo(HaveOccurred())
   330  		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
   331  
   332  		By("installing the chaincode to the org3 peers")
   333  		nwo.InstallChaincode(network, chaincode, org3peer0)
   334  
   335  		By("ensuring org3 peers do not execute the chaincode before approving the definition")
   336  		org3AndOrg1PeerAddresses := []string{
   337  			network.PeerAddress(org3peer0, nwo.ListenPort),
   338  			network.PeerAddress(org1peer0, nwo.ListenPort),
   339  		}
   340  
   341  		sess, err = network.PeerUserSession(org3peer0, "User1", commands.ChaincodeInvoke{
   342  			ChannelID:     "testchannel",
   343  			Orderer:       network.OrdererAddress(orderer, nwo.ListenPort),
   344  			Name:          "My_1st-Chaincode",
   345  			Ctor:          `{"Args":["invoke","a","b","10"]}`,
   346  			PeerAddresses: org3AndOrg1PeerAddresses,
   347  			WaitForEvent:  true,
   348  		})
   349  		Expect(err).NotTo(HaveOccurred())
   350  		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1))
   351  		Expect(sess.Err).To(gbytes.Say("chaincode definition for 'My_1st-Chaincode' at sequence 2 on channel 'testchannel' has not yet been approved by this org"))
   352  
   353  		By("org3 approving the chaincode definition")
   354  		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, network.PeersInOrg("Org3")...)
   355  		nwo.EnsureChaincodeCommitted(network, "testchannel", chaincode.Name, chaincode.Version, chaincode.Sequence, []*nwo.Organization{network.Organization("Org1"), network.Organization("Org2"), network.Organization("Org3")}, org3peer0)
   356  
   357  		By("ensuring chaincode can be invoked and queried by org3")
   358  		org3andOrg1Endorsers := []*nwo.Peer{
   359  			network.Peer("Org3", "peer0"),
   360  			network.Peer("Org1", "peer0"),
   361  		}
   362  		RunQueryInvokeQuery(network, orderer, "My_1st-Chaincode", 80, org3andOrg1Endorsers...)
   363  
   364  		By("deploying a chaincode without an endorsement policy specified")
   365  		chaincode = nwo.Chaincode{
   366  			Name:         "defaultpolicycc",
   367  			Version:      "0.0",
   368  			Path:         chaincodePath,
   369  			Lang:         "binary",
   370  			PackageFile:  filepath.Join(testDir, "modulecc.tar.gz"),
   371  			Ctor:         `{"Args":["init","a","100","b","200"]}`,
   372  			Sequence:     "1",
   373  			InitRequired: true,
   374  			Label:        "my_simple_chaincode",
   375  		}
   376  
   377  		nwo.DeployChaincode(network, "testchannel", orderer, chaincode)
   378  
   379  		By("attempting to invoke the chaincode without a majority")
   380  		sess, err = network.PeerUserSession(org3peer0, "User1", commands.ChaincodeInvoke{
   381  			ChannelID:    "testchannel",
   382  			Orderer:      network.OrdererAddress(orderer, nwo.ListenPort),
   383  			Name:         "defaultpolicycc",
   384  			Ctor:         `{"Args":["invoke","a","b","10"]}`,
   385  			WaitForEvent: true,
   386  		})
   387  		Expect(err).ToNot(HaveOccurred())
   388  		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1))
   389  		Expect(sess.Err).To(gbytes.Say(`\QError: transaction invalidated with status (ENDORSEMENT_POLICY_FAILURE)\E`))
   390  
   391  		By("attempting to invoke the chaincode with a majority")
   392  		sess, err = network.PeerUserSession(org3peer0, "User1", commands.ChaincodeInvoke{
   393  			ChannelID:     "testchannel",
   394  			Orderer:       network.OrdererAddress(orderer, nwo.ListenPort),
   395  			Name:          "defaultpolicycc",
   396  			Ctor:          `{"Args":["invoke","a","b","10"]}`,
   397  			PeerAddresses: org3AndOrg1PeerAddresses,
   398  			WaitForEvent:  true,
   399  		})
   400  		Expect(err).NotTo(HaveOccurred())
   401  		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
   402  		Expect(sess.Err).To(gbytes.Say(`\Qcommitted with status (VALID)\E`))
   403  		Expect(sess.Err).To(gbytes.Say(`Chaincode invoke successful. result: status:200`))
   404  	})
   405  })