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