github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/integration/raft/channel_participation_test.go (about) 1 /* 2 Copyright hechain All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package raft 8 9 import ( 10 "crypto" 11 "crypto/x509" 12 "encoding/json" 13 "encoding/pem" 14 "fmt" 15 "io/ioutil" 16 "net/http" 17 "os" 18 "path/filepath" 19 "syscall" 20 "time" 21 22 docker "github.com/fsouza/go-dockerclient" 23 "github.com/golang/protobuf/proto" 24 "github.com/hechain20/hechain/common/ledger/blockledger/fileledger" 25 "github.com/hechain20/hechain/common/metrics/disabled" 26 "github.com/hechain20/hechain/integration/channelparticipation" 27 conftx "github.com/hechain20/hechain/integration/configtx" 28 "github.com/hechain20/hechain/integration/nwo" 29 "github.com/hechain20/hechain/integration/nwo/commands" 30 "github.com/hechain20/hechain/integration/ordererclient" 31 "github.com/hyperledger/fabric-config/configtx" 32 "github.com/hyperledger/fabric-config/configtx/orderer" 33 "github.com/hyperledger/fabric-protos-go/common" 34 . "github.com/onsi/ginkgo" 35 . "github.com/onsi/gomega" 36 "github.com/onsi/gomega/gbytes" 37 "github.com/onsi/gomega/gexec" 38 "github.com/tedsuo/ifrit" 39 "github.com/tedsuo/ifrit/ginkgomon" 40 ) 41 42 var _ = Describe("ChannelParticipation", func() { 43 var ( 44 testDir string 45 client *docker.Client 46 network *nwo.Network 47 ordererProcesses []ifrit.Process 48 ordererRunners []*ginkgomon.Runner 49 ) 50 51 BeforeEach(func() { 52 var err error 53 testDir, err = ioutil.TempDir("", "channel-participation") 54 Expect(err).NotTo(HaveOccurred()) 55 56 client, err = docker.NewClientFromEnv() 57 Expect(err).NotTo(HaveOccurred()) 58 59 ordererProcesses = []ifrit.Process{} 60 ordererRunners = []*ginkgomon.Runner{} 61 }) 62 63 AfterEach(func() { 64 for _, ordererProcess := range ordererProcesses { 65 ordererProcess.Signal(syscall.SIGTERM) 66 Eventually(ordererProcess.Wait(), network.EventuallyTimeout).Should(Receive()) 67 } 68 if network != nil { 69 network.Cleanup() 70 } 71 os.RemoveAll(testDir) 72 }) 73 74 restartOrderer := func(o *nwo.Orderer, index int) { 75 ordererProcesses[index].Signal(syscall.SIGKILL) 76 Eventually(ordererProcesses[index].Wait(), network.EventuallyTimeout).Should(Receive(MatchError("exit status 137"))) 77 ordererRunner := network.OrdererRunner(o) 78 ordererProcess := ifrit.Invoke(ordererRunner) 79 Eventually(ordererProcess.Ready(), network.EventuallyTimeout).Should(BeClosed()) 80 ordererProcesses[index] = ordererProcess 81 ordererRunners[index] = ordererRunner 82 } 83 84 Describe("three node etcdraft network without a system channel", func() { 85 startOrderer := func(o *nwo.Orderer) { 86 ordererRunner := network.OrdererRunner(o) 87 ordererProcess := ifrit.Invoke(ordererRunner) 88 Eventually(ordererProcess.Ready(), network.EventuallyTimeout).Should(BeClosed()) 89 Eventually(ordererRunner.Err(), network.EventuallyTimeout).Should(gbytes.Say("Registrar initializing without a system channel")) 90 ordererProcesses = append(ordererProcesses, ordererProcess) 91 ordererRunners = append(ordererRunners, ordererRunner) 92 } 93 94 BeforeEach(func() { 95 network = nwo.New(multiNodeEtcdRaftTwoChannels(), testDir, client, StartPort(), components) 96 network.Consensus.ChannelParticipationEnabled = true 97 network.Consensus.BootstrapMethod = "none" 98 network.GenerateConfigTree() 99 network.Bootstrap() 100 }) 101 102 It("starts an orderer but rejects channel creation requests via the legacy channel creation", func() { 103 orderer1 := network.Orderer("orderer1") 104 startOrderer(orderer1) 105 106 cl := channelparticipation.List(network, orderer1) 107 Expect(cl).To(Equal(channelparticipation.ChannelList{})) 108 109 By("attempting to create a channel without a system channel defined") 110 sess, err := network.PeerAdminSession(network.Peer("Org1", "peer0"), commands.ChannelCreate{ 111 ChannelID: "testchannel", 112 Orderer: network.OrdererAddress(orderer1, nwo.ListenPort), 113 File: network.CreateChannelTxPath("testchannel"), 114 OutputBlock: "/dev/null", 115 ClientAuth: network.ClientAuthRequired, 116 }) 117 Expect(err).NotTo(HaveOccurred()) 118 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1)) 119 Eventually(sess.Err, network.EventuallyTimeout).Should(gbytes.Say("channel creation request not allowed because the orderer system channel is not defined")) 120 }) 121 122 It("joins application channels from genesis block and removes a channel using the channel participation API", func() { 123 orderer1 := network.Orderer("orderer1") 124 orderer2 := network.Orderer("orderer2") 125 orderer3 := network.Orderer("orderer3") 126 orderers := []*nwo.Orderer{orderer1, orderer2, orderer3} 127 consenters := []*nwo.Orderer{orderer1, orderer2} 128 peer := network.Peer("Org1", "peer0") 129 130 By("starting all three orderers") 131 for _, o := range orderers { 132 startOrderer(o) 133 cl := channelparticipation.List(network, o) 134 Expect(cl).To(Equal(channelparticipation.ChannelList{})) 135 } 136 137 genesisBlock := applicationChannelGenesisBlock(network, consenters, []*nwo.Peer{peer}, "participation-trophy") 138 expectedChannelInfoPT := channelparticipation.ChannelInfo{ 139 Name: "participation-trophy", 140 URL: "/participation/v1/channels/participation-trophy", 141 Status: "active", 142 ConsensusRelation: "consenter", 143 Height: 1, 144 } 145 146 for _, o := range consenters { 147 By("joining " + o.Name + " to channel as a consenter") 148 channelparticipation.Join(network, o, "participation-trophy", genesisBlock, expectedChannelInfoPT) 149 channelInfo := channelparticipation.ListOne(network, o, "participation-trophy") 150 Expect(channelInfo).To(Equal(expectedChannelInfoPT)) 151 } 152 153 submitPeerTxn(orderer1, peer, network, channelparticipation.ChannelInfo{ 154 Name: "participation-trophy", 155 URL: "/participation/v1/channels/participation-trophy", 156 Status: "active", 157 ConsensusRelation: "consenter", 158 Height: 2, 159 }) 160 161 submitPeerTxn(orderer2, peer, network, channelparticipation.ChannelInfo{ 162 Name: "participation-trophy", 163 URL: "/participation/v1/channels/participation-trophy", 164 Status: "active", 165 ConsensusRelation: "consenter", 166 Height: 3, 167 }) 168 169 By("joining orderer3 to the channel as a follower") 170 // make sure we can join using a config block from one of the other orderers 171 configBlockPT := nwo.GetConfigBlock(network, peer, orderer2, "participation-trophy") 172 expectedChannelInfoPTFollower := channelparticipation.ChannelInfo{ 173 Name: "participation-trophy", 174 URL: "/participation/v1/channels/participation-trophy", 175 Status: "onboarding", 176 ConsensusRelation: "follower", 177 Height: 0, 178 } 179 channelparticipation.Join(network, orderer3, "participation-trophy", configBlockPT, expectedChannelInfoPTFollower) 180 181 By("ensuring orderer3 completes onboarding successfully") 182 expectedChannelInfoPTFollower.Status = "active" 183 expectedChannelInfoPTFollower.Height = 3 184 Eventually(func() channelparticipation.ChannelInfo { 185 return channelparticipation.ListOne(network, orderer3, "participation-trophy") 186 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfoPTFollower)) 187 188 By("adding orderer3 to the consenters set") 189 channelConfig := nwo.GetConfig(network, peer, orderer1, "participation-trophy") 190 c := configtx.New(channelConfig) 191 err := c.Orderer().AddConsenter(consenterChannelConfig(network, orderer3)) 192 Expect(err).NotTo(HaveOccurred()) 193 computeSignSubmitConfigUpdate(network, orderer1, peer, c, "participation-trophy") 194 195 By("ensuring orderer3 transitions from follower to consenter") 196 // config update above added a block 197 expectedChannelInfoPT.Height = 4 198 Eventually(func() channelparticipation.ChannelInfo { 199 return channelparticipation.ListOne(network, orderer3, "participation-trophy") 200 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfoPT)) 201 202 By("submitting transaction to orderer3 to ensure it is active") 203 submitPeerTxn(orderer3, peer, network, channelparticipation.ChannelInfo{ 204 Name: "participation-trophy", 205 URL: "/participation/v1/channels/participation-trophy", 206 Status: "active", 207 ConsensusRelation: "consenter", 208 Height: 5, 209 }) 210 211 By("joining orderer1 to another channel as a consenter") 212 genesisBlockAPT := applicationChannelGenesisBlock(network, []*nwo.Orderer{orderer1}, []*nwo.Peer{peer}, "another-participation-trophy") 213 expectedChannelInfoAPT := channelparticipation.ChannelInfo{ 214 Name: "another-participation-trophy", 215 URL: "/participation/v1/channels/another-participation-trophy", 216 Status: "active", 217 ConsensusRelation: "consenter", 218 Height: 1, 219 } 220 channelparticipation.Join(network, orderer1, "another-participation-trophy", genesisBlockAPT, expectedChannelInfoAPT) 221 channelInfo := channelparticipation.ListOne(network, orderer1, "another-participation-trophy") 222 Expect(channelInfo).To(Equal(expectedChannelInfoAPT)) 223 224 By("listing all channels for orderer1") 225 cl := channelparticipation.List(network, orderer1) 226 channelparticipation.ChannelListMatcher(cl, []string{"participation-trophy", "another-participation-trophy"}) 227 228 By("removing orderer1 from the consenter set") 229 channelConfig = nwo.GetConfig(network, peer, orderer2, "participation-trophy") 230 c = configtx.New(channelConfig) 231 err = c.Orderer().RemoveConsenter(consenterChannelConfig(network, orderer1)) 232 Expect(err).NotTo(HaveOccurred()) 233 computeSignSubmitConfigUpdate(network, orderer2, peer, c, "participation-trophy") 234 235 By("ensuring orderer1 transitions to a follower") 236 Eventually(func() channelparticipation.ChannelInfo { 237 return channelparticipation.ListOne(network, orderer1, "participation-trophy") 238 }, network.EventuallyTimeout).Should(Equal(channelparticipation.ChannelInfo{ 239 Name: "participation-trophy", 240 URL: "/participation/v1/channels/participation-trophy", 241 Status: "active", 242 ConsensusRelation: "follower", 243 Height: 6, 244 })) 245 246 submitPeerTxn(orderer2, peer, network, channelparticipation.ChannelInfo{ 247 Name: "participation-trophy", 248 URL: "/participation/v1/channels/participation-trophy", 249 Status: "active", 250 ConsensusRelation: "consenter", 251 Height: 7, 252 }) 253 254 By("ensuring orderer1 pulls the latest block as a follower") 255 Eventually(func() channelparticipation.ChannelInfo { 256 return channelparticipation.ListOne(network, orderer1, "participation-trophy") 257 }, network.EventuallyTimeout).Should(Equal(channelparticipation.ChannelInfo{ 258 Name: "participation-trophy", 259 URL: "/participation/v1/channels/participation-trophy", 260 Status: "active", 261 ConsensusRelation: "follower", 262 Height: 7, 263 })) 264 265 By("removing orderer1 from a channel") 266 channelparticipation.Remove(network, orderer1, "participation-trophy") 267 Eventually(func() channelparticipation.ChannelList { 268 return channelparticipation.List(network, orderer1) 269 }, network.EventuallyTimeout).Should(Equal(channelparticipation.ChannelList{ 270 SystemChannel: nil, 271 Channels: []channelparticipation.ChannelInfoShort{ 272 { 273 Name: "another-participation-trophy", 274 URL: "/participation/v1/channels/another-participation-trophy", 275 }, 276 }, 277 })) 278 279 By("submitting transaction to orderer1") 280 env := CreateBroadcastEnvelope(network, peer, "participation-trophy", []byte("hello")) 281 resp, err := ordererclient.Broadcast(network, orderer1, env) 282 Expect(err).NotTo(HaveOccurred()) 283 Expect(resp.Status).To(Equal(common.Status_BAD_REQUEST)) 284 285 By("listing all channels for orderer1") 286 cl = channelparticipation.List(network, orderer1) 287 channelparticipation.ChannelListMatcher(cl, []string{"another-participation-trophy"}) 288 289 By("joining orderer1 to channel it was previously removed from as consenter") 290 configBlockPT = nwo.GetConfigBlock(network, peer, orderer2, "participation-trophy") 291 expectedChannelInfoPTFollower = channelparticipation.ChannelInfo{ 292 Name: "participation-trophy", 293 URL: "/participation/v1/channels/participation-trophy", 294 Status: "onboarding", 295 ConsensusRelation: "follower", 296 Height: 0, 297 } 298 channelparticipation.Join(network, orderer1, "participation-trophy", configBlockPT, expectedChannelInfoPTFollower) 299 300 By("ensuring orderer1 completes onboarding successfully") 301 expectedChannelInfoPTFollower.Status = "active" 302 expectedChannelInfoPTFollower.Height = 7 303 Eventually(func() channelparticipation.ChannelInfo { 304 return channelparticipation.ListOne(network, orderer1, "participation-trophy") 305 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfoPTFollower)) 306 307 By("adding orderer1 to the consenters set") 308 channelConfig = nwo.GetConfig(network, peer, orderer3, "participation-trophy") 309 c = configtx.New(channelConfig) 310 err = c.Orderer().AddConsenter(consenterChannelConfig(network, orderer1)) 311 Expect(err).NotTo(HaveOccurred()) 312 computeSignSubmitConfigUpdate(network, orderer3, peer, c, "participation-trophy") 313 314 By("ensuring orderer1 transitions from follower to consenter") 315 expectedChannelInfoPT = channelparticipation.ChannelInfo{ 316 Name: "participation-trophy", 317 URL: "/participation/v1/channels/participation-trophy", 318 Status: "active", 319 ConsensusRelation: "consenter", 320 Height: 8, 321 } 322 Eventually(func() channelparticipation.ChannelInfo { 323 return channelparticipation.ListOne(network, orderer1, "participation-trophy") 324 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfoPT)) 325 326 submitPeerTxn(orderer1, peer, network, channelparticipation.ChannelInfo{ 327 Name: "participation-trophy", 328 URL: "/participation/v1/channels/participation-trophy", 329 Status: "active", 330 ConsensusRelation: "consenter", 331 Height: 9, 332 }) 333 334 By("ensuring the channel is still usable by submitting a transaction to each remaining consenter for the channel") 335 submitPeerTxn(orderer2, peer, network, channelparticipation.ChannelInfo{ 336 Name: "participation-trophy", 337 URL: "/participation/v1/channels/participation-trophy", 338 Status: "active", 339 ConsensusRelation: "consenter", 340 Height: 10, 341 }) 342 343 submitPeerTxn(orderer3, peer, network, channelparticipation.ChannelInfo{ 344 Name: "participation-trophy", 345 URL: "/participation/v1/channels/participation-trophy", 346 Status: "active", 347 ConsensusRelation: "consenter", 348 Height: 11, 349 }) 350 351 By("attempting to join with an invalid block") 352 channelparticipationJoinFailure(network, orderer3, "nice-try", &common.Block{}, http.StatusBadRequest, "invalid join block: block is not a config block") 353 354 By("attempting to join a channel that already exists") 355 channelparticipationJoinFailure(network, orderer3, "participation-trophy", genesisBlock, http.StatusMethodNotAllowed, "cannot join: channel already exists") 356 357 By("attempting to join system channel when app channels already exist") 358 systemChannelBlockBytes, err := ioutil.ReadFile(network.OutputBlockPath(network.SystemChannel.Name)) 359 Expect(err).NotTo(HaveOccurred()) 360 systemChannelBlock := &common.Block{} 361 err = proto.Unmarshal(systemChannelBlockBytes, systemChannelBlock) 362 Expect(err).NotTo(HaveOccurred()) 363 channelparticipationJoinFailure(network, orderer3, "systemchannel", systemChannelBlock, http.StatusForbidden, "cannot join: application channels already exist") 364 }) 365 366 It("joins application channels with join-block as consenter via channel participation api", func() { 367 orderer1 := network.Orderer("orderer1") 368 orderer2 := network.Orderer("orderer2") 369 orderer3 := network.Orderer("orderer3") 370 orderers := []*nwo.Orderer{orderer1, orderer2} 371 peer := network.Peer("Org1", "peer0") 372 373 By("starting two orderers") 374 for _, o := range orderers { 375 startOrderer(o) 376 cl := channelparticipation.List(network, o) 377 Expect(cl).To(Equal(channelparticipation.ChannelList{})) 378 } 379 380 genesisBlock := applicationChannelGenesisBlock(network, orderers, []*nwo.Peer{peer}, "participation-trophy") 381 expectedChannelInfoPT := channelparticipation.ChannelInfo{ 382 Name: "participation-trophy", 383 URL: "/participation/v1/channels/participation-trophy", 384 Status: "active", 385 ConsensusRelation: "consenter", 386 Height: 1, 387 } 388 389 for _, o := range orderers { 390 By("joining " + o.Name + " to channel as a consenter") 391 channelparticipation.Join(network, o, "participation-trophy", genesisBlock, expectedChannelInfoPT) 392 channelInfo := channelparticipation.ListOne(network, o, "participation-trophy") 393 Expect(channelInfo).To(Equal(expectedChannelInfoPT)) 394 } 395 396 submitPeerTxn(orderer1, peer, network, channelparticipation.ChannelInfo{ 397 Name: "participation-trophy", 398 URL: "/participation/v1/channels/participation-trophy", 399 Status: "active", 400 ConsensusRelation: "consenter", 401 Height: 2, 402 }) 403 404 submitPeerTxn(orderer2, peer, network, channelparticipation.ChannelInfo{ 405 Name: "participation-trophy", 406 URL: "/participation/v1/channels/participation-trophy", 407 Status: "active", 408 ConsensusRelation: "consenter", 409 Height: 3, 410 }) 411 412 By("submitting a channel config update") 413 channelConfig := nwo.GetConfig(network, peer, orderer1, "participation-trophy") 414 c := configtx.New(channelConfig) 415 err := c.Orderer().AddCapability("V1_1") 416 Expect(err).NotTo(HaveOccurred()) 417 computeSignSubmitConfigUpdate(network, orderer1, peer, c, "participation-trophy") 418 419 currentBlockNumber := nwo.CurrentConfigBlockNumber(network, peer, orderer1, "participation-trophy") 420 Expect(currentBlockNumber).To(BeNumerically(">", 1)) 421 422 By("starting third orderer") 423 startOrderer(orderer3) 424 cl := channelparticipation.List(network, orderer3) 425 Expect(cl).To(Equal(channelparticipation.ChannelList{})) 426 427 By("adding orderer3 to the consenters set") 428 channelConfig = nwo.GetConfig(network, peer, orderer2, "participation-trophy") 429 c = configtx.New(channelConfig) 430 err = c.Orderer().AddConsenter(consenterChannelConfig(network, orderer3)) 431 Expect(err).NotTo(HaveOccurred()) 432 computeSignSubmitConfigUpdate(network, orderer2, peer, c, "participation-trophy") 433 434 By("joining orderer3 to the channel as a consenter") 435 // make sure we can join using a config block from one of the other orderers 436 configBlockPT := nwo.GetConfigBlock(network, peer, orderer2, "participation-trophy") 437 expectedChannelInfoConsenter := channelparticipation.ChannelInfo{ 438 Name: "participation-trophy", 439 URL: "/participation/v1/channels/participation-trophy", 440 Status: "onboarding", 441 ConsensusRelation: "consenter", 442 Height: 0, 443 } 444 channelparticipation.Join(network, orderer3, "participation-trophy", configBlockPT, expectedChannelInfoConsenter) 445 446 By("ensuring orderer3 completes onboarding successfully") 447 expectedChannelInfoConsenter.Status = "active" 448 expectedChannelInfoConsenter.Height = 5 449 Eventually(func() channelparticipation.ChannelInfo { 450 return channelparticipation.ListOne(network, orderer3, "participation-trophy") 451 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfoConsenter)) 452 453 submitPeerTxn(orderer3, peer, network, channelparticipation.ChannelInfo{ 454 Name: "participation-trophy", 455 URL: "/participation/v1/channels/participation-trophy", 456 Status: "active", 457 ConsensusRelation: "consenter", 458 Height: 6, 459 }) 460 }) 461 462 Context("joining application channels with join-block as follower via channel participation api", func() { 463 var ( 464 orderer1, orderer2, orderer3 *nwo.Orderer 465 orderers []*nwo.Orderer 466 peer *nwo.Peer 467 genesisBlock, configBlock *common.Block 468 ) 469 470 BeforeEach(func() { 471 orderer1 = network.Orderer("orderer1") 472 orderer2 = network.Orderer("orderer2") 473 orderer3 = network.Orderer("orderer3") 474 orderers = []*nwo.Orderer{orderer1, orderer2} 475 peer = network.Peer("Org1", "peer0") 476 477 By("starting two orderers") 478 for _, o := range orderers { 479 startOrderer(o) 480 cl := channelparticipation.List(network, o) 481 Expect(cl).To(Equal(channelparticipation.ChannelList{})) 482 } 483 484 genesisBlock = applicationChannelGenesisBlock(network, orderers, []*nwo.Peer{peer}, "participation-trophy") 485 expectedChannelInfoPT := channelparticipation.ChannelInfo{ 486 Name: "participation-trophy", 487 URL: "/participation/v1/channels/participation-trophy", 488 Status: "active", 489 ConsensusRelation: "consenter", 490 Height: 1, 491 } 492 493 By("joining orderer1 and orderer2 to the channel with a genesis block") 494 for _, o := range orderers { 495 By("joining " + o.Name + " to channel as a consenter") 496 channelparticipation.Join(network, o, "participation-trophy", genesisBlock, expectedChannelInfoPT) 497 channelInfo := channelparticipation.ListOne(network, o, "participation-trophy") 498 Expect(channelInfo).To(Equal(expectedChannelInfoPT)) 499 } 500 501 submitPeerTxn(orderer1, peer, network, channelparticipation.ChannelInfo{ 502 Name: "participation-trophy", 503 URL: "/participation/v1/channels/participation-trophy", 504 Status: "active", 505 ConsensusRelation: "consenter", 506 Height: 2, 507 }) 508 509 submitPeerTxn(orderer2, peer, network, channelparticipation.ChannelInfo{ 510 Name: "participation-trophy", 511 URL: "/participation/v1/channels/participation-trophy", 512 Status: "active", 513 ConsensusRelation: "consenter", 514 Height: 3, 515 }) 516 517 By("submitting a channel config update") 518 channelConfig := nwo.GetConfig(network, peer, orderer1, "participation-trophy") 519 c := configtx.New(channelConfig) 520 err := c.Orderer().AddCapability("V1_1") 521 Expect(err).NotTo(HaveOccurred()) 522 computeSignSubmitConfigUpdate(network, orderer1, peer, c, "participation-trophy") 523 524 currentBlockNumber := nwo.CurrentConfigBlockNumber(network, peer, orderer1, "participation-trophy") 525 Expect(currentBlockNumber).To(BeNumerically(">", 1)) 526 527 By("getting the updated config block") 528 configBlock = nwo.GetConfigBlock(network, peer, orderer2, "participation-trophy") 529 }) 530 531 It("joins the channel as a follower using a config block", func() { 532 By("starting third orderer") 533 startOrderer(orderer3) 534 cl := channelparticipation.List(network, orderer3) 535 Expect(cl).To(Equal(channelparticipation.ChannelList{})) 536 537 By("joining orderer3 to the channel as a follower") 538 // make sure we can join using a config block from one of the other orderers 539 expectedChannelInfoPTFollower := channelparticipation.ChannelInfo{ 540 Name: "participation-trophy", 541 URL: "/participation/v1/channels/participation-trophy", 542 Status: "onboarding", 543 ConsensusRelation: "follower", 544 Height: 0, 545 } 546 channelparticipation.Join(network, orderer3, "participation-trophy", configBlock, expectedChannelInfoPTFollower) 547 548 By("ensuring orderer3 completes onboarding successfully") 549 expectedChannelInfoPTFollower.Status = "active" 550 expectedChannelInfoPTFollower.Height = 4 551 Eventually(func() channelparticipation.ChannelInfo { 552 return channelparticipation.ListOne(network, orderer3, "participation-trophy") 553 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfoPTFollower)) 554 555 By("adding orderer3 to the consenters set") 556 channelConfig := nwo.GetConfig(network, peer, orderer1, "participation-trophy") 557 c := configtx.New(channelConfig) 558 err := c.Orderer().AddConsenter(consenterChannelConfig(network, orderer3)) 559 Expect(err).NotTo(HaveOccurred()) 560 computeSignSubmitConfigUpdate(network, orderer1, peer, c, "participation-trophy") 561 562 By("ensuring orderer3 transitions from follower to consenter") 563 // config update above added a block 564 expectedChannelInfoPT := channelparticipation.ChannelInfo{ 565 Name: "participation-trophy", 566 URL: "/participation/v1/channels/participation-trophy", 567 Status: "active", 568 ConsensusRelation: "consenter", 569 Height: 5, 570 } 571 Eventually(func() channelparticipation.ChannelInfo { 572 return channelparticipation.ListOne(network, orderer3, "participation-trophy") 573 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfoPT)) 574 575 submitPeerTxn(orderer3, peer, network, channelparticipation.ChannelInfo{ 576 Name: "participation-trophy", 577 URL: "/participation/v1/channels/participation-trophy", 578 Status: "active", 579 ConsensusRelation: "consenter", 580 Height: 6, 581 }) 582 }) 583 584 It("recovers from a crash after the join block is written to the pendingops file repo", func() { 585 By("simulating the filesystem state at crash") 586 joinBlockFileRepoPath := filepath.Join(network.OrdererDir(orderer3), "system", "pendingops", "join") 587 err := os.MkdirAll(joinBlockFileRepoPath, 0o755) 588 Expect(err).NotTo(HaveOccurred()) 589 blockPath := filepath.Join(joinBlockFileRepoPath, "participation-trophy.join") 590 configBlockBytes, err := proto.Marshal(configBlock) 591 Expect(err).NotTo(HaveOccurred()) 592 err = ioutil.WriteFile(blockPath, configBlockBytes, 0o600) 593 Expect(err).NotTo(HaveOccurred()) 594 595 By("starting third orderer") 596 startOrderer(orderer3) 597 598 By("ensuring orderer3 completes onboarding successfully") 599 expectedChannelInfoPTFollower := channelparticipation.ChannelInfo{ 600 Name: "participation-trophy", 601 URL: "/participation/v1/channels/participation-trophy", 602 Status: "active", 603 ConsensusRelation: "follower", 604 Height: 4, 605 } 606 Eventually(func() channelparticipation.ChannelInfo { 607 return channelparticipation.ListOne(network, orderer3, "participation-trophy") 608 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfoPTFollower)) 609 }) 610 611 It("recovers from a crash after the join block is written to the pendingops file repo and the ledger directory (but not the ledger) has been created", func() { 612 By("simulating the filesystem state at crash") 613 joinBlockFileRepoPath := filepath.Join(network.OrdererDir(orderer3), "system", "pendingops", "join") 614 err := os.MkdirAll(joinBlockFileRepoPath, 0o755) 615 Expect(err).NotTo(HaveOccurred()) 616 blockPath := filepath.Join(joinBlockFileRepoPath, "participation-trophy.join") 617 configBlockBytes, err := proto.Marshal(configBlock) 618 Expect(err).NotTo(HaveOccurred()) 619 err = ioutil.WriteFile(blockPath, configBlockBytes, 0o600) 620 Expect(err).NotTo(HaveOccurred()) 621 622 // create the ledger directory 623 ledgerPath := filepath.Join(network.OrdererDir(orderer3), "system", "chains", "participation-trophy") 624 err = os.MkdirAll(ledgerPath, 0o755) 625 Expect(err).NotTo(HaveOccurred()) 626 627 By("starting third orderer") 628 startOrderer(orderer3) 629 630 By("ensuring orderer3 completes onboarding successfully") 631 expectedChannelInfoPTFollower := channelparticipation.ChannelInfo{ 632 Name: "participation-trophy", 633 URL: "/participation/v1/channels/participation-trophy", 634 Status: "active", 635 ConsensusRelation: "follower", 636 Height: 4, 637 } 638 Eventually(func() channelparticipation.ChannelInfo { 639 return channelparticipation.ListOne(network, orderer3, "participation-trophy") 640 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfoPTFollower)) 641 }) 642 643 It("recovers from a crash after the join block is written to the pendingops file repo and the ledger has been created", func() { 644 By("simulating the filesystem state at crash") 645 joinBlockFileRepoPath := filepath.Join(network.OrdererDir(orderer3), "system", "pendingops", "join") 646 err := os.MkdirAll(joinBlockFileRepoPath, 0o755) 647 Expect(err).NotTo(HaveOccurred()) 648 blockPath := filepath.Join(joinBlockFileRepoPath, "participation-trophy.join") 649 configBlockBytes, err := proto.Marshal(configBlock) 650 Expect(err).NotTo(HaveOccurred()) 651 err = ioutil.WriteFile(blockPath, configBlockBytes, 0o600) 652 Expect(err).NotTo(HaveOccurred()) 653 654 // create the ledger and add the genesis block 655 ledgerDir := filepath.Join(network.OrdererDir(orderer3), "system") 656 lf, err := fileledger.New(ledgerDir, &disabled.Provider{}) 657 Expect(err).NotTo(HaveOccurred()) 658 ledger, err := lf.GetOrCreate("participation-trophy") 659 Expect(err).NotTo(HaveOccurred()) 660 err = ledger.Append(genesisBlock) 661 Expect(err).NotTo(HaveOccurred()) 662 lf.Close() 663 664 By("starting third orderer") 665 startOrderer(orderer3) 666 667 By("ensuring orderer3 completes onboarding successfully") 668 expectedChannelInfoPTFollower := channelparticipation.ChannelInfo{ 669 Name: "participation-trophy", 670 URL: "/participation/v1/channels/participation-trophy", 671 Status: "active", 672 ConsensusRelation: "follower", 673 Height: 4, 674 } 675 Eventually(func() channelparticipation.ChannelInfo { 676 return channelparticipation.ListOne(network, orderer3, "participation-trophy") 677 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfoPTFollower)) 678 679 By("killing orderer3") 680 ordererProcesses[2].Signal(syscall.SIGKILL) 681 Eventually(ordererProcesses[2].Wait(), network.EventuallyTimeout).Should(Receive(MatchError("exit status 137"))) 682 683 By("submitting transactions while orderer3 is down") 684 submitPeerTxn(orderer1, peer, network, channelparticipation.ChannelInfo{ 685 Name: "participation-trophy", 686 URL: "/participation/v1/channels/participation-trophy", 687 Status: "active", 688 ConsensusRelation: "consenter", 689 Height: 5, 690 }) 691 692 submitPeerTxn(orderer2, peer, network, channelparticipation.ChannelInfo{ 693 Name: "participation-trophy", 694 URL: "/participation/v1/channels/participation-trophy", 695 Status: "active", 696 ConsensusRelation: "consenter", 697 Height: 6, 698 }) 699 700 By("restarting orderer3 (follower) and ensuring it catches up to the blocks it missed") 701 ordererRunner := network.OrdererRunner(orderer3) 702 ordererProcess := ifrit.Invoke(ordererRunner) 703 Eventually(ordererProcess.Ready(), network.EventuallyTimeout).Should(BeClosed()) 704 ordererProcesses[2] = ordererProcess 705 ordererRunners[2] = ordererRunner 706 expectedChannelInfoPTFollower = channelparticipation.ChannelInfo{ 707 Name: "participation-trophy", 708 URL: "/participation/v1/channels/participation-trophy", 709 Status: "active", 710 ConsensusRelation: "follower", 711 Height: 6, 712 } 713 Eventually(func() channelparticipation.ChannelInfo { 714 return channelparticipation.ListOne(network, orderer3, "participation-trophy") 715 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfoPTFollower)) 716 }) 717 }) 718 719 It("creates the system channel on two orderers with a genesis block and joins a third using a config block", func() { 720 orderer1 := network.Orderer("orderer1") 721 orderer2 := network.Orderer("orderer2") 722 orderer3 := network.Orderer("orderer3") 723 orderers1and2 := []*nwo.Orderer{orderer1, orderer2} 724 orderers := []*nwo.Orderer{orderer1, orderer2, orderer3} 725 org1peer0 := network.Peer("Org1", "peer0") 726 org2peer0 := network.Peer("Org2", "peer0") 727 peers := []*nwo.Peer{org1peer0, org2peer0} 728 729 for _, o := range orderers { 730 startOrderer(o) 731 } 732 733 systemChannelGenesisBlock := systemChannelGenesisBlock(network, orderers1and2, peers, network.SystemChannel.Name) 734 735 expectedChannelInfo := channelparticipation.ChannelInfo{ 736 Name: "systemchannel", 737 URL: "/participation/v1/channels/systemchannel", 738 Status: "inactive", 739 ConsensusRelation: "consenter", 740 Height: 1, 741 } 742 743 By("joining orderers to systemchannel") 744 for _, o := range orderers1and2 { 745 channelparticipation.Join(network, o, "systemchannel", systemChannelGenesisBlock, expectedChannelInfo) 746 } 747 748 By("attempting to join a channel when system channel is present") 749 channelparticipationJoinFailure(network, orderer1, "systemchannel", systemChannelGenesisBlock, http.StatusMethodNotAllowed, "cannot join: system channel exists") 750 751 By("ensuring the system channel is unusable before restarting by attempting to submit a transaction") 752 for _, o := range orderers1and2 { 753 By("submitting transaction to " + o.Name) 754 env := CreateBroadcastEnvelope(network, org1peer0, "systemchannel", []byte("hello")) 755 Expect(broadcastTransactionFunc(network, o, env)()).To(Equal(common.Status_FORBIDDEN)) 756 } 757 758 By("restarting all orderers in the system channel") 759 for i, o := range orderers1and2 { 760 restartOrderer(o, i) 761 } 762 763 By("creating a channel that will have only two consenters") 764 network.CreateChannel("testchannel", orderer1, org1peer0) 765 766 expectedChannelInfo = channelparticipation.ChannelInfo{ 767 Name: "testchannel", 768 URL: "/participation/v1/channels/testchannel", 769 Status: "active", 770 ConsensusRelation: "consenter", 771 Height: 1, 772 } 773 for _, o := range orderers1and2 { 774 By("listing single channel for " + o.Name) 775 Eventually(func() channelparticipation.ChannelInfo { 776 return channelparticipation.ListOne(network, o, "testchannel") 777 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfo)) 778 } 779 780 for _, o := range orderers1and2 { 781 By("listing the channels for " + o.Name) 782 cl := channelparticipation.List(network, o) 783 channelparticipation.ChannelListMatcher(cl, []string{"testchannel"}, "systemchannel") 784 } 785 786 expectedChannelInfo = channelparticipation.ChannelInfo{ 787 Name: "systemchannel", 788 URL: "/participation/v1/channels/systemchannel", 789 Status: "active", 790 ConsensusRelation: "consenter", 791 Height: 2, 792 } 793 for _, o := range orderers1and2 { 794 By("listing single channel for " + o.Name) 795 Eventually(func() channelparticipation.ChannelInfo { 796 return channelparticipation.ListOne(network, o, "systemchannel") 797 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfo)) 798 } 799 800 By("submitting transaction to each active orderer to confirm channel is usable") 801 submitPeerTxn(orderer1, org1peer0, network, channelparticipation.ChannelInfo{ 802 Name: "testchannel", 803 URL: "/participation/v1/channels/testchannel", 804 Status: "active", 805 ConsensusRelation: "consenter", 806 Height: 2, 807 }) 808 809 submitPeerTxn(orderer2, org1peer0, network, channelparticipation.ChannelInfo{ 810 Name: "testchannel", 811 URL: "/participation/v1/channels/testchannel", 812 Status: "active", 813 ConsensusRelation: "consenter", 814 Height: 3, 815 }) 816 817 By("creating a second channel that will have three consenters") 818 network.CreateChannel("testchannel2", orderer1, org1peer0) 819 820 expectedChannelInfo = channelparticipation.ChannelInfo{ 821 Name: "testchannel2", 822 URL: "/participation/v1/channels/testchannel2", 823 Status: "active", 824 ConsensusRelation: "consenter", 825 Height: 1, 826 } 827 for _, o := range orderers1and2 { 828 By("listing single channel for " + o.Name) 829 Eventually(func() channelparticipation.ChannelInfo { 830 return channelparticipation.ListOne(network, o, "testchannel2") 831 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfo)) 832 } 833 834 for _, o := range orderers1and2 { 835 By("listing the channels for " + o.Name) 836 cl := channelparticipation.List(network, o) 837 channelparticipation.ChannelListMatcher(cl, []string{"testchannel", "testchannel2"}, "systemchannel") 838 } 839 840 expectedChannelInfo = channelparticipation.ChannelInfo{ 841 Name: "systemchannel", 842 URL: "/participation/v1/channels/systemchannel", 843 Status: "active", 844 ConsensusRelation: "consenter", 845 Height: 3, 846 } 847 for _, o := range orderers1and2 { 848 By("listing single channel for " + o.Name) 849 Eventually(func() channelparticipation.ChannelInfo { 850 return channelparticipation.ListOne(network, o, "systemchannel") 851 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfo)) 852 } 853 854 By("submitting transaction to each active orderer to confirm channel is usable") 855 submitPeerTxn(orderer1, org1peer0, network, channelparticipation.ChannelInfo{ 856 Name: "testchannel2", 857 URL: "/participation/v1/channels/testchannel2", 858 Status: "active", 859 ConsensusRelation: "consenter", 860 Height: 2, 861 }) 862 863 submitPeerTxn(orderer2, org1peer0, network, channelparticipation.ChannelInfo{ 864 Name: "testchannel2", 865 URL: "/participation/v1/channels/testchannel2", 866 Status: "active", 867 ConsensusRelation: "consenter", 868 Height: 3, 869 }) 870 871 By("submitting a channel config update for the system channel, adding orderer3 to consenters set") 872 channelConfig := nwo.GetConfig(network, org1peer0, orderer1, "systemchannel") 873 c := configtx.New(channelConfig) 874 err := c.Orderer().AddConsenter(consenterChannelConfig(network, orderer3)) 875 Expect(err).NotTo(HaveOccurred()) 876 computeSignSubmitConfigUpdate(network, orderer1, org1peer0, c, "systemchannel") 877 currentBlockNumber := nwo.CurrentConfigBlockNumber(network, org1peer0, orderer1, "systemchannel") 878 Expect(currentBlockNumber).To(BeNumerically(">", 1)) 879 880 expectedChannelInfo = channelparticipation.ChannelInfo{ 881 Name: "systemchannel", 882 URL: "/participation/v1/channels/systemchannel", 883 Status: "active", 884 ConsensusRelation: "consenter", 885 Height: 4, 886 } 887 for _, o := range orderers1and2 { 888 By("listing single channel for " + o.Name) 889 Eventually(func() channelparticipation.ChannelInfo { 890 return channelparticipation.ListOne(network, o, "systemchannel") 891 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfo)) 892 } 893 894 By("submitting a channel config update for testchannel2, adding orderer3 to consenters set") 895 channelConfig = nwo.GetConfig(network, org1peer0, orderer1, "testchannel2") 896 c = configtx.New(channelConfig) 897 err = c.Orderer().AddConsenter(consenterChannelConfig(network, orderer3)) 898 Expect(err).NotTo(HaveOccurred()) 899 computeSignSubmitConfigUpdate(network, orderer1, org1peer0, c, "testchannel2") 900 currentBlockNumber = nwo.CurrentConfigBlockNumber(network, org1peer0, orderer1, "testchannel2") 901 Expect(currentBlockNumber).To(BeNumerically(">", 2)) 902 903 expectedChannelInfo = channelparticipation.ChannelInfo{ 904 Name: "testchannel2", 905 URL: "/participation/v1/channels/testchannel2", 906 Status: "active", 907 ConsensusRelation: "consenter", 908 Height: 4, 909 } 910 for _, o := range orderers1and2 { 911 By("listing single channel for " + o.Name) 912 Eventually(func() channelparticipation.ChannelInfo { 913 return channelparticipation.ListOne(network, o, "testchannel2") 914 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfo)) 915 } 916 917 By("joining orderer3 to the system channel") 918 // make sure we can join using a config block from one of the other orderers 919 920 configBlockSC := nwo.GetConfigBlock(network, org1peer0, orderer2, "systemchannel") 921 Expect(configBlockSC.Header.Number).To(Equal(uint64(3))) 922 923 expectedChannelInfo = channelparticipation.ChannelInfo{ 924 Name: "systemchannel", 925 URL: "/participation/v1/channels/systemchannel", 926 Status: "inactive", 927 ConsensusRelation: "consenter", 928 Height: 0, 929 } 930 channelparticipation.Join(network, orderer3, "systemchannel", configBlockSC, expectedChannelInfo) 931 932 By("restarting orderer3") 933 restartOrderer(orderer3, 2) 934 935 By("listing the channels for orderer3") 936 cl := channelparticipation.List(network, orderer3) 937 channelparticipation.ChannelListMatcher(cl, []string{"testchannel", "testchannel2"}, "systemchannel") 938 939 By("ensuring orderer3 catches up to the latest height as an active consenter") 940 expectedChannelInfo.Status = "active" 941 expectedChannelInfo.Height = 4 942 Eventually(func() channelparticipation.ChannelInfo { 943 return channelparticipation.ListOne(network, orderer3, "systemchannel") 944 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfo)) 945 946 By("submitting a channel config update to add orderer3 to the endpoints") 947 channelConfig = nwo.GetConfig(network, org1peer0, orderer1, "systemchannel") 948 c = configtx.New(channelConfig) 949 host, port := conftx.OrdererHostPort(network, orderer3) 950 err = c.Orderer().Organization(orderer3.Organization).SetEndpoint( 951 configtx.Address{ 952 Host: host, 953 Port: port, 954 }, 955 ) 956 Expect(err).NotTo(HaveOccurred()) 957 computeSignSubmitConfigUpdate(network, orderer2, org1peer0, c, "systemchannel") 958 959 By("ensuring all orderers are active consenters for the system channel") 960 expectedChannelInfo = channelparticipation.ChannelInfo{ 961 Name: "systemchannel", 962 URL: "/participation/v1/channels/systemchannel", 963 Status: "active", 964 ConsensusRelation: "consenter", 965 Height: 5, 966 } 967 for _, o := range orderers { 968 By("listing single channel for " + o.Name) 969 Eventually(func() channelparticipation.ChannelInfo { 970 return channelparticipation.ListOne(network, o, "systemchannel") 971 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfo)) 972 } 973 974 By("ensuring orderer3 becomes an active consenter for the testchannel2 application channel") 975 expectedChannelInfo = channelparticipation.ChannelInfo{ 976 Name: "testchannel2", 977 URL: "/participation/v1/channels/testchannel2", 978 Status: "active", 979 ConsensusRelation: "consenter", 980 Height: 4, 981 } 982 Eventually(func() channelparticipation.ChannelInfo { 983 return channelparticipation.ListOne(network, orderer3, "testchannel2") 984 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfo)) 985 986 By("submitting transactions to ensure the testchannel2 application channel is usable") 987 submitPeerTxn(orderer3, org1peer0, network, channelparticipation.ChannelInfo{ 988 Name: "testchannel2", 989 URL: "/participation/v1/channels/testchannel2", 990 Status: "active", 991 ConsensusRelation: "consenter", 992 Height: 5, 993 }) 994 995 submitPeerTxn(orderer2, org1peer0, network, channelparticipation.ChannelInfo{ 996 Name: "testchannel2", 997 URL: "/participation/v1/channels/testchannel2", 998 Status: "active", 999 ConsensusRelation: "consenter", 1000 Height: 6, 1001 }) 1002 1003 submitPeerTxn(orderer1, org1peer0, network, channelparticipation.ChannelInfo{ 1004 Name: "testchannel2", 1005 URL: "/participation/v1/channels/testchannel2", 1006 Status: "active", 1007 ConsensusRelation: "consenter", 1008 Height: 7, 1009 }) 1010 1011 By("ensuring orderer3 becomes an inactive config-tracker for the testchannel application channel") 1012 expectedChannelInfo = channelparticipation.ChannelInfo{ 1013 Name: "testchannel", 1014 URL: "/participation/v1/channels/testchannel", 1015 Status: "inactive", 1016 ConsensusRelation: "config-tracker", 1017 Height: 1, 1018 } 1019 Eventually(func() channelparticipation.ChannelInfo { 1020 return channelparticipation.ListOne(network, orderer3, "testchannel") 1021 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfo)) 1022 }) 1023 1024 It("requires a client certificate to connect when TLS is enabled", func() { 1025 orderer := network.Orderer("orderer1") 1026 _, unauthClient := nwo.OrdererOperationalClients(network, orderer) 1027 ordererAddress := fmt.Sprintf("127.0.0.1:%d", network.OrdererPort(orderer, nwo.AdminPort)) 1028 listChannelsURL := fmt.Sprintf("https://%s/participation/v1/channels", ordererAddress) 1029 1030 _, err := unauthClient.Get(listChannelsURL) 1031 Expect(err).To(MatchError(fmt.Sprintf("Get \"%s\": dial tcp %s: connect: connection refused", listChannelsURL, ordererAddress))) 1032 }) 1033 }) 1034 1035 Describe("three node etcdraft network with a system channel", func() { 1036 startOrderer := func(o *nwo.Orderer) { 1037 ordererRunner := network.OrdererRunner(o) 1038 ordererProcess := ifrit.Invoke(ordererRunner) 1039 Eventually(ordererProcess.Ready(), network.EventuallyTimeout).Should(BeClosed()) 1040 ordererProcesses = append(ordererProcesses, ordererProcess) 1041 ordererRunners = append(ordererRunners, ordererRunner) 1042 } 1043 1044 restartOrderer := func(o *nwo.Orderer, index int) { 1045 ordererProcesses[index].Signal(syscall.SIGKILL) 1046 Eventually(ordererProcesses[index].Wait(), network.EventuallyTimeout).Should(Receive(MatchError("exit status 137"))) 1047 ordererRunner := network.OrdererRunner(o) 1048 ordererProcess := ifrit.Invoke(ordererRunner) 1049 Eventually(ordererProcess.Ready(), network.EventuallyTimeout).Should(BeClosed()) 1050 ordererProcesses[index] = ordererProcess 1051 ordererRunners[index] = ordererRunner 1052 } 1053 1054 BeforeEach(func() { 1055 network = nwo.New(nwo.MultiNodeEtcdRaft(), testDir, client, StartPort(), components) 1056 network.GenerateConfigTree() 1057 network.Bootstrap() 1058 }) 1059 1060 It("joins channels using the legacy channel creation mechanism and then removes the system channel to transition to the channel participation API", func() { 1061 orderer1 := network.Orderer("orderer1") 1062 orderer2 := network.Orderer("orderer2") 1063 orderer3 := network.Orderer("orderer3") 1064 orderers := []*nwo.Orderer{orderer1, orderer2, orderer3} 1065 peer := network.Peer("Org1", "peer0") 1066 for _, o := range orderers { 1067 startOrderer(o) 1068 } 1069 1070 By("creating an application channel using system channel") 1071 network.CreateChannel("testchannel", orderer1, peer) 1072 1073 By("broadcasting envelopes to each orderer") 1074 for _, o := range orderers { 1075 env := CreateBroadcastEnvelope(network, peer, "testchannel", []byte("hello")) 1076 Eventually(broadcastTransactionFunc(network, o, env), network.EventuallyTimeout).Should(Equal(common.Status_SUCCESS)) 1077 } 1078 1079 By("enabling the channel participation API on each orderer") 1080 network.Consensus.ChannelParticipationEnabled = true 1081 network.Consensus.BootstrapMethod = "none" 1082 for i, o := range orderers { 1083 network.GenerateOrdererConfig(o) 1084 restartOrderer(o, i) 1085 } 1086 1087 By("listing the channels") 1088 expectedChannelInfo := channelparticipation.ChannelInfo{ 1089 Name: "testchannel", 1090 URL: "/participation/v1/channels/testchannel", 1091 Status: "active", 1092 ConsensusRelation: "consenter", 1093 Height: 4, 1094 } 1095 for _, o := range orderers { 1096 By("listing single channel") 1097 Eventually(func() channelparticipation.ChannelInfo { 1098 return channelparticipation.ListOne(network, o, "testchannel") 1099 }, network.EventuallyTimeout).Should(Equal(expectedChannelInfo)) 1100 By("listing all channels") 1101 cl := channelparticipation.List(network, o) 1102 channelparticipation.ChannelListMatcher(cl, []string{"testchannel"}, "systemchannel") 1103 } 1104 1105 By("submitting a transaction to ensure the system channel is active after restart") 1106 submitOrdererTxn(orderer2, network, channelparticipation.ChannelInfo{ 1107 Name: "systemchannel", 1108 URL: "/participation/v1/channels/systemchannel", 1109 Status: "active", 1110 ConsensusRelation: "consenter", 1111 Height: 3, 1112 }) 1113 1114 By("submitting a transaction to ensure the application channel is active after restart") 1115 submitPeerTxn(orderer2, peer, network, channelparticipation.ChannelInfo{ 1116 Name: "testchannel", 1117 URL: "/participation/v1/channels/testchannel", 1118 Status: "active", 1119 ConsensusRelation: "consenter", 1120 Height: 5, 1121 }) 1122 1123 By("removing orderer3 from the consenters set") 1124 channelConfig := nwo.GetConfig(network, peer, orderer2, "testchannel") 1125 c := configtx.New(channelConfig) 1126 err := c.Orderer().RemoveConsenter(consenterChannelConfig(network, orderer3)) 1127 Expect(err).NotTo(HaveOccurred()) 1128 computeSignSubmitConfigUpdate(network, orderer2, peer, c, "testchannel") 1129 1130 By("ensuring orderer3 transitions to inactive/config-tracker") 1131 Eventually(func() channelparticipation.ChannelInfo { 1132 return channelparticipation.ListOne(network, orderer3, "testchannel") 1133 }, network.EventuallyTimeout).Should(Equal(channelparticipation.ChannelInfo{ 1134 Name: "testchannel", 1135 URL: "/participation/v1/channels/testchannel", 1136 Status: "inactive", 1137 ConsensusRelation: "config-tracker", 1138 Height: 6, 1139 })) 1140 1141 By("ensuring orderers 1 and 2 receive the block") 1142 orderers1and2 := []*nwo.Orderer{orderer1, orderer2} 1143 for _, o := range orderers1and2 { 1144 Eventually(func() channelparticipation.ChannelInfo { 1145 return channelparticipation.ListOne(network, o, "testchannel") 1146 }, network.EventuallyTimeout).Should(Equal(channelparticipation.ChannelInfo{ 1147 Name: "testchannel", 1148 URL: "/participation/v1/channels/testchannel", 1149 Status: "active", 1150 ConsensusRelation: "consenter", 1151 Height: 6, 1152 })) 1153 } 1154 1155 By("submitting a transaction to each active orderer") 1156 submitPeerTxn(orderer1, peer, network, channelparticipation.ChannelInfo{ 1157 Name: "testchannel", 1158 URL: "/participation/v1/channels/testchannel", 1159 Status: "active", 1160 ConsensusRelation: "consenter", 1161 Height: 7, 1162 }) 1163 1164 submitPeerTxn(orderer2, peer, network, channelparticipation.ChannelInfo{ 1165 Name: "testchannel", 1166 URL: "/participation/v1/channels/testchannel", 1167 Status: "active", 1168 ConsensusRelation: "consenter", 1169 Height: 8, 1170 }) 1171 1172 By("restarting orderer3 to ensure it still reports inactive/config-tracker") 1173 restartOrderer(orderer3, 2) 1174 Eventually(func() channelparticipation.ChannelInfo { 1175 return channelparticipation.ListOne(network, orderer3, "testchannel") 1176 }, network.EventuallyTimeout).Should(Equal(channelparticipation.ChannelInfo{ 1177 Name: "testchannel", 1178 URL: "/participation/v1/channels/testchannel", 1179 Status: "inactive", 1180 ConsensusRelation: "config-tracker", 1181 Height: 6, 1182 })) 1183 1184 By("attempting to join a channel when the system channel is present") 1185 genesisBlock := applicationChannelGenesisBlock(network, orderers, []*nwo.Peer{peer}, "participation-trophy") 1186 channelparticipationJoinFailure(network, orderers[0], "participation-trophy", genesisBlock, http.StatusMethodNotAllowed, "cannot join: system channel exists") 1187 1188 By("attempting to remove a channel when the system channel is present") 1189 channelparticipationRemoveFailure(network, orderers[0], "testchannel", http.StatusMethodNotAllowed, "cannot remove: system channel exists") 1190 1191 By("submitting a transaction to ensure the system channel is active after restart") 1192 submitOrdererTxn(orderer3, network, channelparticipation.ChannelInfo{ 1193 Name: "systemchannel", 1194 URL: "/participation/v1/channels/systemchannel", 1195 Status: "active", 1196 ConsensusRelation: "consenter", 1197 Height: 4, 1198 }) 1199 1200 By("putting the system channel into maintenance mode") 1201 channelConfig = nwo.GetConfig(network, peer, orderer2, "systemchannel") 1202 c = configtx.New(channelConfig) 1203 err = c.Orderer().SetConsensusState(orderer.ConsensusStateMaintenance) 1204 Expect(err).NotTo(HaveOccurred()) 1205 computeSignSubmitConfigUpdate(network, orderer2, peer, c, "systemchannel") 1206 1207 By("removing the system channel with the channel participation API") 1208 for _, o := range orderers { 1209 channelparticipation.Remove(network, o, "systemchannel") 1210 } 1211 1212 By("listing the channels after removing the system channel") 1213 for _, o := range orderers1and2 { 1214 cl := channelparticipation.List(network, o) 1215 channelparticipation.ChannelListMatcher(cl, []string{"testchannel"}) 1216 } 1217 cl := channelparticipation.List(network, orderer3) 1218 channelparticipation.ChannelListMatcher(cl, nil) 1219 1220 By("fetching a block from each orderer to ensure a leader has been elected for the existing application channel") 1221 for _, o := range orderers1and2 { 1222 FetchBlock(network, o, 0, "testchannel") 1223 } 1224 1225 By("submitting a transaction to each active orderer on testchannel") 1226 submitPeerTxn(orderer1, peer, network, channelparticipation.ChannelInfo{ 1227 Name: "testchannel", 1228 URL: "/participation/v1/channels/testchannel", 1229 Status: "active", 1230 ConsensusRelation: "consenter", 1231 Height: 9, 1232 }) 1233 1234 submitPeerTxn(orderer2, peer, network, channelparticipation.ChannelInfo{ 1235 Name: "testchannel", 1236 URL: "/participation/v1/channels/testchannel", 1237 Status: "active", 1238 ConsensusRelation: "consenter", 1239 Height: 10, 1240 }) 1241 1242 By("using the channel participation API to join a new channel") 1243 expectedChannelInfoPT := channelparticipation.ChannelInfo{ 1244 Name: "participation-trophy", 1245 URL: "/participation/v1/channels/participation-trophy", 1246 Status: "active", 1247 ConsensusRelation: "consenter", 1248 Height: 1, 1249 } 1250 1251 for _, o := range orderers { 1252 By("joining " + o.Name + " to channel as a consenter") 1253 channelparticipation.Join(network, o, "participation-trophy", genesisBlock, expectedChannelInfoPT) 1254 channelInfo := channelparticipation.ListOne(network, o, "participation-trophy") 1255 Expect(channelInfo).To(Equal(expectedChannelInfoPT)) 1256 } 1257 1258 submitPeerTxn(orderer1, peer, network, channelparticipation.ChannelInfo{ 1259 Name: "participation-trophy", 1260 URL: "/participation/v1/channels/participation-trophy", 1261 Status: "active", 1262 ConsensusRelation: "consenter", 1263 Height: 2, 1264 }) 1265 1266 submitPeerTxn(orderer2, peer, network, channelparticipation.ChannelInfo{ 1267 Name: "participation-trophy", 1268 URL: "/participation/v1/channels/participation-trophy", 1269 Status: "active", 1270 ConsensusRelation: "consenter", 1271 Height: 3, 1272 }) 1273 1274 submitPeerTxn(orderer3, peer, network, channelparticipation.ChannelInfo{ 1275 Name: "participation-trophy", 1276 URL: "/participation/v1/channels/participation-trophy", 1277 Status: "active", 1278 ConsensusRelation: "consenter", 1279 Height: 4, 1280 }) 1281 }) 1282 }) 1283 }) 1284 1285 // submit a transaction signed by the peer and ensure it was 1286 // committed to the ledger 1287 func submitPeerTxn(o *nwo.Orderer, peer *nwo.Peer, n *nwo.Network, expectedChannelInfo channelparticipation.ChannelInfo) { 1288 env := CreateBroadcastEnvelope(n, peer, expectedChannelInfo.Name, []byte("hello")) 1289 submitTxn(o, env, n, expectedChannelInfo) 1290 } 1291 1292 // submit a transaction signed by the orderer and ensure it is 1293 // committed to the ledger 1294 func submitOrdererTxn(o *nwo.Orderer, n *nwo.Network, expectedChannelInfo channelparticipation.ChannelInfo) { 1295 env := CreateBroadcastEnvelope(n, o, expectedChannelInfo.Name, []byte("hello")) 1296 submitTxn(o, env, n, expectedChannelInfo) 1297 } 1298 1299 // submit the envelope to the orderer and ensure it is committed 1300 // to the ledger 1301 func submitTxn(o *nwo.Orderer, env *common.Envelope, n *nwo.Network, expectedChannelInfo channelparticipation.ChannelInfo) { 1302 By("submitting a transaction to " + o.Name) 1303 Eventually(broadcastTransactionFunc(n, o, env), n.EventuallyTimeout, time.Second).Should(Equal(common.Status_SUCCESS)) 1304 1305 By("checking the channel info on " + o.Name) 1306 Eventually(func() channelparticipation.ChannelInfo { 1307 return channelparticipation.ListOne(n, o, expectedChannelInfo.Name) 1308 }, n.EventuallyTimeout).Should(Equal(expectedChannelInfo)) 1309 } 1310 1311 func applicationChannelGenesisBlock(n *nwo.Network, orderers []*nwo.Orderer, peers []*nwo.Peer, channel string) *common.Block { 1312 ordererOrgs, consenters := ordererOrganizationsAndConsenters(n, orderers) 1313 peerOrgs := peerOrganizations(n, peers) 1314 1315 channelConfig := configtx.Channel{ 1316 Orderer: configtx.Orderer{ 1317 OrdererType: "etcdraft", 1318 Organizations: ordererOrgs, 1319 EtcdRaft: orderer.EtcdRaft{ 1320 Consenters: consenters, 1321 Options: orderer.EtcdRaftOptions{ 1322 TickInterval: "500ms", 1323 ElectionTick: 10, 1324 HeartbeatTick: 1, 1325 MaxInflightBlocks: 5, 1326 SnapshotIntervalSize: 16 * 1024 * 1024, // 16 MB 1327 }, 1328 }, 1329 Policies: map[string]configtx.Policy{ 1330 "Readers": { 1331 Type: "ImplicitMeta", 1332 Rule: "ANY Readers", 1333 }, 1334 "Writers": { 1335 Type: "ImplicitMeta", 1336 Rule: "ANY Writers", 1337 }, 1338 "Admins": { 1339 Type: "ImplicitMeta", 1340 Rule: "MAJORITY Admins", 1341 }, 1342 "BlockValidation": { 1343 Type: "ImplicitMeta", 1344 Rule: "ANY Writers", 1345 }, 1346 }, 1347 Capabilities: []string{"V2_0"}, 1348 BatchSize: orderer.BatchSize{ 1349 MaxMessageCount: 100, 1350 AbsoluteMaxBytes: 1024 * 1024, 1351 PreferredMaxBytes: 512 * 1024, 1352 }, 1353 BatchTimeout: 2 * time.Second, 1354 State: "STATE_NORMAL", 1355 }, 1356 Application: configtx.Application{ 1357 Organizations: peerOrgs, 1358 Capabilities: []string{"V2_0"}, 1359 Policies: map[string]configtx.Policy{ 1360 "Readers": { 1361 Type: "ImplicitMeta", 1362 Rule: "ANY Readers", 1363 }, 1364 "Writers": { 1365 Type: "ImplicitMeta", 1366 Rule: "ANY Writers", 1367 }, 1368 "Admins": { 1369 Type: "ImplicitMeta", 1370 Rule: "MAJORITY Admins", 1371 }, 1372 "Endorsement": { 1373 Type: "ImplicitMeta", 1374 Rule: "MAJORITY Endorsement", 1375 }, 1376 "LifecycleEndorsement": { 1377 Type: "ImplicitMeta", 1378 Rule: "MAJORITY Endorsement", 1379 }, 1380 }, 1381 }, 1382 Capabilities: []string{"V2_0"}, 1383 Policies: map[string]configtx.Policy{ 1384 "Readers": { 1385 Type: "ImplicitMeta", 1386 Rule: "ANY Readers", 1387 }, 1388 "Writers": { 1389 Type: "ImplicitMeta", 1390 Rule: "ANY Writers", 1391 }, 1392 "Admins": { 1393 Type: "ImplicitMeta", 1394 Rule: "MAJORITY Admins", 1395 }, 1396 }, 1397 } 1398 1399 genesisBlock, err := configtx.NewApplicationChannelGenesisBlock(channelConfig, channel) 1400 Expect(err).NotTo(HaveOccurred()) 1401 1402 return genesisBlock 1403 } 1404 1405 func systemChannelGenesisBlock(n *nwo.Network, orderers []*nwo.Orderer, peers []*nwo.Peer, channel string) *common.Block { 1406 ordererOrgs, consenters := ordererOrganizationsAndConsenters(n, orderers) 1407 peerOrgs := peerOrganizations(n, peers) 1408 1409 channelConfig := configtx.Channel{ 1410 Orderer: configtx.Orderer{ 1411 OrdererType: "etcdraft", 1412 Organizations: ordererOrgs, 1413 EtcdRaft: orderer.EtcdRaft{ 1414 Consenters: consenters, 1415 Options: orderer.EtcdRaftOptions{ 1416 TickInterval: "500ms", 1417 ElectionTick: 10, 1418 HeartbeatTick: 1, 1419 MaxInflightBlocks: 5, 1420 SnapshotIntervalSize: 16 * 1024 * 1024, // 16 MB 1421 }, 1422 }, 1423 Policies: map[string]configtx.Policy{ 1424 "Readers": { 1425 Type: "ImplicitMeta", 1426 Rule: "ANY Readers", 1427 }, 1428 "Writers": { 1429 Type: "ImplicitMeta", 1430 Rule: "ANY Writers", 1431 }, 1432 "Admins": { 1433 Type: "ImplicitMeta", 1434 Rule: "MAJORITY Admins", 1435 }, 1436 "BlockValidation": { 1437 Type: "ImplicitMeta", 1438 Rule: "ANY Writers", 1439 }, 1440 }, 1441 Capabilities: []string{"V2_0"}, 1442 BatchSize: orderer.BatchSize{ 1443 MaxMessageCount: 100, 1444 AbsoluteMaxBytes: 1024 * 1024, 1445 PreferredMaxBytes: 512 * 1024, 1446 }, 1447 BatchTimeout: 2 * time.Second, 1448 State: "STATE_NORMAL", 1449 }, 1450 Consortiums: []configtx.Consortium{ 1451 { 1452 Name: n.Consortiums[0].Name, 1453 Organizations: peerOrgs, 1454 }, 1455 }, 1456 Capabilities: []string{"V2_0"}, 1457 Policies: map[string]configtx.Policy{ 1458 "Readers": { 1459 Type: "ImplicitMeta", 1460 Rule: "ANY Readers", 1461 }, 1462 "Writers": { 1463 Type: "ImplicitMeta", 1464 Rule: "ANY Writers", 1465 }, 1466 "Admins": { 1467 Type: "ImplicitMeta", 1468 Rule: "MAJORITY Admins", 1469 }, 1470 }, 1471 } 1472 1473 genesisBlock, err := configtx.NewSystemChannelGenesisBlock(channelConfig, channel) 1474 Expect(err).NotTo(HaveOccurred()) 1475 1476 return genesisBlock 1477 } 1478 1479 // parseCertificate loads the PEM-encoded x509 certificate at the specified 1480 // path. 1481 func parseCertificate(path string) *x509.Certificate { 1482 certBytes, err := ioutil.ReadFile(path) 1483 Expect(err).NotTo(HaveOccurred()) 1484 pemBlock, _ := pem.Decode(certBytes) 1485 cert, err := x509.ParseCertificate(pemBlock.Bytes) 1486 Expect(err).NotTo(HaveOccurred()) 1487 return cert 1488 } 1489 1490 // parsePrivateKey loads the PEM-encoded private key at the specified path. 1491 func parsePrivateKey(path string) crypto.PrivateKey { 1492 pkBytes, err := ioutil.ReadFile(path) 1493 Expect(err).NotTo(HaveOccurred()) 1494 pemBlock, _ := pem.Decode(pkBytes) 1495 privateKey, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes) 1496 Expect(err).NotTo(HaveOccurred()) 1497 return privateKey 1498 } 1499 1500 func ordererOrganizationsAndConsenters(n *nwo.Network, orderers []*nwo.Orderer) ([]configtx.Organization, []orderer.Consenter) { 1501 ordererOrgsMap := map[string]*configtx.Organization{} 1502 consenters := make([]orderer.Consenter, len(orderers)) 1503 1504 for i, o := range orderers { 1505 rootCert := parseCertificate(n.OrdererCACert(o)) 1506 adminCert := parseCertificate(n.OrdererUserCert(o, "Admin")) 1507 tlsRootCert := parseCertificate(filepath.Join(n.OrdererLocalTLSDir(o), "ca.crt")) 1508 1509 orgConfig, ok := ordererOrgsMap[o.Organization] 1510 if !ok { 1511 orgConfig := configtxOrganization(n.Organization(o.Organization), rootCert, adminCert, tlsRootCert) 1512 orgConfig.OrdererEndpoints = []string{ 1513 n.OrdererAddress(o, nwo.ListenPort), 1514 } 1515 ordererOrgsMap[o.Organization] = &orgConfig 1516 } else { 1517 orgConfig.OrdererEndpoints = append(orgConfig.OrdererEndpoints, n.OrdererAddress(o, nwo.ListenPort)) 1518 orgConfig.MSP.RootCerts = append(orgConfig.MSP.RootCerts, rootCert) 1519 orgConfig.MSP.Admins = append(orgConfig.MSP.Admins, adminCert) 1520 orgConfig.MSP.TLSRootCerts = append(orgConfig.MSP.TLSRootCerts, tlsRootCert) 1521 } 1522 1523 consenters[i] = consenterChannelConfig(n, o) 1524 } 1525 1526 ordererOrgs := []configtx.Organization{} 1527 for _, o := range ordererOrgsMap { 1528 ordererOrgs = append(ordererOrgs, *o) 1529 } 1530 1531 return ordererOrgs, consenters 1532 } 1533 1534 // constructs the peer organizations for a config block. It should be passed 1535 // only one peer per organization. 1536 func peerOrganizations(n *nwo.Network, peers []*nwo.Peer) []configtx.Organization { 1537 peerOrgs := make([]configtx.Organization, len(peers)) 1538 for i, p := range peers { 1539 rootCert := parseCertificate(n.PeerCACert(p)) 1540 adminCert := parseCertificate(n.PeerUserCert(p, "Admin")) 1541 tlsRootCert := parseCertificate(filepath.Join(n.PeerLocalTLSDir(p), "ca.crt")) 1542 1543 peerOrgs[i] = configtxOrganization(n.Organization(p.Organization), rootCert, adminCert, tlsRootCert) 1544 } 1545 1546 return peerOrgs 1547 } 1548 1549 func configtxOrganization(org *nwo.Organization, rootCert, adminCert, tlsRootCert *x509.Certificate) configtx.Organization { 1550 return configtx.Organization{ 1551 Name: org.Name, 1552 Policies: map[string]configtx.Policy{ 1553 "Readers": { 1554 Type: "Signature", 1555 Rule: fmt.Sprintf("OR('%s.member')", org.MSPID), 1556 }, 1557 "Writers": { 1558 Type: "Signature", 1559 Rule: fmt.Sprintf("OR('%s.member')", org.MSPID), 1560 }, 1561 "Admins": { 1562 Type: "Signature", 1563 Rule: fmt.Sprintf("OR('%s.admin')", org.MSPID), 1564 }, 1565 }, 1566 MSP: configtx.MSP{ 1567 Name: org.MSPID, 1568 RootCerts: []*x509.Certificate{rootCert}, 1569 Admins: []*x509.Certificate{adminCert}, 1570 TLSRootCerts: []*x509.Certificate{tlsRootCert}, 1571 }, 1572 } 1573 } 1574 1575 func computeSignSubmitConfigUpdate(n *nwo.Network, o *nwo.Orderer, p *nwo.Peer, c configtx.ConfigTx, channel string) { 1576 configUpdate, err := c.ComputeMarshaledUpdate(channel) 1577 Expect(err).NotTo(HaveOccurred()) 1578 1579 signingIdentity := configtx.SigningIdentity{ 1580 Certificate: parseCertificate(n.OrdererUserCert(o, "Admin")), 1581 PrivateKey: parsePrivateKey(n.OrdererUserKey(o, "Admin")), 1582 MSPID: n.Organization(o.Organization).MSPID, 1583 } 1584 signature, err := signingIdentity.CreateConfigSignature(configUpdate) 1585 Expect(err).NotTo(HaveOccurred()) 1586 1587 configUpdateEnvelope, err := configtx.NewEnvelope(configUpdate, signature) 1588 Expect(err).NotTo(HaveOccurred()) 1589 err = signingIdentity.SignEnvelope(configUpdateEnvelope) 1590 Expect(err).NotTo(HaveOccurred()) 1591 1592 currentBlockNumber := nwo.CurrentConfigBlockNumber(n, p, o, channel) 1593 1594 Eventually(broadcastTransactionFunc(n, o, configUpdateEnvelope), n.EventuallyTimeout).Should(Equal(common.Status_SUCCESS)) 1595 1596 ccb := func() uint64 { return nwo.CurrentConfigBlockNumber(n, p, o, channel) } 1597 Eventually(ccb, n.EventuallyTimeout).Should(BeNumerically(">", currentBlockNumber)) 1598 } 1599 1600 func broadcastTransactionFunc(n *nwo.Network, o *nwo.Orderer, env *common.Envelope) func() common.Status { 1601 return func() common.Status { 1602 resp, err := ordererclient.Broadcast(n, o, env) 1603 Expect(err).NotTo(HaveOccurred()) 1604 return resp.Status 1605 } 1606 } 1607 1608 func consenterChannelConfig(n *nwo.Network, o *nwo.Orderer) orderer.Consenter { 1609 host, port := conftx.OrdererClusterHostPort(n, o) 1610 tlsCert := parseCertificate(filepath.Join(n.OrdererLocalTLSDir(o), "server.crt")) 1611 return orderer.Consenter{ 1612 Address: orderer.EtcdAddress{ 1613 Host: host, 1614 Port: port, 1615 }, 1616 ClientTLSCert: tlsCert, 1617 ServerTLSCert: tlsCert, 1618 } 1619 } 1620 1621 type errorResponse struct { 1622 Error string `json:"error"` 1623 } 1624 1625 func channelparticipationJoinFailure(n *nwo.Network, o *nwo.Orderer, channel string, block *common.Block, expectedStatus int, expectedError string) { 1626 blockBytes, err := proto.Marshal(block) 1627 Expect(err).NotTo(HaveOccurred()) 1628 url := fmt.Sprintf("https://127.0.0.1:%d/participation/v1/channels", n.OrdererPort(o, nwo.AdminPort)) 1629 req := channelparticipation.GenerateJoinRequest(url, channel, blockBytes) 1630 authClient, _ := nwo.OrdererOperationalClients(n, o) 1631 1632 doBodyFailure(authClient, req, expectedStatus, expectedError) 1633 } 1634 1635 func doBodyFailure(client *http.Client, req *http.Request, expectedStatus int, expectedError string) { 1636 resp, err := client.Do(req) 1637 Expect(err).NotTo(HaveOccurred()) 1638 Expect(resp.StatusCode).To(Equal(expectedStatus)) 1639 body, err := ioutil.ReadAll(resp.Body) 1640 Expect(err).NotTo(HaveOccurred()) 1641 resp.Body.Close() 1642 1643 errorResponse := &errorResponse{} 1644 err = json.Unmarshal(body, errorResponse) 1645 Expect(err).NotTo(HaveOccurred()) 1646 Expect(errorResponse.Error).To(Equal(expectedError)) 1647 } 1648 1649 func channelparticipationRemoveFailure(n *nwo.Network, o *nwo.Orderer, channel string, expectedStatus int, expectedError string) { 1650 authClient, _ := nwo.OrdererOperationalClients(n, o) 1651 url := fmt.Sprintf("https://127.0.0.1:%d/participation/v1/channels/%s", n.OrdererPort(o, nwo.AdminPort), channel) 1652 1653 req, err := http.NewRequest(http.MethodDelete, url, nil) 1654 Expect(err).NotTo(HaveOccurred()) 1655 1656 doBodyFailure(authClient, req, expectedStatus, expectedError) 1657 } 1658 1659 func multiNodeEtcdRaftTwoChannels() *nwo.Config { 1660 config := nwo.MultiNodeEtcdRaft() 1661 config.Channels = []*nwo.Channel{ 1662 {Name: "testchannel", Profile: "TwoOrgsChannel"}, 1663 {Name: "testchannel2", Profile: "TwoOrgsChannel"}, 1664 } 1665 1666 for _, peer := range config.Peers { 1667 peer.Channels = []*nwo.PeerChannel{ 1668 {Name: "testchannel", Anchor: true}, 1669 {Name: "testchannel2", Anchor: true}, 1670 } 1671 } 1672 1673 return config 1674 }