github.com/theQRL/go-zond@v0.1.1/les/handler_test.go (about) 1 // Copyright 2016 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 package les 18 19 import ( 20 "encoding/binary" 21 "math/big" 22 "math/rand" 23 "testing" 24 "time" 25 26 "github.com/theQRL/go-zond/common" 27 "github.com/theQRL/go-zond/common/mclock" 28 "github.com/theQRL/go-zond/consensus/ethash" 29 "github.com/theQRL/go-zond/core" 30 "github.com/theQRL/go-zond/core/rawdb" 31 "github.com/theQRL/go-zond/core/txpool" 32 "github.com/theQRL/go-zond/core/types" 33 "github.com/theQRL/go-zond/crypto" 34 "github.com/theQRL/go-zond/light" 35 "github.com/theQRL/go-zond/p2p" 36 "github.com/theQRL/go-zond/params" 37 "github.com/theQRL/go-zond/rlp" 38 "github.com/theQRL/go-zond/trie" 39 "github.com/theQRL/go-zond/zond/downloader" 40 ) 41 42 func expectResponse(r p2p.MsgReader, msgcode, reqID, bv uint64, data interface{}) error { 43 type resp struct { 44 ReqID, BV uint64 45 Data interface{} 46 } 47 return p2p.ExpectMsg(r, msgcode, resp{reqID, bv, data}) 48 } 49 50 // Tests that block headers can be retrieved from a remote chain based on user queries. 51 func TestGetBlockHeadersLes2(t *testing.T) { testGetBlockHeaders(t, 2) } 52 func TestGetBlockHeadersLes3(t *testing.T) { testGetBlockHeaders(t, 3) } 53 func TestGetBlockHeadersLes4(t *testing.T) { testGetBlockHeaders(t, 4) } 54 55 func testGetBlockHeaders(t *testing.T, protocol int) { 56 netconfig := testnetConfig{ 57 blocks: downloader.MaxHeaderFetch + 15, 58 protocol: protocol, 59 nopruning: true, 60 } 61 server, _, tearDown := newClientServerEnv(t, netconfig) 62 defer tearDown() 63 64 rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol) 65 defer closePeer() 66 bc := server.handler.blockchain 67 68 // Create a "random" unknown hash for testing 69 var unknown common.Hash 70 for i := range unknown { 71 unknown[i] = byte(i) 72 } 73 // Create a batch of tests for various scenarios 74 limit := uint64(MaxHeaderFetch) 75 tests := []struct { 76 query *GetBlockHeadersData // The query to execute for header retrieval 77 expect []common.Hash // The hashes of the block whose headers are expected 78 }{ 79 // A single random block should be retrievable by hash and number too 80 { 81 &GetBlockHeadersData{Origin: hashOrNumber{Hash: bc.GetBlockByNumber(limit / 2).Hash()}, Amount: 1}, 82 []common.Hash{bc.GetBlockByNumber(limit / 2).Hash()}, 83 }, { 84 &GetBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1}, 85 []common.Hash{bc.GetBlockByNumber(limit / 2).Hash()}, 86 }, 87 // Multiple headers should be retrievable in both directions 88 { 89 &GetBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3}, 90 []common.Hash{ 91 bc.GetBlockByNumber(limit / 2).Hash(), 92 bc.GetBlockByNumber(limit/2 + 1).Hash(), 93 bc.GetBlockByNumber(limit/2 + 2).Hash(), 94 }, 95 }, { 96 &GetBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true}, 97 []common.Hash{ 98 bc.GetBlockByNumber(limit / 2).Hash(), 99 bc.GetBlockByNumber(limit/2 - 1).Hash(), 100 bc.GetBlockByNumber(limit/2 - 2).Hash(), 101 }, 102 }, 103 // Multiple headers with skip lists should be retrievable 104 { 105 &GetBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3}, 106 []common.Hash{ 107 bc.GetBlockByNumber(limit / 2).Hash(), 108 bc.GetBlockByNumber(limit/2 + 4).Hash(), 109 bc.GetBlockByNumber(limit/2 + 8).Hash(), 110 }, 111 }, { 112 &GetBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true}, 113 []common.Hash{ 114 bc.GetBlockByNumber(limit / 2).Hash(), 115 bc.GetBlockByNumber(limit/2 - 4).Hash(), 116 bc.GetBlockByNumber(limit/2 - 8).Hash(), 117 }, 118 }, 119 // The chain endpoints should be retrievable 120 { 121 &GetBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1}, 122 []common.Hash{bc.GetBlockByNumber(0).Hash()}, 123 }, { 124 &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64()}, Amount: 1}, 125 []common.Hash{bc.CurrentBlock().Hash()}, 126 }, 127 // Ensure protocol limits are honored 128 //{ 129 // &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64()() - 1}, Amount: limit + 10, Reverse: true}, 130 // []common.Hash{}, 131 //}, 132 // Check that requesting more than available is handled gracefully 133 { 134 &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64() - 4}, Skip: 3, Amount: 3}, 135 []common.Hash{ 136 bc.GetBlockByNumber(bc.CurrentBlock().Number.Uint64() - 4).Hash(), 137 bc.GetBlockByNumber(bc.CurrentBlock().Number.Uint64()).Hash(), 138 }, 139 }, { 140 &GetBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true}, 141 []common.Hash{ 142 bc.GetBlockByNumber(4).Hash(), 143 bc.GetBlockByNumber(0).Hash(), 144 }, 145 }, 146 // Check that requesting more than available is handled gracefully, even if mid skip 147 { 148 &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64() - 4}, Skip: 2, Amount: 3}, 149 []common.Hash{ 150 bc.GetBlockByNumber(bc.CurrentBlock().Number.Uint64() - 4).Hash(), 151 bc.GetBlockByNumber(bc.CurrentBlock().Number.Uint64() - 1).Hash(), 152 }, 153 }, { 154 &GetBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true}, 155 []common.Hash{ 156 bc.GetBlockByNumber(4).Hash(), 157 bc.GetBlockByNumber(1).Hash(), 158 }, 159 }, 160 // Check that non existing headers aren't returned 161 { 162 &GetBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1}, 163 []common.Hash{}, 164 }, { 165 &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64() + 1}, Amount: 1}, 166 []common.Hash{}, 167 }, 168 } 169 // Run each of the tests and verify the results against the chain 170 var reqID uint64 171 for i, tt := range tests { 172 // Collect the headers to expect in the response 173 var headers []*types.Header 174 for _, hash := range tt.expect { 175 headers = append(headers, bc.GetHeaderByHash(hash)) 176 } 177 // Send the hash request and verify the response 178 reqID++ 179 180 sendRequest(rawPeer.app, GetBlockHeadersMsg, reqID, tt.query) 181 if err := expectResponse(rawPeer.app, BlockHeadersMsg, reqID, testBufLimit, headers); err != nil { 182 t.Errorf("test %d: headers mismatch: %v", i, err) 183 } 184 } 185 } 186 187 // Tests that block contents can be retrieved from a remote chain based on their hashes. 188 func TestGetBlockBodiesLes2(t *testing.T) { testGetBlockBodies(t, 2) } 189 func TestGetBlockBodiesLes3(t *testing.T) { testGetBlockBodies(t, 3) } 190 func TestGetBlockBodiesLes4(t *testing.T) { testGetBlockBodies(t, 4) } 191 192 func testGetBlockBodies(t *testing.T, protocol int) { 193 netconfig := testnetConfig{ 194 blocks: downloader.MaxHeaderFetch + 15, 195 protocol: protocol, 196 nopruning: true, 197 } 198 server, _, tearDown := newClientServerEnv(t, netconfig) 199 defer tearDown() 200 201 rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol) 202 defer closePeer() 203 204 bc := server.handler.blockchain 205 206 // Create a batch of tests for various scenarios 207 limit := MaxBodyFetch 208 tests := []struct { 209 random int // Number of blocks to fetch randomly from the chain 210 explicit []common.Hash // Explicitly requested blocks 211 available []bool // Availability of explicitly requested blocks 212 expected int // Total number of existing blocks to expect 213 }{ 214 {1, nil, nil, 1}, // A single random block should be retrievable 215 {10, nil, nil, 10}, // Multiple random blocks should be retrievable 216 {limit, nil, nil, limit}, // The maximum possible blocks should be retrievable 217 //{limit + 1, nil, nil, limit}, // No more than the possible block count should be returned 218 {0, []common.Hash{bc.Genesis().Hash()}, []bool{true}, 1}, // The genesis block should be retrievable 219 {0, []common.Hash{bc.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable 220 {0, []common.Hash{{}}, []bool{false}, 0}, // A non existent block should not be returned 221 222 // Existing and non-existing blocks interleaved should not cause problems 223 {0, []common.Hash{ 224 {}, 225 bc.GetBlockByNumber(1).Hash(), 226 {}, 227 bc.GetBlockByNumber(10).Hash(), 228 {}, 229 bc.GetBlockByNumber(100).Hash(), 230 {}, 231 }, []bool{false, true, false, true, false, true, false}, 3}, 232 } 233 // Run each of the tests and verify the results against the chain 234 var reqID uint64 235 for i, tt := range tests { 236 // Collect the hashes to request, and the response to expect 237 var hashes []common.Hash 238 seen := make(map[int64]bool) 239 var bodies []*types.Body 240 241 for j := 0; j < tt.random; j++ { 242 for { 243 num := rand.Int63n(int64(bc.CurrentBlock().Number.Uint64())) 244 if !seen[num] { 245 seen[num] = true 246 247 block := bc.GetBlockByNumber(uint64(num)) 248 hashes = append(hashes, block.Hash()) 249 if len(bodies) < tt.expected { 250 bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles()}) 251 } 252 break 253 } 254 } 255 } 256 for j, hash := range tt.explicit { 257 hashes = append(hashes, hash) 258 if tt.available[j] && len(bodies) < tt.expected { 259 block := bc.GetBlockByHash(hash) 260 bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles()}) 261 } 262 } 263 reqID++ 264 265 // Send the hash request and verify the response 266 sendRequest(rawPeer.app, GetBlockBodiesMsg, reqID, hashes) 267 if err := expectResponse(rawPeer.app, BlockBodiesMsg, reqID, testBufLimit, bodies); err != nil { 268 t.Errorf("test %d: bodies mismatch: %v", i, err) 269 } 270 } 271 } 272 273 // Tests that the contract codes can be retrieved based on account addresses. 274 func TestGetCodeLes2(t *testing.T) { testGetCode(t, 2) } 275 func TestGetCodeLes3(t *testing.T) { testGetCode(t, 3) } 276 func TestGetCodeLes4(t *testing.T) { testGetCode(t, 4) } 277 278 func testGetCode(t *testing.T, protocol int) { 279 // Assemble the test environment 280 netconfig := testnetConfig{ 281 blocks: 4, 282 protocol: protocol, 283 nopruning: true, 284 } 285 server, _, tearDown := newClientServerEnv(t, netconfig) 286 defer tearDown() 287 288 rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol) 289 defer closePeer() 290 291 bc := server.handler.blockchain 292 293 var codereqs []*CodeReq 294 var codes [][]byte 295 for i := uint64(0); i <= bc.CurrentBlock().Number.Uint64(); i++ { 296 header := bc.GetHeaderByNumber(i) 297 req := &CodeReq{ 298 BHash: header.Hash(), 299 AccountAddress: testContractAddr[:], 300 } 301 codereqs = append(codereqs, req) 302 if i >= testContractDeployed { 303 codes = append(codes, testContractCodeDeployed) 304 } 305 } 306 307 sendRequest(rawPeer.app, GetCodeMsg, 42, codereqs) 308 if err := expectResponse(rawPeer.app, CodeMsg, 42, testBufLimit, codes); err != nil { 309 t.Errorf("codes mismatch: %v", err) 310 } 311 } 312 313 // Tests that the stale contract codes can't be retrieved based on account addresses. 314 func TestGetStaleCodeLes2(t *testing.T) { testGetStaleCode(t, 2) } 315 func TestGetStaleCodeLes3(t *testing.T) { testGetStaleCode(t, 3) } 316 func TestGetStaleCodeLes4(t *testing.T) { testGetStaleCode(t, 4) } 317 318 func testGetStaleCode(t *testing.T, protocol int) { 319 netconfig := testnetConfig{ 320 blocks: core.TriesInMemory + 4, 321 protocol: protocol, 322 nopruning: true, 323 } 324 server, _, tearDown := newClientServerEnv(t, netconfig) 325 defer tearDown() 326 327 rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol) 328 defer closePeer() 329 330 bc := server.handler.blockchain 331 332 check := func(number uint64, expected [][]byte) { 333 req := &CodeReq{ 334 BHash: bc.GetHeaderByNumber(number).Hash(), 335 AccountAddress: testContractAddr[:], 336 } 337 sendRequest(rawPeer.app, GetCodeMsg, 42, []*CodeReq{req}) 338 if err := expectResponse(rawPeer.app, CodeMsg, 42, testBufLimit, expected); err != nil { 339 t.Errorf("codes mismatch: %v", err) 340 } 341 } 342 check(0, [][]byte{}) // Non-exist contract 343 check(testContractDeployed, [][]byte{}) // Stale contract 344 check(bc.CurrentHeader().Number.Uint64(), [][]byte{testContractCodeDeployed}) // Fresh contract 345 } 346 347 // Tests that the transaction receipts can be retrieved based on hashes. 348 func TestGetReceiptLes2(t *testing.T) { testGetReceipt(t, 2) } 349 func TestGetReceiptLes3(t *testing.T) { testGetReceipt(t, 3) } 350 func TestGetReceiptLes4(t *testing.T) { testGetReceipt(t, 4) } 351 352 func testGetReceipt(t *testing.T, protocol int) { 353 // Assemble the test environment 354 netconfig := testnetConfig{ 355 blocks: 4, 356 protocol: protocol, 357 nopruning: true, 358 } 359 server, _, tearDown := newClientServerEnv(t, netconfig) 360 defer tearDown() 361 362 rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol) 363 defer closePeer() 364 365 bc := server.handler.blockchain 366 367 // Collect the hashes to request, and the response to expect 368 var receipts []types.Receipts 369 var hashes []common.Hash 370 for i := uint64(0); i <= bc.CurrentBlock().Number.Uint64(); i++ { 371 block := bc.GetBlockByNumber(i) 372 373 hashes = append(hashes, block.Hash()) 374 receipts = append(receipts, rawdb.ReadReceipts(server.db, block.Hash(), block.NumberU64(), block.Time(), bc.Config())) 375 } 376 // Send the hash request and verify the response 377 sendRequest(rawPeer.app, GetReceiptsMsg, 42, hashes) 378 if err := expectResponse(rawPeer.app, ReceiptsMsg, 42, testBufLimit, receipts); err != nil { 379 t.Errorf("receipts mismatch: %v", err) 380 } 381 } 382 383 // Tests that trie merkle proofs can be retrieved 384 func TestGetProofsLes2(t *testing.T) { testGetProofs(t, 2) } 385 func TestGetProofsLes3(t *testing.T) { testGetProofs(t, 3) } 386 func TestGetProofsLes4(t *testing.T) { testGetProofs(t, 4) } 387 388 func testGetProofs(t *testing.T, protocol int) { 389 // Assemble the test environment 390 netconfig := testnetConfig{ 391 blocks: 4, 392 protocol: protocol, 393 nopruning: true, 394 } 395 server, _, tearDown := newClientServerEnv(t, netconfig) 396 defer tearDown() 397 398 rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol) 399 defer closePeer() 400 401 bc := server.handler.blockchain 402 403 var proofreqs []ProofReq 404 proofsV2 := light.NewNodeSet() 405 406 accounts := []common.Address{bankAddr, userAddr1, userAddr2, signerAddr, {}} 407 for i := uint64(0); i <= bc.CurrentBlock().Number.Uint64(); i++ { 408 header := bc.GetHeaderByNumber(i) 409 trie, _ := trie.New(trie.StateTrieID(header.Root), server.backend.Blockchain().TrieDB()) 410 411 for _, acc := range accounts { 412 req := ProofReq{ 413 BHash: header.Hash(), 414 Key: crypto.Keccak256(acc[:]), 415 } 416 proofreqs = append(proofreqs, req) 417 trie.Prove(crypto.Keccak256(acc[:]), proofsV2) 418 } 419 } 420 // Send the proof request and verify the response 421 sendRequest(rawPeer.app, GetProofsV2Msg, 42, proofreqs) 422 if err := expectResponse(rawPeer.app, ProofsV2Msg, 42, testBufLimit, proofsV2.NodeList()); err != nil { 423 t.Errorf("proofs mismatch: %v", err) 424 } 425 } 426 427 // Tests that the stale contract codes can't be retrieved based on account addresses. 428 func TestGetStaleProofLes2(t *testing.T) { testGetStaleProof(t, 2) } 429 func TestGetStaleProofLes3(t *testing.T) { testGetStaleProof(t, 3) } 430 func TestGetStaleProofLes4(t *testing.T) { testGetStaleProof(t, 4) } 431 432 func testGetStaleProof(t *testing.T, protocol int) { 433 netconfig := testnetConfig{ 434 blocks: core.TriesInMemory + 4, 435 protocol: protocol, 436 nopruning: true, 437 } 438 server, _, tearDown := newClientServerEnv(t, netconfig) 439 defer tearDown() 440 441 rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol) 442 defer closePeer() 443 444 bc := server.handler.blockchain 445 446 check := func(number uint64, wantOK bool) { 447 var ( 448 header = bc.GetHeaderByNumber(number) 449 account = crypto.Keccak256(userAddr1.Bytes()) 450 ) 451 req := &ProofReq{ 452 BHash: header.Hash(), 453 Key: account, 454 } 455 sendRequest(rawPeer.app, GetProofsV2Msg, 42, []*ProofReq{req}) 456 457 var expected []rlp.RawValue 458 if wantOK { 459 proofsV2 := light.NewNodeSet() 460 t, _ := trie.New(trie.StateTrieID(header.Root), server.backend.Blockchain().TrieDB()) 461 t.Prove(account, proofsV2) 462 expected = proofsV2.NodeList() 463 } 464 if err := expectResponse(rawPeer.app, ProofsV2Msg, 42, testBufLimit, expected); err != nil { 465 t.Errorf("codes mismatch: %v", err) 466 } 467 } 468 check(0, false) // Non-exist proof 469 check(2, false) // Stale proof 470 check(bc.CurrentHeader().Number.Uint64(), true) // Fresh proof 471 } 472 473 // Tests that CHT proofs can be correctly retrieved. 474 func TestGetCHTProofsLes2(t *testing.T) { testGetCHTProofs(t, 2) } 475 func TestGetCHTProofsLes3(t *testing.T) { testGetCHTProofs(t, 3) } 476 func TestGetCHTProofsLes4(t *testing.T) { testGetCHTProofs(t, 4) } 477 478 func testGetCHTProofs(t *testing.T, protocol int) { 479 var ( 480 config = light.TestServerIndexerConfig 481 waitIndexers = func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 482 for { 483 cs, _, _ := cIndexer.Sections() 484 if cs >= 1 { 485 break 486 } 487 time.Sleep(10 * time.Millisecond) 488 } 489 } 490 netconfig = testnetConfig{ 491 blocks: int(config.ChtSize + config.ChtConfirms), 492 protocol: protocol, 493 indexFn: waitIndexers, 494 nopruning: true, 495 } 496 ) 497 server, _, tearDown := newClientServerEnv(t, netconfig) 498 defer tearDown() 499 500 rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol) 501 defer closePeer() 502 503 bc := server.handler.blockchain 504 505 // Assemble the proofs from the different protocols 506 header := bc.GetHeaderByNumber(config.ChtSize - 1) 507 rlp, _ := rlp.EncodeToBytes(header) 508 509 key := make([]byte, 8) 510 binary.BigEndian.PutUint64(key, config.ChtSize-1) 511 512 proofsV2 := HelperTrieResps{ 513 AuxData: [][]byte{rlp}, 514 } 515 root := light.GetChtRoot(server.db, 0, bc.GetHeaderByNumber(config.ChtSize-1).Hash()) 516 trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, string(rawdb.ChtTablePrefix)), trie.HashDefaults)) 517 trie.Prove(key, &proofsV2.Proofs) 518 // Assemble the requests for the different protocols 519 requestsV2 := []HelperTrieReq{{ 520 Type: htCanonical, 521 TrieIdx: 0, 522 Key: key, 523 AuxReq: htAuxHeader, 524 }} 525 // Send the proof request and verify the response 526 sendRequest(rawPeer.app, GetHelperTrieProofsMsg, 42, requestsV2) 527 if err := expectResponse(rawPeer.app, HelperTrieProofsMsg, 42, testBufLimit, proofsV2); err != nil { 528 t.Errorf("proofs mismatch: %v", err) 529 } 530 } 531 532 func TestGetBloombitsProofsLes2(t *testing.T) { testGetBloombitsProofs(t, 2) } 533 func TestGetBloombitsProofsLes3(t *testing.T) { testGetBloombitsProofs(t, 3) } 534 func TestGetBloombitsProofsLes4(t *testing.T) { testGetBloombitsProofs(t, 4) } 535 536 // Tests that bloombits proofs can be correctly retrieved. 537 func testGetBloombitsProofs(t *testing.T, protocol int) { 538 var ( 539 config = light.TestServerIndexerConfig 540 waitIndexers = func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 541 for { 542 bts, _, _ := btIndexer.Sections() 543 if bts >= 1 { 544 break 545 } 546 time.Sleep(10 * time.Millisecond) 547 } 548 } 549 netconfig = testnetConfig{ 550 blocks: int(config.BloomTrieSize + config.BloomTrieConfirms), 551 protocol: protocol, 552 indexFn: waitIndexers, 553 nopruning: true, 554 } 555 ) 556 server, _, tearDown := newClientServerEnv(t, netconfig) 557 defer tearDown() 558 559 rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol) 560 defer closePeer() 561 562 bc := server.handler.blockchain 563 564 // Request and verify each bit of the bloom bits proofs 565 for bit := 0; bit < 2048; bit++ { 566 // Assemble the request and proofs for the bloombits 567 key := make([]byte, 10) 568 569 binary.BigEndian.PutUint16(key[:2], uint16(bit)) 570 // Only the first bloom section has data. 571 binary.BigEndian.PutUint64(key[2:], 0) 572 573 requests := []HelperTrieReq{{ 574 Type: htBloomBits, 575 TrieIdx: 0, 576 Key: key, 577 }} 578 var proofs HelperTrieResps 579 580 root := light.GetBloomTrieRoot(server.db, 0, bc.GetHeaderByNumber(config.BloomTrieSize-1).Hash()) 581 trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, string(rawdb.BloomTrieTablePrefix)), trie.HashDefaults)) 582 trie.Prove(key, &proofs.Proofs) 583 584 // Send the proof request and verify the response 585 sendRequest(rawPeer.app, GetHelperTrieProofsMsg, 42, requests) 586 if err := expectResponse(rawPeer.app, HelperTrieProofsMsg, 42, testBufLimit, proofs); err != nil { 587 t.Errorf("bit %d: proofs mismatch: %v", bit, err) 588 } 589 } 590 } 591 592 func TestTransactionStatusLes2(t *testing.T) { testTransactionStatus(t, lpv2) } 593 func TestTransactionStatusLes3(t *testing.T) { testTransactionStatus(t, lpv3) } 594 func TestTransactionStatusLes4(t *testing.T) { testTransactionStatus(t, lpv4) } 595 596 func testTransactionStatus(t *testing.T, protocol int) { 597 netconfig := testnetConfig{ 598 protocol: protocol, 599 nopruning: true, 600 } 601 server, _, tearDown := newClientServerEnv(t, netconfig) 602 defer tearDown() 603 604 rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol) 605 defer closePeer() 606 607 server.handler.addTxsSync = true 608 609 chain := server.handler.blockchain 610 611 var reqID uint64 612 613 test := func(tx *types.Transaction, send bool, expStatus light.TxStatus) { 614 t.Helper() 615 616 reqID++ 617 if send { 618 sendRequest(rawPeer.app, SendTxV2Msg, reqID, types.Transactions{tx}) 619 } else { 620 sendRequest(rawPeer.app, GetTxStatusMsg, reqID, []common.Hash{tx.Hash()}) 621 } 622 if err := expectResponse(rawPeer.app, TxStatusMsg, reqID, testBufLimit, []light.TxStatus{expStatus}); err != nil { 623 t.Errorf("transaction status mismatch: %v", err) 624 } 625 } 626 signer := types.HomesteadSigner{} 627 628 // test error status by sending an underpriced transaction 629 tx0, _ := types.SignTx(types.NewTransaction(0, userAddr1, big.NewInt(10000), params.TxGas, nil, nil), signer, bankKey) 630 test(tx0, true, light.TxStatus{Status: txpool.TxStatusUnknown, Error: "transaction underpriced: tip needed 1, tip permitted 0"}) 631 632 tx1, _ := types.SignTx(types.NewTransaction(0, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, bankKey) 633 test(tx1, false, light.TxStatus{Status: txpool.TxStatusUnknown}) // query before sending, should be unknown 634 test(tx1, true, light.TxStatus{Status: txpool.TxStatusPending}) // send valid processable tx, should return pending 635 test(tx1, true, light.TxStatus{Status: txpool.TxStatusPending}) // adding it again should not return an error 636 637 tx2, _ := types.SignTx(types.NewTransaction(1, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, bankKey) 638 tx3, _ := types.SignTx(types.NewTransaction(2, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, bankKey) 639 // send transactions in the wrong order, tx3 should be queued 640 test(tx3, true, light.TxStatus{Status: txpool.TxStatusQueued}) 641 test(tx2, true, light.TxStatus{Status: txpool.TxStatusPending}) 642 // query again, now tx3 should be pending too 643 test(tx3, false, light.TxStatus{Status: txpool.TxStatusPending}) 644 645 // generate and add a block with tx1 and tx2 included 646 gchain, _ := core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), server.db, 1, func(i int, block *core.BlockGen) { 647 block.AddTx(tx1) 648 block.AddTx(tx2) 649 }) 650 if _, err := chain.InsertChain(gchain); err != nil { 651 panic(err) 652 } 653 // wait until TxPool processes the inserted block 654 for i := 0; i < 10; i++ { 655 if pending, _ := server.handler.txpool.Stats(); pending == 1 { 656 break 657 } 658 time.Sleep(100 * time.Millisecond) 659 } 660 if pending, _ := server.handler.txpool.Stats(); pending != 1 { 661 t.Fatalf("pending count mismatch: have %d, want 1", pending) 662 } 663 // Discard new block announcement 664 msg, _ := rawPeer.app.ReadMsg() 665 msg.Discard() 666 667 // check if their status is included now 668 block1hash := rawdb.ReadCanonicalHash(server.db, 1) 669 test(tx1, false, light.TxStatus{Status: txpool.TxStatusIncluded, Lookup: &rawdb.LegacyTxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}}) 670 671 test(tx2, false, light.TxStatus{Status: txpool.TxStatusIncluded, Lookup: &rawdb.LegacyTxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}}) 672 673 // create a reorg that rolls them back 674 gchain, _ = core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), server.db, 2, func(i int, block *core.BlockGen) {}) 675 if _, err := chain.InsertChain(gchain); err != nil { 676 panic(err) 677 } 678 // wait until TxPool processes the reorg 679 for i := 0; i < 10; i++ { 680 if pending, _ := server.handler.txpool.Stats(); pending == 3 { 681 break 682 } 683 time.Sleep(100 * time.Millisecond) 684 } 685 if pending, _ := server.handler.txpool.Stats(); pending != 3 { 686 t.Fatalf("pending count mismatch: have %d, want 3", pending) 687 } 688 // Discard new block announcement 689 msg, _ = rawPeer.app.ReadMsg() 690 msg.Discard() 691 692 // check if their status is pending again 693 test(tx1, false, light.TxStatus{Status: txpool.TxStatusPending}) 694 test(tx2, false, light.TxStatus{Status: txpool.TxStatusPending}) 695 } 696 697 func TestStopResumeLES3(t *testing.T) { testStopResume(t, lpv3) } 698 func TestStopResumeLES4(t *testing.T) { testStopResume(t, lpv4) } 699 700 func testStopResume(t *testing.T, protocol int) { 701 netconfig := testnetConfig{ 702 protocol: protocol, 703 simClock: true, 704 nopruning: true, 705 } 706 server, _, tearDown := newClientServerEnv(t, netconfig) 707 defer tearDown() 708 709 server.handler.server.costTracker.testing = true 710 server.handler.server.costTracker.testCostList = testCostList(testBufLimit / 10) 711 712 rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol) 713 defer closePeer() 714 715 var ( 716 reqID uint64 717 expBuf = testBufLimit 718 testCost = testBufLimit / 10 719 ) 720 header := server.handler.blockchain.CurrentHeader() 721 req := func() { 722 reqID++ 723 sendRequest(rawPeer.app, GetBlockHeadersMsg, reqID, &GetBlockHeadersData{Origin: hashOrNumber{Hash: header.Hash()}, Amount: 1}) 724 } 725 for i := 1; i <= 5; i++ { 726 // send requests while we still have enough buffer and expect a response 727 for expBuf >= testCost { 728 req() 729 expBuf -= testCost 730 if err := expectResponse(rawPeer.app, BlockHeadersMsg, reqID, expBuf, []*types.Header{header}); err != nil { 731 t.Errorf("expected response and failed: %v", err) 732 } 733 } 734 // send some more requests in excess and expect a single StopMsg 735 c := i 736 for c > 0 { 737 req() 738 c-- 739 } 740 if err := p2p.ExpectMsg(rawPeer.app, StopMsg, nil); err != nil { 741 t.Errorf("expected StopMsg and failed: %v", err) 742 } 743 // wait until the buffer is recharged by half of the limit 744 wait := testBufLimit / testBufRecharge / 2 745 server.clock.(*mclock.Simulated).Run(time.Millisecond * time.Duration(wait)) 746 747 // expect a ResumeMsg with the partially recharged buffer value 748 expBuf += testBufRecharge * wait 749 if err := p2p.ExpectMsg(rawPeer.app, ResumeMsg, expBuf); err != nil { 750 t.Errorf("expected ResumeMsg and failed: %v", err) 751 } 752 } 753 }