github.com/calmw/ethereum@v0.1.1/les/test_helper.go (about) 1 // Copyright 2019 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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-ethereum 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-ethereum 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. Client based network and Server 19 // based network can be created easily with available APIs. 20 21 package les 22 23 import ( 24 "context" 25 "crypto/rand" 26 "fmt" 27 "math/big" 28 "testing" 29 "time" 30 31 "github.com/calmw/ethereum/accounts/abi/bind/backends" 32 "github.com/calmw/ethereum/common" 33 "github.com/calmw/ethereum/common/mclock" 34 "github.com/calmw/ethereum/consensus" 35 "github.com/calmw/ethereum/consensus/ethash" 36 "github.com/calmw/ethereum/core" 37 "github.com/calmw/ethereum/core/forkid" 38 "github.com/calmw/ethereum/core/rawdb" 39 "github.com/calmw/ethereum/core/txpool" 40 "github.com/calmw/ethereum/core/types" 41 "github.com/calmw/ethereum/crypto" 42 "github.com/calmw/ethereum/eth/ethconfig" 43 "github.com/calmw/ethereum/ethdb" 44 "github.com/calmw/ethereum/event" 45 "github.com/calmw/ethereum/les/flowcontrol" 46 vfs "github.com/calmw/ethereum/les/vflux/server" 47 "github.com/calmw/ethereum/light" 48 "github.com/calmw/ethereum/p2p" 49 "github.com/calmw/ethereum/p2p/enode" 50 "github.com/calmw/ethereum/params" 51 ) 52 53 var ( 54 bankKey, _ = crypto.GenerateKey() 55 bankAddr = crypto.PubkeyToAddress(bankKey.PublicKey) 56 bankFunds = big.NewInt(1_000_000_000_000_000_000) 57 58 userKey1, _ = crypto.GenerateKey() 59 userKey2, _ = crypto.GenerateKey() 60 userAddr1 = crypto.PubkeyToAddress(userKey1.PublicKey) 61 userAddr2 = crypto.PubkeyToAddress(userKey2.PublicKey) 62 63 testContractAddr common.Address 64 testContractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056") 65 testContractCodeDeployed = testContractCode[16:] 66 testContractDeployed = uint64(2) 67 68 testEventEmitterCode = common.Hex2Bytes("60606040523415600e57600080fd5b7f57050ab73f6b9ebdd9f76b8d4997793f48cf956e965ee070551b9ca0bb71584e60405160405180910390a160358060476000396000f3006060604052600080fd00a165627a7a723058203f727efcad8b5811f8cb1fc2620ce5e8c63570d697aef968172de296ea3994140029") 69 70 // Checkpoint oracle relative fields 71 signerKey, _ = crypto.GenerateKey() 72 signerAddr = crypto.PubkeyToAddress(signerKey.PublicKey) 73 ) 74 75 var ( 76 // The token bucket buffer limit for testing purpose. 77 testBufLimit = uint64(1000000) 78 79 // The buffer recharging speed for testing purpose. 80 testBufRecharge = uint64(1000) 81 ) 82 83 /* 84 contract test { 85 86 uint256[100] data; 87 88 function Put(uint256 addr, uint256 value) { 89 data[addr] = value; 90 } 91 92 function Get(uint256 addr) constant returns (uint256 value) { 93 return data[addr]; 94 } 95 } 96 */ 97 98 // prepare pre-commits specified number customized blocks into chain. 99 func prepare(n int, backend *backends.SimulatedBackend) { 100 var ( 101 ctx = context.Background() 102 signer = types.HomesteadSigner{} 103 ) 104 for i := 0; i < n; i++ { 105 switch i { 106 case 0: 107 // Builtin-block 108 // number: 1 109 // txs: 1 110 111 // bankUser transfers some ether to user1 112 nonce, _ := backend.PendingNonceAt(ctx, bankAddr) 113 tx, _ := types.SignTx(types.NewTransaction(nonce, userAddr1, big.NewInt(10_000_000_000_000_000), params.TxGas, big.NewInt(params.InitialBaseFee), nil), signer, bankKey) 114 backend.SendTransaction(ctx, tx) 115 case 1: 116 // Builtin-block 117 // number: 2 118 // txs: 4 119 120 bankNonce, _ := backend.PendingNonceAt(ctx, bankAddr) 121 userNonce1, _ := backend.PendingNonceAt(ctx, userAddr1) 122 123 // bankUser transfers more ether to user1 124 tx1, _ := types.SignTx(types.NewTransaction(bankNonce, userAddr1, big.NewInt(1_000_000_000_000_000), params.TxGas, big.NewInt(params.InitialBaseFee), nil), signer, bankKey) 125 backend.SendTransaction(ctx, tx1) 126 127 // user1 relays ether to user2 128 tx2, _ := types.SignTx(types.NewTransaction(userNonce1, userAddr2, big.NewInt(1_000_000_000_000_000), params.TxGas, big.NewInt(params.InitialBaseFee), 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(params.InitialBaseFee), testContractCode), signer, userKey1) 133 backend.SendTransaction(ctx, tx3) 134 testContractAddr = crypto.CreateAddress(userAddr1, userNonce1+1) 135 136 // user1 deploys a event contract 137 tx4, _ := types.SignTx(types.NewContractCreation(userNonce1+2, big.NewInt(0), 200000, big.NewInt(params.InitialBaseFee), testEventEmitterCode), signer, userKey1) 138 backend.SendTransaction(ctx, tx4) 139 case 2: 140 // Builtin-block 141 // number: 3 142 // txs: 2 143 144 // bankUser transfer some ether to signer 145 bankNonce, _ := backend.PendingNonceAt(ctx, bankAddr) 146 tx1, _ := types.SignTx(types.NewTransaction(bankNonce, signerAddr, big.NewInt(1000000000), params.TxGas, big.NewInt(params.InitialBaseFee), nil), signer, bankKey) 147 backend.SendTransaction(ctx, tx1) 148 149 // invoke test contract 150 data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") 151 tx2, _ := types.SignTx(types.NewTransaction(bankNonce+1, testContractAddr, big.NewInt(0), 100000, big.NewInt(params.InitialBaseFee), data), signer, bankKey) 152 backend.SendTransaction(ctx, tx2) 153 case 3: 154 // Builtin-block 155 // number: 4 156 // txs: 1 157 158 // invoke test contract 159 bankNonce, _ := backend.PendingNonceAt(ctx, bankAddr) 160 data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") 161 tx, _ := types.SignTx(types.NewTransaction(bankNonce, testContractAddr, big.NewInt(0), 100000, big.NewInt(params.InitialBaseFee), data), signer, bankKey) 162 backend.SendTransaction(ctx, tx) 163 } 164 backend.Commit() 165 } 166 } 167 168 // testIndexers creates a set of indexers with specified params for testing purpose. 169 func testIndexers(db ethdb.Database, odr light.OdrBackend, config *light.IndexerConfig, disablePruning bool) []*core.ChainIndexer { 170 var indexers [3]*core.ChainIndexer 171 indexers[0] = light.NewChtIndexer(db, odr, config.ChtSize, config.ChtConfirms, disablePruning) 172 indexers[1] = core.NewBloomIndexer(db, config.BloomSize, config.BloomConfirms) 173 indexers[2] = light.NewBloomTrieIndexer(db, odr, config.BloomSize, config.BloomTrieSize, disablePruning) 174 // make bloomTrieIndexer as a child indexer of bloom indexer. 175 indexers[1].AddChildIndexer(indexers[2]) 176 return indexers[:] 177 } 178 179 func newTestClientHandler(backend *backends.SimulatedBackend, odr *LesOdr, indexers []*core.ChainIndexer, db ethdb.Database, peers *serverPeerSet, ulcServers []string, ulcFraction int) (*clientHandler, func()) { 180 var ( 181 evmux = new(event.TypeMux) 182 engine = ethash.NewFaker() 183 gspec = core.Genesis{ 184 Config: params.AllEthashProtocolChanges, 185 Alloc: core.GenesisAlloc{bankAddr: {Balance: bankFunds}}, 186 GasLimit: 100000000, 187 BaseFee: big.NewInt(params.InitialBaseFee), 188 } 189 ) 190 genesis := gspec.MustCommit(db) 191 chain, _ := light.NewLightChain(odr, gspec.Config, engine) 192 193 client := &LightEthereum{ 194 lesCommons: lesCommons{ 195 genesis: genesis.Hash(), 196 config: ðconfig.Config{LightPeers: 100, NetworkId: NetworkId}, 197 chainConfig: params.AllEthashProtocolChanges, 198 iConfig: light.TestClientIndexerConfig, 199 chainDb: db, 200 chainReader: chain, 201 closeCh: make(chan struct{}), 202 }, 203 peers: peers, 204 reqDist: odr.retriever.dist, 205 retriever: odr.retriever, 206 odr: odr, 207 engine: engine, 208 blockchain: chain, 209 eventMux: evmux, 210 merger: consensus.NewMerger(rawdb.NewMemoryDatabase()), 211 } 212 client.handler = newClientHandler(ulcServers, ulcFraction, client) 213 214 client.handler.start() 215 return client.handler, func() { 216 client.handler.stop() 217 } 218 } 219 220 func newTestServerHandler(blocks int, indexers []*core.ChainIndexer, db ethdb.Database, clock mclock.Clock) (*serverHandler, *backends.SimulatedBackend, func()) { 221 var ( 222 gspec = core.Genesis{ 223 Config: params.AllEthashProtocolChanges, 224 Alloc: core.GenesisAlloc{bankAddr: {Balance: bankFunds}}, 225 GasLimit: 100000000, 226 BaseFee: big.NewInt(params.InitialBaseFee), 227 } 228 ) 229 genesis := gspec.MustCommit(db) 230 231 // create a simulation backend and pre-commit several customized block to the database. 232 simulation := backends.NewSimulatedBackendWithDatabase(db, gspec.Alloc, 100000000) 233 prepare(blocks, simulation) 234 235 txpoolConfig := txpool.DefaultConfig 236 txpoolConfig.Journal = "" 237 txpool := txpool.NewTxPool(txpoolConfig, gspec.Config, simulation.Blockchain()) 238 239 server := &LesServer{ 240 lesCommons: lesCommons{ 241 genesis: genesis.Hash(), 242 config: ðconfig.Config{LightPeers: 100, NetworkId: NetworkId}, 243 chainConfig: params.AllEthashProtocolChanges, 244 iConfig: light.TestServerIndexerConfig, 245 chainDb: db, 246 chainReader: simulation.Blockchain(), 247 closeCh: make(chan struct{}), 248 }, 249 peers: newClientPeerSet(), 250 servingQueue: newServingQueue(int64(time.Millisecond*10), 1), 251 defParams: flowcontrol.ServerParams{ 252 BufLimit: testBufLimit, 253 MinRecharge: testBufRecharge, 254 }, 255 fcManager: flowcontrol.NewClientManager(nil, clock), 256 } 257 server.costTracker, server.minCapacity = newCostTracker(db, server.config) 258 server.costTracker.testCostList = testCostList(0) // Disable flow control mechanism. 259 server.clientPool = vfs.NewClientPool(db, testBufRecharge, defaultConnectedBias, clock, alwaysTrueFn) 260 server.clientPool.Start() 261 server.clientPool.SetLimits(10000, 10000) // Assign enough capacity for clientpool 262 server.handler = newServerHandler(server, simulation.Blockchain(), db, txpool, func() bool { return true }) 263 server.servingQueue.setThreads(4) 264 server.handler.start() 265 closer := func() { server.Stop() } 266 return server.handler, simulation, closer 267 } 268 269 func alwaysTrueFn() bool { 270 return true 271 } 272 273 // testPeer is a simulated peer to allow testing direct network calls. 274 type testPeer struct { 275 cpeer *clientPeer 276 speer *serverPeer 277 278 net p2p.MsgReadWriter // Network layer reader/writer to simulate remote messaging 279 app *p2p.MsgPipeRW // Application layer reader/writer to simulate the local side 280 } 281 282 // handshakeWithServer executes the handshake with the remote server peer. 283 func (p *testPeer) handshakeWithServer(t *testing.T, td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, forkID forkid.ID) { 284 // It only works for the simulated client peer 285 if p.cpeer == nil { 286 t.Fatal("handshake for client peer only") 287 } 288 var sendList keyValueList 289 sendList = sendList.add("protocolVersion", uint64(p.cpeer.version)) 290 sendList = sendList.add("networkId", uint64(NetworkId)) 291 sendList = sendList.add("headTd", td) 292 sendList = sendList.add("headHash", head) 293 sendList = sendList.add("headNum", headNum) 294 sendList = sendList.add("genesisHash", genesis) 295 if p.cpeer.version >= lpv4 { 296 sendList = sendList.add("forkID", &forkID) 297 } 298 if err := p2p.ExpectMsg(p.app, StatusMsg, nil); err != nil { 299 t.Fatalf("status recv: %v", err) 300 } 301 if err := p2p.Send(p.app, StatusMsg, &sendList); err != nil { 302 t.Fatalf("status send: %v", err) 303 } 304 } 305 306 // handshakeWithClient executes the handshake with the remote client peer. 307 func (p *testPeer) handshakeWithClient(t *testing.T, td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, forkID forkid.ID, costList RequestCostList, recentTxLookup uint64) { 308 // It only works for the simulated client peer 309 if p.speer == nil { 310 t.Fatal("handshake for server peer only") 311 } 312 var sendList keyValueList 313 sendList = sendList.add("protocolVersion", uint64(p.speer.version)) 314 sendList = sendList.add("networkId", uint64(NetworkId)) 315 sendList = sendList.add("headTd", td) 316 sendList = sendList.add("headHash", head) 317 sendList = sendList.add("headNum", headNum) 318 sendList = sendList.add("genesisHash", genesis) 319 sendList = sendList.add("serveHeaders", nil) 320 sendList = sendList.add("serveChainSince", uint64(0)) 321 sendList = sendList.add("serveStateSince", uint64(0)) 322 sendList = sendList.add("serveRecentState", uint64(core.TriesInMemory-4)) 323 sendList = sendList.add("txRelay", nil) 324 sendList = sendList.add("flowControl/BL", testBufLimit) 325 sendList = sendList.add("flowControl/MRR", testBufRecharge) 326 sendList = sendList.add("flowControl/MRC", costList) 327 if p.speer.version >= lpv4 { 328 sendList = sendList.add("forkID", &forkID) 329 sendList = sendList.add("recentTxLookup", recentTxLookup) 330 } 331 if err := p2p.ExpectMsg(p.app, StatusMsg, nil); err != nil { 332 t.Fatalf("status recv: %v", err) 333 } 334 if err := p2p.Send(p.app, StatusMsg, &sendList); err != nil { 335 t.Fatalf("status send: %v", err) 336 } 337 } 338 339 // close terminates the local side of the peer, notifying the remote protocol 340 // manager of termination. 341 func (p *testPeer) close() { 342 p.app.Close() 343 } 344 345 func newTestPeerPair(name string, version int, server *serverHandler, client *clientHandler, noInitAnnounce bool) (*testPeer, *testPeer, error) { 346 // Create a message pipe to communicate through 347 app, net := p2p.MsgPipe() 348 349 // Generate a random id and create the peer 350 var id enode.ID 351 rand.Read(id[:]) 352 353 peer1 := newClientPeer(version, NetworkId, p2p.NewPeer(id, name, nil), net) 354 peer2 := newServerPeer(version, NetworkId, false, p2p.NewPeer(id, name, nil), app) 355 356 // Start the peer on a new thread 357 errc1 := make(chan error, 1) 358 errc2 := make(chan error, 1) 359 go func() { 360 select { 361 case <-server.closeCh: 362 errc1 <- p2p.DiscQuitting 363 case errc1 <- server.handle(peer1): 364 } 365 }() 366 go func() { 367 select { 368 case <-client.closeCh: 369 errc2 <- p2p.DiscQuitting 370 case errc2 <- client.handle(peer2, noInitAnnounce): 371 } 372 }() 373 // Ensure the connection is established or exits when any error occurs 374 for { 375 select { 376 case err := <-errc1: 377 return nil, nil, fmt.Errorf("failed to establish protocol connection %v", err) 378 case err := <-errc2: 379 return nil, nil, fmt.Errorf("failed to establish protocol connection %v", err) 380 default: 381 } 382 if peer1.serving.Load() && peer2.serving.Load() { 383 break 384 } 385 time.Sleep(50 * time.Millisecond) 386 } 387 return &testPeer{cpeer: peer1, net: net, app: app}, &testPeer{speer: peer2, net: app, app: net}, nil 388 } 389 390 type indexerCallback func(*core.ChainIndexer, *core.ChainIndexer, *core.ChainIndexer) 391 392 // testClient represents a client object for testing with necessary auxiliary fields. 393 type testClient struct { 394 clock mclock.Clock 395 db ethdb.Database 396 peer *testPeer 397 handler *clientHandler 398 399 chtIndexer *core.ChainIndexer 400 bloomIndexer *core.ChainIndexer 401 bloomTrieIndexer *core.ChainIndexer 402 } 403 404 // newRawPeer creates a new server peer connects to the server and do the handshake. 405 func (client *testClient) newRawPeer(t *testing.T, name string, version int, recentTxLookup uint64) (*testPeer, func(), <-chan error) { 406 // Create a message pipe to communicate through 407 app, net := p2p.MsgPipe() 408 409 // Generate a random id and create the peer 410 var id enode.ID 411 rand.Read(id[:]) 412 peer := newServerPeer(version, NetworkId, false, p2p.NewPeer(id, name, nil), net) 413 414 // Start the peer on a new thread 415 errCh := make(chan error, 1) 416 go func() { 417 select { 418 case <-client.handler.closeCh: 419 errCh <- p2p.DiscQuitting 420 case errCh <- client.handler.handle(peer, false): 421 } 422 }() 423 tp := &testPeer{ 424 app: app, 425 net: net, 426 speer: peer, 427 } 428 var ( 429 genesis = client.handler.backend.blockchain.Genesis() 430 head = client.handler.backend.blockchain.CurrentHeader() 431 td = client.handler.backend.blockchain.GetTd(head.Hash(), head.Number.Uint64()) 432 ) 433 forkID := forkid.NewID(client.handler.backend.blockchain.Config(), genesis.Hash(), head.Number.Uint64(), head.Time) 434 tp.handshakeWithClient(t, td, head.Hash(), head.Number.Uint64(), genesis.Hash(), forkID, testCostList(0), recentTxLookup) // disable flow control by default 435 436 // Ensure the connection is established or exits when any error occurs 437 for { 438 select { 439 case <-errCh: 440 return nil, nil, nil 441 default: 442 } 443 if peer.serving.Load() { 444 break 445 } 446 time.Sleep(50 * time.Millisecond) 447 } 448 closePeer := func() { 449 tp.speer.close() 450 tp.close() 451 } 452 return tp, closePeer, errCh 453 } 454 455 // testServer represents a server object for testing with necessary auxiliary fields. 456 type testServer struct { 457 clock mclock.Clock 458 backend *backends.SimulatedBackend 459 db ethdb.Database 460 peer *testPeer 461 handler *serverHandler 462 463 chtIndexer *core.ChainIndexer 464 bloomIndexer *core.ChainIndexer 465 bloomTrieIndexer *core.ChainIndexer 466 } 467 468 // newRawPeer creates a new client peer connects to the server and do the handshake. 469 func (server *testServer) newRawPeer(t *testing.T, name string, version int) (*testPeer, func(), <-chan error) { 470 // Create a message pipe to communicate through 471 app, net := p2p.MsgPipe() 472 473 // Generate a random id and create the peer 474 var id enode.ID 475 rand.Read(id[:]) 476 peer := newClientPeer(version, NetworkId, p2p.NewPeer(id, name, nil), net) 477 478 // Start the peer on a new thread 479 errCh := make(chan error, 1) 480 go func() { 481 select { 482 case <-server.handler.closeCh: 483 errCh <- p2p.DiscQuitting 484 case errCh <- server.handler.handle(peer): 485 } 486 }() 487 tp := &testPeer{ 488 app: app, 489 net: net, 490 cpeer: peer, 491 } 492 var ( 493 genesis = server.handler.blockchain.Genesis() 494 head = server.handler.blockchain.CurrentHeader() 495 td = server.handler.blockchain.GetTd(head.Hash(), head.Number.Uint64()) 496 ) 497 forkID := forkid.NewID(server.handler.blockchain.Config(), genesis.Hash(), head.Number.Uint64(), head.Time) 498 tp.handshakeWithServer(t, td, head.Hash(), head.Number.Uint64(), genesis.Hash(), forkID) 499 500 // Ensure the connection is established or exits when any error occurs 501 for { 502 select { 503 case <-errCh: 504 return nil, nil, nil 505 default: 506 } 507 if peer.serving.Load() { 508 break 509 } 510 time.Sleep(50 * time.Millisecond) 511 } 512 closePeer := func() { 513 tp.cpeer.close() 514 tp.close() 515 } 516 return tp, closePeer, errCh 517 } 518 519 // testnetConfig wraps all the configurations for testing network. 520 type testnetConfig struct { 521 blocks int 522 protocol int 523 indexFn indexerCallback 524 ulcServers []string 525 ulcFraction int 526 simClock bool 527 connect bool 528 nopruning bool 529 } 530 531 func newClientServerEnv(t *testing.T, config testnetConfig) (*testServer, *testClient, func()) { 532 var ( 533 sdb = rawdb.NewMemoryDatabase() 534 cdb = rawdb.NewMemoryDatabase() 535 speers = newServerPeerSet() 536 ) 537 var clock mclock.Clock = &mclock.System{} 538 if config.simClock { 539 clock = &mclock.Simulated{} 540 } 541 dist := newRequestDistributor(speers, clock) 542 rm := newRetrieveManager(speers, dist, func() time.Duration { return time.Millisecond * 500 }) 543 odr := NewLesOdr(cdb, light.TestClientIndexerConfig, speers, rm) 544 545 sindexers := testIndexers(sdb, nil, light.TestServerIndexerConfig, true) 546 cIndexers := testIndexers(cdb, odr, light.TestClientIndexerConfig, config.nopruning) 547 548 scIndexer, sbIndexer, sbtIndexer := sindexers[0], sindexers[1], sindexers[2] 549 ccIndexer, cbIndexer, cbtIndexer := cIndexers[0], cIndexers[1], cIndexers[2] 550 odr.SetIndexers(ccIndexer, cbIndexer, cbtIndexer) 551 552 server, b, serverClose := newTestServerHandler(config.blocks, sindexers, sdb, clock) 553 client, clientClose := newTestClientHandler(b, odr, cIndexers, cdb, speers, config.ulcServers, config.ulcFraction) 554 555 scIndexer.Start(server.blockchain) 556 sbIndexer.Start(server.blockchain) 557 ccIndexer.Start(client.backend.blockchain) 558 cbIndexer.Start(client.backend.blockchain) 559 560 if config.indexFn != nil { 561 config.indexFn(scIndexer, sbIndexer, sbtIndexer) 562 } 563 var ( 564 err error 565 speer, cpeer *testPeer 566 ) 567 if config.connect { 568 done := make(chan struct{}) 569 client.syncEnd = func(_ *types.Header) { close(done) } 570 cpeer, speer, err = newTestPeerPair("peer", config.protocol, server, client, false) 571 if err != nil { 572 t.Fatalf("Failed to connect testing peers %v", err) 573 } 574 select { 575 case <-done: 576 case <-time.After(10 * time.Second): 577 t.Fatal("test peer did not connect and sync within 3s") 578 } 579 } 580 s := &testServer{ 581 clock: clock, 582 backend: b, 583 db: sdb, 584 peer: cpeer, 585 handler: server, 586 chtIndexer: scIndexer, 587 bloomIndexer: sbIndexer, 588 bloomTrieIndexer: sbtIndexer, 589 } 590 c := &testClient{ 591 clock: clock, 592 db: cdb, 593 peer: speer, 594 handler: client, 595 chtIndexer: ccIndexer, 596 bloomIndexer: cbIndexer, 597 bloomTrieIndexer: cbtIndexer, 598 } 599 teardown := func() { 600 if config.connect { 601 speer.close() 602 cpeer.close() 603 cpeer.cpeer.close() 604 speer.speer.close() 605 } 606 ccIndexer.Close() 607 cbIndexer.Close() 608 scIndexer.Close() 609 sbIndexer.Close() 610 dist.close() 611 serverClose() 612 b.Close() 613 clientClose() 614 } 615 return s, c, teardown 616 } 617 618 // NewFuzzerPeer creates a client peer for test purposes, and also returns 619 // a function to close the peer: this is needed to avoid goroutine leaks in the 620 // exec queue. 621 func NewFuzzerPeer(version int) (p *clientPeer, closer func()) { 622 p = newClientPeer(version, 0, p2p.NewPeer(enode.ID{}, "", nil), nil) 623 return p, func() { p.peerCommons.close() } 624 }