github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/eth/handler_test.go (about) 1 // Copyright 2015 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 eth 18 19 import ( 20 "math" 21 "math/big" 22 "math/rand" 23 "testing" 24 25 "github.com/wanchain/go-wanchain/common" 26 "github.com/wanchain/go-wanchain/core" 27 "github.com/wanchain/go-wanchain/core/state" 28 "github.com/wanchain/go-wanchain/core/types" 29 "github.com/wanchain/go-wanchain/crypto" 30 "github.com/wanchain/go-wanchain/eth/downloader" 31 "github.com/wanchain/go-wanchain/ethdb" 32 "github.com/wanchain/go-wanchain/p2p" 33 "github.com/wanchain/go-wanchain/params" 34 ) 35 36 var bigTxGas = new(big.Int).SetUint64(params.TxGas) 37 38 // Tests that protocol versions and modes of operations are matched up properly. 39 func TestProtocolCompatibility(t *testing.T) { 40 // Define the compatibility chart 41 tests := []struct { 42 version uint 43 mode downloader.SyncMode 44 compatible bool 45 }{ 46 {61, downloader.FullSync, true}, {62, downloader.FullSync, true}, {63, downloader.FullSync, true}, 47 {61, downloader.FastSync, false}, {62, downloader.FastSync, false}, {63, downloader.FastSync, true}, 48 } 49 // Make sure anything we screw up is restored 50 backup := ProtocolVersions 51 defer func() { ProtocolVersions = backup }() 52 53 // Try all available compatibility configs and check for errors 54 for i, tt := range tests { 55 ProtocolVersions = []uint{tt.version} 56 57 pm, err := newTestProtocolManager(tt.mode, 0, nil, nil) 58 if pm != nil { 59 defer pm.Stop() 60 } 61 if (err == nil && !tt.compatible) || (err != nil && tt.compatible) { 62 t.Errorf("test %d: compatibility mismatch: have error %v, want compatibility %v", i, err, tt.compatible) 63 } 64 } 65 } 66 67 // Tests that block headers can be retrieved from a remote chain based on user queries. 68 func TestGetBlockHeaders62(t *testing.T) { testGetBlockHeaders(t, 62) } 69 func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) } 70 71 func testGetBlockHeaders(t *testing.T, protocol int) { 72 pm := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxHashFetch+15, nil, nil) 73 peer, _ := newTestPeer("peer", protocol, pm, true) 74 defer peer.close() 75 76 // Create a "random" unknown hash for testing 77 var unknown common.Hash 78 for i := range unknown { 79 unknown[i] = byte(i) 80 } 81 // Create a batch of tests for various scenarios 82 limit := uint64(downloader.MaxHeaderFetch) 83 tests := []struct { 84 query *getBlockHeadersData // The query to execute for header retrieval 85 expect []common.Hash // The hashes of the block whose headers are expected 86 }{ 87 // A single random block should be retrievable by hash and number too 88 { 89 &getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, Amount: 1}, 90 []common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, 91 }, { 92 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1}, 93 []common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, 94 }, 95 // Multiple headers should be retrievable in both directions 96 { 97 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3}, 98 []common.Hash{ 99 pm.blockchain.GetBlockByNumber(limit / 2).Hash(), 100 pm.blockchain.GetBlockByNumber(limit/2 + 1).Hash(), 101 pm.blockchain.GetBlockByNumber(limit/2 + 2).Hash(), 102 }, 103 }, { 104 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true}, 105 []common.Hash{ 106 pm.blockchain.GetBlockByNumber(limit / 2).Hash(), 107 pm.blockchain.GetBlockByNumber(limit/2 - 1).Hash(), 108 pm.blockchain.GetBlockByNumber(limit/2 - 2).Hash(), 109 }, 110 }, 111 // Multiple headers with skip lists should be retrievable 112 { 113 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3}, 114 []common.Hash{ 115 pm.blockchain.GetBlockByNumber(limit / 2).Hash(), 116 pm.blockchain.GetBlockByNumber(limit/2 + 4).Hash(), 117 pm.blockchain.GetBlockByNumber(limit/2 + 8).Hash(), 118 }, 119 }, { 120 &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true}, 121 []common.Hash{ 122 pm.blockchain.GetBlockByNumber(limit / 2).Hash(), 123 pm.blockchain.GetBlockByNumber(limit/2 - 4).Hash(), 124 pm.blockchain.GetBlockByNumber(limit/2 - 8).Hash(), 125 }, 126 }, 127 // The chain endpoints should be retrievable 128 { 129 &getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1}, 130 []common.Hash{pm.blockchain.GetBlockByNumber(0).Hash()}, 131 }, { 132 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64()}, Amount: 1}, 133 []common.Hash{pm.blockchain.CurrentBlock().Hash()}, 134 }, 135 // Ensure protocol limits are honored 136 { 137 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true}, 138 pm.blockchain.GetBlockHashesFromHash(pm.blockchain.CurrentBlock().Hash(), limit), 139 }, 140 // Check that requesting more than available is handled gracefully 141 { 142 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3}, 143 []common.Hash{ 144 pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(), 145 pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64()).Hash(), 146 }, 147 }, { 148 &getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true}, 149 []common.Hash{ 150 pm.blockchain.GetBlockByNumber(4).Hash(), 151 pm.blockchain.GetBlockByNumber(0).Hash(), 152 }, 153 }, 154 // Check that requesting more than available is handled gracefully, even if mid skip 155 { 156 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3}, 157 []common.Hash{ 158 pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(), 159 pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 1).Hash(), 160 }, 161 }, { 162 &getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true}, 163 []common.Hash{ 164 pm.blockchain.GetBlockByNumber(4).Hash(), 165 pm.blockchain.GetBlockByNumber(1).Hash(), 166 }, 167 }, 168 // Check a corner case where requesting more can iterate past the endpoints 169 { 170 &getBlockHeadersData{Origin: hashOrNumber{Number: 2}, Amount: 5, Reverse: true}, 171 []common.Hash{ 172 pm.blockchain.GetBlockByNumber(2).Hash(), 173 pm.blockchain.GetBlockByNumber(1).Hash(), 174 pm.blockchain.GetBlockByNumber(0).Hash(), 175 }, 176 }, 177 // Check a corner case where skipping overflow loops back into the chain start 178 { 179 &getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(3).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64 - 1}, 180 []common.Hash{ 181 pm.blockchain.GetBlockByNumber(3).Hash(), 182 }, 183 }, 184 // Check a corner case where skipping overflow loops back to the same header 185 { 186 &getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(1).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64}, 187 []common.Hash{ 188 pm.blockchain.GetBlockByNumber(1).Hash(), 189 }, 190 }, 191 // Check that non existing headers aren't returned 192 { 193 &getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1}, 194 []common.Hash{}, 195 }, { 196 &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() + 1}, Amount: 1}, 197 []common.Hash{}, 198 }, 199 } 200 // Run each of the tests and verify the results against the chain 201 for i, tt := range tests { 202 // Collect the headers to expect in the response 203 headers := []*types.Header{} 204 for _, hash := range tt.expect { 205 headers = append(headers, pm.blockchain.GetBlockByHash(hash).Header()) 206 } 207 // Send the hash request and verify the response 208 p2p.Send(peer.app, 0x03, tt.query) 209 if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil { 210 t.Errorf("test %d: headers mismatch: %v", i, err) 211 } 212 // If the test used number origins, repeat with hashes as the too 213 if tt.query.Origin.Hash == (common.Hash{}) { 214 if origin := pm.blockchain.GetBlockByNumber(tt.query.Origin.Number); origin != nil { 215 tt.query.Origin.Hash, tt.query.Origin.Number = origin.Hash(), 0 216 217 p2p.Send(peer.app, 0x03, tt.query) 218 if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil { 219 t.Errorf("test %d: headers mismatch: %v", i, err) 220 } 221 } 222 } 223 } 224 } 225 226 // Tests that block contents can be retrieved from a remote chain based on their hashes. 227 func TestGetBlockBodies62(t *testing.T) { testGetBlockBodies(t, 62) } 228 func TestGetBlockBodies63(t *testing.T) { testGetBlockBodies(t, 63) } 229 230 func testGetBlockBodies(t *testing.T, protocol int) { 231 pm := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxBlockFetch+15, nil, nil) 232 peer, _ := newTestPeer("peer", protocol, pm, true) 233 defer peer.close() 234 235 // Create a batch of tests for various scenarios 236 limit := downloader.MaxBlockFetch 237 tests := []struct { 238 random int // Number of blocks to fetch randomly from the chain 239 explicit []common.Hash // Explicitly requested blocks 240 available []bool // Availability of explicitly requested blocks 241 expected int // Total number of existing blocks to expect 242 }{ 243 {1, nil, nil, 1}, // A single random block should be retrievable 244 {10, nil, nil, 10}, // Multiple random blocks should be retrievable 245 {limit, nil, nil, limit}, // The maximum possible blocks should be retrievable 246 {limit + 1, nil, nil, limit}, // No more than the possible block count should be returned 247 {0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1}, // The genesis block should be retrievable 248 {0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable 249 {0, []common.Hash{{}}, []bool{false}, 0}, // A non existent block should not be returned 250 251 // Existing and non-existing blocks interleaved should not cause problems 252 {0, []common.Hash{ 253 {}, 254 pm.blockchain.GetBlockByNumber(1).Hash(), 255 {}, 256 pm.blockchain.GetBlockByNumber(10).Hash(), 257 {}, 258 pm.blockchain.GetBlockByNumber(100).Hash(), 259 {}, 260 }, []bool{false, true, false, true, false, true, false}, 3}, 261 } 262 // Run each of the tests and verify the results against the chain 263 for i, tt := range tests { 264 // Collect the hashes to request, and the response to expect 265 hashes, seen := []common.Hash{}, make(map[int64]bool) 266 bodies := []*blockBody{} 267 268 for j := 0; j < tt.random; j++ { 269 for { 270 num := rand.Int63n(int64(pm.blockchain.CurrentBlock().NumberU64())) 271 if !seen[num] { 272 seen[num] = true 273 274 block := pm.blockchain.GetBlockByNumber(uint64(num)) 275 hashes = append(hashes, block.Hash()) 276 if len(bodies) < tt.expected { 277 bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()}) 278 } 279 break 280 } 281 } 282 } 283 for j, hash := range tt.explicit { 284 hashes = append(hashes, hash) 285 if tt.available[j] && len(bodies) < tt.expected { 286 block := pm.blockchain.GetBlockByHash(hash) 287 bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()}) 288 } 289 } 290 // Send the hash request and verify the response 291 p2p.Send(peer.app, 0x05, hashes) 292 if err := p2p.ExpectMsg(peer.app, 0x06, bodies); err != nil { 293 t.Errorf("test %d: bodies mismatch: %v", i, err) 294 } 295 } 296 } 297 298 // Tests that the node state database can be retrieved based on hashes. 299 func TestGetNodeData63(t *testing.T) { testGetNodeData(t, 63) } 300 301 func testGetNodeData(t *testing.T, protocol int) { 302 // Define three accounts to simulate transactions with 303 acc1Key, _ := crypto.HexToECDSA("9780c4081b5b1191d664c5f55efab9c5de6f6c9678b9f61d7b1a17f3fc208aa3") 304 acc2Key, _ := crypto.HexToECDSA("3be6eec899911423f4f375f72bf0eaf5efdd248bc539fb45adcf17829c979bb1") 305 acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) 306 acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) 307 308 // signer := types.HomesteadSigner{} 309 signer := types.NewEIP155Signer(big.NewInt(1)) 310 // Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test) 311 generator := func(i int, block *core.BlockGen) { 312 switch i { 313 case 0: 314 // In block 1, the test bank sends account #1 some wan. 315 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) 316 block.AddTx(tx) 317 case 1: 318 // In block 2, the test bank sends some more ether to account #1. 319 // acc1Addr passes it on to account #2. 320 tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) 321 tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) 322 block.AddTx(tx1) 323 block.AddTx(tx2) 324 case 2: 325 // Block 3 is empty but was mined by account #2. 326 block.SetCoinbase(acc2Addr) 327 block.SetExtra([]byte("yeehaw")) 328 } 329 } 330 // Assemble the test environment 331 pm := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil) 332 peer, _ := newTestPeer("peer", protocol, pm, true) 333 defer peer.close() 334 335 // Fetch for now the entire chain db 336 hashes := []common.Hash{} 337 for _, key := range pm.chaindb.(*ethdb.MemDatabase).Keys() { 338 if len(key) == len(common.Hash{}) { 339 hashes = append(hashes, common.BytesToHash(key)) 340 } 341 } 342 p2p.Send(peer.app, 0x0d, hashes) 343 msg, err := peer.app.ReadMsg() 344 if err != nil { 345 t.Fatalf("failed to read node data response: %v", err) 346 } 347 if msg.Code != 0x0e { 348 t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, 0x0c) 349 } 350 var data [][]byte 351 if err := msg.Decode(&data); err != nil { 352 t.Fatalf("failed to decode response node data: %v", err) 353 } 354 // Verify that all hashes correspond to the requested data, and reconstruct a state tree 355 for i, want := range hashes { 356 if hash := crypto.Keccak256Hash(data[i]); hash != want { 357 t.Errorf("data hash mismatch: have %x, want %x", hash, want) 358 } 359 } 360 statedb, _ := ethdb.NewMemDatabase() 361 for i := 0; i < len(data); i++ { 362 statedb.Put(hashes[i].Bytes(), data[i]) 363 } 364 accounts := []common.Address{testBank, acc1Addr, acc2Addr} 365 for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { 366 trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), state.NewDatabase(statedb)) 367 368 for j, acc := range accounts { 369 state, _ := pm.blockchain.State() 370 bw := state.GetBalance(acc) 371 bh := trie.GetBalance(acc) 372 373 if (bw != nil && bh == nil) || (bw == nil && bh != nil) { 374 t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw) 375 } 376 if bw != nil && bh != nil && bw.Cmp(bw) != 0 { 377 t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw) 378 } 379 } 380 } 381 } 382 383 // Tests that the transaction receipts can be retrieved based on hashes. 384 func TestGetReceipt63(t *testing.T) { testGetReceipt(t, 63) } 385 386 func testGetReceipt(t *testing.T, protocol int) { 387 // Define three accounts to simulate transactions with 388 acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 389 acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 390 acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) 391 acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) 392 393 signer := types.HomesteadSigner{} 394 // Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test) 395 generator := func(i int, block *core.BlockGen) { 396 switch i { 397 case 0: 398 // In block 1, the test bank sends account #1 some ether. 399 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) 400 block.AddTx(tx) 401 case 1: 402 // In block 2, the test bank sends some more ether to account #1. 403 // acc1Addr passes it on to account #2. 404 tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) 405 tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) 406 block.AddTx(tx1) 407 block.AddTx(tx2) 408 case 2: 409 // Block 3 is empty but was mined by account #2. 410 block.SetCoinbase(acc2Addr) 411 block.SetExtra([]byte("yeehaw")) 412 } 413 } 414 // Assemble the test environment 415 pm := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil) 416 peer, _ := newTestPeer("peer", protocol, pm, true) 417 defer peer.close() 418 419 // Collect the hashes to request, and the response to expect 420 hashes, receipts := []common.Hash{}, []types.Receipts{} 421 for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { 422 block := pm.blockchain.GetBlockByNumber(i) 423 424 hashes = append(hashes, block.Hash()) 425 receipts = append(receipts, core.GetBlockReceipts(pm.chaindb, block.Hash(), block.NumberU64())) 426 } 427 // Send the hash request and verify the response 428 p2p.Send(peer.app, 0x0f, hashes) 429 if err := p2p.ExpectMsg(peer.app, 0x10, receipts); err != nil { 430 t.Errorf("receipts mismatch: %v", err) 431 } 432 }