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