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