github.com/core-coin/go-core/v2@v2.1.9/les/test_helper.go (about) 1 // Copyright 2019 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-core library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 // This file contains some shares testing functionality, common to multiple 18 // different files and modules being tested. 19 20 package les 21 22 import ( 23 "context" 24 "crypto/rand" 25 "fmt" 26 "math/big" 27 "sync/atomic" 28 "testing" 29 "time" 30 31 "github.com/core-coin/go-core/v2/xcbdb" 32 33 "github.com/core-coin/go-core/v2/consensus/cryptore" 34 35 "github.com/core-coin/go-core/v2/accounts/abi/bind" 36 "github.com/core-coin/go-core/v2/accounts/abi/bind/backends" 37 "github.com/core-coin/go-core/v2/common" 38 "github.com/core-coin/go-core/v2/common/mclock" 39 "github.com/core-coin/go-core/v2/contracts/checkpointoracle/contract" 40 "github.com/core-coin/go-core/v2/core" 41 "github.com/core-coin/go-core/v2/core/rawdb" 42 "github.com/core-coin/go-core/v2/core/types" 43 "github.com/core-coin/go-core/v2/crypto" 44 "github.com/core-coin/go-core/v2/event" 45 "github.com/core-coin/go-core/v2/les/checkpointoracle" 46 "github.com/core-coin/go-core/v2/les/flowcontrol" 47 "github.com/core-coin/go-core/v2/light" 48 "github.com/core-coin/go-core/v2/p2p" 49 "github.com/core-coin/go-core/v2/p2p/enode" 50 "github.com/core-coin/go-core/v2/p2p/nodestate" 51 "github.com/core-coin/go-core/v2/params" 52 "github.com/core-coin/go-core/v2/xcb" 53 ) 54 55 var ( 56 bankKey, _ = crypto.GenerateKey(rand.Reader) 57 bankFunds = big.NewInt(1000000000000000000) 58 59 userKey1, _ = crypto.GenerateKey(rand.Reader) 60 userKey2, _ = crypto.GenerateKey(rand.Reader) 61 62 testContractAddr common.Address 63 testContractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056") 64 testContractCodeDeployed = testContractCode[16:] 65 testContractDeployed = uint64(2) 66 67 testEventEmitterCode = common.Hex2Bytes("60606040523415600e57600080fd5b7f57050ab73f6b9ebdd9f76b8d4997793f48cf956e965ee070551b9ca0bb71584e60405160405180910390a160358060476000396000f3006060604052600080fd00a165627a7a723058203f727efcad8b5811f8cb1fc2620ce5e8c63570d697aef968172de296ea3994140029") 68 69 // Checkpoint registrar relative 70 registrarAddr common.Address 71 signerKey, _ = crypto.GenerateKey(rand.Reader) 72 ) 73 74 var ( 75 // The block frequency for creating checkpoint(only used in test) 76 sectionSize = big.NewInt(128) 77 78 // The number of confirmations needed to generate a checkpoint(only used in test). 79 processConfirms = big.NewInt(1) 80 81 // The token bucket buffer limit for testing purpose. 82 testBufLimit = uint64(1000000) 83 84 // The buffer recharging speed for testing purpose. 85 testBufRecharge = uint64(1000) 86 ) 87 88 /* 89 contract test { 90 91 uint256[100] data; 92 93 function Put(uint256 addr, uint256 value) { 94 data[addr] = value; 95 } 96 97 function Get(uint256 addr) constant returns (uint256 value) { 98 return data[addr]; 99 } 100 } 101 */ 102 103 // prepare pre-commits specified number customized blocks into chain. 104 func prepare(n int, backend *backends.SimulatedBackend) { 105 var ( 106 ctx = context.Background() 107 signer = types.NewNucleusSigner(backend.Blockchain().Config().NetworkID) 108 ) 109 for i := 0; i < n; i++ { 110 switch i { 111 case 0: 112 // deploy checkpoint contract 113 auth, _ := bind.NewKeyedTransactorWithNetworkID(bankKey, big.NewInt(1)) 114 registrarAddr, _, _, _ = contract.DeployCheckpointOracle(auth, backend, []common.Address{signerKey.Address()}, sectionSize, processConfirms, big.NewInt(1)) 115 // bankUser transfers some core to user1 116 nonce, _ := backend.PendingNonceAt(ctx, bankKey.Address()) 117 tx, _ := types.SignTx(types.NewTransaction(nonce, userKey1.Address(), big.NewInt(10000), params.TxEnergy, nil, nil), signer, bankKey) 118 backend.SendTransaction(ctx, tx) 119 case 1: 120 bankNonce, _ := backend.PendingNonceAt(ctx, bankKey.Address()) 121 userNonce1, _ := backend.PendingNonceAt(ctx, userKey1.Address()) 122 123 // bankUser transfers more core to user1 124 tx1, _ := types.SignTx(types.NewTransaction(bankNonce, userKey1.Address(), big.NewInt(1000), params.TxEnergy, nil, nil), signer, bankKey) 125 backend.SendTransaction(ctx, tx1) 126 127 // user1 relays core to user2 128 tx2, _ := types.SignTx(types.NewTransaction(userNonce1, userKey2.Address(), big.NewInt(1000), params.TxEnergy, nil, nil), signer, userKey1) 129 backend.SendTransaction(ctx, tx2) 130 131 // user1 deploys a test contract 132 tx3, _ := types.SignTx(types.NewContractCreation(userNonce1+1, big.NewInt(0), 200000, big.NewInt(0), testContractCode), signer, userKey1) 133 backend.SendTransaction(ctx, tx3) 134 testContractAddr = crypto.CreateAddress(userKey1.Address(), userNonce1+1) 135 136 // user1 deploys a event contract 137 tx4, _ := types.SignTx(types.NewContractCreation(userNonce1+2, big.NewInt(0), 200000, big.NewInt(0), testEventEmitterCode), signer, userKey1) 138 backend.SendTransaction(ctx, tx4) 139 case 2: 140 // bankUser transfer some core to signer 141 bankNonce, _ := backend.PendingNonceAt(ctx, bankKey.Address()) 142 tx1, _ := types.SignTx(types.NewTransaction(bankNonce, signerKey.Address(), big.NewInt(1000000000), params.TxEnergy, nil, nil), signer, bankKey) 143 backend.SendTransaction(ctx, tx1) 144 145 // invoke test contract 146 data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") 147 tx2, _ := types.SignTx(types.NewTransaction(bankNonce+1, testContractAddr, big.NewInt(0), 100000, nil, data), signer, bankKey) 148 backend.SendTransaction(ctx, tx2) 149 case 3: 150 // invoke test contract 151 bankNonce, _ := backend.PendingNonceAt(ctx, bankKey.Address()) 152 data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") 153 tx, _ := types.SignTx(types.NewTransaction(bankNonce, testContractAddr, big.NewInt(0), 100000, nil, data), signer, bankKey) 154 backend.SendTransaction(ctx, tx) 155 } 156 backend.Commit() 157 } 158 } 159 160 // testIndexers creates a set of indexers with specified params for testing purpose. 161 func testIndexers(db xcbdb.Database, odr light.OdrBackend, config *light.IndexerConfig, disablePruning bool) []*core.ChainIndexer { 162 var indexers [3]*core.ChainIndexer 163 indexers[0] = light.NewChtIndexer(db, odr, config.ChtSize, config.ChtConfirms, disablePruning) 164 indexers[1] = xcb.NewBloomIndexer(db, config.BloomSize, config.BloomConfirms) 165 indexers[2] = light.NewBloomTrieIndexer(db, odr, config.BloomSize, config.BloomTrieSize, disablePruning) 166 // make bloomTrieIndexer as a child indexer of bloom indexer. 167 indexers[1].AddChildIndexer(indexers[2]) 168 return indexers[:] 169 } 170 171 func newTestClientHandler(backend *backends.SimulatedBackend, odr *LesOdr, indexers []*core.ChainIndexer, db xcbdb.Database, peers *serverPeerSet, ulcServers []string, ulcFraction int) *clientHandler { 172 var ( 173 cvmux = new(event.TypeMux) 174 engine = cryptore.NewFaker() 175 gspec = core.Genesis{ 176 Config: params.MainnetChainConfig, 177 Alloc: core.GenesisAlloc{bankKey.Address(): {Balance: bankFunds}}, 178 EnergyLimit: 100000000, 179 } 180 oracle *checkpointoracle.CheckpointOracle 181 ) 182 genesis := gspec.MustCommit(db) 183 chain, _ := light.NewLightChain(odr, gspec.Config, engine, nil) 184 if indexers != nil { 185 checkpointConfig := ¶ms.CheckpointOracleConfig{ 186 Address: crypto.CreateAddress(bankKey.Address(), 0), 187 Signers: []common.Address{signerKey.Address()}, 188 Threshold: 1, 189 } 190 getLocal := func(index uint64) params.TrustedCheckpoint { 191 chtIndexer := indexers[0] 192 sectionHead := chtIndexer.SectionHead(index) 193 return params.TrustedCheckpoint{ 194 SectionIndex: index, 195 SectionHead: sectionHead, 196 CHTRoot: light.GetChtRoot(db, index, sectionHead), 197 BloomRoot: light.GetBloomTrieRoot(db, index, sectionHead), 198 } 199 } 200 oracle = checkpointoracle.New(checkpointConfig, getLocal) 201 } 202 client := &LightCore{ 203 lesCommons: lesCommons{ 204 genesis: genesis.Hash(), 205 config: &xcb.Config{LightPeers: 100, NetworkId: NetworkId}, 206 chainConfig: params.MainnetChainConfig, 207 iConfig: light.TestClientIndexerConfig, 208 chainDb: db, 209 oracle: oracle, 210 chainReader: chain, 211 closeCh: make(chan struct{}), 212 }, 213 peers: peers, 214 reqDist: odr.retriever.dist, 215 retriever: odr.retriever, 216 odr: odr, 217 engine: engine, 218 blockchain: chain, 219 eventMux: cvmux, 220 } 221 client.handler = newClientHandler(ulcServers, ulcFraction, nil, client) 222 223 if client.oracle != nil { 224 client.oracle.Start(backend) 225 } 226 client.handler.start() 227 return client.handler 228 } 229 230 func newTestServerHandler(blocks int, indexers []*core.ChainIndexer, db xcbdb.Database, clock mclock.Clock) (*serverHandler, *backends.SimulatedBackend) { 231 var ( 232 gspec = core.Genesis{ 233 Config: params.MainnetChainConfig, 234 Alloc: core.GenesisAlloc{bankKey.Address(): {Balance: bankFunds}}, 235 EnergyLimit: 100000000, 236 } 237 oracle *checkpointoracle.CheckpointOracle 238 ) 239 genesis := gspec.MustCommit(db) 240 241 // create a simulation backend and pre-commit several customized block to the database. 242 simulation := backends.NewSimulatedBackendWithDatabase(db, gspec.Alloc, 100000000) 243 prepare(blocks, simulation) 244 245 txpoolConfig := core.DefaultTxPoolConfig 246 txpoolConfig.Journal = "" 247 txpool := core.NewTxPool(txpoolConfig, gspec.Config, simulation.Blockchain()) 248 if indexers != nil { 249 checkpointConfig := ¶ms.CheckpointOracleConfig{ 250 Address: crypto.CreateAddress(bankKey.Address(), 0), 251 Signers: []common.Address{signerKey.Address()}, 252 Threshold: 1, 253 } 254 getLocal := func(index uint64) params.TrustedCheckpoint { 255 chtIndexer := indexers[0] 256 sectionHead := chtIndexer.SectionHead(index) 257 return params.TrustedCheckpoint{ 258 SectionIndex: index, 259 SectionHead: sectionHead, 260 CHTRoot: light.GetChtRoot(db, index, sectionHead), 261 BloomRoot: light.GetBloomTrieRoot(db, index, sectionHead), 262 } 263 } 264 oracle = checkpointoracle.New(checkpointConfig, getLocal) 265 } 266 ns := nodestate.NewNodeStateMachine(nil, nil, mclock.System{}, serverSetup) 267 server := &LesServer{ 268 lesCommons: lesCommons{ 269 genesis: genesis.Hash(), 270 config: &xcb.Config{LightPeers: 100, NetworkId: NetworkId}, 271 chainConfig: params.MainnetChainConfig, 272 iConfig: light.TestServerIndexerConfig, 273 chainDb: db, 274 chainReader: simulation.Blockchain(), 275 oracle: oracle, 276 closeCh: make(chan struct{}), 277 }, 278 ns: ns, 279 broadcaster: newBroadcaster(ns), 280 servingQueue: newServingQueue(int64(time.Millisecond*10), 1), 281 defParams: flowcontrol.ServerParams{ 282 BufLimit: testBufLimit, 283 MinRecharge: testBufRecharge, 284 }, 285 fcManager: flowcontrol.NewClientManager(nil, clock), 286 } 287 server.costTracker, server.minCapacity = newCostTracker(db, server.config) 288 server.costTracker.testCostList = testCostList(0) // Disable flow control mechanism. 289 server.clientPool = newClientPool(ns, db, testBufRecharge, defaultConnectedBias, clock, func(id enode.ID) {}) 290 server.clientPool.setLimits(10000, 10000) // Assign enough capacity for clientpool 291 server.handler = newServerHandler(server, simulation.Blockchain(), db, txpool, func() bool { return true }) 292 if server.oracle != nil { 293 server.oracle.Start(simulation) 294 } 295 server.servingQueue.setThreads(4) 296 ns.Start() 297 server.handler.start() 298 return server.handler, simulation 299 } 300 301 // testPeer is a simulated peer to allow testing direct network calls. 302 type testPeer struct { 303 cpeer *clientPeer 304 speer *serverPeer 305 306 net p2p.MsgReadWriter // Network layer reader/writer to simulate remote messaging 307 app *p2p.MsgPipeRW // Application layer reader/writer to simulate the local side 308 } 309 310 // newTestPeer creates a new peer registered at the given protocol manager. 311 func newTestPeer(t *testing.T, name string, version int, handler *serverHandler, shake bool, testCost uint64) (*testPeer, <-chan error) { 312 // Create a message pipe to communicate through 313 app, net := p2p.MsgPipe() 314 315 // Generate a random id and create the peer 316 var id enode.ID 317 rand.Read(id[:]) 318 peer := newClientPeer(version, NetworkId, p2p.NewPeer(id, name, nil), net) 319 320 // Start the peer on a new thread 321 errCh := make(chan error, 1) 322 go func() { 323 select { 324 case <-handler.closeCh: 325 errCh <- p2p.DiscQuitting 326 case errCh <- handler.handle(peer): 327 } 328 }() 329 tp := &testPeer{ 330 app: app, 331 net: net, 332 cpeer: peer, 333 } 334 // Execute any implicitly requested handshakes and return 335 if shake { 336 // Customize the cost table if required. 337 if testCost != 0 { 338 handler.server.costTracker.testCostList = testCostList(testCost) 339 } 340 var ( 341 genesis = handler.blockchain.Genesis() 342 head = handler.blockchain.CurrentHeader() 343 td = handler.blockchain.GetTd(head.Hash(), head.Number.Uint64()) 344 ) 345 tp.handshake(t, td, head.Hash(), head.Number.Uint64(), genesis.Hash(), testCostList(testCost)) 346 } 347 return tp, errCh 348 } 349 350 // close terminates the local side of the peer, notifying the remote protocol 351 // manager of termination. 352 func (p *testPeer) close() { 353 p.app.Close() 354 } 355 356 func newTestPeerPair(name string, version int, server *serverHandler, client *clientHandler) (*testPeer, *testPeer, error) { 357 // Create a message pipe to communicate through 358 app, net := p2p.MsgPipe() 359 360 // Generate a random id and create the peer 361 var id enode.ID 362 rand.Read(id[:]) 363 364 peer1 := newClientPeer(version, NetworkId, p2p.NewPeer(id, name, nil), net) 365 peer2 := newServerPeer(version, NetworkId, false, p2p.NewPeer(id, name, nil), app) 366 367 // Start the peer on a new thread 368 errc1 := make(chan error, 1) 369 errc2 := make(chan error, 1) 370 go func() { 371 select { 372 case <-server.closeCh: 373 errc1 <- p2p.DiscQuitting 374 case errc1 <- server.handle(peer1): 375 } 376 }() 377 go func() { 378 select { 379 case <-client.closeCh: 380 errc2 <- p2p.DiscQuitting 381 case errc2 <- client.handle(peer2): 382 } 383 }() 384 // Ensure the connection is established or exits when any error occurs 385 for { 386 select { 387 case err := <-errc1: 388 return nil, nil, fmt.Errorf("Failed to establish protocol connection %v", err) 389 case err := <-errc2: 390 return nil, nil, fmt.Errorf("Failed to establish protocol connection %v", err) 391 default: 392 } 393 if atomic.LoadUint32(&peer1.serving) == 1 && atomic.LoadUint32(&peer2.serving) == 1 { 394 break 395 } 396 time.Sleep(50 * time.Millisecond) 397 } 398 return &testPeer{cpeer: peer1, net: net, app: app}, &testPeer{speer: peer2, net: app, app: net}, nil 399 } 400 401 // handshake simulates a trivial handshake that expects the same state from the 402 // remote side as we are simulating locally. 403 func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, costList RequestCostList) { 404 var expList keyValueList 405 expList = expList.add("protocolVersion", uint64(p.cpeer.version)) 406 expList = expList.add("networkId", uint64(NetworkId)) 407 expList = expList.add("headTd", td) 408 expList = expList.add("headHash", head) 409 expList = expList.add("headNum", headNum) 410 expList = expList.add("genesisHash", genesis) 411 sendList := make(keyValueList, len(expList)) 412 copy(sendList, expList) 413 expList = expList.add("serveHeaders", nil) 414 expList = expList.add("serveChainSince", uint64(0)) 415 expList = expList.add("serveStateSince", uint64(0)) 416 expList = expList.add("serveRecentState", uint64(core.TriesInMemory-4)) 417 expList = expList.add("txRelay", nil) 418 expList = expList.add("flowControl/BL", testBufLimit) 419 expList = expList.add("flowControl/MRR", testBufRecharge) 420 expList = expList.add("flowControl/MRC", costList) 421 422 if err := p2p.ExpectMsg(p.app, StatusMsg, expList); err != nil { 423 t.Fatalf("status recv: %v", err) 424 } 425 if err := p2p.Send(p.app, StatusMsg, sendList); err != nil { 426 t.Fatalf("status send: %v", err) 427 } 428 p.cpeer.fcParams = flowcontrol.ServerParams{ 429 BufLimit: testBufLimit, 430 MinRecharge: testBufRecharge, 431 } 432 } 433 434 type indexerCallback func(*core.ChainIndexer, *core.ChainIndexer, *core.ChainIndexer) 435 436 // testClient represents a client for testing with necessary auxiliary fields. 437 type testClient struct { 438 clock mclock.Clock 439 db xcbdb.Database 440 peer *testPeer 441 handler *clientHandler 442 443 chtIndexer *core.ChainIndexer 444 bloomIndexer *core.ChainIndexer 445 bloomTrieIndexer *core.ChainIndexer 446 } 447 448 // testServer represents a server for testing with necessary auxiliary fields. 449 type testServer struct { 450 clock mclock.Clock 451 backend *backends.SimulatedBackend 452 db xcbdb.Database 453 peer *testPeer 454 handler *serverHandler 455 456 chtIndexer *core.ChainIndexer 457 bloomIndexer *core.ChainIndexer 458 bloomTrieIndexer *core.ChainIndexer 459 } 460 461 func newServerEnv(t *testing.T, blocks int, protocol int, callback indexerCallback, simClock bool, newPeer bool, testCost uint64) (*testServer, func()) { 462 db := rawdb.NewMemoryDatabase() 463 indexers := testIndexers(db, nil, light.TestServerIndexerConfig, true) 464 465 var clock mclock.Clock = &mclock.System{} 466 if simClock { 467 clock = &mclock.Simulated{} 468 } 469 handler, b := newTestServerHandler(blocks, indexers, db, clock) 470 471 var peer *testPeer 472 if newPeer { 473 peer, _ = newTestPeer(t, "peer", protocol, handler, true, testCost) 474 } 475 476 cIndexer, bIndexer, btIndexer := indexers[0], indexers[1], indexers[2] 477 cIndexer.Start(handler.blockchain) 478 bIndexer.Start(handler.blockchain) 479 480 // Wait until indexers generate enough index data. 481 if callback != nil { 482 callback(cIndexer, bIndexer, btIndexer) 483 } 484 server := &testServer{ 485 clock: clock, 486 backend: b, 487 db: db, 488 peer: peer, 489 handler: handler, 490 chtIndexer: cIndexer, 491 bloomIndexer: bIndexer, 492 bloomTrieIndexer: btIndexer, 493 } 494 teardown := func() { 495 if newPeer { 496 peer.close() 497 peer.cpeer.close() 498 b.Close() 499 } 500 cIndexer.Close() 501 bIndexer.Close() 502 } 503 return server, teardown 504 } 505 506 func newClientServerEnv(t *testing.T, blocks int, protocol int, callback indexerCallback, ulcServers []string, ulcFraction int, simClock bool, connect bool, disablePruning bool) (*testServer, *testClient, func()) { 507 sdb, cdb := rawdb.NewMemoryDatabase(), rawdb.NewMemoryDatabase() 508 speers := newServerPeerSet() 509 510 var clock mclock.Clock = &mclock.System{} 511 if simClock { 512 clock = &mclock.Simulated{} 513 } 514 dist := newRequestDistributor(speers, clock) 515 rm := newRetrieveManager(speers, dist, func() time.Duration { return time.Millisecond * 1000 }) 516 odr := NewLesOdr(cdb, light.TestClientIndexerConfig, rm) 517 518 sindexers := testIndexers(sdb, nil, light.TestServerIndexerConfig, true) 519 cIndexers := testIndexers(cdb, odr, light.TestClientIndexerConfig, disablePruning) 520 521 scIndexer, sbIndexer, sbtIndexer := sindexers[0], sindexers[1], sindexers[2] 522 ccIndexer, cbIndexer, cbtIndexer := cIndexers[0], cIndexers[1], cIndexers[2] 523 odr.SetIndexers(ccIndexer, cbIndexer, cbtIndexer) 524 525 server, b := newTestServerHandler(blocks, sindexers, sdb, clock) 526 client := newTestClientHandler(b, odr, cIndexers, cdb, speers, ulcServers, ulcFraction) 527 528 scIndexer.Start(server.blockchain) 529 sbIndexer.Start(server.blockchain) 530 ccIndexer.Start(client.backend.blockchain) 531 cbIndexer.Start(client.backend.blockchain) 532 533 if callback != nil { 534 callback(scIndexer, sbIndexer, sbtIndexer) 535 } 536 var ( 537 err error 538 speer, cpeer *testPeer 539 ) 540 if connect { 541 done := make(chan struct{}) 542 client.syncDone = func() { close(done) } 543 cpeer, speer, err = newTestPeerPair("peer", protocol, server, client) 544 if err != nil { 545 t.Fatalf("Failed to connect testing peers %v", err) 546 } 547 select { 548 case <-done: 549 case <-time.After(10 * time.Second): 550 t.Fatal("test peer did not connect and sync within 3s") 551 } 552 } 553 s := &testServer{ 554 clock: clock, 555 backend: b, 556 db: sdb, 557 peer: cpeer, 558 handler: server, 559 chtIndexer: scIndexer, 560 bloomIndexer: sbIndexer, 561 bloomTrieIndexer: sbtIndexer, 562 } 563 c := &testClient{ 564 clock: clock, 565 db: cdb, 566 peer: speer, 567 handler: client, 568 chtIndexer: ccIndexer, 569 bloomIndexer: cbIndexer, 570 bloomTrieIndexer: cbtIndexer, 571 } 572 teardown := func() { 573 if connect { 574 speer.close() 575 cpeer.close() 576 cpeer.cpeer.close() 577 speer.speer.close() 578 } 579 ccIndexer.Close() 580 cbIndexer.Close() 581 scIndexer.Close() 582 sbIndexer.Close() 583 b.Close() 584 } 585 return s, c, teardown 586 }