github.com/ethereum/go-ethereum@v1.16.1/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 if i > 0 { 290 t.Log("\n") 291 } 292 t.Logf("-- Test %d", i) 293 t.Log(tc.desc) 294 t.Log(" request:") 295 t.Logf(" root: %x", tc.root) 296 t.Logf(" range: %#x - %#x", tc.startingHash, tc.limitHash) 297 t.Logf(" responseBytes: %d", tc.nBytes) 298 if err := s.snapGetAccountRange(t, &tc); err != nil { 299 t.Errorf("test %d failed: %v", i, err) 300 } 301 } 302 } 303 304 func hashAdd(h common.Hash, n int64) common.Hash { 305 hb := h.Big() 306 return common.BigToHash(hb.Add(hb, big.NewInt(n))) 307 } 308 309 func findNonEmptyStorageRoot(accounts []state.DumpAccount) common.Hash { 310 for i := range accounts { 311 if len(accounts[i].Storage) != 0 { 312 return common.BytesToHash(accounts[i].Root) 313 } 314 } 315 panic("can't find account with non-empty storage") 316 } 317 318 type stRangesTest struct { 319 root common.Hash 320 accounts []common.Hash 321 origin []byte 322 limit []byte 323 nBytes uint64 324 325 expSlots [][]*snap.StorageData 326 327 desc string 328 } 329 330 // TestSnapGetStorageRanges various forms of GetStorageRanges requests. 331 func (s *Suite) TestSnapGetStorageRanges(t *utesting.T) { 332 var ( 333 acct = common.HexToAddress("0x8bebc8ba651aee624937e7d897853ac30c95a067") 334 acctHash = common.BytesToHash(s.chain.state[acct].AddressHash) 335 ffHash = common.MaxHash 336 zero = common.Hash{} 337 blockroot = s.chain.Head().Root() 338 ) 339 340 // These are the storage slots of the test account, encoded as snap response data. 341 acctSlots := []*snap.StorageData{ 342 { 343 Hash: common.HexToHash("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"), 344 Body: []byte{0x02}, 345 }, 346 { 347 Hash: common.HexToHash("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"), 348 Body: []byte{0x01}, 349 }, 350 { 351 Hash: common.HexToHash("0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b"), 352 Body: []byte{0x03}, 353 }, 354 } 355 356 tests := []stRangesTest{ 357 /* 358 Some tests against this account: 359 360 "0x8bebc8ba651aee624937e7d897853ac30c95a067": { 361 "balance": "1", 362 "nonce": 1, 363 "root": "0xe318dff15b33aa7f2f12d5567d58628e3e3f2e8859e46b56981a4083b391da17", 364 "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", 365 "storage": { 366 // Note: keys below are hashed!!! 367 "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace": "02", 368 "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": "01", 369 "0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b": "03" 370 }, 371 "key": "0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099" 372 } 373 */ 374 375 { // [:] -> [slot1, slot2, slot3] 376 desc: `This request has a range of 00..ff. 377 The server should return all storage slots of the test account.`, 378 root: blockroot, 379 accounts: []common.Hash{acctHash}, 380 origin: zero[:], 381 limit: ffHash[:], 382 nBytes: 500, 383 expSlots: [][]*snap.StorageData{acctSlots}, 384 }, 385 386 { // [slot1:] -> [slot1, slot2, slot3] 387 desc: `This test requests slots starting at the first available key. 388 The server should return all storage slots of the test account.`, 389 root: blockroot, 390 accounts: []common.Hash{acctHash}, 391 origin: common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"), 392 limit: ffHash[:], 393 nBytes: 1000, 394 expSlots: [][]*snap.StorageData{acctSlots}, 395 }, 396 397 { // [slot1+:] -> [slot2, slot3] 398 desc: `This test requests slots starting at a key one past the first available key. 399 The server should return the remaining two slots of the test account.`, 400 root: blockroot, 401 accounts: []common.Hash{acctHash}, 402 origin: common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf"), 403 limit: ffHash[:], 404 nBytes: 500, 405 expSlots: [][]*snap.StorageData{acctSlots[1:]}, 406 }, 407 408 { // [slot1:slot2] -> [slot1, slot2] 409 desc: `This test requests a range which is exactly the first and second available key.`, 410 root: blockroot, 411 accounts: []common.Hash{acctHash}, 412 origin: common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"), 413 limit: common.FromHex("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"), 414 nBytes: 500, 415 expSlots: [][]*snap.StorageData{acctSlots[:2]}, 416 }, 417 418 { // [slot1+:slot2+] -> [slot2, slot3] 419 desc: `This test requests a range where limitHash is after the second, but before the third slot 420 of the test account. The server should return slots [2,3] (i.e. the 'next available' needs to be returned).`, 421 root: blockroot, 422 accounts: []common.Hash{acctHash}, 423 origin: common.FromHex("0x4fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 424 limit: common.FromHex("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7"), 425 nBytes: 500, 426 expSlots: [][]*snap.StorageData{acctSlots[1:]}, 427 }, 428 } 429 430 for i, tc := range tests { 431 if i > 0 { 432 t.Log("\n") 433 } 434 t.Logf("-- Test %d", i) 435 t.Log(tc.desc) 436 t.Log(" request:") 437 t.Logf(" root: %x", tc.root) 438 t.Logf(" accounts: %x", tc.accounts) 439 t.Logf(" range: %#x - %#x", tc.origin, tc.limit) 440 t.Logf(" responseBytes: %d", tc.nBytes) 441 if err := s.snapGetStorageRanges(t, &tc); err != nil { 442 t.Errorf(" failed: %v", err) 443 } 444 } 445 } 446 447 type byteCodesTest struct { 448 nBytes uint64 449 hashes []common.Hash 450 451 expHashes int 452 453 desc string 454 } 455 456 // TestSnapGetByteCodes various forms of GetByteCodes requests. 457 func (s *Suite) TestSnapGetByteCodes(t *utesting.T) { 458 var ( 459 allHashes = s.chain.CodeHashes() 460 headRoot = s.chain.Head().Root() 461 genesisRoot = s.chain.RootAt(0) 462 ) 463 464 tests := []byteCodesTest{ 465 // A few stateroots 466 { 467 desc: `Here we request state roots as code hashes. The server should deliver an empty response with no items.`, 468 nBytes: 10000, 469 hashes: []common.Hash{genesisRoot, headRoot}, 470 expHashes: 0, 471 }, 472 { 473 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.`, 474 nBytes: 10000, 475 hashes: []common.Hash{genesisRoot, genesisRoot}, 476 expHashes: 0, 477 }, 478 // Empties 479 { 480 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.`, 481 nBytes: 10000, 482 hashes: []common.Hash{types.EmptyRootHash}, 483 expHashes: 0, 484 }, 485 { 486 desc: `Here we request the empty code hash. The server should deliver an empty response item.`, 487 nBytes: 10000, 488 hashes: []common.Hash{types.EmptyCodeHash}, 489 expHashes: 1, 490 }, 491 { 492 desc: `In this test, we request the empty code hash three times. The server should deliver the empty item three times.`, 493 nBytes: 10000, 494 hashes: []common.Hash{types.EmptyCodeHash, types.EmptyCodeHash, types.EmptyCodeHash}, 495 expHashes: 3, 496 }, 497 // The existing bytecodes 498 { 499 desc: `Here we request all available contract codes. The server should deliver them all in one response.`, 500 nBytes: 100000, 501 hashes: allHashes, 502 expHashes: len(allHashes), 503 }, 504 // The existing, with limited byte arg 505 { 506 desc: `In this test, the request has a bytes limit of one. The server should deliver one item.`, 507 nBytes: 1, 508 hashes: allHashes, 509 expHashes: 1, 510 }, 511 { 512 desc: `In this test, the request has a bytes limit of zero. The server should deliver one item.`, 513 nBytes: 0, 514 hashes: allHashes, 515 expHashes: 1, 516 }, 517 // Request the same hash multiple times. 518 { 519 desc: `This test requests the same code hash multiple times. The server should deliver it multiple times.`, 520 nBytes: 1000, 521 hashes: []common.Hash{allHashes[0], allHashes[0], allHashes[0], allHashes[0]}, 522 expHashes: 4, 523 }, 524 } 525 526 for i, tc := range tests { 527 if i > 0 { 528 t.Log("\n") 529 } 530 t.Logf("-- Test %d", i) 531 t.Log(tc.desc) 532 t.Log(" request:") 533 t.Logf(" hashes: %x", tc.hashes) 534 t.Logf(" responseBytes: %d", tc.nBytes) 535 if err := s.snapGetByteCodes(t, &tc); err != nil { 536 t.Errorf("failed: %v", err) 537 } 538 } 539 } 540 541 type trieNodesTest struct { 542 root common.Hash 543 paths []snap.TrieNodePathSet 544 nBytes uint64 545 546 expHashes []common.Hash // expected response 547 expReject bool // if true, request should be rejected 548 549 desc string 550 } 551 552 func decodeNibbles(nibbles []byte, bytes []byte) { 553 for bi, ni := 0, 0; ni < len(nibbles); bi, ni = bi+1, ni+2 { 554 bytes[bi] = nibbles[ni]<<4 | nibbles[ni+1] 555 } 556 } 557 558 // hasTerm returns whether a hex key has the terminator flag. 559 func hasTerm(s []byte) bool { 560 return len(s) > 0 && s[len(s)-1] == 16 561 } 562 563 func keybytesToHex(str []byte) []byte { 564 l := len(str)*2 + 1 565 var nibbles = make([]byte, l) 566 for i, b := range str { 567 nibbles[i*2] = b / 16 568 nibbles[i*2+1] = b % 16 569 } 570 nibbles[l-1] = 16 571 return nibbles 572 } 573 574 func hexToCompact(hex []byte) []byte { 575 terminator := byte(0) 576 if hasTerm(hex) { 577 terminator = 1 578 hex = hex[:len(hex)-1] 579 } 580 buf := make([]byte, len(hex)/2+1) 581 buf[0] = terminator << 5 // the flag byte 582 if len(hex)&1 == 1 { 583 buf[0] |= 1 << 4 // odd flag 584 buf[0] |= hex[0] // first nibble is contained in the first byte 585 hex = hex[1:] 586 } 587 decodeNibbles(hex, buf[1:]) 588 return buf 589 } 590 591 // TestSnapTrieNodes various forms of GetTrieNodes requests. 592 func (s *Suite) TestSnapTrieNodes(t *utesting.T) { 593 var ( 594 // This is the known address of the snap storage testing contract. 595 storageAcct = common.HexToAddress("0x8bebc8ba651aee624937e7d897853ac30c95a067") 596 storageAcctHash = common.BytesToHash(s.chain.state[storageAcct].AddressHash) 597 // This is the known address of an existing account. 598 key = common.FromHex("0xa87387b50b481431c6ccdb9ae99a54d4dcdd4a3eff75d7b17b4818f7bbfc21e9") 599 empty = types.EmptyCodeHash 600 accPaths []snap.TrieNodePathSet 601 ) 602 for i := 1; i <= 65; i++ { 603 accPaths = append(accPaths, makeSnapPath(key, i)) 604 } 605 606 tests := []trieNodesTest{ 607 { 608 desc: `In this test, we send an empty request to the node.`, 609 root: s.chain.Head().Root(), 610 paths: nil, 611 nBytes: 500, 612 expHashes: nil, 613 }, 614 615 { 616 desc: `In this test, we send a request containing an empty path-set. 617 The server should reject the request.`, 618 root: s.chain.Head().Root(), 619 paths: []snap.TrieNodePathSet{ 620 {}, // zero-length pathset should 'abort' and kick us off 621 {[]byte{0}}, 622 }, 623 nBytes: 5000, 624 expHashes: []common.Hash{}, 625 expReject: true, 626 }, 627 628 { 629 desc: `Here we request the root node of the trie. The server should respond with the root node.`, 630 root: s.chain.RootAt(int(s.chain.Head().NumberU64() - 1)), 631 paths: []snap.TrieNodePathSet{ 632 {[]byte{0}}, 633 {[]byte{1}, []byte{0}}, 634 }, 635 nBytes: 5000, 636 expHashes: []common.Hash{s.chain.RootAt(int(s.chain.Head().NumberU64() - 1))}, 637 }, 638 639 { // nonsensically long path 640 desc: `In this test, we request a very long trie node path. The server should respond with an empty node (keccak256("")).`, 641 root: s.chain.Head().Root(), 642 paths: []snap.TrieNodePathSet{ 643 {[]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, 644 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}}, 645 }, 646 nBytes: 5000, 647 expHashes: []common.Hash{types.EmptyCodeHash}, 648 }, 649 650 { 651 // The leaf is only a couple of levels down, so the continued trie traversal causes lookup failures. 652 desc: `Here we request some known accounts from the state.`, 653 root: s.chain.Head().Root(), 654 paths: accPaths, 655 nBytes: 5000, 656 expHashes: []common.Hash{ 657 // It's a bit unfortunate these are hard-coded, but the result depends on 658 // a lot of aspects of the state trie and can't be guessed in a simple 659 // way. So you'll have to update this when the test chain is changed. 660 common.HexToHash("0x3e963a69401a70224cbfb8c0cc2249b019041a538675d71ccf80c9328d114e2e"), 661 common.HexToHash("0xd0670d09cdfbf3c6320eb3e92c47c57baa6c226551a2d488c05581091e6b1689"), 662 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 663 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 664 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 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}, 668 }, 669 670 { 671 desc: `In this test, we request some known accounts in state. The requested paths are NOT in key order.`, 672 root: s.chain.Head().Root(), 673 paths: []snap.TrieNodePathSet{ 674 accPaths[10], accPaths[1], accPaths[0], 675 }, 676 nBytes: 5000, 677 // As with the previous test, this result depends on the whole tree and will have to 678 // be updated when the test chain is changed. 679 expHashes: []common.Hash{ 680 empty, 681 common.HexToHash("0xd0670d09cdfbf3c6320eb3e92c47c57baa6c226551a2d488c05581091e6b1689"), 682 common.HexToHash("0x3e963a69401a70224cbfb8c0cc2249b019041a538675d71ccf80c9328d114e2e"), 683 }, 684 }, 685 686 // Storage tests. 687 // These use the known storage test account. 688 689 { 690 desc: `This test requests the storage root node of a known account.`, 691 root: s.chain.Head().Root(), 692 paths: []snap.TrieNodePathSet{ 693 { 694 storageAcctHash[:], 695 []byte{0}, 696 }, 697 }, 698 nBytes: 5000, 699 expHashes: []common.Hash{ 700 common.HexToHash("0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790"), 701 }, 702 }, 703 704 { 705 desc: `This test requests multiple storage nodes of a known account.`, 706 root: s.chain.Head().Root(), 707 paths: []snap.TrieNodePathSet{ 708 { 709 storageAcctHash[:], 710 []byte{0}, 711 []byte{0x1b}, 712 }, 713 }, 714 nBytes: 5000, 715 expHashes: []common.Hash{ 716 common.HexToHash("0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790"), 717 common.HexToHash("0xf4984a11f61a2921456141df88de6e1a710d28681b91af794c5a721e47839cd7"), 718 }, 719 }, 720 } 721 722 for i, tc := range tests { 723 if i > 0 { 724 t.Log("\n") 725 } 726 t.Logf("-- Test %d", i) 727 t.Log(tc.desc) 728 t.Log(" request:") 729 t.Logf(" root: %x", tc.root) 730 t.Logf(" paths: %x", tc.paths) 731 t.Logf(" responseBytes: %d", tc.nBytes) 732 733 if err := s.snapGetTrieNodes(t, &tc); err != nil { 734 t.Errorf(" failed: %v", err) 735 } 736 } 737 } 738 739 func makeSnapPath(key []byte, length int) snap.TrieNodePathSet { 740 hex := keybytesToHex(key)[:length] 741 hex[len(hex)-1] = 0 // remove term flag 742 hKey := hexToCompact(hex) 743 return snap.TrieNodePathSet{hKey} 744 } 745 746 func (s *Suite) snapGetAccountRange(t *utesting.T, tc *accRangeTest) error { 747 conn, err := s.dialSnap() 748 if err != nil { 749 t.Fatalf("dial failed: %v", err) 750 } 751 defer conn.Close() 752 if err = conn.peer(s.chain, nil); err != nil { 753 t.Fatalf("peering failed: %v", err) 754 } 755 // write request 756 req := &snap.GetAccountRangePacket{ 757 ID: uint64(rand.Int63()), 758 Root: tc.root, 759 Origin: tc.startingHash, 760 Limit: tc.limitHash, 761 Bytes: tc.nBytes, 762 } 763 msg, err := conn.snapRequest(snap.GetAccountRangeMsg, req) 764 if err != nil { 765 return fmt.Errorf("account range request failed: %v", err) 766 } 767 res, ok := msg.(*snap.AccountRangePacket) 768 if !ok { 769 return fmt.Errorf("account range response wrong: %T %v", msg, msg) 770 } 771 if exp, got := tc.expAccounts, len(res.Accounts); exp != got { 772 return fmt.Errorf("expected %d accounts, got %d", exp, got) 773 } 774 // Check that the encoding order is correct 775 for i := 1; i < len(res.Accounts); i++ { 776 if bytes.Compare(res.Accounts[i-1].Hash[:], res.Accounts[i].Hash[:]) >= 0 { 777 return fmt.Errorf("accounts not monotonically increasing: #%d [%x] vs #%d [%x]", i-1, res.Accounts[i-1].Hash[:], i, res.Accounts[i].Hash[:]) 778 } 779 } 780 var ( 781 hashes []common.Hash 782 accounts [][]byte 783 proof = res.Proof 784 ) 785 hashes, accounts, err = res.Unpack() 786 if err != nil { 787 return err 788 } 789 if len(hashes) == 0 && len(accounts) == 0 && len(proof) == 0 { 790 return nil 791 } 792 if len(hashes) > 0 { 793 if exp, got := tc.expFirst, res.Accounts[0].Hash; exp != got { 794 return fmt.Errorf("expected first account %#x, got %#x", exp, got) 795 } 796 if exp, got := tc.expLast, res.Accounts[len(res.Accounts)-1].Hash; exp != got { 797 return fmt.Errorf("expected last account %#x, got %#x", exp, got) 798 } 799 } 800 // Reconstruct a partial trie from the response and verify it 801 keys := make([][]byte, len(hashes)) 802 for i, key := range hashes { 803 keys[i] = common.CopyBytes(key[:]) 804 } 805 nodes := make(trienode.ProofList, len(proof)) 806 for i, node := range proof { 807 nodes[i] = node 808 } 809 proofdb := nodes.Set() 810 811 _, err = trie.VerifyRangeProof(tc.root, tc.startingHash[:], keys, accounts, proofdb) 812 return err 813 } 814 815 func (s *Suite) snapGetStorageRanges(t *utesting.T, tc *stRangesTest) error { 816 conn, err := s.dialSnap() 817 if err != nil { 818 t.Fatalf("dial failed: %v", err) 819 } 820 defer conn.Close() 821 if err = conn.peer(s.chain, nil); err != nil { 822 t.Fatalf("peering failed: %v", err) 823 } 824 825 // write request 826 req := &snap.GetStorageRangesPacket{ 827 ID: uint64(rand.Int63()), 828 Root: tc.root, 829 Accounts: tc.accounts, 830 Origin: tc.origin, 831 Limit: tc.limit, 832 Bytes: tc.nBytes, 833 } 834 msg, err := conn.snapRequest(snap.GetStorageRangesMsg, req) 835 if err != nil { 836 return fmt.Errorf("account range request failed: %v", err) 837 } 838 res, ok := msg.(*snap.StorageRangesPacket) 839 if !ok { 840 return fmt.Errorf("account range response wrong: %T %v", msg, msg) 841 } 842 843 // Ensure the ranges are monotonically increasing 844 for i, slots := range res.Slots { 845 for j := 1; j < len(slots); j++ { 846 if bytes.Compare(slots[j-1].Hash[:], slots[j].Hash[:]) >= 0 { 847 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[:]) 848 } 849 } 850 } 851 852 // Compute expected slot hashes. 853 var expHashes [][]common.Hash 854 for _, acct := range tc.expSlots { 855 var list []common.Hash 856 for _, s := range acct { 857 list = append(list, s.Hash) 858 } 859 expHashes = append(expHashes, list) 860 } 861 862 // Check response. 863 if !reflect.DeepEqual(res.Slots, tc.expSlots) { 864 t.Log(" expected slot hashes:", expHashes) 865 return fmt.Errorf("wrong storage slots in response: %#v", res.Slots) 866 } 867 return nil 868 } 869 870 func (s *Suite) snapGetByteCodes(t *utesting.T, tc *byteCodesTest) error { 871 conn, err := s.dialSnap() 872 if err != nil { 873 t.Fatalf("dial failed: %v", err) 874 } 875 defer conn.Close() 876 if err = conn.peer(s.chain, nil); err != nil { 877 t.Fatalf("peering failed: %v", err) 878 } 879 // write request 880 req := &snap.GetByteCodesPacket{ 881 ID: uint64(rand.Int63()), 882 Hashes: tc.hashes, 883 Bytes: tc.nBytes, 884 } 885 msg, err := conn.snapRequest(snap.GetByteCodesMsg, req) 886 if err != nil { 887 return fmt.Errorf("getBytecodes request failed: %v", err) 888 } 889 res, ok := msg.(*snap.ByteCodesPacket) 890 if !ok { 891 return fmt.Errorf("bytecodes response wrong: %T %v", msg, msg) 892 } 893 if exp, got := tc.expHashes, len(res.Codes); exp != got { 894 for i, c := range res.Codes { 895 t.Logf("%d. %#x\n", i, c) 896 } 897 return fmt.Errorf("expected %d bytecodes, got %d", exp, got) 898 } 899 // Cross reference the requested bytecodes with the response to find gaps 900 // that the serving node is missing 901 var ( 902 bytecodes = res.Codes 903 hasher = crypto.NewKeccakState() 904 hash = make([]byte, 32) 905 codes = make([][]byte, len(req.Hashes)) 906 ) 907 908 for i, j := 0, 0; i < len(bytecodes); i++ { 909 // Find the next hash that we've been served, leaving misses with nils 910 hasher.Reset() 911 hasher.Write(bytecodes[i]) 912 hasher.Read(hash) 913 914 for j < len(req.Hashes) && !bytes.Equal(hash, req.Hashes[j][:]) { 915 j++ 916 } 917 if j < len(req.Hashes) { 918 codes[j] = bytecodes[i] 919 j++ 920 continue 921 } 922 // We've either ran out of hashes, or got unrequested data 923 return errors.New("unexpected bytecode") 924 } 925 926 return nil 927 } 928 929 func (s *Suite) snapGetTrieNodes(t *utesting.T, tc *trieNodesTest) error { 930 conn, err := s.dialSnap() 931 if err != nil { 932 t.Fatalf("dial failed: %v", err) 933 } 934 defer conn.Close() 935 if err = conn.peer(s.chain, nil); err != nil { 936 t.Fatalf("peering failed: %v", err) 937 } 938 939 // write0 request 940 req := &snap.GetTrieNodesPacket{ 941 ID: uint64(rand.Int63()), 942 Root: tc.root, 943 Paths: tc.paths, 944 Bytes: tc.nBytes, 945 } 946 msg, err := conn.snapRequest(snap.GetTrieNodesMsg, req) 947 if err != nil { 948 if tc.expReject { 949 return nil 950 } 951 return fmt.Errorf("trienodes request failed: %v", err) 952 } 953 res, ok := msg.(*snap.TrieNodesPacket) 954 if !ok { 955 return fmt.Errorf("trienodes response wrong: %T %v", msg, msg) 956 } 957 958 // Check the correctness 959 960 // Cross reference the requested trienodes with the response to find gaps 961 // that the serving node is missing 962 hasher := crypto.NewKeccakState() 963 hash := make([]byte, 32) 964 trienodes := res.Nodes 965 if got, want := len(trienodes), len(tc.expHashes); got != want { 966 return fmt.Errorf("wrong trienode count, got %d, want %d", got, want) 967 } 968 for i, trienode := range trienodes { 969 hasher.Reset() 970 hasher.Write(trienode) 971 hasher.Read(hash) 972 if got, want := hash, tc.expHashes[i]; !bytes.Equal(got, want[:]) { 973 t.Logf(" hash %d wrong, got %#x, want %#x\n", i, got, want) 974 err = fmt.Errorf("hash %d wrong, got %#x, want %#x", i, got, want) 975 } 976 } 977 return err 978 }