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