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