github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/cmd/devp2p/internal/ethtest/snap.go (about) 1 // Copyright 2022 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package ethtest 18 19 import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "math/big" 24 "math/rand" 25 "reflect" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/core/state" 29 "github.com/ethereum/go-ethereum/core/types" 30 "github.com/ethereum/go-ethereum/crypto" 31 "github.com/ethereum/go-ethereum/eth/protocols/snap" 32 "github.com/ethereum/go-ethereum/internal/utesting" 33 "github.com/ethereum/go-ethereum/trie" 34 "github.com/ethereum/go-ethereum/trie/trienode" 35 ) 36 37 func (c *Conn) snapRequest(code uint64, msg any) (any, error) { 38 if err := c.Write(snapProto, code, msg); err != nil { 39 return nil, fmt.Errorf("could not write to connection: %v", err) 40 } 41 return c.ReadSnap() 42 } 43 44 func (s *Suite) TestSnapStatus(t *utesting.T) { 45 conn, err := s.dialSnap() 46 if err != nil { 47 t.Fatalf("dial failed: %v", err) 48 } 49 defer conn.Close() 50 if err := conn.peer(s.chain, nil); err != nil { 51 t.Fatalf("peering failed: %v", err) 52 } 53 } 54 55 type accRangeTest struct { 56 nBytes uint64 57 root common.Hash 58 startingHash common.Hash 59 limitHash common.Hash 60 61 expAccounts int 62 expFirst common.Hash 63 expLast common.Hash 64 65 desc string 66 } 67 68 // TestSnapGetAccountRange various forms of GetAccountRange requests. 69 func (s *Suite) TestSnapGetAccountRange(t *utesting.T) { 70 var ( 71 ffHash = common.MaxHash 72 zero = common.Hash{} 73 74 // test values derived from chain/ account dump 75 root = s.chain.Head().Root() 76 headstate = s.chain.AccountsInHashOrder() 77 firstKey = common.BytesToHash(headstate[0].AddressHash) 78 secondKey = common.BytesToHash(headstate[1].AddressHash) 79 storageRoot = findNonEmptyStorageRoot(headstate) 80 ) 81 82 tests := []accRangeTest{ 83 // Tests decreasing the number of bytes 84 { 85 nBytes: 4000, 86 root: root, 87 startingHash: zero, 88 limitHash: ffHash, 89 expAccounts: 86, 90 expFirst: firstKey, 91 expLast: common.HexToHash("0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099"), 92 desc: "In this test, we request the entire state range, but limit the response to 4000 bytes.", 93 }, 94 { 95 nBytes: 3000, 96 root: root, 97 startingHash: zero, 98 limitHash: ffHash, 99 expAccounts: 65, 100 expFirst: firstKey, 101 expLast: common.HexToHash("0x2e6fe1362b3e388184fd7bf08e99e74170b26361624ffd1c5f646da7067b58b6"), 102 desc: "In this test, we request the entire state range, but limit the response to 3000 bytes.", 103 }, 104 { 105 nBytes: 2000, 106 root: root, 107 startingHash: zero, 108 limitHash: ffHash, 109 expAccounts: 44, 110 expFirst: firstKey, 111 expLast: common.HexToHash("0x1c3f74249a4892081ba0634a819aec9ed25f34c7653f5719b9098487e65ab595"), 112 desc: "In this test, we request the entire state range, but limit the response to 2000 bytes.", 113 }, 114 { 115 nBytes: 1, 116 root: root, 117 startingHash: zero, 118 limitHash: ffHash, 119 expAccounts: 1, 120 expFirst: firstKey, 121 expLast: firstKey, 122 desc: `In this test, we request the entire state range, but limit the response to 1 byte. 123 The server should return the first account of the state.`, 124 }, 125 { 126 nBytes: 0, 127 root: root, 128 startingHash: zero, 129 limitHash: ffHash, 130 expAccounts: 1, 131 expFirst: firstKey, 132 expLast: firstKey, 133 desc: `Here we request with a responseBytes limit of zero. 134 The server should return one account.`, 135 }, 136 137 // Tests variations of the range 138 { 139 nBytes: 4000, 140 root: root, 141 startingHash: hashAdd(firstKey, -500), 142 limitHash: hashAdd(firstKey, 1), 143 expAccounts: 2, 144 expFirst: firstKey, 145 expLast: secondKey, 146 desc: `In this test, we request a range where startingHash is before the first available 147 account key, and limitHash is after. The server should return the first and second 148 account of the state (because the second account is the 'next available').`, 149 }, 150 151 { 152 nBytes: 4000, 153 root: root, 154 startingHash: hashAdd(firstKey, -500), 155 limitHash: hashAdd(firstKey, -450), 156 expAccounts: 1, 157 expFirst: firstKey, 158 expLast: firstKey, 159 desc: `Here we request range where both bounds are before the first available account key. 160 This should return the first account (even though it's out of bounds).`, 161 }, 162 163 // More range tests: 164 { 165 nBytes: 4000, 166 root: root, 167 startingHash: zero, 168 limitHash: zero, 169 expAccounts: 1, 170 expFirst: firstKey, 171 expLast: firstKey, 172 desc: `In this test, both startingHash and limitHash are zero. 173 The server should return the first available account.`, 174 }, 175 { 176 nBytes: 4000, 177 root: root, 178 startingHash: firstKey, 179 limitHash: ffHash, 180 expAccounts: 86, 181 expFirst: firstKey, 182 expLast: common.HexToHash("0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099"), 183 desc: `In this test, startingHash is exactly the first available account key. 184 The server should return the first available account of the state as the first item.`, 185 }, 186 { 187 nBytes: 4000, 188 root: root, 189 startingHash: hashAdd(firstKey, 1), 190 limitHash: ffHash, 191 expAccounts: 86, 192 expFirst: secondKey, 193 expLast: common.HexToHash("0x4615e5f5df5b25349a00ad313c6cd0436b6c08ee5826e33a018661997f85ebaa"), 194 desc: `In this test, startingHash is after the first available key. 195 The server should return the second account of the state as the first item.`, 196 }, 197 198 // Test different root hashes 199 200 { 201 nBytes: 4000, 202 root: common.Hash{0x13, 0x37}, 203 startingHash: zero, 204 limitHash: ffHash, 205 expAccounts: 0, 206 expFirst: zero, 207 expLast: zero, 208 desc: `This test requests a non-existent state root.`, 209 }, 210 211 // The genesis stateroot (we expect it to not be served) 212 { 213 nBytes: 4000, 214 root: s.chain.RootAt(0), 215 startingHash: zero, 216 limitHash: ffHash, 217 expAccounts: 0, 218 expFirst: zero, 219 expLast: zero, 220 desc: `This test requests data at the state root of the genesis block. We expect the 221 server to return no data because genesis is older than 127 blocks.`, 222 }, 223 224 { 225 nBytes: 4000, 226 root: s.chain.RootAt(int(s.chain.Head().Number().Uint64()) - 127), 227 startingHash: zero, 228 limitHash: ffHash, 229 expAccounts: 84, 230 expFirst: firstKey, 231 expLast: common.HexToHash("0x580aa878e2f92d113a12c0a3ce3c21972b03dbe80786858d49a72097e2c491a3"), 232 desc: `This test requests data at a state root that is 127 blocks old. 233 We expect the server to have this state available.`, 234 }, 235 236 { 237 nBytes: 4000, 238 root: storageRoot, 239 startingHash: zero, 240 limitHash: ffHash, 241 expAccounts: 0, 242 expFirst: zero, 243 expLast: zero, 244 desc: `This test requests data at a state root that is actually the storage root of 245 an existing account. The server is supposed to ignore this request.`, 246 }, 247 248 // And some non-sensical requests 249 250 { 251 nBytes: 4000, 252 root: root, 253 startingHash: ffHash, 254 limitHash: zero, 255 expAccounts: 0, 256 expFirst: zero, 257 expLast: zero, 258 desc: `In this test, the startingHash is after limitHash (wrong order). The server 259 should ignore this invalid request.`, 260 }, 261 262 { 263 nBytes: 4000, 264 root: root, 265 startingHash: firstKey, 266 limitHash: hashAdd(firstKey, -1), 267 expAccounts: 1, 268 expFirst: firstKey, 269 expLast: firstKey, 270 desc: `In this test, the startingHash is the first available key, and limitHash is 271 a key before startingHash (wrong order). The server should return the first available key.`, 272 }, 273 274 // range from [firstkey, 0], wrong order. Expect to get first key. 275 { 276 nBytes: 4000, 277 root: root, 278 startingHash: firstKey, 279 limitHash: zero, 280 expAccounts: 1, 281 expFirst: firstKey, 282 expLast: firstKey, 283 desc: `In this test, the startingHash is the first available key and limitHash is zero. 284 (wrong order). The server should return the first available key.`, 285 }, 286 } 287 288 for i, tc := range tests { 289 tc := tc 290 if i > 0 { 291 t.Log("\n") 292 } 293 t.Logf("-- Test %d", i) 294 t.Log(tc.desc) 295 t.Log(" request:") 296 t.Logf(" root: %x", tc.root) 297 t.Logf(" range: %#x - %#x", tc.startingHash, tc.limitHash) 298 t.Logf(" responseBytes: %d", tc.nBytes) 299 if err := s.snapGetAccountRange(t, &tc); err != nil { 300 t.Errorf("test %d failed: %v", i, err) 301 } 302 } 303 } 304 305 func hashAdd(h common.Hash, n int64) common.Hash { 306 hb := h.Big() 307 return common.BigToHash(hb.Add(hb, big.NewInt(n))) 308 } 309 310 func findNonEmptyStorageRoot(accounts []state.DumpAccount) common.Hash { 311 for i := range accounts { 312 if len(accounts[i].Storage) != 0 { 313 return common.BytesToHash(accounts[i].Root) 314 } 315 } 316 panic("can't find account with non-empty storage") 317 } 318 319 type stRangesTest struct { 320 root common.Hash 321 accounts []common.Hash 322 origin []byte 323 limit []byte 324 nBytes uint64 325 326 expSlots [][]*snap.StorageData 327 328 desc string 329 } 330 331 // TestSnapGetStorageRanges various forms of GetStorageRanges requests. 332 func (s *Suite) TestSnapGetStorageRanges(t *utesting.T) { 333 var ( 334 acct = common.HexToAddress("0x8bebc8ba651aee624937e7d897853ac30c95a067") 335 acctHash = common.BytesToHash(s.chain.state[acct].AddressHash) 336 ffHash = common.MaxHash 337 zero = common.Hash{} 338 blockroot = s.chain.Head().Root() 339 ) 340 341 // These are the storage slots of the test account, encoded as snap response data. 342 acctSlots := []*snap.StorageData{ 343 { 344 Hash: common.HexToHash("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"), 345 Body: []byte{0x02}, 346 }, 347 { 348 Hash: common.HexToHash("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"), 349 Body: []byte{0x01}, 350 }, 351 { 352 Hash: common.HexToHash("0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b"), 353 Body: []byte{0x03}, 354 }, 355 } 356 357 tests := []stRangesTest{ 358 /* 359 Some tests against this account: 360 361 "0x8bebc8ba651aee624937e7d897853ac30c95a067": { 362 "balance": "1", 363 "nonce": 1, 364 "root": "0xe318dff15b33aa7f2f12d5567d58628e3e3f2e8859e46b56981a4083b391da17", 365 "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", 366 "storage": { 367 // Note: keys below are hashed!!! 368 "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace": "02", 369 "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": "01", 370 "0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b": "03" 371 }, 372 "key": "0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099" 373 } 374 */ 375 376 { // [:] -> [slot1, slot2, slot3] 377 desc: `This request has a range of 00..ff. 378 The server should return all storage slots of the test account.`, 379 root: blockroot, 380 accounts: []common.Hash{acctHash}, 381 origin: zero[:], 382 limit: ffHash[:], 383 nBytes: 500, 384 expSlots: [][]*snap.StorageData{acctSlots}, 385 }, 386 387 { // [slot1:] -> [slot1, slot2, slot3] 388 desc: `This test requests slots starting at the first available key. 389 The server should return all storage slots of the test account.`, 390 root: blockroot, 391 accounts: []common.Hash{acctHash}, 392 origin: common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"), 393 limit: ffHash[:], 394 nBytes: 1000, 395 expSlots: [][]*snap.StorageData{acctSlots}, 396 }, 397 398 { // [slot1+:] -> [slot2, slot3] 399 desc: `This test requests slots starting at a key one past the first available key. 400 The server should return the remaining two slots of the test account.`, 401 root: blockroot, 402 accounts: []common.Hash{acctHash}, 403 origin: common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf"), 404 limit: ffHash[:], 405 nBytes: 500, 406 expSlots: [][]*snap.StorageData{acctSlots[1:]}, 407 }, 408 409 { // [slot1:slot2] -> [slot1, slot2] 410 desc: `This test requests a range which is exactly the first and second available key.`, 411 root: blockroot, 412 accounts: []common.Hash{acctHash}, 413 origin: common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"), 414 limit: common.FromHex("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"), 415 nBytes: 500, 416 expSlots: [][]*snap.StorageData{acctSlots[:2]}, 417 }, 418 419 { // [slot1+:slot2+] -> [slot2, slot3] 420 desc: `This test requests a range where limitHash is after the second, but before the third slot 421 of the test account. The server should return slots [2,3] (i.e. the 'next available' needs to be returned).`, 422 root: blockroot, 423 accounts: []common.Hash{acctHash}, 424 origin: common.FromHex("0x4fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 425 limit: common.FromHex("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7"), 426 nBytes: 500, 427 expSlots: [][]*snap.StorageData{acctSlots[1:]}, 428 }, 429 } 430 431 for i, tc := range tests { 432 tc := tc 433 if i > 0 { 434 t.Log("\n") 435 } 436 t.Logf("-- Test %d", i) 437 t.Log(tc.desc) 438 t.Log(" request:") 439 t.Logf(" root: %x", tc.root) 440 t.Logf(" accounts: %x", tc.accounts) 441 t.Logf(" range: %#x - %#x", tc.origin, tc.limit) 442 t.Logf(" responseBytes: %d", tc.nBytes) 443 if err := s.snapGetStorageRanges(t, &tc); err != nil { 444 t.Errorf(" failed: %v", err) 445 } 446 } 447 } 448 449 type byteCodesTest struct { 450 nBytes uint64 451 hashes []common.Hash 452 453 expHashes int 454 455 desc string 456 } 457 458 // TestSnapGetByteCodes various forms of GetByteCodes requests. 459 func (s *Suite) TestSnapGetByteCodes(t *utesting.T) { 460 var ( 461 allHashes = s.chain.CodeHashes() 462 headRoot = s.chain.Head().Root() 463 genesisRoot = s.chain.RootAt(0) 464 ) 465 466 tests := []byteCodesTest{ 467 // A few stateroots 468 { 469 desc: `Here we request state roots as code hashes. The server should deliver an empty response with no items.`, 470 nBytes: 10000, 471 hashes: []common.Hash{genesisRoot, headRoot}, 472 expHashes: 0, 473 }, 474 { 475 desc: `Here we request the genesis state root (which is not an existing code hash) two times. The server should deliver an empty response with no items.`, 476 nBytes: 10000, 477 hashes: []common.Hash{genesisRoot, genesisRoot}, 478 expHashes: 0, 479 }, 480 // Empties 481 { 482 desc: `Here we request the empty state root (which is not an existing code hash). The server should deliver an empty response with no items.`, 483 nBytes: 10000, 484 hashes: []common.Hash{types.EmptyRootHash}, 485 expHashes: 0, 486 }, 487 { 488 desc: `Here we request the empty code hash. The server should deliver an empty response item.`, 489 nBytes: 10000, 490 hashes: []common.Hash{types.EmptyCodeHash}, 491 expHashes: 1, 492 }, 493 { 494 desc: `In this test, we request the empty code hash three times. The server should deliver the empty item three times.`, 495 nBytes: 10000, 496 hashes: []common.Hash{types.EmptyCodeHash, types.EmptyCodeHash, types.EmptyCodeHash}, 497 expHashes: 3, 498 }, 499 // The existing bytecodes 500 { 501 desc: `Here we request all available contract codes. The server should deliver them all in one response.`, 502 nBytes: 100000, 503 hashes: allHashes, 504 expHashes: len(allHashes), 505 }, 506 // The existing, with limited byte arg 507 { 508 desc: `In this test, the request has a bytes limit of one. The server should deliver one item.`, 509 nBytes: 1, 510 hashes: allHashes, 511 expHashes: 1, 512 }, 513 { 514 desc: `In this test, the request has a bytes limit of zero. The server should deliver one item.`, 515 nBytes: 0, 516 hashes: allHashes, 517 expHashes: 1, 518 }, 519 // Request the same hash multiple times. 520 { 521 desc: `This test requests the same code hash multiple times. The server should deliver it multiple times.`, 522 nBytes: 1000, 523 hashes: []common.Hash{allHashes[0], allHashes[0], allHashes[0], allHashes[0]}, 524 expHashes: 4, 525 }, 526 } 527 528 for i, tc := range tests { 529 tc := tc 530 if i > 0 { 531 t.Log("\n") 532 } 533 t.Logf("-- Test %d", i) 534 t.Log(tc.desc) 535 t.Log(" request:") 536 t.Logf(" hashes: %x", tc.hashes) 537 t.Logf(" responseBytes: %d", tc.nBytes) 538 if err := s.snapGetByteCodes(t, &tc); err != nil { 539 t.Errorf("failed: %v", err) 540 } 541 } 542 } 543 544 type trieNodesTest struct { 545 root common.Hash 546 paths []snap.TrieNodePathSet 547 nBytes uint64 548 549 expHashes []common.Hash // expected response 550 expReject bool // if true, request should be rejected 551 552 desc string 553 } 554 555 func decodeNibbles(nibbles []byte, bytes []byte) { 556 for bi, ni := 0, 0; ni < len(nibbles); bi, ni = bi+1, ni+2 { 557 bytes[bi] = nibbles[ni]<<4 | nibbles[ni+1] 558 } 559 } 560 561 // hasTerm returns whether a hex key has the terminator flag. 562 func hasTerm(s []byte) bool { 563 return len(s) > 0 && s[len(s)-1] == 16 564 } 565 566 func keybytesToHex(str []byte) []byte { 567 l := len(str)*2 + 1 568 var nibbles = make([]byte, l) 569 for i, b := range str { 570 nibbles[i*2] = b / 16 571 nibbles[i*2+1] = b % 16 572 } 573 nibbles[l-1] = 16 574 return nibbles 575 } 576 577 func hexToCompact(hex []byte) []byte { 578 terminator := byte(0) 579 if hasTerm(hex) { 580 terminator = 1 581 hex = hex[:len(hex)-1] 582 } 583 buf := make([]byte, len(hex)/2+1) 584 buf[0] = terminator << 5 // the flag byte 585 if len(hex)&1 == 1 { 586 buf[0] |= 1 << 4 // odd flag 587 buf[0] |= hex[0] // first nibble is contained in the first byte 588 hex = hex[1:] 589 } 590 decodeNibbles(hex, buf[1:]) 591 return buf 592 } 593 594 // TestSnapTrieNodes various forms of GetTrieNodes requests. 595 func (s *Suite) TestSnapTrieNodes(t *utesting.T) { 596 var ( 597 // This is the known address of the snap storage testing contract. 598 storageAcct = common.HexToAddress("0x8bebc8ba651aee624937e7d897853ac30c95a067") 599 storageAcctHash = common.BytesToHash(s.chain.state[storageAcct].AddressHash) 600 // This is the known address of an existing account. 601 key = common.FromHex("0xa87387b50b481431c6ccdb9ae99a54d4dcdd4a3eff75d7b17b4818f7bbfc21e9") 602 empty = types.EmptyCodeHash 603 accPaths []snap.TrieNodePathSet 604 ) 605 for i := 1; i <= 65; i++ { 606 accPaths = append(accPaths, makeSnapPath(key, i)) 607 } 608 609 tests := []trieNodesTest{ 610 { 611 desc: `In this test, we send an empty request to the node.`, 612 root: s.chain.Head().Root(), 613 paths: nil, 614 nBytes: 500, 615 expHashes: nil, 616 }, 617 618 { 619 desc: `In this test, we send a request containing an empty path-set. 620 The server should reject the request.`, 621 root: s.chain.Head().Root(), 622 paths: []snap.TrieNodePathSet{ 623 {}, // zero-length pathset should 'abort' and kick us off 624 {[]byte{0}}, 625 }, 626 nBytes: 5000, 627 expHashes: []common.Hash{}, 628 expReject: true, 629 }, 630 631 { 632 desc: `Here we request the root node of the trie. The server should respond with the root node.`, 633 root: s.chain.RootAt(int(s.chain.Head().NumberU64() - 1)), 634 paths: []snap.TrieNodePathSet{ 635 {[]byte{0}}, 636 {[]byte{1}, []byte{0}}, 637 }, 638 nBytes: 5000, 639 expHashes: []common.Hash{s.chain.RootAt(int(s.chain.Head().NumberU64() - 1))}, 640 }, 641 642 { // nonsensically long path 643 desc: `In this test, we request a very long trie node path. The server should respond with an empty node (keccak256("")).`, 644 root: s.chain.Head().Root(), 645 paths: []snap.TrieNodePathSet{ 646 {[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 647 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8}}, 648 }, 649 nBytes: 5000, 650 expHashes: []common.Hash{types.EmptyCodeHash}, 651 }, 652 653 { 654 // The leaf is only a couple of levels down, so the continued trie traversal causes lookup failures. 655 desc: `Here we request some known accounts from the state.`, 656 root: s.chain.Head().Root(), 657 paths: accPaths, 658 nBytes: 5000, 659 expHashes: []common.Hash{ 660 // It's a bit unfortunate these are hard-coded, but the result depends on 661 // a lot of aspects of the state trie and can't be guessed in a simple 662 // way. So you'll have to update this when the test chain is changed. 663 common.HexToHash("0x3e963a69401a70224cbfb8c0cc2249b019041a538675d71ccf80c9328d114e2e"), 664 common.HexToHash("0xd0670d09cdfbf3c6320eb3e92c47c57baa6c226551a2d488c05581091e6b1689"), 665 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 666 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 667 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 668 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 669 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 670 empty, empty, empty}, 671 }, 672 673 { 674 desc: `In this test, we request some known accounts in state. The requested paths are NOT in key order.`, 675 root: s.chain.Head().Root(), 676 paths: []snap.TrieNodePathSet{ 677 accPaths[10], accPaths[1], accPaths[0], 678 }, 679 nBytes: 5000, 680 // As with the previous test, this result depends on the whole tree and will have to 681 // be updated when the test chain is changed. 682 expHashes: []common.Hash{ 683 empty, 684 common.HexToHash("0xd0670d09cdfbf3c6320eb3e92c47c57baa6c226551a2d488c05581091e6b1689"), 685 common.HexToHash("0x3e963a69401a70224cbfb8c0cc2249b019041a538675d71ccf80c9328d114e2e"), 686 }, 687 }, 688 689 // Storage tests. 690 // These use the known storage test account. 691 692 { 693 desc: `This test requests the storage root node of a known account.`, 694 root: s.chain.Head().Root(), 695 paths: []snap.TrieNodePathSet{ 696 { 697 storageAcctHash[:], 698 []byte{0}, 699 }, 700 }, 701 nBytes: 5000, 702 expHashes: []common.Hash{ 703 common.HexToHash("0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790"), 704 }, 705 }, 706 707 { 708 desc: `This test requests multiple storage nodes of a known account.`, 709 root: s.chain.Head().Root(), 710 paths: []snap.TrieNodePathSet{ 711 { 712 storageAcctHash[:], 713 []byte{0}, 714 []byte{0x1b}, 715 }, 716 }, 717 nBytes: 5000, 718 expHashes: []common.Hash{ 719 common.HexToHash("0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790"), 720 common.HexToHash("0xf4984a11f61a2921456141df88de6e1a710d28681b91af794c5a721e47839cd7"), 721 }, 722 }, 723 } 724 725 for i, tc := range tests { 726 tc := tc 727 if i > 0 { 728 t.Log("\n") 729 } 730 t.Logf("-- Test %d", i) 731 t.Log(tc.desc) 732 t.Log(" request:") 733 t.Logf(" root: %x", tc.root) 734 t.Logf(" paths: %x", tc.paths) 735 t.Logf(" responseBytes: %d", tc.nBytes) 736 737 if err := s.snapGetTrieNodes(t, &tc); err != nil { 738 t.Errorf(" failed: %v", err) 739 } 740 } 741 } 742 743 func makeSnapPath(key []byte, length int) snap.TrieNodePathSet { 744 hex := keybytesToHex(key)[:length] 745 hex[len(hex)-1] = 0 // remove term flag 746 hKey := hexToCompact(hex) 747 return snap.TrieNodePathSet{hKey} 748 } 749 750 func (s *Suite) snapGetAccountRange(t *utesting.T, tc *accRangeTest) error { 751 conn, err := s.dialSnap() 752 if err != nil { 753 t.Fatalf("dial failed: %v", err) 754 } 755 defer conn.Close() 756 if err = conn.peer(s.chain, nil); err != nil { 757 t.Fatalf("peering failed: %v", err) 758 } 759 // write request 760 req := &snap.GetAccountRangePacket{ 761 ID: uint64(rand.Int63()), 762 Root: tc.root, 763 Origin: tc.startingHash, 764 Limit: tc.limitHash, 765 Bytes: tc.nBytes, 766 } 767 msg, err := conn.snapRequest(snap.GetAccountRangeMsg, req) 768 if err != nil { 769 return fmt.Errorf("account range request failed: %v", err) 770 } 771 res, ok := msg.(*snap.AccountRangePacket) 772 if !ok { 773 return fmt.Errorf("account range response wrong: %T %v", msg, msg) 774 } 775 if exp, got := tc.expAccounts, len(res.Accounts); exp != got { 776 return fmt.Errorf("expected %d accounts, got %d", exp, got) 777 } 778 // Check that the encoding order is correct 779 for i := 1; i < len(res.Accounts); i++ { 780 if bytes.Compare(res.Accounts[i-1].Hash[:], res.Accounts[i].Hash[:]) >= 0 { 781 return fmt.Errorf("accounts not monotonically increasing: #%d [%x] vs #%d [%x]", i-1, res.Accounts[i-1].Hash[:], i, res.Accounts[i].Hash[:]) 782 } 783 } 784 var ( 785 hashes []common.Hash 786 accounts [][]byte 787 proof = res.Proof 788 ) 789 hashes, accounts, err = res.Unpack() 790 if err != nil { 791 return err 792 } 793 if len(hashes) == 0 && len(accounts) == 0 && len(proof) == 0 { 794 return nil 795 } 796 if len(hashes) > 0 { 797 if exp, got := tc.expFirst, res.Accounts[0].Hash; exp != got { 798 return fmt.Errorf("expected first account %#x, got %#x", exp, got) 799 } 800 if exp, got := tc.expLast, res.Accounts[len(res.Accounts)-1].Hash; exp != got { 801 return fmt.Errorf("expected last account %#x, got %#x", exp, got) 802 } 803 } 804 // Reconstruct a partial trie from the response and verify it 805 keys := make([][]byte, len(hashes)) 806 for i, key := range hashes { 807 keys[i] = common.CopyBytes(key[:]) 808 } 809 nodes := make(trienode.ProofList, len(proof)) 810 for i, node := range proof { 811 nodes[i] = node 812 } 813 proofdb := nodes.Set() 814 815 _, err = trie.VerifyRangeProof(tc.root, tc.startingHash[:], keys, accounts, proofdb) 816 return err 817 } 818 819 func (s *Suite) snapGetStorageRanges(t *utesting.T, tc *stRangesTest) error { 820 conn, err := s.dialSnap() 821 if err != nil { 822 t.Fatalf("dial failed: %v", err) 823 } 824 defer conn.Close() 825 if err = conn.peer(s.chain, nil); err != nil { 826 t.Fatalf("peering failed: %v", err) 827 } 828 829 // write request 830 req := &snap.GetStorageRangesPacket{ 831 ID: uint64(rand.Int63()), 832 Root: tc.root, 833 Accounts: tc.accounts, 834 Origin: tc.origin, 835 Limit: tc.limit, 836 Bytes: tc.nBytes, 837 } 838 msg, err := conn.snapRequest(snap.GetStorageRangesMsg, req) 839 if err != nil { 840 return fmt.Errorf("account range request failed: %v", err) 841 } 842 res, ok := msg.(*snap.StorageRangesPacket) 843 if !ok { 844 return fmt.Errorf("account range response wrong: %T %v", msg, msg) 845 } 846 847 // Ensure the ranges are monotonically increasing 848 for i, slots := range res.Slots { 849 for j := 1; j < len(slots); j++ { 850 if bytes.Compare(slots[j-1].Hash[:], slots[j].Hash[:]) >= 0 { 851 return fmt.Errorf("storage slots not monotonically increasing for account #%d: #%d [%x] vs #%d [%x]", i, j-1, slots[j-1].Hash[:], j, slots[j].Hash[:]) 852 } 853 } 854 } 855 856 // Compute expected slot hashes. 857 var expHashes [][]common.Hash 858 for _, acct := range tc.expSlots { 859 var list []common.Hash 860 for _, s := range acct { 861 list = append(list, s.Hash) 862 } 863 expHashes = append(expHashes, list) 864 } 865 866 // Check response. 867 if !reflect.DeepEqual(res.Slots, tc.expSlots) { 868 t.Log(" expected slot hashes:", expHashes) 869 return fmt.Errorf("wrong storage slots in response: %#v", res.Slots) 870 } 871 return nil 872 } 873 874 func (s *Suite) snapGetByteCodes(t *utesting.T, tc *byteCodesTest) error { 875 conn, err := s.dialSnap() 876 if err != nil { 877 t.Fatalf("dial failed: %v", err) 878 } 879 defer conn.Close() 880 if err = conn.peer(s.chain, nil); err != nil { 881 t.Fatalf("peering failed: %v", err) 882 } 883 // write request 884 req := &snap.GetByteCodesPacket{ 885 ID: uint64(rand.Int63()), 886 Hashes: tc.hashes, 887 Bytes: tc.nBytes, 888 } 889 msg, err := conn.snapRequest(snap.GetByteCodesMsg, req) 890 if err != nil { 891 return fmt.Errorf("getBytecodes request failed: %v", err) 892 } 893 res, ok := msg.(*snap.ByteCodesPacket) 894 if !ok { 895 return fmt.Errorf("bytecodes response wrong: %T %v", msg, msg) 896 } 897 if exp, got := tc.expHashes, len(res.Codes); exp != got { 898 for i, c := range res.Codes { 899 t.Logf("%d. %#x\n", i, c) 900 } 901 return fmt.Errorf("expected %d bytecodes, got %d", exp, got) 902 } 903 // Cross reference the requested bytecodes with the response to find gaps 904 // that the serving node is missing 905 var ( 906 bytecodes = res.Codes 907 hasher = crypto.NewKeccakState() 908 hash = make([]byte, 32) 909 codes = make([][]byte, len(req.Hashes)) 910 ) 911 912 for i, j := 0, 0; i < len(bytecodes); i++ { 913 // Find the next hash that we've been served, leaving misses with nils 914 hasher.Reset() 915 hasher.Write(bytecodes[i]) 916 hasher.Read(hash) 917 918 for j < len(req.Hashes) && !bytes.Equal(hash, req.Hashes[j][:]) { 919 j++ 920 } 921 if j < len(req.Hashes) { 922 codes[j] = bytecodes[i] 923 j++ 924 continue 925 } 926 // We've either ran out of hashes, or got unrequested data 927 return errors.New("unexpected bytecode") 928 } 929 930 return nil 931 } 932 933 func (s *Suite) snapGetTrieNodes(t *utesting.T, tc *trieNodesTest) error { 934 conn, err := s.dialSnap() 935 if err != nil { 936 t.Fatalf("dial failed: %v", err) 937 } 938 defer conn.Close() 939 if err = conn.peer(s.chain, nil); err != nil { 940 t.Fatalf("peering failed: %v", err) 941 } 942 943 // write0 request 944 req := &snap.GetTrieNodesPacket{ 945 ID: uint64(rand.Int63()), 946 Root: tc.root, 947 Paths: tc.paths, 948 Bytes: tc.nBytes, 949 } 950 msg, err := conn.snapRequest(snap.GetTrieNodesMsg, req) 951 if err != nil { 952 if tc.expReject { 953 return nil 954 } 955 return fmt.Errorf("trienodes request failed: %v", err) 956 } 957 res, ok := msg.(*snap.TrieNodesPacket) 958 if !ok { 959 return fmt.Errorf("trienodes response wrong: %T %v", msg, msg) 960 } 961 962 // Check the correctness 963 964 // Cross reference the requested trienodes with the response to find gaps 965 // that the serving node is missing 966 hasher := crypto.NewKeccakState() 967 hash := make([]byte, 32) 968 trienodes := res.Nodes 969 if got, want := len(trienodes), len(tc.expHashes); got != want { 970 return fmt.Errorf("wrong trienode count, got %d, want %d", got, want) 971 } 972 for i, trienode := range trienodes { 973 hasher.Reset() 974 hasher.Write(trienode) 975 hasher.Read(hash) 976 if got, want := hash, tc.expHashes[i]; !bytes.Equal(got, want[:]) { 977 t.Logf(" hash %d wrong, got %#x, want %#x\n", i, got, want) 978 err = fmt.Errorf("hash %d wrong, got %#x, want %#x", i, got, want) 979 } 980 } 981 return err 982 }