github.com/m3shine/gochain@v2.2.26+incompatible/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 "context" 21 "encoding/binary" 22 "math/big" 23 "math/rand" 24 "testing" 25 "time" 26 27 "github.com/gochain-io/gochain/common" 28 "github.com/gochain-io/gochain/consensus/clique" 29 "github.com/gochain-io/gochain/core" 30 "github.com/gochain-io/gochain/core/rawdb" 31 "github.com/gochain-io/gochain/core/types" 32 "github.com/gochain-io/gochain/crypto" 33 "github.com/gochain-io/gochain/eth/downloader" 34 "github.com/gochain-io/gochain/ethdb" 35 "github.com/gochain-io/gochain/light" 36 "github.com/gochain-io/gochain/p2p" 37 "github.com/gochain-io/gochain/params" 38 "github.com/gochain-io/gochain/rlp" 39 "github.com/gochain-io/gochain/trie" 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 TestGetBlockHeadersLes1(t *testing.T) { testGetBlockHeaders(t, 1) } 52 func TestGetBlockHeadersLes2(t *testing.T) { testGetBlockHeaders(t, 2) } 53 54 func testGetBlockHeaders(t *testing.T, protocol int) { 55 ctx := context.Background() 56 db := ethdb.NewMemDatabase() 57 pm := newTestProtocolManagerMust(ctx, t, false, downloader.MaxHashFetch+15, nil, nil, nil, db) 58 bc := pm.blockchain.(*core.BlockChain) 59 peer, _ := newTestPeer(ctx, t, "peer", protocol, pm, true) 60 defer peer.close() 61 62 // Create a "random" unknown hash for testing 63 var unknown common.Hash 64 for i := range unknown { 65 unknown[i] = byte(i) 66 } 67 // Create a batch of tests for various scenarios 68 limit := uint64(MaxHeaderFetch) 69 tests := []struct { 70 query *getBlockHeadersData // The query to execute for header retrieval 71 expect []common.Hash // The hashes of the block whose headers are expected 72 }{ 73 // A single random block should be retrievable by hash and number too 74 { 75 &getBlockHeadersData{Origin: hashOrNumber{Hash: bc.GetBlockByNumber(limit / 2).Hash()}, Amount: 1}, 76 []common.Hash{bc.GetBlockByNumber(limit / 2).Hash()}, 77 }, { 78 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1}, 79 []common.Hash{bc.GetBlockByNumber(limit / 2).Hash()}, 80 }, 81 // Multiple headers should be retrievable in both directions 82 { 83 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3}, 84 []common.Hash{ 85 bc.GetBlockByNumber(limit / 2).Hash(), 86 bc.GetBlockByNumber(limit/2 + 1).Hash(), 87 bc.GetBlockByNumber(limit/2 + 2).Hash(), 88 }, 89 }, { 90 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true}, 91 []common.Hash{ 92 bc.GetBlockByNumber(limit / 2).Hash(), 93 bc.GetBlockByNumber(limit/2 - 1).Hash(), 94 bc.GetBlockByNumber(limit/2 - 2).Hash(), 95 }, 96 }, 97 // Multiple headers with skip lists should be retrievable 98 { 99 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3}, 100 []common.Hash{ 101 bc.GetBlockByNumber(limit / 2).Hash(), 102 bc.GetBlockByNumber(limit/2 + 4).Hash(), 103 bc.GetBlockByNumber(limit/2 + 8).Hash(), 104 }, 105 }, { 106 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true}, 107 []common.Hash{ 108 bc.GetBlockByNumber(limit / 2).Hash(), 109 bc.GetBlockByNumber(limit/2 - 4).Hash(), 110 bc.GetBlockByNumber(limit/2 - 8).Hash(), 111 }, 112 }, 113 // The chain endpoints should be retrievable 114 { 115 &getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1}, 116 []common.Hash{bc.GetBlockByNumber(0).Hash()}, 117 }, { 118 &getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64()}, Amount: 1}, 119 []common.Hash{bc.CurrentBlock().Hash()}, 120 }, 121 // Ensure protocol limits are honored 122 /*{ 123 &getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true}, 124 bc.GetBlockHashesFromHash(bc.CurrentBlock().Hash(), limit), 125 },*/ 126 // Check that requesting more than available is handled gracefully 127 { 128 &getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3}, 129 []common.Hash{ 130 bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 4).Hash(), 131 bc.GetBlockByNumber(bc.CurrentBlock().NumberU64()).Hash(), 132 }, 133 }, { 134 &getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true}, 135 []common.Hash{ 136 bc.GetBlockByNumber(4).Hash(), 137 bc.GetBlockByNumber(0).Hash(), 138 }, 139 }, 140 // Check that requesting more than available is handled gracefully, even if mid skip 141 { 142 &getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3}, 143 []common.Hash{ 144 bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 4).Hash(), 145 bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1).Hash(), 146 }, 147 }, { 148 &getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true}, 149 []common.Hash{ 150 bc.GetBlockByNumber(4).Hash(), 151 bc.GetBlockByNumber(1).Hash(), 152 }, 153 }, 154 // Check that non existing headers aren't returned 155 { 156 &getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1}, 157 []common.Hash{}, 158 }, { 159 &getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() + 1}, Amount: 1}, 160 []common.Hash{}, 161 }, 162 } 163 // Run each of the tests and verify the results against the chain 164 var reqID uint64 165 for i, tt := range tests { 166 // Collect the headers to expect in the response 167 headers := []*types.Header{} 168 for _, hash := range tt.expect { 169 headers = append(headers, bc.GetHeaderByHash(hash)) 170 } 171 // Send the hash request and verify the response 172 reqID++ 173 cost := peer.GetRequestCost(GetBlockHeadersMsg, int(tt.query.Amount)) 174 sendRequest(peer.app, GetBlockHeadersMsg, reqID, cost, tt.query) 175 if err := expectResponse(peer.app, BlockHeadersMsg, reqID, testBufLimit, headers); err != nil { 176 t.Errorf("test %d: headers mismatch: %v", i, err) 177 } 178 } 179 } 180 181 // Tests that block contents can be retrieved from a remote chain based on their hashes. 182 func TestGetBlockBodiesLes1(t *testing.T) { testGetBlockBodies(t, 1) } 183 func TestGetBlockBodiesLes2(t *testing.T) { testGetBlockBodies(t, 2) } 184 185 func testGetBlockBodies(t *testing.T, protocol int) { 186 ctx := context.Background() 187 db := ethdb.NewMemDatabase() 188 pm := newTestProtocolManagerMust(ctx, t, false, downloader.MaxBlockFetch+15, nil, nil, nil, db) 189 bc := pm.blockchain.(*core.BlockChain) 190 peer, _ := newTestPeer(ctx, t, "peer", protocol, pm, true) 191 defer peer.close() 192 193 // Create a batch of tests for various scenarios 194 limit := MaxBodyFetch 195 tests := []struct { 196 random int // Number of blocks to fetch randomly from the chain 197 explicit []common.Hash // Explicitly requested blocks 198 available []bool // Availability of explicitly requested blocks 199 expected int // Total number of existing blocks to expect 200 }{ 201 {1, nil, nil, 1}, // A single random block should be retrievable 202 {10, nil, nil, 10}, // Multiple random blocks should be retrievable 203 {limit, nil, nil, limit}, // The maximum possible blocks should be retrievable 204 //{limit + 1, nil, nil, limit}, // No more than the possible block count should be returned 205 {0, []common.Hash{bc.Genesis().Hash()}, []bool{true}, 1}, // The genesis block should be retrievable 206 {0, []common.Hash{bc.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable 207 {0, []common.Hash{{}}, []bool{false}, 0}, // A non existent block should not be returned 208 209 // Existing and non-existing blocks interleaved should not cause problems 210 {0, []common.Hash{ 211 {}, 212 bc.GetBlockByNumber(1).Hash(), 213 {}, 214 bc.GetBlockByNumber(10).Hash(), 215 {}, 216 bc.GetBlockByNumber(100).Hash(), 217 {}, 218 }, []bool{false, true, false, true, false, true, false}, 3}, 219 } 220 // Run each of the tests and verify the results against the chain 221 var reqID uint64 222 for i, tt := range tests { 223 // Collect the hashes to request, and the response to expect 224 hashes, seen := []common.Hash{}, make(map[int64]bool) 225 bodies := []*types.Body{} 226 227 for j := 0; j < tt.random; j++ { 228 for { 229 num := rand.Int63n(int64(bc.CurrentBlock().NumberU64())) 230 if !seen[num] { 231 seen[num] = true 232 233 block := bc.GetBlockByNumber(uint64(num)) 234 hashes = append(hashes, block.Hash()) 235 if len(bodies) < tt.expected { 236 bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles()}) 237 } 238 break 239 } 240 } 241 } 242 for j, hash := range tt.explicit { 243 hashes = append(hashes, hash) 244 if tt.available[j] && len(bodies) < tt.expected { 245 block := bc.GetBlockByHash(hash) 246 bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles()}) 247 } 248 } 249 reqID++ 250 // Send the hash request and verify the response 251 cost := peer.GetRequestCost(GetBlockBodiesMsg, len(hashes)) 252 sendRequest(peer.app, GetBlockBodiesMsg, reqID, cost, hashes) 253 if err := expectResponse(peer.app, BlockBodiesMsg, reqID, testBufLimit, bodies); err != nil { 254 t.Errorf("test %d: bodies mismatch: %v", i, err) 255 } 256 } 257 } 258 259 // Tests that the contract codes can be retrieved based on account addresses. 260 func TestGetCodeLes1(t *testing.T) { testGetCode(t, 1) } 261 func TestGetCodeLes2(t *testing.T) { testGetCode(t, 2) } 262 263 func testGetCode(t *testing.T, protocol int) { 264 ctx := context.Background() 265 // Assemble the test environment 266 db := ethdb.NewMemDatabase() 267 pm := newTestProtocolManagerMust(ctx, t, false, 4, testChainGen, nil, nil, db) 268 bc := pm.blockchain.(*core.BlockChain) 269 peer, _ := newTestPeer(ctx, t, "peer", protocol, pm, true) 270 defer peer.close() 271 272 var codereqs []*CodeReq 273 var codes [][]byte 274 275 for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ { 276 header := bc.GetHeaderByNumber(i) 277 req := &CodeReq{ 278 BHash: header.Hash(), 279 AccKey: crypto.Keccak256(testContractAddr[:]), 280 } 281 codereqs = append(codereqs, req) 282 if i >= testContractDeployed { 283 codes = append(codes, testContractCodeDeployed) 284 } 285 } 286 287 cost := peer.GetRequestCost(GetCodeMsg, len(codereqs)) 288 sendRequest(peer.app, GetCodeMsg, 42, cost, codereqs) 289 if err := expectResponse(peer.app, CodeMsg, 42, testBufLimit, codes); err != nil { 290 t.Errorf("codes mismatch: %v", err) 291 } 292 } 293 294 // Tests that the transaction receipts can be retrieved based on hashes. 295 func TestGetReceiptLes1(t *testing.T) { testGetReceipt(t, 1) } 296 func TestGetReceiptLes2(t *testing.T) { testGetReceipt(t, 2) } 297 298 func testGetReceipt(t *testing.T, protocol int) { 299 ctx := context.Background() 300 // Assemble the test environment 301 db := ethdb.NewMemDatabase() 302 pm := newTestProtocolManagerMust(ctx, t, false, 4, testChainGen, nil, nil, db) 303 bc := pm.blockchain.(*core.BlockChain) 304 peer, _ := newTestPeer(ctx, t, "peer", protocol, pm, true) 305 defer peer.close() 306 307 // Collect the hashes to request, and the response to expect 308 hashes, receipts := []common.Hash{}, []types.Receipts{} 309 for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ { 310 block := bc.GetBlockByNumber(i) 311 312 hashes = append(hashes, block.Hash()) 313 receipts = append(receipts, rawdb.ReadReceipts(db, block.Hash(), block.NumberU64())) 314 } 315 // Send the hash request and verify the response 316 cost := peer.GetRequestCost(GetReceiptsMsg, len(hashes)) 317 sendRequest(peer.app, GetReceiptsMsg, 42, cost, hashes) 318 if err := expectResponse(peer.app, ReceiptsMsg, 42, testBufLimit, receipts); err != nil { 319 t.Errorf("receipts mismatch: %v", err) 320 } 321 } 322 323 // Tests that trie merkle proofs can be retrieved 324 func TestGetProofsLes1(t *testing.T) { testGetProofs(t, 1) } 325 func TestGetProofsLes2(t *testing.T) { testGetProofs(t, 2) } 326 327 func testGetProofs(t *testing.T, protocol int) { 328 ctx := context.Background() 329 // Assemble the test environment 330 db := ethdb.NewMemDatabase() 331 pm := newTestProtocolManagerMust(ctx, t, false, 4, testChainGen, nil, nil, db) 332 bc := pm.blockchain.(*core.BlockChain) 333 peer, _ := newTestPeer(ctx, t, "peer", protocol, pm, true) 334 defer peer.close() 335 336 var ( 337 proofreqs []ProofReq 338 proofsV1 [][]rlp.RawValue 339 ) 340 proofsV2 := light.NewNodeSet() 341 342 accounts := []common.Address{testBankAddress, acc1Addr, acc2Addr, {}} 343 for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ { 344 header := bc.GetHeaderByNumber(i) 345 root := header.Root 346 trie, _ := trie.New(root, trie.NewDatabase(db)) 347 348 for _, acc := range accounts { 349 req := ProofReq{ 350 BHash: header.Hash(), 351 Key: crypto.Keccak256(acc[:]), 352 } 353 proofreqs = append(proofreqs, req) 354 355 switch protocol { 356 case 1: 357 var proof light.NodeList 358 trie.Prove(crypto.Keccak256(acc[:]), 0, &proof) 359 proofsV1 = append(proofsV1, proof) 360 case 2: 361 trie.Prove(crypto.Keccak256(acc[:]), 0, proofsV2) 362 } 363 } 364 } 365 // Send the proof request and verify the response 366 switch protocol { 367 case 1: 368 cost := peer.GetRequestCost(GetProofsV1Msg, len(proofreqs)) 369 sendRequest(peer.app, GetProofsV1Msg, 42, cost, proofreqs) 370 if err := expectResponse(peer.app, ProofsV1Msg, 42, testBufLimit, proofsV1); err != nil { 371 t.Errorf("proofs mismatch: %v", err) 372 } 373 case 2: 374 cost := peer.GetRequestCost(GetProofsV2Msg, len(proofreqs)) 375 sendRequest(peer.app, GetProofsV2Msg, 42, cost, proofreqs) 376 if err := expectResponse(peer.app, ProofsV2Msg, 42, testBufLimit, proofsV2.NodeList()); err != nil { 377 t.Errorf("proofs mismatch: %v", err) 378 } 379 } 380 } 381 382 // Tests that CHT proofs can be correctly retrieved. 383 func TestGetCHTProofsLes1(t *testing.T) { testGetCHTProofs(t, 1) } 384 func TestGetCHTProofsLes2(t *testing.T) { testGetCHTProofs(t, 2) } 385 386 func testGetCHTProofs(t *testing.T, protocol int) { 387 t.Skip("unreliable test") 388 ctx := context.Background() 389 // Figure out the client's CHT frequency 390 frequency := uint64(light.CHTFrequencyClient) 391 if protocol == 1 { 392 frequency = uint64(light.CHTFrequencyServer) 393 } 394 // Assemble the test environment 395 db := ethdb.NewMemDatabase() 396 pm := newTestProtocolManagerMust(ctx, t, false, int(frequency)+light.HelperTrieProcessConfirmations, testChainGen, nil, nil, db) 397 bc := pm.blockchain.(*core.BlockChain) 398 peer, _ := newTestPeer(ctx, t, "peer", protocol, pm, true) 399 defer peer.close() 400 401 // Wait a while for the CHT indexer to process the new headers 402 time.Sleep(100 * time.Millisecond * time.Duration(frequency/light.CHTFrequencyServer)) // Chain indexer throttling 403 time.Sleep(250 * time.Millisecond) // CI tester slack 404 405 // Assemble the proofs from the different protocols 406 header := bc.GetHeaderByNumber(frequency) 407 rlp, _ := rlp.EncodeToBytes(header) 408 409 key := make([]byte, 8) 410 binary.BigEndian.PutUint64(key, frequency) 411 412 proofsV1 := []ChtResp{{ 413 Header: header, 414 }} 415 proofsV2 := HelperTrieResps{ 416 AuxData: [][]byte{rlp}, 417 } 418 switch protocol { 419 case 1: 420 root := light.GetChtRoot(db, 0, bc.GetHeaderByNumber(frequency-1).Hash()) 421 trie, _ := trie.New(root, trie.NewDatabase(common.NewTablePrefixer(db.GlobalTable(), light.ChtTablePrefix))) 422 423 var proof light.NodeList 424 trie.Prove(key, 0, &proof) 425 proofsV1[0].Proof = proof 426 427 case 2: 428 root := light.GetChtV2Root(db, 0, bc.GetHeaderByNumber(frequency-1).Hash()) 429 trie, _ := trie.New(root, trie.NewDatabase(common.NewTablePrefixer(db.GlobalTable(), light.ChtTablePrefix))) 430 trie.Prove(key, 0, &proofsV2.Proofs) 431 } 432 // Assemble the requests for the different protocols 433 requestsV1 := []ChtReq{{ 434 ChtNum: 1, 435 BlockNum: frequency, 436 }} 437 requestsV2 := []HelperTrieReq{{ 438 Type: htCanonical, 439 TrieIdx: 0, 440 Key: key, 441 AuxReq: auxHeader, 442 }} 443 // Send the proof request and verify the response 444 switch protocol { 445 case 1: 446 cost := peer.GetRequestCost(GetHeaderProofsMsg, len(requestsV1)) 447 sendRequest(peer.app, GetHeaderProofsMsg, 42, cost, requestsV1) 448 if err := expectResponse(peer.app, HeaderProofsMsg, 42, testBufLimit, proofsV1); err != nil { 449 t.Errorf("proofs mismatch: %v", err) 450 } 451 case 2: 452 cost := peer.GetRequestCost(GetHelperTrieProofsMsg, len(requestsV2)) 453 sendRequest(peer.app, GetHelperTrieProofsMsg, 42, cost, requestsV2) 454 if err := expectResponse(peer.app, HelperTrieProofsMsg, 42, testBufLimit, proofsV2); err != nil { 455 t.Errorf("proofs mismatch: %v", err) 456 } 457 } 458 } 459 460 // Tests that bloombits proofs can be correctly retrieved. 461 func TestGetBloombitsProofs(t *testing.T) { 462 ctx := context.Background() 463 // Assemble the test environment 464 db := ethdb.NewMemDatabase() 465 pm := newTestProtocolManagerMust(ctx, t, false, light.BloomTrieFrequency+256, testChainGen, nil, nil, db) 466 bc := pm.blockchain.(*core.BlockChain) 467 peer, _ := newTestPeer(ctx, t, "peer", 2, pm, true) 468 defer peer.close() 469 470 // Wait a while for the bloombits indexer to process the new headers 471 time.Sleep(100 * time.Millisecond * time.Duration(light.BloomTrieFrequency/4096)) // Chain indexer throttling 472 time.Sleep(250 * time.Millisecond) // CI tester slack 473 474 // Request and verify each bit of the bloom bits proofs 475 for bit := 0; bit < 2048; bit++ { 476 // Assemble therequest and proofs for the bloombits 477 key := make([]byte, 10) 478 479 binary.BigEndian.PutUint16(key[:2], uint16(bit)) 480 binary.BigEndian.PutUint64(key[2:], uint64(light.BloomTrieFrequency)) 481 482 requests := []HelperTrieReq{{ 483 Type: htBloomBits, 484 TrieIdx: 0, 485 Key: key, 486 }} 487 var proofs HelperTrieResps 488 489 root := light.GetBloomTrieRoot(db, 0, bc.GetHeaderByNumber(light.BloomTrieFrequency-1).Hash()) 490 trie, _ := trie.New(root, trie.NewDatabase(common.NewTablePrefixer(db.GlobalTable(), light.BloomTrieTablePrefix))) 491 trie.Prove(key, 0, &proofs.Proofs) 492 493 // Send the proof request and verify the response 494 cost := peer.GetRequestCost(GetHelperTrieProofsMsg, len(requests)) 495 sendRequest(peer.app, GetHelperTrieProofsMsg, 42, cost, requests) 496 if err := expectResponse(peer.app, HelperTrieProofsMsg, 42, testBufLimit, proofs); err != nil { 497 t.Errorf("bit %d: proofs mismatch: %v", bit, err) 498 } 499 } 500 } 501 502 func TestTransactionStatusLes2(t *testing.T) { 503 ctx := context.Background() 504 db := ethdb.NewMemDatabase() 505 pm := newTestProtocolManagerMust(ctx, t, false, 0, nil, nil, nil, db) 506 chain := pm.blockchain.(*core.BlockChain) 507 config := core.DefaultTxPoolConfig 508 config.Journal = "" 509 txpool := core.NewTxPool(config, params.TestChainConfig, chain) 510 pm.txpool = txpool 511 peer, _ := newTestPeer(ctx, t, "peer", 2, pm, true) 512 defer peer.close() 513 514 var reqID uint64 515 516 test := func(tx *types.Transaction, send bool, expStatus txStatus) { 517 reqID++ 518 if send { 519 cost := peer.GetRequestCost(SendTxV2Msg, 1) 520 sendRequest(peer.app, SendTxV2Msg, reqID, cost, types.Transactions{tx}) 521 } else { 522 cost := peer.GetRequestCost(GetTxStatusMsg, 1) 523 sendRequest(peer.app, GetTxStatusMsg, reqID, cost, []common.Hash{tx.Hash()}) 524 } 525 if err := expectResponse(peer.app, TxStatusMsg, reqID, testBufLimit, []txStatus{expStatus}); err != nil { 526 t.Errorf("transaction status mismatch") 527 } 528 } 529 530 signer := types.HomesteadSigner{} 531 532 // test error status by sending an underpriced transaction 533 tx0, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) 534 test(tx0, true, txStatus{Status: core.TxStatusUnknown, Error: core.ErrUnderpriced.Error()}) 535 536 tx1, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey) 537 test(tx1, false, txStatus{Status: core.TxStatusUnknown}) // query before sending, should be unknown 538 test(tx1, true, txStatus{Status: core.TxStatusPending}) // send valid processable tx, should return pending 539 test(tx1, true, txStatus{Status: core.TxStatusPending}) // adding it again should not return an error 540 541 tx2, _ := types.SignTx(types.NewTransaction(1, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey) 542 tx3, _ := types.SignTx(types.NewTransaction(2, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey) 543 // send transactions in the wrong order, tx3 should be queued 544 test(tx3, true, txStatus{Status: core.TxStatusQueued}) 545 test(tx2, true, txStatus{Status: core.TxStatusPending}) 546 // query again, now tx3 should be pending too 547 test(tx3, false, txStatus{Status: core.TxStatusPending}) 548 549 engine := clique.NewFaker() 550 // generate and add a block with tx1 and tx2 included 551 gchain, _ := core.GenerateChain(ctx, params.TestChainConfig, chain.GetBlockByNumber(0), engine, db, 1, func(ctx context.Context, i int, block *core.BlockGen) { 552 block.AddTx(ctx, tx1) 553 block.AddTx(ctx, tx2) 554 }) 555 if _, err := chain.InsertChain(ctx, gchain); err != nil { 556 panic(err) 557 } 558 // wait until TxPool processes the inserted block 559 for i := 0; i < 200; i++ { 560 if pending, _ := txpool.Stats(); pending == 1 { 561 break 562 } 563 time.Sleep(100 * time.Millisecond) 564 } 565 if pending, _ := txpool.Stats(); pending != 1 { 566 t.Fatalf("pending count mismatch: have %d, want 1", pending) 567 } 568 569 // check if their status is included now 570 block1hash := rawdb.ReadCanonicalHash(db, 1) 571 test(tx1, false, txStatus{Status: core.TxStatusIncluded, Lookup: &rawdb.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}}) 572 test(tx2, false, txStatus{Status: core.TxStatusIncluded, Lookup: &rawdb.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}}) 573 574 // create a reorg that rolls them back 575 gchain, _ = core.GenerateChain(ctx, params.TestChainConfig, chain.GetBlockByNumber(0), engine, db, 2, func(ctx context.Context, i int, block *core.BlockGen) {}) 576 if _, err := chain.InsertChain(ctx, gchain); err != nil { 577 panic(err) 578 } 579 // wait until TxPool processes the reorg 580 for i := 0; i < 200; i++ { 581 if pending, _ := txpool.Stats(); pending == 3 { 582 break 583 } 584 time.Sleep(100 * time.Millisecond) 585 } 586 if pending, _ := txpool.Stats(); pending != 3 { 587 t.Fatalf("pending count mismatch: have %d, want 3", pending) 588 } 589 // check if their status is pending again 590 test(tx1, false, txStatus{Status: core.TxStatusPending}) 591 test(tx2, false, txStatus{Status: core.TxStatusPending}) 592 }