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