github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/core/deliverservice/deliveryclient_test.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package deliverclient 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "runtime" 24 "sync" 25 "sync/atomic" 26 "testing" 27 "time" 28 29 "github.com/hyperledger/fabric/core/deliverservice/blocksprovider" 30 "github.com/hyperledger/fabric/core/deliverservice/mocks" 31 "github.com/hyperledger/fabric/gossip/api" 32 "github.com/hyperledger/fabric/gossip/common" 33 "github.com/hyperledger/fabric/msp/mgmt/testtools" 34 "github.com/hyperledger/fabric/protos/orderer" 35 "github.com/stretchr/testify/assert" 36 "google.golang.org/grpc" 37 ) 38 39 func init() { 40 msptesttools.LoadMSPSetupForTesting() 41 } 42 43 const ( 44 goRoutineTestWaitTimeout = time.Second * 15 45 ) 46 47 var ( 48 lock = sync.Mutex{} 49 ) 50 51 type mockBlocksDelivererFactory struct { 52 mockCreate func() (blocksprovider.BlocksDeliverer, error) 53 } 54 55 func (mock *mockBlocksDelivererFactory) Create() (blocksprovider.BlocksDeliverer, error) { 56 return mock.mockCreate() 57 } 58 59 type mockMCS struct { 60 } 61 62 func (*mockMCS) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common.PKIidType { 63 return common.PKIidType("pkiID") 64 } 65 66 func (*mockMCS) VerifyBlock(chainID common.ChainID, seqNum uint64, signedBlock []byte) error { 67 return nil 68 } 69 70 func (*mockMCS) Sign(msg []byte) ([]byte, error) { 71 return msg, nil 72 } 73 74 func (*mockMCS) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error { 75 return nil 76 } 77 78 func (*mockMCS) VerifyByChannel(chainID common.ChainID, peerIdentity api.PeerIdentityType, signature, message []byte) error { 79 return nil 80 } 81 82 func (*mockMCS) ValidateIdentity(peerIdentity api.PeerIdentityType) error { 83 return nil 84 } 85 86 func TestNewDeliverService(t *testing.T) { 87 defer ensureNoGoroutineLeak(t)() 88 gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64, 1)} 89 factory := &struct{ mockBlocksDelivererFactory }{} 90 91 blocksDeliverer := &mocks.MockBlocksDeliverer{} 92 blocksDeliverer.MockRecv = mocks.MockRecv 93 94 factory.mockCreate = func() (blocksprovider.BlocksDeliverer, error) { 95 return blocksDeliverer, nil 96 } 97 abcf := func(*grpc.ClientConn) orderer.AtomicBroadcastClient { 98 return &mocks.MockAtomicBroadcastClient{blocksDeliverer} 99 } 100 101 connFactory := func(_ string) func(string) (*grpc.ClientConn, error) { 102 return func(endpoint string) (*grpc.ClientConn, error) { 103 lock.Lock() 104 defer lock.Unlock() 105 return newConnection(), nil 106 } 107 } 108 service, err := NewDeliverService(&Config{ 109 Endpoints: []string{"a"}, 110 Gossip: gossipServiceAdapter, 111 CryptoSvc: &mockMCS{}, 112 ABCFactory: abcf, 113 ConnFactory: connFactory, 114 }) 115 assert.NoError(t, err) 116 assert.NoError(t, service.StartDeliverForChannel("TEST_CHAINID", &mocks.MockLedgerInfo{0}, func() {})) 117 118 // Lets start deliver twice 119 assert.Error(t, service.StartDeliverForChannel("TEST_CHAINID", &mocks.MockLedgerInfo{0}, func() {}), "can't start delivery") 120 // Lets stop deliver that not started 121 assert.Error(t, service.StopDeliverForChannel("TEST_CHAINID2"), "can't stop delivery") 122 123 // Let it try to simulate a few recv -> gossip rounds 124 time.Sleep(time.Second) 125 assert.NoError(t, service.StopDeliverForChannel("TEST_CHAINID")) 126 time.Sleep(time.Duration(10) * time.Millisecond) 127 // Make sure to stop all blocks providers 128 service.Stop() 129 time.Sleep(time.Duration(500) * time.Millisecond) 130 assert.Equal(t, 0, connNumber) 131 assertBlockDissemination(0, gossipServiceAdapter.GossipBlockDisseminations, t) 132 assert.Equal(t, atomic.LoadInt32(&blocksDeliverer.RecvCnt), atomic.LoadInt32(&gossipServiceAdapter.AddPayloadsCnt)) 133 assert.Error(t, service.StartDeliverForChannel("TEST_CHAINID", &mocks.MockLedgerInfo{0}, func() {}), "Delivery service is stopping") 134 assert.Error(t, service.StopDeliverForChannel("TEST_CHAINID"), "Delivery service is stopping") 135 } 136 137 func TestDeliverServiceRestart(t *testing.T) { 138 defer ensureNoGoroutineLeak(t)() 139 // Scenario: bring up ordering service instance, then shut it down, and then resurrect it. 140 // Client is expected to reconnect to it, and to ask for a block sequence that is the next block 141 // after the last block it got from the previous incarnation of the ordering service. 142 143 os := mocks.NewOrderer(5611, t) 144 145 time.Sleep(time.Second) 146 gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)} 147 148 service, err := NewDeliverService(&Config{ 149 Endpoints: []string{"localhost:5611"}, 150 Gossip: gossipServiceAdapter, 151 CryptoSvc: &mockMCS{}, 152 ABCFactory: DefaultABCFactory, 153 ConnFactory: DefaultConnectionFactory, 154 }) 155 assert.NoError(t, err) 156 157 li := &mocks.MockLedgerInfo{Height: uint64(100)} 158 os.SetNextExpectedSeek(uint64(100)) 159 160 err = service.StartDeliverForChannel("TEST_CHAINID", li, func() {}) 161 assert.NoError(t, err, "can't start delivery") 162 // Check that delivery client requests blocks in order 163 go os.SendBlock(uint64(100)) 164 assertBlockDissemination(100, gossipServiceAdapter.GossipBlockDisseminations, t) 165 go os.SendBlock(uint64(101)) 166 assertBlockDissemination(101, gossipServiceAdapter.GossipBlockDisseminations, t) 167 go os.SendBlock(uint64(102)) 168 assertBlockDissemination(102, gossipServiceAdapter.GossipBlockDisseminations, t) 169 os.Shutdown() 170 time.Sleep(time.Second * 3) 171 os = mocks.NewOrderer(5611, t) 172 li.Height = 103 173 os.SetNextExpectedSeek(uint64(103)) 174 go os.SendBlock(uint64(103)) 175 assertBlockDissemination(103, gossipServiceAdapter.GossipBlockDisseminations, t) 176 service.Stop() 177 os.Shutdown() 178 } 179 180 func TestDeliverServiceFailover(t *testing.T) { 181 defer ensureNoGoroutineLeak(t)() 182 // Scenario: bring up 2 ordering service instances, 183 // and shut down the instance that the client has connected to. 184 // Client is expected to connect to the other instance, and to ask for a block sequence that is the next block 185 // after the last block it got from the ordering service that was shut down. 186 // Then, shut down the other node, and bring back the first (that was shut down first). 187 188 os1 := mocks.NewOrderer(5612, t) 189 os2 := mocks.NewOrderer(5613, t) 190 191 time.Sleep(time.Second) 192 gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)} 193 194 service, err := NewDeliverService(&Config{ 195 Endpoints: []string{"localhost:5612", "localhost:5613"}, 196 Gossip: gossipServiceAdapter, 197 CryptoSvc: &mockMCS{}, 198 ABCFactory: DefaultABCFactory, 199 ConnFactory: DefaultConnectionFactory, 200 }) 201 assert.NoError(t, err) 202 li := &mocks.MockLedgerInfo{Height: uint64(100)} 203 os1.SetNextExpectedSeek(uint64(100)) 204 os2.SetNextExpectedSeek(uint64(100)) 205 206 err = service.StartDeliverForChannel("TEST_CHAINID", li, func() {}) 207 assert.NoError(t, err, "can't start delivery") 208 // We need to discover to which instance the client connected to 209 go os1.SendBlock(uint64(100)) 210 instance2fail := os1 211 reincarnatedNodePort := 5612 212 instance2failSecond := os2 213 select { 214 case seq := <-gossipServiceAdapter.GossipBlockDisseminations: 215 assert.Equal(t, uint64(100), seq) 216 case <-time.After(time.Second * 2): 217 // Shutdown first instance and replace it, in order to make an instance 218 // with an empty sending channel 219 os1.Shutdown() 220 time.Sleep(time.Second) 221 os1 = mocks.NewOrderer(5612, t) 222 instance2fail = os2 223 instance2failSecond = os1 224 reincarnatedNodePort = 5613 225 // Ensure we really are connected to the second instance, 226 // by making it send a block 227 go os2.SendBlock(uint64(100)) 228 assertBlockDissemination(100, gossipServiceAdapter.GossipBlockDisseminations, t) 229 } 230 231 atomic.StoreUint64(&li.Height, uint64(101)) 232 os1.SetNextExpectedSeek(uint64(101)) 233 os2.SetNextExpectedSeek(uint64(101)) 234 // Fail the orderer node the client is connected to 235 instance2fail.Shutdown() 236 time.Sleep(time.Second) 237 // Ensure the client asks blocks from the other ordering service node 238 go instance2failSecond.SendBlock(uint64(101)) 239 assertBlockDissemination(101, gossipServiceAdapter.GossipBlockDisseminations, t) 240 atomic.StoreUint64(&li.Height, uint64(102)) 241 // Now shut down the 2nd node 242 instance2failSecond.Shutdown() 243 time.Sleep(time.Second * 1) 244 // Bring up the first one 245 os := mocks.NewOrderer(reincarnatedNodePort, t) 246 os.SetNextExpectedSeek(102) 247 go os.SendBlock(uint64(102)) 248 assertBlockDissemination(102, gossipServiceAdapter.GossipBlockDisseminations, t) 249 os.Shutdown() 250 service.Stop() 251 } 252 253 func TestDeliverServiceServiceUnavailable(t *testing.T) { 254 orgMaxRetryDelay := blocksprovider.MaxRetryDelay 255 blocksprovider.MaxRetryDelay = time.Millisecond * 200 256 defer func() { blocksprovider.MaxRetryDelay = orgMaxRetryDelay }() 257 defer ensureNoGoroutineLeak(t)() 258 // Scenario: bring up 2 ordering service instances, 259 // Make the instance the client connects to fail after a delivery of a block and send SERVICE_UNAVAILABLE 260 // whenever subsequent seeks are sent to it. 261 // The client is expected to connect to the other instance, and to ask for a block sequence that is the next block 262 // after the last block it got from the first ordering service node. 263 264 os1 := mocks.NewOrderer(5615, t) 265 os2 := mocks.NewOrderer(5616, t) 266 267 gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)} 268 269 service, err := NewDeliverService(&Config{ 270 Endpoints: []string{"localhost:5615", "localhost:5616"}, 271 Gossip: gossipServiceAdapter, 272 CryptoSvc: &mockMCS{}, 273 ABCFactory: DefaultABCFactory, 274 ConnFactory: DefaultConnectionFactory, 275 }) 276 assert.NoError(t, err) 277 li := &mocks.MockLedgerInfo{Height: 100} 278 os1.SetNextExpectedSeek(li.Height) 279 os2.SetNextExpectedSeek(li.Height) 280 281 err = service.StartDeliverForChannel("TEST_CHAINID", li, func() {}) 282 assert.NoError(t, err, "can't start delivery") 283 284 waitForConnectionToSomeOSN := func() (*mocks.Orderer, *mocks.Orderer) { 285 for { 286 if os1.ConnCount() > 0 { 287 return os1, os2 288 } 289 if os2.ConnCount() > 0 { 290 return os2, os1 291 } 292 time.Sleep(time.Millisecond * 100) 293 } 294 } 295 296 activeInstance, backupInstance := waitForConnectionToSomeOSN() 297 assert.NotNil(t, activeInstance) 298 assert.NotNil(t, backupInstance) 299 // Check that delivery client get connected to active 300 assert.Equal(t, activeInstance.ConnCount(), 1) 301 // and not connected to backup instances 302 assert.Equal(t, backupInstance.ConnCount(), 0) 303 304 // Send first block 305 go activeInstance.SendBlock(li.Height) 306 307 assertBlockDissemination(li.Height, gossipServiceAdapter.GossipBlockDisseminations, t) 308 li.Height++ 309 310 // Backup instance should expect a seek of 101 since we got 100 311 backupInstance.SetNextExpectedSeek(li.Height) 312 // Have backup instance prepare to send a block 313 backupInstance.SendBlock(li.Height) 314 315 // Fail instance delivery client connected to 316 activeInstance.Fail() 317 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 318 defer cancel() 319 320 wg := sync.WaitGroup{} 321 wg.Add(1) 322 323 go func(ctx context.Context) { 324 defer wg.Done() 325 for { 326 select { 327 case <-time.After(time.Millisecond * 100): 328 if backupInstance.ConnCount() > 0 { 329 return 330 } 331 case <-ctx.Done(): 332 return 333 } 334 } 335 }(ctx) 336 337 wg.Wait() 338 assert.NoError(t, ctx.Err(), "Delivery client has not failed over to alive ordering service") 339 // Check that delivery client was indeed connected 340 assert.Equal(t, backupInstance.ConnCount(), 1) 341 // Ensure the client asks blocks from the other ordering service node 342 assertBlockDissemination(li.Height, gossipServiceAdapter.GossipBlockDisseminations, t) 343 344 // Cleanup 345 os1.Shutdown() 346 os2.Shutdown() 347 service.Stop() 348 } 349 350 func TestDeliverServiceShutdown(t *testing.T) { 351 defer ensureNoGoroutineLeak(t)() 352 // Scenario: Launch an ordering service node and let the client pull some blocks. 353 // Then, shut down the client, and check that it is no longer fetching blocks. 354 os := mocks.NewOrderer(5614, t) 355 356 time.Sleep(time.Second) 357 gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)} 358 359 service, err := NewDeliverService(&Config{ 360 Endpoints: []string{"localhost:5614"}, 361 Gossip: gossipServiceAdapter, 362 CryptoSvc: &mockMCS{}, 363 ABCFactory: DefaultABCFactory, 364 ConnFactory: DefaultConnectionFactory, 365 }) 366 assert.NoError(t, err) 367 368 li := &mocks.MockLedgerInfo{Height: uint64(100)} 369 os.SetNextExpectedSeek(uint64(100)) 370 err = service.StartDeliverForChannel("TEST_CHAINID", li, func() {}) 371 assert.NoError(t, err, "can't start delivery") 372 373 // Check that delivery service requests blocks in order 374 go os.SendBlock(uint64(100)) 375 assertBlockDissemination(100, gossipServiceAdapter.GossipBlockDisseminations, t) 376 go os.SendBlock(uint64(101)) 377 assertBlockDissemination(101, gossipServiceAdapter.GossipBlockDisseminations, t) 378 atomic.StoreUint64(&li.Height, uint64(102)) 379 os.SetNextExpectedSeek(uint64(102)) 380 // Now stop the delivery service and make sure we don't disseminate a block 381 service.Stop() 382 go os.SendBlock(uint64(102)) 383 select { 384 case <-gossipServiceAdapter.GossipBlockDisseminations: 385 assert.Fail(t, "Disseminated a block after shutting down the delivery service") 386 case <-time.After(time.Second * 2): 387 } 388 os.Shutdown() 389 time.Sleep(time.Second) 390 } 391 392 func TestDeliverServiceShutdownRespawn(t *testing.T) { 393 // Scenario: Launch an ordering service node and let the client pull some blocks. 394 // Then, wait a few seconds, and don't send any blocks. 395 // Afterwards - start a new instance and shut down the old instance. 396 SetReconnectTotalTimeThreshold(time.Second) 397 defer func() { 398 SetReconnectTotalTimeThreshold(time.Second * 60 * 5) 399 }() 400 defer ensureNoGoroutineLeak(t)() 401 402 osn1 := mocks.NewOrderer(5614, t) 403 404 time.Sleep(time.Second) 405 gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)} 406 407 service, err := NewDeliverService(&Config{ 408 Endpoints: []string{"localhost:5614", "localhost:5615"}, 409 Gossip: gossipServiceAdapter, 410 CryptoSvc: &mockMCS{}, 411 ABCFactory: DefaultABCFactory, 412 ConnFactory: DefaultConnectionFactory, 413 }) 414 assert.NoError(t, err) 415 416 li := &mocks.MockLedgerInfo{Height: uint64(100)} 417 osn1.SetNextExpectedSeek(uint64(100)) 418 err = service.StartDeliverForChannel("TEST_CHAINID", li, func() {}) 419 assert.NoError(t, err, "can't start delivery") 420 421 // Check that delivery service requests blocks in order 422 go osn1.SendBlock(uint64(100)) 423 assertBlockDissemination(100, gossipServiceAdapter.GossipBlockDisseminations, t) 424 go osn1.SendBlock(uint64(101)) 425 assertBlockDissemination(101, gossipServiceAdapter.GossipBlockDisseminations, t) 426 atomic.StoreUint64(&li.Height, uint64(102)) 427 // Now wait for a few seconds 428 time.Sleep(time.Second * 2) 429 // Now start the new instance 430 osn2 := mocks.NewOrderer(5615, t) 431 // Now stop the old instance 432 osn1.Shutdown() 433 // Send a block from osn2 434 osn2.SetNextExpectedSeek(uint64(102)) 435 go osn2.SendBlock(uint64(102)) 436 // Ensure it is received 437 assertBlockDissemination(102, gossipServiceAdapter.GossipBlockDisseminations, t) 438 service.Stop() 439 osn2.Shutdown() 440 } 441 442 func TestDeliverServiceBadConfig(t *testing.T) { 443 // Empty endpoints 444 service, err := NewDeliverService(&Config{ 445 Endpoints: []string{}, 446 Gossip: &mocks.MockGossipServiceAdapter{}, 447 CryptoSvc: &mockMCS{}, 448 ABCFactory: DefaultABCFactory, 449 ConnFactory: DefaultConnectionFactory, 450 }) 451 assert.Error(t, err) 452 assert.Nil(t, service) 453 454 // Nil gossip adapter 455 service, err = NewDeliverService(&Config{ 456 Endpoints: []string{"a"}, 457 Gossip: nil, 458 CryptoSvc: &mockMCS{}, 459 ABCFactory: DefaultABCFactory, 460 ConnFactory: DefaultConnectionFactory, 461 }) 462 assert.Error(t, err) 463 assert.Nil(t, service) 464 465 // Nil crypto service 466 service, err = NewDeliverService(&Config{ 467 Endpoints: []string{"a"}, 468 Gossip: &mocks.MockGossipServiceAdapter{}, 469 CryptoSvc: nil, 470 ABCFactory: DefaultABCFactory, 471 ConnFactory: DefaultConnectionFactory, 472 }) 473 assert.Error(t, err) 474 assert.Nil(t, service) 475 476 // Nil ABCFactory 477 service, err = NewDeliverService(&Config{ 478 Endpoints: []string{"a"}, 479 Gossip: &mocks.MockGossipServiceAdapter{}, 480 CryptoSvc: &mockMCS{}, 481 ABCFactory: nil, 482 ConnFactory: DefaultConnectionFactory, 483 }) 484 assert.Error(t, err) 485 assert.Nil(t, service) 486 487 // Nil connFactory 488 service, err = NewDeliverService(&Config{ 489 Endpoints: []string{"a"}, 490 Gossip: &mocks.MockGossipServiceAdapter{}, 491 CryptoSvc: &mockMCS{}, 492 ABCFactory: DefaultABCFactory, 493 }) 494 assert.Error(t, err) 495 assert.Nil(t, service) 496 } 497 498 func TestRetryPolicyOverflow(t *testing.T) { 499 connFactory := func(channelID string) func(endpoint string) (*grpc.ClientConn, error) { 500 return func(_ string) (*grpc.ClientConn, error) { 501 return nil, errors.New("") 502 } 503 } 504 client := (&deliverServiceImpl{conf: &Config{ConnFactory: connFactory}}).newClient("TEST", &mocks.MockLedgerInfo{Height: uint64(100)}) 505 assert.NotNil(t, client.shouldRetry) 506 for i := 0; i < 100; i++ { 507 retryTime, _ := client.shouldRetry(i, time.Second) 508 assert.True(t, retryTime <= time.Hour && retryTime > 0) 509 } 510 } 511 512 func assertBlockDissemination(expectedSeq uint64, ch chan uint64, t *testing.T) { 513 select { 514 case seq := <-ch: 515 assert.Equal(t, expectedSeq, seq) 516 case <-time.After(time.Second * 5): 517 assert.FailNow(t, fmt.Sprintf("Didn't gossip a new block with seq num %d within a timely manner", expectedSeq)) 518 t.Fatal() 519 } 520 } 521 522 func ensureNoGoroutineLeak(t *testing.T) func() { 523 goroutineCountAtStart := runtime.NumGoroutine() 524 return func() { 525 start := time.Now() 526 timeLimit := start.Add(goRoutineTestWaitTimeout) 527 for time.Now().Before(timeLimit) { 528 time.Sleep(time.Millisecond * 500) 529 if goroutineCountAtStart >= runtime.NumGoroutine() { 530 return 531 } 532 } 533 assert.Fail(t, "Some goroutine(s) didn't finish: %s", getStackTrace()) 534 } 535 } 536 537 func getStackTrace() string { 538 buf := make([]byte, 1<<16) 539 runtime.Stack(buf, true) 540 return string(buf) 541 }