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