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