github.com/yous1230/fabric@v2.0.0-beta.0.20191224111736-74345bee6ac2+incompatible/orderer/common/cluster/util_test.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package cluster_test 8 9 import ( 10 "crypto/x509" 11 "encoding/pem" 12 "errors" 13 "fmt" 14 "io/ioutil" 15 "strings" 16 "sync" 17 "testing" 18 "time" 19 20 "github.com/golang/protobuf/proto" 21 "github.com/hyperledger/fabric-protos-go/common" 22 "github.com/hyperledger/fabric-protos-go/msp" 23 "github.com/hyperledger/fabric/bccsp/sw" 24 "github.com/hyperledger/fabric/common/capabilities" 25 "github.com/hyperledger/fabric/common/channelconfig" 26 "github.com/hyperledger/fabric/common/configtx" 27 "github.com/hyperledger/fabric/common/configtx/test" 28 "github.com/hyperledger/fabric/common/crypto/tlsgen" 29 "github.com/hyperledger/fabric/common/flogging" 30 "github.com/hyperledger/fabric/common/policies" 31 "github.com/hyperledger/fabric/core/comm" 32 "github.com/hyperledger/fabric/core/config/configtest" 33 "github.com/hyperledger/fabric/internal/configtxgen/encoder" 34 "github.com/hyperledger/fabric/internal/configtxgen/genesisconfig" 35 "github.com/hyperledger/fabric/orderer/common/cluster" 36 "github.com/hyperledger/fabric/orderer/common/cluster/mocks" 37 "github.com/hyperledger/fabric/protoutil" 38 "github.com/stretchr/testify/assert" 39 "github.com/stretchr/testify/mock" 40 "go.uber.org/zap" 41 "go.uber.org/zap/zapcore" 42 ) 43 44 //go:generate counterfeiter -o mocks/policy.go --fake-name Policy . policy 45 46 type policy interface { 47 policies.Policy 48 } 49 50 //go:generate counterfeiter -o mocks/policy_manager.go --fake-name PolicyManager . policyManager 51 52 type policyManager interface { 53 policies.Manager 54 } 55 56 func TestParallelStubActivation(t *testing.T) { 57 t.Parallel() 58 // Scenario: Activate the stub from different goroutines in parallel. 59 stub := &cluster.Stub{} 60 var wg sync.WaitGroup 61 n := 100 62 wg.Add(n) 63 instance := &cluster.RemoteContext{} 64 var activationCount int 65 maybeCreateInstance := func() (*cluster.RemoteContext, error) { 66 activationCount++ 67 return instance, nil 68 } 69 70 for i := 0; i < n; i++ { 71 go func() { 72 defer wg.Done() 73 stub.Activate(maybeCreateInstance) 74 }() 75 } 76 wg.Wait() 77 activatedStub := stub.RemoteContext 78 // Ensure the instance is the reference we stored 79 // and not any other reference, i.e - it wasn't 80 // copied by value. 81 assert.True(t, activatedStub == instance) 82 // Ensure the method was invoked only once. 83 assert.Equal(t, activationCount, 1) 84 } 85 86 func TestDialerCustomKeepAliveOptions(t *testing.T) { 87 t.Parallel() 88 ca, err := tlsgen.NewCA() 89 assert.NoError(t, err) 90 91 clientKeyPair, err := ca.NewClientCertKeyPair() 92 clientConfig := comm.ClientConfig{ 93 KaOpts: comm.KeepaliveOptions{ 94 ClientTimeout: time.Second * 12345, 95 }, 96 Timeout: time.Millisecond * 100, 97 SecOpts: comm.SecureOptions{ 98 RequireClientCert: true, 99 Key: clientKeyPair.Key, 100 Certificate: clientKeyPair.Cert, 101 ServerRootCAs: [][]byte{ca.CertBytes()}, 102 UseTLS: true, 103 ClientRootCAs: [][]byte{ca.CertBytes()}, 104 }, 105 } 106 107 dialer := &cluster.PredicateDialer{Config: clientConfig} 108 timeout := dialer.Config.KaOpts.ClientTimeout 109 assert.Equal(t, time.Second*12345, timeout) 110 } 111 112 func TestPredicateDialerUpdateRootCAs(t *testing.T) { 113 t.Parallel() 114 115 node1 := newTestNode(t) 116 defer node1.stop() 117 118 anotherTLSCA, err := tlsgen.NewCA() 119 assert.NoError(t, err) 120 121 dialer := &cluster.PredicateDialer{ 122 Config: node1.clientConfig.Clone(), 123 } 124 dialer.Config.SecOpts.ServerRootCAs = [][]byte{anotherTLSCA.CertBytes()} 125 dialer.Config.Timeout = time.Second 126 dialer.Config.AsyncConnect = false 127 128 _, err = dialer.Dial(node1.srv.Address(), nil) 129 assert.Error(t, err) 130 131 // Update root TLS CAs asynchronously to make sure we don't have a data race. 132 go func() { 133 dialer.UpdateRootCAs(node1.clientConfig.SecOpts.ServerRootCAs) 134 }() 135 136 // Eventually we should succeed connecting. 137 for i := 0; i < 10; i++ { 138 conn, err := dialer.Dial(node1.srv.Address(), nil) 139 if err == nil { 140 conn.Close() 141 return 142 } 143 } 144 145 assert.Fail(t, "could not connect after 10 attempts despite changing TLS CAs") 146 } 147 148 func TestDialerBadConfig(t *testing.T) { 149 t.Parallel() 150 emptyCertificate := []byte("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----") 151 dialer := &cluster.PredicateDialer{ 152 Config: comm.ClientConfig{ 153 SecOpts: comm.SecureOptions{ 154 UseTLS: true, 155 ServerRootCAs: [][]byte{emptyCertificate}, 156 }, 157 }, 158 } 159 _, err := dialer.Dial("127.0.0.1:8080", func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 160 return nil 161 }) 162 assert.EqualError(t, err, "error adding root certificate: asn1: syntax error: sequence truncated") 163 } 164 165 func TestDERtoPEM(t *testing.T) { 166 t.Parallel() 167 ca, err := tlsgen.NewCA() 168 assert.NoError(t, err) 169 keyPair, err := ca.NewServerCertKeyPair("localhost") 170 assert.NoError(t, err) 171 assert.Equal(t, cluster.DERtoPEM(keyPair.TLSCert.Raw), string(keyPair.Cert)) 172 } 173 174 func TestStandardDialer(t *testing.T) { 175 t.Parallel() 176 emptyCertificate := []byte("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----") 177 certPool := [][]byte{emptyCertificate} 178 config := comm.ClientConfig{SecOpts: comm.SecureOptions{UseTLS: true, ServerRootCAs: certPool}} 179 standardDialer := &cluster.StandardDialer{ 180 Config: config, 181 } 182 _, err := standardDialer.Dial(cluster.EndpointCriteria{Endpoint: "127.0.0.1:8080", TLSRootCAs: certPool}) 183 assert.EqualError(t, 184 err, 185 "failed creating gRPC client: error adding root certificate: asn1: syntax error: sequence truncated", 186 ) 187 } 188 189 func TestVerifyBlockSignature(t *testing.T) { 190 verifier := &mocks.BlockVerifier{} 191 var nilConfigEnvelope *common.ConfigEnvelope 192 verifier.On("VerifyBlockSignature", mock.Anything, nilConfigEnvelope).Return(nil) 193 194 block := createBlockChain(3, 3)[0] 195 196 // The block should have a valid structure 197 err := cluster.VerifyBlockSignature(block, verifier, nil) 198 assert.NoError(t, err) 199 200 for _, testCase := range []struct { 201 name string 202 mutateBlock func(*common.Block) *common.Block 203 errorContains string 204 }{ 205 { 206 name: "nil metadata", 207 errorContains: "no metadata in block", 208 mutateBlock: func(block *common.Block) *common.Block { 209 block.Metadata = nil 210 return block 211 }, 212 }, 213 { 214 name: "zero metadata slice", 215 errorContains: "no metadata in block", 216 mutateBlock: func(block *common.Block) *common.Block { 217 block.Metadata.Metadata = nil 218 return block 219 }, 220 }, 221 { 222 name: "nil metadata", 223 errorContains: "failed unmarshaling medatata for signatures", 224 mutateBlock: func(block *common.Block) *common.Block { 225 block.Metadata.Metadata[0] = []byte{1, 2, 3} 226 return block 227 }, 228 }, 229 { 230 name: "bad signature header", 231 errorContains: "failed unmarshaling signature header", 232 mutateBlock: func(block *common.Block) *common.Block { 233 metadata := protoutil.GetMetadataFromBlockOrPanic(block, common.BlockMetadataIndex_SIGNATURES) 234 metadata.Signatures[0].SignatureHeader = []byte{1, 2, 3} 235 block.Metadata.Metadata[common.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(metadata) 236 return block 237 }, 238 }, 239 } { 240 testCase := testCase 241 t.Run(testCase.name, func(t *testing.T) { 242 // Create a copy of the block 243 blockCopy := &common.Block{} 244 err := proto.Unmarshal(protoutil.MarshalOrPanic(block), blockCopy) 245 assert.NoError(t, err) 246 // Mutate the block to sabotage it 247 blockCopy = testCase.mutateBlock(blockCopy) 248 err = cluster.VerifyBlockSignature(blockCopy, verifier, nil) 249 assert.Contains(t, err.Error(), testCase.errorContains) 250 }) 251 } 252 } 253 254 func TestVerifyBlockHash(t *testing.T) { 255 var start uint64 = 3 256 var end uint64 = 23 257 258 verify := func(blockchain []*common.Block) error { 259 for i := 0; i < len(blockchain); i++ { 260 err := cluster.VerifyBlockHash(i, blockchain) 261 if err != nil { 262 return err 263 } 264 } 265 return nil 266 } 267 268 // Verify that createBlockChain() creates a valid blockchain 269 assert.NoError(t, verify(createBlockChain(start, end))) 270 271 twoBlocks := createBlockChain(2, 3) 272 twoBlocks[0].Header = nil 273 assert.EqualError(t, cluster.VerifyBlockHash(1, twoBlocks), "previous block header is nil") 274 275 // Index out of bounds 276 blockchain := createBlockChain(start, end) 277 err := cluster.VerifyBlockHash(100, blockchain) 278 assert.EqualError(t, err, "index 100 out of bounds (total 21 blocks)") 279 280 for _, testCase := range []struct { 281 name string 282 mutateBlockSequence func([]*common.Block) []*common.Block 283 errorContains string 284 }{ 285 { 286 name: "non consecutive sequences", 287 errorContains: "sequences 12 and 666 were received consecutively", 288 mutateBlockSequence: func(blockSequence []*common.Block) []*common.Block { 289 blockSequence[len(blockSequence)/2].Header.Number = 666 290 assignHashes(blockSequence) 291 return blockSequence 292 }, 293 }, 294 { 295 name: "data hash mismatch", 296 errorContains: "computed hash of block (13) (dcb2ec1c5e482e4914cb953ff8eedd12774b244b12912afbe6001ba5de9ff800)" + 297 " doesn't match claimed hash (07)", 298 mutateBlockSequence: func(blockSequence []*common.Block) []*common.Block { 299 blockSequence[len(blockSequence)/2].Header.DataHash = []byte{7} 300 return blockSequence 301 }, 302 }, 303 { 304 name: "prev hash mismatch", 305 errorContains: "block [12]'s hash " + 306 "(866351705f1c2f13e10d52ead9d0ca3b80689ede8cc8bf70a6d60c67578323f4) " + 307 "mismatches block [13]'s prev block hash (07)", 308 mutateBlockSequence: func(blockSequence []*common.Block) []*common.Block { 309 blockSequence[len(blockSequence)/2].Header.PreviousHash = []byte{7} 310 return blockSequence 311 }, 312 }, 313 { 314 name: "nil block header", 315 errorContains: "missing block header", 316 mutateBlockSequence: func(blockSequence []*common.Block) []*common.Block { 317 blockSequence[0].Header = nil 318 return blockSequence 319 }, 320 }, 321 } { 322 testCase := testCase 323 t.Run(testCase.name, func(t *testing.T) { 324 blockchain := createBlockChain(start, end) 325 blockchain = testCase.mutateBlockSequence(blockchain) 326 err := verify(blockchain) 327 assert.EqualError(t, err, testCase.errorContains) 328 }) 329 } 330 } 331 332 func TestVerifyBlocks(t *testing.T) { 333 var sigSet1 []*protoutil.SignedData 334 var sigSet2 []*protoutil.SignedData 335 336 configEnvelope1 := &common.ConfigEnvelope{ 337 Config: &common.Config{ 338 Sequence: 1, 339 }, 340 } 341 configEnvelope2 := &common.ConfigEnvelope{ 342 Config: &common.Config{ 343 Sequence: 2, 344 }, 345 } 346 configTransaction := func(envelope *common.ConfigEnvelope) *common.Envelope { 347 return &common.Envelope{ 348 Payload: protoutil.MarshalOrPanic(&common.Payload{ 349 Data: protoutil.MarshalOrPanic(envelope), 350 Header: &common.Header{ 351 ChannelHeader: protoutil.MarshalOrPanic(&common.ChannelHeader{ 352 Type: int32(common.HeaderType_CONFIG), 353 }), 354 }, 355 }), 356 } 357 } 358 359 for _, testCase := range []struct { 360 name string 361 configureVerifier func(*mocks.BlockVerifier) 362 mutateBlockSequence func([]*common.Block) []*common.Block 363 expectedError string 364 verifierExpectedCalls int 365 }{ 366 { 367 name: "empty sequence", 368 mutateBlockSequence: func(blockSequence []*common.Block) []*common.Block { 369 return nil 370 }, 371 expectedError: "buffer is empty", 372 }, 373 { 374 name: "prev hash mismatch", 375 mutateBlockSequence: func(blockSequence []*common.Block) []*common.Block { 376 blockSequence[len(blockSequence)/2].Header.PreviousHash = []byte{7} 377 return blockSequence 378 }, 379 expectedError: "block [74]'s hash " + 380 "(5cb4bd1b6a73f81afafd96387bb7ff4473c2425929d0862586f5fbfa12d762dd) " + 381 "mismatches block [75]'s prev block hash (07)", 382 }, 383 { 384 name: "bad signature", 385 mutateBlockSequence: func(blockSequence []*common.Block) []*common.Block { 386 return blockSequence 387 }, 388 configureVerifier: func(verifier *mocks.BlockVerifier) { 389 var nilEnvelope *common.ConfigEnvelope 390 verifier.On("VerifyBlockSignature", mock.Anything, nilEnvelope).Return(errors.New("bad signature")) 391 }, 392 expectedError: "bad signature", 393 verifierExpectedCalls: 1, 394 }, 395 { 396 name: "block that its type cannot be classified", 397 mutateBlockSequence: func(blockSequence []*common.Block) []*common.Block { 398 blockSequence[len(blockSequence)/2].Data = &common.BlockData{ 399 Data: [][]byte{protoutil.MarshalOrPanic(&common.Envelope{})}, 400 } 401 blockSequence[len(blockSequence)/2].Header.DataHash = protoutil.BlockDataHash(blockSequence[len(blockSequence)/2].Data) 402 assignHashes(blockSequence) 403 return blockSequence 404 }, 405 expectedError: "nil header in payload", 406 }, 407 { 408 name: "config blocks in the sequence need to be verified and one of them is improperly signed", 409 mutateBlockSequence: func(blockSequence []*common.Block) []*common.Block { 410 var err error 411 // Put a config transaction in block n / 4 412 blockSequence[len(blockSequence)/4].Data = &common.BlockData{ 413 Data: [][]byte{protoutil.MarshalOrPanic(configTransaction(configEnvelope1))}, 414 } 415 blockSequence[len(blockSequence)/4].Header.DataHash = protoutil.BlockDataHash(blockSequence[len(blockSequence)/4].Data) 416 417 // Put a config transaction in block n / 2 418 blockSequence[len(blockSequence)/2].Data = &common.BlockData{ 419 Data: [][]byte{protoutil.MarshalOrPanic(configTransaction(configEnvelope2))}, 420 } 421 blockSequence[len(blockSequence)/2].Header.DataHash = protoutil.BlockDataHash(blockSequence[len(blockSequence)/2].Data) 422 423 assignHashes(blockSequence) 424 425 sigSet1, err = cluster.SignatureSetFromBlock(blockSequence[len(blockSequence)/4]) 426 assert.NoError(t, err) 427 sigSet2, err = cluster.SignatureSetFromBlock(blockSequence[len(blockSequence)/2]) 428 assert.NoError(t, err) 429 430 return blockSequence 431 }, 432 configureVerifier: func(verifier *mocks.BlockVerifier) { 433 var nilEnvelope *common.ConfigEnvelope 434 // The first config block, validates correctly. 435 verifier.On("VerifyBlockSignature", sigSet1, nilEnvelope).Return(nil).Once() 436 // However, the second config block - validates incorrectly. 437 confEnv1 := &common.ConfigEnvelope{} 438 proto.Unmarshal(protoutil.MarshalOrPanic(configEnvelope1), confEnv1) 439 verifier.On("VerifyBlockSignature", sigSet2, confEnv1).Return(errors.New("bad signature")).Once() 440 }, 441 expectedError: "bad signature", 442 verifierExpectedCalls: 2, 443 }, 444 { 445 name: "config block in the sequence needs to be verified, and it is properly signed", 446 mutateBlockSequence: func(blockSequence []*common.Block) []*common.Block { 447 var err error 448 // Put a config transaction in block n / 4 449 blockSequence[len(blockSequence)/4].Data = &common.BlockData{ 450 Data: [][]byte{protoutil.MarshalOrPanic(configTransaction(configEnvelope1))}, 451 } 452 blockSequence[len(blockSequence)/4].Header.DataHash = protoutil.BlockDataHash(blockSequence[len(blockSequence)/4].Data) 453 454 assignHashes(blockSequence) 455 456 sigSet1, err = cluster.SignatureSetFromBlock(blockSequence[len(blockSequence)/4]) 457 assert.NoError(t, err) 458 459 sigSet2, err = cluster.SignatureSetFromBlock(blockSequence[len(blockSequence)-1]) 460 assert.NoError(t, err) 461 462 return blockSequence 463 }, 464 configureVerifier: func(verifier *mocks.BlockVerifier) { 465 var nilEnvelope *common.ConfigEnvelope 466 confEnv1 := &common.ConfigEnvelope{} 467 proto.Unmarshal(protoutil.MarshalOrPanic(configEnvelope1), confEnv1) 468 verifier.On("VerifyBlockSignature", sigSet1, nilEnvelope).Return(nil).Once() 469 verifier.On("VerifyBlockSignature", sigSet2, confEnv1).Return(nil).Once() 470 }, 471 // We have a single config block in the 'middle' of the chain, so we have 2 verifications total: 472 // The last block, and the config block. 473 verifierExpectedCalls: 2, 474 }, 475 { 476 name: "last two blocks are config blocks, last block only verified once", 477 mutateBlockSequence: func(blockSequence []*common.Block) []*common.Block { 478 var err error 479 // Put a config transaction in block n-2 and in n-1 480 blockSequence[len(blockSequence)-2].Data = &common.BlockData{ 481 Data: [][]byte{protoutil.MarshalOrPanic(configTransaction(configEnvelope1))}, 482 } 483 blockSequence[len(blockSequence)-2].Header.DataHash = protoutil.BlockDataHash(blockSequence[len(blockSequence)-2].Data) 484 485 blockSequence[len(blockSequence)-1].Data = &common.BlockData{ 486 Data: [][]byte{protoutil.MarshalOrPanic(configTransaction(configEnvelope2))}, 487 } 488 blockSequence[len(blockSequence)-1].Header.DataHash = protoutil.BlockDataHash(blockSequence[len(blockSequence)-1].Data) 489 490 assignHashes(blockSequence) 491 492 sigSet1, err = cluster.SignatureSetFromBlock(blockSequence[len(blockSequence)-2]) 493 assert.NoError(t, err) 494 495 sigSet2, err = cluster.SignatureSetFromBlock(blockSequence[len(blockSequence)-1]) 496 assert.NoError(t, err) 497 498 return blockSequence 499 }, 500 configureVerifier: func(verifier *mocks.BlockVerifier) { 501 var nilEnvelope *common.ConfigEnvelope 502 confEnv1 := &common.ConfigEnvelope{} 503 proto.Unmarshal(protoutil.MarshalOrPanic(configEnvelope1), confEnv1) 504 verifier.On("VerifyBlockSignature", sigSet1, nilEnvelope).Return(nil).Once() 505 // We ensure that the signature set of the last block is verified using the config envelope of the block 506 // before it. 507 verifier.On("VerifyBlockSignature", sigSet2, confEnv1).Return(nil).Once() 508 // Note that we do not record a call to verify the last block, with the config envelope extracted from the block itself. 509 }, 510 // We have 2 config blocks, yet we only verify twice- the first config block, and the next config block, but no more, 511 // since the last block is a config block. 512 verifierExpectedCalls: 2, 513 }, 514 } { 515 testCase := testCase 516 t.Run(testCase.name, func(t *testing.T) { 517 blockchain := createBlockChain(50, 100) 518 blockchain = testCase.mutateBlockSequence(blockchain) 519 verifier := &mocks.BlockVerifier{} 520 if testCase.configureVerifier != nil { 521 testCase.configureVerifier(verifier) 522 } 523 err := cluster.VerifyBlocks(blockchain, verifier) 524 if testCase.expectedError != "" { 525 assert.EqualError(t, err, testCase.expectedError) 526 } else { 527 assert.NoError(t, err) 528 } 529 }) 530 } 531 } 532 533 func assignHashes(blockchain []*common.Block) { 534 for i := 1; i < len(blockchain); i++ { 535 blockchain[i].Header.PreviousHash = protoutil.BlockHeaderHash(blockchain[i-1].Header) 536 } 537 } 538 539 func createBlockChain(start, end uint64) []*common.Block { 540 newBlock := func(seq uint64) *common.Block { 541 sHdr := &common.SignatureHeader{ 542 Creator: []byte{1, 2, 3}, 543 Nonce: []byte{9, 5, 42, 66}, 544 } 545 block := protoutil.NewBlock(seq, nil) 546 blockSignature := &common.MetadataSignature{ 547 SignatureHeader: protoutil.MarshalOrPanic(sHdr), 548 } 549 block.Metadata.Metadata[common.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&common.Metadata{ 550 Value: nil, 551 Signatures: []*common.MetadataSignature{ 552 blockSignature, 553 }, 554 }) 555 556 txn := protoutil.MarshalOrPanic(&common.Envelope{ 557 Payload: protoutil.MarshalOrPanic(&common.Payload{ 558 Header: &common.Header{}, 559 }), 560 }) 561 block.Data.Data = append(block.Data.Data, txn) 562 return block 563 } 564 var blockchain []*common.Block 565 for seq := uint64(start); seq <= uint64(end); seq++ { 566 block := newBlock(seq) 567 block.Data.Data = append(block.Data.Data, make([]byte, 100)) 568 block.Header.DataHash = protoutil.BlockDataHash(block.Data) 569 blockchain = append(blockchain, block) 570 } 571 assignHashes(blockchain) 572 return blockchain 573 } 574 575 func TestEndpointconfigFromConfigBlockGreenPath(t *testing.T) { 576 t.Run("global endpoints", func(t *testing.T) { 577 block, err := test.MakeGenesisBlock("mychannel") 578 assert.NoError(t, err) 579 580 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 581 assert.NoError(t, err) 582 // For a block that doesn't have per org endpoints, 583 // we take the global endpoints 584 injectGlobalOrdererEndpoint(t, block, "globalEndpoint") 585 endpointConfig, err := cluster.EndpointconfigFromConfigBlock(block, cryptoProvider) 586 assert.NoError(t, err) 587 assert.Len(t, endpointConfig, 1) 588 assert.Equal(t, "globalEndpoint", endpointConfig[0].Endpoint) 589 590 bl, _ := pem.Decode(endpointConfig[0].TLSRootCAs[0]) 591 cert, err := x509.ParseCertificate(bl.Bytes) 592 assert.NoError(t, err) 593 594 assert.True(t, cert.IsCA) 595 }) 596 597 t.Run("per org endpoints", func(t *testing.T) { 598 block, err := test.MakeGenesisBlock("mychannel") 599 assert.NoError(t, err) 600 601 // Make a second config. 602 gConf := genesisconfig.Load(genesisconfig.SampleSingleMSPSoloProfile, configtest.GetDevConfigDir()) 603 gConf.Orderer.Capabilities = map[string]bool{ 604 capabilities.OrdererV2_0: true, 605 } 606 channelGroup, err := encoder.NewChannelGroup(gConf) 607 assert.NoError(t, err) 608 609 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 610 assert.NoError(t, err) 611 bundle, err := channelconfig.NewBundle("mychannel", &common.Config{ChannelGroup: channelGroup}, cryptoProvider) 612 assert.NoError(t, err) 613 614 msps, err := bundle.MSPManager().GetMSPs() 615 assert.NoError(t, err) 616 caBytes := msps["SampleOrg"].GetTLSRootCerts()[0] 617 618 assert.NoError(t, err) 619 injectAdditionalTLSCAEndpointPair(t, block, "anotherEndpoint", caBytes, "fooOrg") 620 endpointConfig, err := cluster.EndpointconfigFromConfigBlock(block, cryptoProvider) 621 assert.NoError(t, err) 622 // And ensure that the endpoints that are taken, are the per org ones. 623 assert.Len(t, endpointConfig, 2) 624 for _, endpoint := range endpointConfig { 625 // If this is the original organization (and not the clone), 626 // the TLS CA is 'caBytes' read from the second block. 627 if endpoint.Endpoint == "anotherEndpoint" { 628 assert.Len(t, endpoint.TLSRootCAs, 1) 629 assert.Equal(t, caBytes, endpoint.TLSRootCAs[0]) 630 continue 631 } 632 // Else, our endpoints are from the original org, and the TLS CA is something else. 633 assert.NotEqual(t, caBytes, endpoint.TLSRootCAs[0]) 634 // The endpoints we expect to see are something else. 635 assert.Equal(t, 0, strings.Index(endpoint.Endpoint, "127.0.0.1:")) 636 bl, _ := pem.Decode(endpoint.TLSRootCAs[0]) 637 cert, err := x509.ParseCertificate(bl.Bytes) 638 assert.NoError(t, err) 639 assert.True(t, cert.IsCA) 640 } 641 }) 642 } 643 644 func TestEndpointconfigFromConfigBlockFailures(t *testing.T) { 645 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 646 assert.NoError(t, err) 647 648 t.Run("nil block", func(t *testing.T) { 649 certs, err := cluster.EndpointconfigFromConfigBlock(nil, cryptoProvider) 650 assert.Nil(t, certs) 651 assert.EqualError(t, err, "nil block") 652 }) 653 654 t.Run("nil block data", func(t *testing.T) { 655 certs, err := cluster.EndpointconfigFromConfigBlock(&common.Block{}, cryptoProvider) 656 assert.Nil(t, certs) 657 assert.EqualError(t, err, "block data is nil") 658 }) 659 660 t.Run("no envelope", func(t *testing.T) { 661 certs, err := cluster.EndpointconfigFromConfigBlock(&common.Block{ 662 Data: &common.BlockData{}, 663 }, cryptoProvider) 664 assert.Nil(t, certs) 665 assert.EqualError(t, err, "envelope index out of bounds") 666 }) 667 668 t.Run("bad envelope", func(t *testing.T) { 669 certs, err := cluster.EndpointconfigFromConfigBlock(&common.Block{ 670 Data: &common.BlockData{ 671 Data: [][]byte{{}}, 672 }, 673 }, cryptoProvider) 674 assert.Nil(t, certs) 675 assert.EqualError(t, err, "failed extracting bundle from envelope: envelope header cannot be nil") 676 }) 677 } 678 679 func TestConfigFromBlockBadInput(t *testing.T) { 680 for _, testCase := range []struct { 681 name string 682 block *common.Block 683 expectedError string 684 }{ 685 { 686 name: "nil block", 687 expectedError: "empty block", 688 block: nil, 689 }, 690 { 691 name: "nil block data", 692 expectedError: "empty block", 693 block: &common.Block{}, 694 }, 695 { 696 name: "no data in block", 697 expectedError: "empty block", 698 block: &common.Block{Data: &common.BlockData{}}, 699 }, 700 { 701 name: "invalid payload", 702 expectedError: "error unmarshaling Envelope: proto: common.Envelope: illegal tag 0 (wire type 1)", 703 block: &common.Block{Data: &common.BlockData{Data: [][]byte{{1, 2, 3}}}}, 704 }, 705 { 706 name: "bad genesis block", 707 expectedError: "invalid config envelope: proto: common.ConfigEnvelope: illegal tag 0 (wire type 1)", 708 block: &common.Block{ 709 Header: &common.BlockHeader{}, Data: &common.BlockData{Data: [][]byte{protoutil.MarshalOrPanic(&common.Envelope{ 710 Payload: protoutil.MarshalOrPanic(&common.Payload{ 711 Data: []byte{1, 2, 3}, 712 }), 713 })}}}, 714 }, 715 { 716 name: "invalid envelope in block", 717 expectedError: "error unmarshaling Envelope: proto: common.Envelope: illegal tag 0 (wire type 1)", 718 block: &common.Block{Data: &common.BlockData{Data: [][]byte{{1, 2, 3}}}}, 719 }, 720 { 721 name: "invalid payload in block envelope", 722 expectedError: "error unmarshaling Payload: proto: common.Payload: illegal tag 0 (wire type 1)", 723 block: &common.Block{Data: &common.BlockData{Data: [][]byte{protoutil.MarshalOrPanic(&common.Envelope{ 724 Payload: []byte{1, 2, 3}, 725 })}}}, 726 }, 727 { 728 name: "invalid channel header", 729 expectedError: "error unmarshaling ChannelHeader: proto: common.ChannelHeader: illegal tag 0 (wire type 1)", 730 block: &common.Block{ 731 Header: &common.BlockHeader{Number: 1}, 732 Data: &common.BlockData{Data: [][]byte{protoutil.MarshalOrPanic(&common.Envelope{ 733 Payload: protoutil.MarshalOrPanic(&common.Payload{ 734 Header: &common.Header{ 735 ChannelHeader: []byte{1, 2, 3}, 736 }, 737 }), 738 })}}}, 739 }, 740 { 741 name: "invalid config block", 742 expectedError: "invalid config envelope: proto: common.ConfigEnvelope: illegal tag 0 (wire type 1)", 743 block: &common.Block{ 744 Header: &common.BlockHeader{}, 745 Data: &common.BlockData{Data: [][]byte{protoutil.MarshalOrPanic(&common.Envelope{ 746 Payload: protoutil.MarshalOrPanic(&common.Payload{ 747 Data: []byte{1, 2, 3}, 748 Header: &common.Header{ 749 ChannelHeader: protoutil.MarshalOrPanic(&common.ChannelHeader{ 750 Type: int32(common.HeaderType_CONFIG), 751 }), 752 }, 753 }), 754 })}}}, 755 }, 756 } { 757 t.Run(testCase.name, func(t *testing.T) { 758 conf, err := cluster.ConfigFromBlock(testCase.block) 759 assert.Nil(t, conf) 760 assert.EqualError(t, err, testCase.expectedError) 761 }) 762 } 763 } 764 765 func TestBlockValidationPolicyVerifier(t *testing.T) { 766 t.Parallel() 767 config := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir()) 768 group, err := encoder.NewChannelGroup(config) 769 assert.NoError(t, err) 770 assert.NotNil(t, group) 771 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 772 assert.NoError(t, err) 773 774 validConfigEnvelope := &common.ConfigEnvelope{ 775 Config: &common.Config{ 776 ChannelGroup: group, 777 }, 778 } 779 780 for _, testCase := range []struct { 781 description string 782 expectedError string 783 envelope *common.ConfigEnvelope 784 policyMap map[string]policies.Policy 785 policy policies.Policy 786 }{ 787 /** 788 { 789 description: "policy not found", 790 expectedError: "policy /Channel/Orderer/BlockValidation wasn't found", 791 }, 792 */ 793 { 794 description: "policy evaluation fails", 795 expectedError: "invalid signature", 796 policy: &mocks.Policy{ 797 EvaluateSignedDataStub: func([]*protoutil.SignedData) error { 798 return errors.New("invalid signature") 799 }, 800 }, 801 }, 802 { 803 description: "bad config envelope", 804 expectedError: "config must contain a channel group", 805 policy: &mocks.Policy{}, 806 envelope: &common.ConfigEnvelope{Config: &common.Config{}}, 807 }, 808 { 809 description: "good config envelope overrides custom policy manager", 810 policy: &mocks.Policy{ 811 EvaluateSignedDataStub: func([]*protoutil.SignedData) error { 812 return errors.New("invalid signature") 813 }, 814 }, 815 envelope: validConfigEnvelope, 816 }, 817 } { 818 t.Run(testCase.description, func(t *testing.T) { 819 mockPolicyManager := &mocks.PolicyManager{} 820 if testCase.policy != nil { 821 mockPolicyManager.GetPolicyReturns(testCase.policy, true) 822 } else { 823 mockPolicyManager.GetPolicyReturns(nil, false) 824 } 825 mockPolicyManager.GetPolicyReturns(testCase.policy, true) 826 verifier := &cluster.BlockValidationPolicyVerifier{ 827 Logger: flogging.MustGetLogger("test"), 828 Channel: "mychannel", 829 PolicyMgr: mockPolicyManager, 830 BCCSP: cryptoProvider, 831 } 832 833 err := verifier.VerifyBlockSignature(nil, testCase.envelope) 834 if testCase.expectedError != "" { 835 assert.EqualError(t, err, testCase.expectedError) 836 } else { 837 assert.NoError(t, err) 838 } 839 }) 840 } 841 } 842 843 func TestBlockVerifierAssembler(t *testing.T) { 844 t.Parallel() 845 config := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir()) 846 group, err := encoder.NewChannelGroup(config) 847 assert.NoError(t, err) 848 assert.NotNil(t, group) 849 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 850 assert.NoError(t, err) 851 852 t.Run("Good config envelope", func(t *testing.T) { 853 bva := &cluster.BlockVerifierAssembler{BCCSP: cryptoProvider} 854 verifier, err := bva.VerifierFromConfig(&common.ConfigEnvelope{ 855 Config: &common.Config{ 856 ChannelGroup: group, 857 }, 858 }, "mychannel") 859 assert.NoError(t, err) 860 861 assert.NoError(t, verifier.VerifyBlockSignature(nil, nil)) 862 }) 863 864 t.Run("Bad config envelope", func(t *testing.T) { 865 bva := &cluster.BlockVerifierAssembler{BCCSP: cryptoProvider} 866 _, err := bva.VerifierFromConfig(&common.ConfigEnvelope{}, "mychannel") 867 assert.EqualError(t, err, "failed extracting bundle from envelope: channelconfig Config cannot be nil") 868 }) 869 } 870 871 func TestLastConfigBlock(t *testing.T) { 872 blockRetriever := &mocks.BlockRetriever{} 873 blockRetriever.On("Block", uint64(42)).Return(&common.Block{}) 874 blockRetriever.On("Block", uint64(666)).Return(nil) 875 876 for _, testCase := range []struct { 877 name string 878 block *common.Block 879 blockRetriever cluster.BlockRetriever 880 expectedError string 881 }{ 882 { 883 name: "nil block", 884 expectedError: "nil block", 885 blockRetriever: blockRetriever, 886 }, 887 { 888 name: "nil support", 889 expectedError: "nil blockRetriever", 890 block: &common.Block{}, 891 }, 892 { 893 name: "nil metadata", 894 expectedError: "no metadata in block", 895 blockRetriever: blockRetriever, 896 block: &common.Block{}, 897 }, 898 { 899 name: "no last config block metadata", 900 expectedError: "no metadata in block", 901 blockRetriever: blockRetriever, 902 block: &common.Block{ 903 Metadata: &common.BlockMetadata{ 904 Metadata: [][]byte{{}}, 905 }, 906 }, 907 }, 908 { 909 name: "bad metadata in block", 910 blockRetriever: blockRetriever, 911 expectedError: "error unmarshaling metadata from block at index " + 912 "[LAST_CONFIG]: proto: common.Metadata: illegal tag 0 (wire type 1)", 913 block: &common.Block{ 914 Metadata: &common.BlockMetadata{ 915 Metadata: [][]byte{{}, {1, 2, 3}}, 916 }, 917 }, 918 }, 919 { 920 name: "no block with index", 921 block: &common.Block{ 922 Metadata: &common.BlockMetadata{ 923 Metadata: [][]byte{{}, protoutil.MarshalOrPanic(&common.Metadata{ 924 Value: protoutil.MarshalOrPanic(&common.LastConfig{Index: 666}), 925 })}, 926 }, 927 }, 928 expectedError: "unable to retrieve last config block [666]", 929 blockRetriever: blockRetriever, 930 }, 931 { 932 name: "valid last config block", 933 block: &common.Block{ 934 Metadata: &common.BlockMetadata{ 935 Metadata: [][]byte{{}, protoutil.MarshalOrPanic(&common.Metadata{ 936 Value: protoutil.MarshalOrPanic(&common.LastConfig{Index: 42}), 937 })}, 938 }, 939 }, 940 blockRetriever: blockRetriever, 941 }, 942 } { 943 testCase := testCase 944 t.Run(testCase.name, func(t *testing.T) { 945 block, err := cluster.LastConfigBlock(testCase.block, testCase.blockRetriever) 946 if testCase.expectedError == "" { 947 assert.NoError(t, err) 948 assert.NotNil(t, block) 949 return 950 } 951 assert.EqualError(t, err, testCase.expectedError) 952 assert.Nil(t, block) 953 }) 954 } 955 } 956 957 func TestVerificationRegistryRegisterVerifier(t *testing.T) { 958 t.Parallel() 959 960 blockBytes, err := ioutil.ReadFile("testdata/mychannel.block") 961 assert.NoError(t, err) 962 963 block := &common.Block{} 964 assert.NoError(t, proto.Unmarshal(blockBytes, block)) 965 966 verifier := &mocks.BlockVerifier{} 967 968 verifierFactory := &mocks.VerifierFactory{} 969 verifierFactory.On("VerifierFromConfig", 970 mock.Anything, "mychannel").Return(verifier, nil) 971 972 registry := &cluster.VerificationRegistry{ 973 Logger: flogging.MustGetLogger("test"), 974 VerifiersByChannel: make(map[string]cluster.BlockVerifier), 975 VerifierFactory: verifierFactory, 976 } 977 978 var loadCount int 979 registry.LoadVerifier = func(chain string) cluster.BlockVerifier { 980 assert.Equal(t, "mychannel", chain) 981 loadCount++ 982 return verifier 983 } 984 985 v := registry.RetrieveVerifier("mychannel") 986 assert.Nil(t, v) 987 988 registry.RegisterVerifier("mychannel") 989 v = registry.RetrieveVerifier("mychannel") 990 assert.Equal(t, verifier, v) 991 assert.Equal(t, 1, loadCount) 992 993 // If the verifier exists, this is a no-op 994 registry.RegisterVerifier("mychannel") 995 assert.Equal(t, 1, loadCount) 996 } 997 998 func TestVerificationRegistry(t *testing.T) { 999 t.Parallel() 1000 blockBytes, err := ioutil.ReadFile("testdata/mychannel.block") 1001 assert.NoError(t, err) 1002 1003 block := &common.Block{} 1004 assert.NoError(t, proto.Unmarshal(blockBytes, block)) 1005 1006 flogging.ActivateSpec("test=DEBUG") 1007 defer flogging.Reset() 1008 1009 verifier := &mocks.BlockVerifier{} 1010 1011 for _, testCase := range []struct { 1012 description string 1013 verifiersByChannel map[string]cluster.BlockVerifier 1014 blockCommitted *common.Block 1015 channelCommitted string 1016 channelRetrieved string 1017 expectedVerifier cluster.BlockVerifier 1018 verifierFromConfig cluster.BlockVerifier 1019 verifierFromConfigErr error 1020 loggedMessages map[string]struct{} 1021 }{ 1022 { 1023 description: "bad block", 1024 blockCommitted: &common.Block{}, 1025 channelRetrieved: "foo", 1026 channelCommitted: "foo", 1027 loggedMessages: map[string]struct{}{ 1028 "Failed parsing block of channel foo: empty block, content: " + 1029 "{\n\t\"data\": null,\n\t\"header\": null,\n\t\"metadata\": null\n}\n": {}, 1030 "No verifier for channel foo exists": {}, 1031 }, 1032 expectedVerifier: nil, 1033 }, 1034 { 1035 description: "not a config block", 1036 blockCommitted: createBlockChain(5, 5)[0], 1037 channelRetrieved: "foo", 1038 channelCommitted: "foo", 1039 loggedMessages: map[string]struct{}{ 1040 "No verifier for channel foo exists": {}, 1041 "Committed block [5] for channel foo that is not a config block": {}, 1042 }, 1043 expectedVerifier: nil, 1044 }, 1045 { 1046 description: "valid block but verifier from config fails", 1047 blockCommitted: block, 1048 verifierFromConfigErr: errors.New("invalid MSP config"), 1049 channelRetrieved: "bar", 1050 channelCommitted: "bar", 1051 loggedMessages: map[string]struct{}{ 1052 "Failed creating a verifier from a " + 1053 "config block for channel bar: invalid MSP config, " + 1054 "content: " + cluster.BlockToString(block): {}, 1055 "No verifier for channel bar exists": {}, 1056 }, 1057 expectedVerifier: nil, 1058 }, 1059 { 1060 description: "valid block and verifier from config succeeds but wrong channel retrieved", 1061 blockCommitted: block, 1062 verifierFromConfig: verifier, 1063 channelRetrieved: "foo", 1064 channelCommitted: "bar", 1065 loggedMessages: map[string]struct{}{ 1066 "No verifier for channel foo exists": {}, 1067 "Committed config block [0] for channel bar": {}, 1068 }, 1069 expectedVerifier: nil, 1070 verifiersByChannel: make(map[string]cluster.BlockVerifier), 1071 }, 1072 { 1073 description: "valid block and verifier from config succeeds", 1074 blockCommitted: block, 1075 verifierFromConfig: verifier, 1076 channelRetrieved: "bar", 1077 channelCommitted: "bar", 1078 loggedMessages: map[string]struct{}{ 1079 "Committed config block [0] for channel bar": {}, 1080 }, 1081 expectedVerifier: verifier, 1082 verifiersByChannel: make(map[string]cluster.BlockVerifier), 1083 }, 1084 } { 1085 t.Run(testCase.description, func(t *testing.T) { 1086 verifierFactory := &mocks.VerifierFactory{} 1087 verifierFactory.On("VerifierFromConfig", 1088 mock.Anything, testCase.channelCommitted).Return(testCase.verifierFromConfig, testCase.verifierFromConfigErr) 1089 1090 registry := &cluster.VerificationRegistry{ 1091 Logger: flogging.MustGetLogger("test"), 1092 VerifiersByChannel: testCase.verifiersByChannel, 1093 VerifierFactory: verifierFactory, 1094 } 1095 1096 loggedEntriesByMethods := make(map[string]struct{}) 1097 // Configure the logger to collect the message logged 1098 registry.Logger = registry.Logger.WithOptions(zap.Hooks(func(entry zapcore.Entry) error { 1099 loggedEntriesByMethods[entry.Message] = struct{}{} 1100 return nil 1101 })) 1102 1103 registry.BlockCommitted(testCase.blockCommitted, testCase.channelCommitted) 1104 verifier := registry.RetrieveVerifier(testCase.channelRetrieved) 1105 1106 assert.Equal(t, testCase.loggedMessages, loggedEntriesByMethods) 1107 assert.Equal(t, testCase.expectedVerifier, verifier) 1108 }) 1109 } 1110 } 1111 1112 func TestLedgerInterceptor(t *testing.T) { 1113 block := &common.Block{} 1114 1115 ledger := &mocks.LedgerWriter{} 1116 ledger.On("Append", block).Return(nil).Once() 1117 1118 var intercepted bool 1119 1120 var interceptedLedger cluster.LedgerWriter = &cluster.LedgerInterceptor{ 1121 Channel: "mychannel", 1122 LedgerWriter: ledger, 1123 InterceptBlockCommit: func(b *common.Block, channel string) { 1124 assert.Equal(t, block, b) 1125 assert.Equal(t, "mychannel", channel) 1126 intercepted = true 1127 }, 1128 } 1129 1130 err := interceptedLedger.Append(block) 1131 assert.NoError(t, err) 1132 assert.True(t, intercepted) 1133 ledger.AssertCalled(t, "Append", block) 1134 } 1135 1136 func injectAdditionalTLSCAEndpointPair(t *testing.T, block *common.Block, endpoint string, tlsCA []byte, orgName string) { 1137 // Unwrap the layers until we reach the orderer addresses 1138 env, err := protoutil.ExtractEnvelope(block, 0) 1139 assert.NoError(t, err) 1140 payload, err := protoutil.UnmarshalPayload(env.Payload) 1141 assert.NoError(t, err) 1142 confEnv, err := configtx.UnmarshalConfigEnvelope(payload.Data) 1143 assert.NoError(t, err) 1144 ordererGrp := confEnv.Config.ChannelGroup.Groups[channelconfig.OrdererGroupKey].Groups 1145 // Get the first orderer org config 1146 var firstOrdererConfig *common.ConfigGroup 1147 for _, grp := range ordererGrp { 1148 firstOrdererConfig = grp 1149 break 1150 } 1151 // Duplicate it. 1152 secondOrdererConfig := proto.Clone(firstOrdererConfig).(*common.ConfigGroup) 1153 ordererGrp[orgName] = secondOrdererConfig 1154 // Reach the FabricMSPConfig buried in it. 1155 mspConfig := &msp.MSPConfig{} 1156 err = proto.Unmarshal(secondOrdererConfig.Values[channelconfig.MSPKey].Value, mspConfig) 1157 assert.NoError(t, err) 1158 1159 fabricConfig := &msp.FabricMSPConfig{} 1160 err = proto.Unmarshal(mspConfig.Config, fabricConfig) 1161 assert.NoError(t, err) 1162 1163 // Plant the given TLS CA in it. 1164 fabricConfig.TlsRootCerts = [][]byte{tlsCA} 1165 // No intermediate root CAs, to make the test simpler. 1166 fabricConfig.TlsIntermediateCerts = nil 1167 // Rename it. 1168 fabricConfig.Name = orgName 1169 1170 // Pack the MSP config back into the config 1171 secondOrdererConfig.Values[channelconfig.MSPKey].Value = protoutil.MarshalOrPanic(&msp.MSPConfig{ 1172 Config: protoutil.MarshalOrPanic(fabricConfig), 1173 Type: mspConfig.Type, 1174 }) 1175 1176 // Inject the endpoint 1177 ordererOrgProtos := &common.OrdererAddresses{ 1178 Addresses: []string{endpoint}, 1179 } 1180 secondOrdererConfig.Values[channelconfig.EndpointsKey].Value = protoutil.MarshalOrPanic(ordererOrgProtos) 1181 1182 // Fold everything back into the block 1183 payload.Data = protoutil.MarshalOrPanic(confEnv) 1184 env.Payload = protoutil.MarshalOrPanic(payload) 1185 block.Data.Data[0] = protoutil.MarshalOrPanic(env) 1186 } 1187 1188 func TestEndpointCriteriaString(t *testing.T) { 1189 // The top cert is the issuer of the bottom cert 1190 certs := `-----BEGIN CERTIFICATE----- 1191 MIIBozCCAUigAwIBAgIQMXmzUnikiAZDr4VsrBL+rzAKBggqhkjOPQQDAjAxMS8w 1192 LQYDVQQFEyY2NTc2NDA3Njc5ODcwOTA3OTEwNDM5NzkxMTAwNzA0Mzk3Njg3OTAe 1193 Fw0xOTExMTEyMDM5MDRaFw0yOTExMDkyMDM5MDRaMDExLzAtBgNVBAUTJjY1NzY0 1194 MDc2Nzk4NzA5MDc5MTA0Mzk3OTExMDA3MDQzOTc2ODc5MFkwEwYHKoZIzj0CAQYI 1195 KoZIzj0DAQcDQgAEzBBkRvWgasCKf1pejwpOu+1Fv9FffOZMHnna/7lfMrAqOs8d 1196 HMDVU7mSexu7YNTpAwm4vkdHXi35H8zlVABTxaNCMEAwDgYDVR0PAQH/BAQDAgGm 1197 MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/ 1198 MAoGCCqGSM49BAMCA0kAMEYCIQCXqXoYLAJN9diIdGxPlRQJgJLju4brWXZfyt3s 1199 E9TjFwIhAOuUJjcOchdP6UA9WLnVWciEo1Omf59NgfHL1gUPb/t6 1200 -----END CERTIFICATE----- 1201 -----BEGIN CERTIFICATE----- 1202 MIIBpDCCAUqgAwIBAgIRAIyvtL0z1xQ+NecXeH1HmmAwCgYIKoZIzj0EAwIwMTEv 1203 MC0GA1UEBRMmNjU3NjQwNzY3OTg3MDkwNzkxMDQzOTc5MTEwMDcwNDM5NzY4Nzkw 1204 HhcNMTkxMTExMjAzOTA0WhcNMTkxMTEyMjAzOTA0WjAyMTAwLgYDVQQFEycxODcw 1205 MDQyMzcxODQwMjY5Mzk2ODUxNzk1NzM3MzIyMTc2OTA3MjAwWTATBgcqhkjOPQIB 1206 BggqhkjOPQMBBwNCAARZBFDBOfC7T9RbsX+PgyE6sM7ocuwn6krIGjc00ICivFgQ 1207 qdHMU7hiswiYwSvwh9MDHlprCRW3ycSgEYQgKU5to0IwQDAOBgNVHQ8BAf8EBAMC 1208 BaAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA8GA1UdEQQIMAaHBH8A 1209 AAEwCgYIKoZIzj0EAwIDSAAwRQIhAK6G7qr/ClszCFP25gsflA31+7eoss5vi3o4 1210 qz8bY+s6AiBvO0aOfE8M4ibjmRE4vSXo0+gkOIJKqZcmiRdnJSr8Xw== 1211 -----END CERTIFICATE-----` 1212 1213 epc := cluster.EndpointCriteria{ 1214 Endpoint: "orderer.example.com:7050", 1215 TLSRootCAs: [][]byte{[]byte(certs)}, 1216 } 1217 1218 actual := fmt.Sprint(epc) 1219 expected := `{"CAs":[{"Expired":false,"Issuer":"self","Subject":"SERIALNUMBER=65764076798709079104397911007043976879"},{"Expired":true,"Issuer":"SERIALNUMBER=65764076798709079104397911007043976879","Subject":"SERIALNUMBER=187004237184026939685179573732217690720"}],"Endpoint":"orderer.example.com:7050"}` 1220 assert.Equal(t, expected, actual) 1221 }