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