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