github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/integration/configtx/configtx_test.go (about)

     1  /*
     2  Copyright IBM Corp All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package configtx
     8  
     9  import (
    10  	"crypto"
    11  	"crypto/x509"
    12  	"encoding/pem"
    13  	"io/ioutil"
    14  	"os"
    15  	"syscall"
    16  	"time"
    17  
    18  	docker "github.com/fsouza/go-dockerclient"
    19  	"github.com/golang/protobuf/proto"
    20  	"github.com/hyperledger/fabric-config/configtx"
    21  	"github.com/hyperledger/fabric-protos-go/common"
    22  	"github.com/osdi23p228/fabric/integration/nwo"
    23  	"github.com/osdi23p228/fabric/integration/nwo/commands"
    24  	"github.com/tedsuo/ifrit"
    25  
    26  	. "github.com/onsi/ginkgo"
    27  	. "github.com/onsi/gomega"
    28  )
    29  
    30  var _ = Describe("ConfigTx", func() {
    31  	var (
    32  		client  *docker.Client
    33  		testDir string
    34  		network *nwo.Network
    35  		process ifrit.Process
    36  	)
    37  
    38  	BeforeEach(func() {
    39  		var err error
    40  		testDir, err = ioutil.TempDir("", "config")
    41  		Expect(err).NotTo(HaveOccurred())
    42  
    43  		client, err = docker.NewClientFromEnv()
    44  		Expect(err).NotTo(HaveOccurred())
    45  
    46  		network = nwo.New(nwo.BasicSolo(), testDir, client, StartPort(), components)
    47  
    48  		// Generate config
    49  		network.GenerateConfigTree()
    50  
    51  		// bootstrap the network
    52  		network.Bootstrap()
    53  
    54  		networkRunner := network.NetworkGroupRunner()
    55  		process = ifrit.Invoke(networkRunner)
    56  		Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())
    57  	})
    58  
    59  	AfterEach(func() {
    60  		if process != nil {
    61  			process.Signal(syscall.SIGTERM)
    62  			Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
    63  		}
    64  		if network != nil {
    65  			network.Cleanup()
    66  		}
    67  
    68  		os.RemoveAll(testDir)
    69  	})
    70  
    71  	It("creates channels and updates them using fabric-config/configtx", func() {
    72  		orderer := network.Orderer("orderer")
    73  		org1peer0 := network.Peer("Org1", "peer0")
    74  
    75  		By("setting up the channel")
    76  		channel := configtx.Channel{
    77  			Consortium: "SampleConsortium",
    78  			Application: configtx.Application{
    79  				Organizations: []configtx.Organization{
    80  					{
    81  						Name: "Org1",
    82  					},
    83  					{
    84  						Name: "Org2",
    85  					},
    86  				},
    87  				Capabilities: []string{"V1_3"},
    88  				ACLs:         map[string]string{"event/Block": "/Channel/Application/Readers"},
    89  				Policies: map[string]configtx.Policy{
    90  					configtx.ReadersPolicyKey: {
    91  						Type: configtx.ImplicitMetaPolicyType,
    92  						Rule: "ANY Readers",
    93  					},
    94  					configtx.WritersPolicyKey: {
    95  						Type: configtx.ImplicitMetaPolicyType,
    96  						Rule: "ANY Writers",
    97  					},
    98  					configtx.AdminsPolicyKey: {
    99  						Type: configtx.ImplicitMetaPolicyType,
   100  						Rule: "MAJORITY Admins",
   101  					},
   102  					configtx.EndorsementPolicyKey: {
   103  						Type: configtx.ImplicitMetaPolicyType,
   104  						Rule: "MAJORITY Endorsement",
   105  					},
   106  					configtx.LifecycleEndorsementPolicyKey: {
   107  						Type: configtx.ImplicitMetaPolicyType,
   108  						Rule: "MAJORITY Endorsement",
   109  					},
   110  				},
   111  			},
   112  		}
   113  
   114  		channelID := "testchannel"
   115  		createChannelUpdate, err := configtx.NewMarshaledCreateChannelTx(channel, channelID)
   116  		Expect(err).NotTo(HaveOccurred())
   117  
   118  		envelope, err := configtx.NewEnvelope(createChannelUpdate)
   119  		Expect(err).NotTo(HaveOccurred())
   120  		envBytes, err := proto.Marshal(envelope)
   121  		Expect(err).NotTo(HaveOccurred())
   122  		channelCreateTxPath := network.CreateChannelTxPath("testchannel")
   123  		err = ioutil.WriteFile(channelCreateTxPath, envBytes, 0644)
   124  		Expect(err).NotTo(HaveOccurred())
   125  
   126  		By("creating the channel")
   127  		createChannel := func() int {
   128  			sess, err := network.PeerAdminSession(org1peer0, commands.ChannelCreate{
   129  				ChannelID:   "testchannel",
   130  				Orderer:     network.OrdererAddress(orderer, nwo.ListenPort),
   131  				File:        channelCreateTxPath,
   132  				OutputBlock: "/dev/null",
   133  				ClientAuth:  network.ClientAuthRequired,
   134  			})
   135  			Expect(err).NotTo(HaveOccurred())
   136  			return sess.Wait(network.EventuallyTimeout).ExitCode()
   137  		}
   138  		Eventually(createChannel, network.EventuallyTimeout).Should(Equal(0))
   139  
   140  		By("joining all peers to the channel")
   141  		testPeers := network.PeersWithChannel("testchannel")
   142  		network.JoinChannel("testchannel", orderer, testPeers...)
   143  
   144  		By("getting the current channel config")
   145  		org2peer0 := network.Peer("Org2", "peer0")
   146  		channelConfig := nwo.GetConfig(network, org2peer0, orderer, "testchannel")
   147  		c := configtx.New(channelConfig)
   148  
   149  		By("updating orderer channel configuration")
   150  		o := c.Orderer()
   151  		oConfig, err := o.Configuration()
   152  		Expect(err).NotTo(HaveOccurred())
   153  		oConfig.BatchTimeout = 2 * time.Second
   154  		err = o.SetConfiguration(oConfig)
   155  		Expect(err).NotTo(HaveOccurred())
   156  		host, port := OrdererHostPort(network, orderer)
   157  		err = o.Organization(orderer.Organization).SetEndpoint(configtx.Address{Host: host, Port: port + 1})
   158  		Expect(err).NotTo(HaveOccurred())
   159  
   160  		By("computing the config update")
   161  		configUpdate, err := c.ComputeMarshaledUpdate("testchannel")
   162  		Expect(err).NotTo(HaveOccurred())
   163  
   164  		By("creating a detached signature for the orderer")
   165  		signingIdentity := configtx.SigningIdentity{
   166  			Certificate: parseOrdererAdminX509Certificate(network, orderer),
   167  			PrivateKey:  parseOrdererAdminPrivateKey(network, orderer),
   168  			MSPID:       network.Organization(orderer.Organization).MSPID,
   169  		}
   170  		signature, err := signingIdentity.CreateConfigSignature(configUpdate)
   171  		Expect(err).NotTo(HaveOccurred())
   172  
   173  		By("creating a signed config update envelope with the orderer's detached signature")
   174  		configUpdateEnvelope, err := configtx.NewEnvelope(configUpdate, signature)
   175  		Expect(err).NotTo(HaveOccurred())
   176  		err = signingIdentity.SignEnvelope(configUpdateEnvelope)
   177  		Expect(err).NotTo(HaveOccurred())
   178  
   179  		currentBlockNumber := nwo.CurrentConfigBlockNumber(network, org2peer0, orderer, "testchannel")
   180  
   181  		By("submitting the channel config update")
   182  		resp, err := nwo.Broadcast(network, orderer, configUpdateEnvelope)
   183  		Expect(err).NotTo(HaveOccurred())
   184  		Expect(resp.Status).To(Equal(common.Status_SUCCESS))
   185  
   186  		ccb := func() uint64 { return nwo.CurrentConfigBlockNumber(network, org2peer0, orderer, "testchannel") }
   187  		Eventually(ccb, network.EventuallyTimeout).Should(BeNumerically(">", currentBlockNumber))
   188  
   189  		By("ensuring the active channel config matches the submitted config")
   190  		updatedChannelConfig := nwo.GetConfig(network, org2peer0, orderer, "testchannel")
   191  		Expect(proto.Equal(c.UpdatedConfig(), updatedChannelConfig)).To(BeTrue())
   192  
   193  		By("checking the current application capabilities")
   194  		c = configtx.New(updatedChannelConfig)
   195  		a := c.Application()
   196  		capabilities, err := a.Capabilities()
   197  		Expect(err).NotTo(HaveOccurred())
   198  		Expect(capabilities).To(HaveLen(1))
   199  		Expect(capabilities).To(ContainElement("V1_3"))
   200  
   201  		By("enabling V2_0 application capabilities")
   202  		err = a.AddCapability("V2_0")
   203  		Expect(err).NotTo(HaveOccurred())
   204  
   205  		By("checking the application capabilities after update")
   206  		capabilities, err = a.Capabilities()
   207  		Expect(err).NotTo(HaveOccurred())
   208  		Expect(capabilities).To(HaveLen(2))
   209  		Expect(capabilities).To(ContainElements("V1_3", "V2_0"))
   210  
   211  		By("computing the config update")
   212  		configUpdate, err = c.ComputeMarshaledUpdate("testchannel")
   213  		Expect(err).NotTo(HaveOccurred())
   214  
   215  		By("creating detached signatures for each peer")
   216  		signingIdentities := make([]configtx.SigningIdentity, len(testPeers))
   217  		signatures := make([]*common.ConfigSignature, len(testPeers))
   218  		for i, p := range testPeers {
   219  			signingIdentity := configtx.SigningIdentity{
   220  				Certificate: parsePeerAdminX509Certificate(network, p),
   221  				PrivateKey:  parsePeerAdminPrivateKey(network, p),
   222  				MSPID:       network.Organization(p.Organization).MSPID,
   223  			}
   224  			signingIdentities[i] = signingIdentity
   225  			signature, err := signingIdentity.CreateConfigSignature(configUpdate)
   226  			Expect(err).NotTo(HaveOccurred())
   227  			signatures[i] = signature
   228  		}
   229  
   230  		By("creating a signed config update envelope with the detached peer signatures")
   231  		configUpdateEnvelope, err = configtx.NewEnvelope(configUpdate, signatures...)
   232  		Expect(err).NotTo(HaveOccurred())
   233  		err = signingIdentities[0].SignEnvelope(configUpdateEnvelope)
   234  		Expect(err).NotTo(HaveOccurred())
   235  
   236  		currentBlockNumber = nwo.CurrentConfigBlockNumber(network, org2peer0, orderer, "testchannel")
   237  
   238  		By("submitting the channel config update")
   239  		resp, err = nwo.Broadcast(network, orderer, configUpdateEnvelope)
   240  		Expect(err).NotTo(HaveOccurred())
   241  		Expect(resp.Status).To(Equal(common.Status_SUCCESS))
   242  
   243  		ccb = func() uint64 { return nwo.CurrentConfigBlockNumber(network, org2peer0, orderer, "testchannel") }
   244  		Eventually(ccb, network.EventuallyTimeout).Should(BeNumerically(">", currentBlockNumber))
   245  
   246  		By("ensuring the active channel config matches the submitted config")
   247  		updatedChannelConfig = nwo.GetConfig(network, org2peer0, orderer, "testchannel")
   248  		Expect(proto.Equal(c.UpdatedConfig(), updatedChannelConfig)).To(BeTrue())
   249  
   250  		By("adding the anchor peer for each org")
   251  		for _, peer := range network.AnchorsForChannel("testchannel") {
   252  			By("getting the current channel config")
   253  			channelConfig = nwo.GetConfig(network, peer, orderer, "testchannel")
   254  			c = configtx.New(channelConfig)
   255  			peerOrg := c.Application().Organization(peer.Organization)
   256  
   257  			By("adding the anchor peer for " + peer.Organization)
   258  			host, port := PeerHostPort(network, peer)
   259  			err = peerOrg.AddAnchorPeer(configtx.Address{Host: host, Port: port})
   260  			Expect(err).NotTo(HaveOccurred())
   261  
   262  			By("computing the config update")
   263  			configUpdate, err = c.ComputeMarshaledUpdate("testchannel")
   264  			Expect(err).NotTo(HaveOccurred())
   265  
   266  			By("creating a detached signature")
   267  			signingIdentity := configtx.SigningIdentity{
   268  				Certificate: parsePeerAdminX509Certificate(network, peer),
   269  				PrivateKey:  parsePeerAdminPrivateKey(network, peer),
   270  				MSPID:       network.Organization(peer.Organization).MSPID,
   271  			}
   272  			signature, err := signingIdentity.CreateConfigSignature(configUpdate)
   273  			Expect(err).NotTo(HaveOccurred())
   274  
   275  			By("creating a signed config update envelope with the detached peer signature")
   276  			configUpdateEnvelope, err = configtx.NewEnvelope(configUpdate, signature)
   277  			Expect(err).NotTo(HaveOccurred())
   278  			err = signingIdentity.SignEnvelope(configUpdateEnvelope)
   279  			Expect(err).NotTo(HaveOccurred())
   280  
   281  			currentBlockNumber = nwo.CurrentConfigBlockNumber(network, peer, orderer, "testchannel")
   282  
   283  			By("submitting the channel config update for " + peer.Organization)
   284  			resp, err = nwo.Broadcast(network, orderer, configUpdateEnvelope)
   285  			Expect(err).NotTo(HaveOccurred())
   286  			Expect(resp.Status).To(Equal(common.Status_SUCCESS))
   287  
   288  			ccb = func() uint64 { return nwo.CurrentConfigBlockNumber(network, peer, orderer, "testchannel") }
   289  			Eventually(ccb, network.EventuallyTimeout).Should(BeNumerically(">", currentBlockNumber))
   290  
   291  			By("ensuring the active channel config matches the submitted config")
   292  			updatedChannelConfig = nwo.GetConfig(network, peer, orderer, "testchannel")
   293  			Expect(proto.Equal(c.UpdatedConfig(), updatedChannelConfig)).To(BeTrue())
   294  		}
   295  	})
   296  })
   297  
   298  func parsePeerAdminX509Certificate(n *nwo.Network, p *nwo.Peer) *x509.Certificate {
   299  	return parseCertificate(n.PeerUserCert(p, "Admin"))
   300  }
   301  
   302  func parseOrdererAdminX509Certificate(n *nwo.Network, o *nwo.Orderer) *x509.Certificate {
   303  	return parseCertificate(n.OrdererUserCert(o, "Admin"))
   304  }
   305  
   306  func parseCertificate(filename string) *x509.Certificate {
   307  	certBytes, err := ioutil.ReadFile(filename)
   308  	Expect(err).NotTo(HaveOccurred())
   309  	pemBlock, _ := pem.Decode(certBytes)
   310  	cert, err := x509.ParseCertificate(pemBlock.Bytes)
   311  	Expect(err).NotTo(HaveOccurred())
   312  	return cert
   313  }
   314  
   315  func parsePeerAdminPrivateKey(n *nwo.Network, p *nwo.Peer) crypto.PrivateKey {
   316  	return parsePrivateKey(n.PeerUserKey(p, "Admin"))
   317  }
   318  
   319  func parseOrdererAdminPrivateKey(n *nwo.Network, o *nwo.Orderer) crypto.PrivateKey {
   320  	return parsePrivateKey(n.OrdererUserKey(o, "Admin"))
   321  }
   322  
   323  func parsePrivateKey(filename string) crypto.PrivateKey {
   324  	pkBytes, err := ioutil.ReadFile(filename)
   325  	Expect(err).NotTo(HaveOccurred())
   326  	pemBlock, _ := pem.Decode(pkBytes)
   327  	privateKey, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes)
   328  	Expect(err).NotTo(HaveOccurred())
   329  	return privateKey
   330  }