github.com/calmw/ethereum@v0.1.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/rand" 24 25 "github.com/calmw/ethereum/common" 26 "github.com/calmw/ethereum/core/types" 27 "github.com/calmw/ethereum/crypto" 28 "github.com/calmw/ethereum/eth/protocols/snap" 29 "github.com/calmw/ethereum/internal/utesting" 30 "github.com/calmw/ethereum/light" 31 "github.com/calmw/ethereum/trie" 32 "golang.org/x/crypto/sha3" 33 ) 34 35 func (s *Suite) TestSnapStatus(t *utesting.T) { 36 conn, err := s.dialSnap() 37 if err != nil { 38 t.Fatalf("dial failed: %v", err) 39 } 40 defer conn.Close() 41 if err := conn.peer(s.chain, nil); err != nil { 42 t.Fatalf("peering failed: %v", err) 43 } 44 } 45 46 type accRangeTest struct { 47 nBytes uint64 48 root common.Hash 49 origin common.Hash 50 limit common.Hash 51 52 expAccounts int 53 expFirst common.Hash 54 expLast common.Hash 55 } 56 57 // TestSnapGetAccountRange various forms of GetAccountRange requests. 58 func (s *Suite) TestSnapGetAccountRange(t *utesting.T) { 59 var ( 60 root = s.chain.RootAt(999) 61 ffHash = common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") 62 zero = common.Hash{} 63 firstKeyMinus1 = common.HexToHash("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf29") 64 firstKey = common.HexToHash("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a") 65 firstKeyPlus1 = common.HexToHash("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2b") 66 secondKey = common.HexToHash("0x09e47cd5056a689e708f22fe1f932709a320518e444f5f7d8d46a3da523d6606") 67 storageRoot = common.HexToHash("0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790") 68 ) 69 for i, tc := range []accRangeTest{ 70 // Tests decreasing the number of bytes 71 {4000, root, zero, ffHash, 76, firstKey, common.HexToHash("0xd2669dcf3858e7f1eecb8b5fedbf22fbea3e9433848a75035f79d68422c2dcda")}, 72 {3000, root, zero, ffHash, 57, firstKey, common.HexToHash("0x9b63fa753ece5cb90657d02ecb15df4dc1508d8c1d187af1bf7f1a05e747d3c7")}, 73 {2000, root, zero, ffHash, 38, firstKey, common.HexToHash("0x5e6140ecae4354a9e8f47559a8c6209c1e0e69cb077b067b528556c11698b91f")}, 74 {1, root, zero, ffHash, 1, firstKey, firstKey}, 75 76 // Tests variations of the range 77 // 78 // [00b to firstkey]: should return [firstkey, secondkey], where secondkey is out of bounds 79 {4000, root, common.HexToHash("0x00bf000000000000000000000000000000000000000000000000000000000000"), common.HexToHash("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2b"), 2, firstKey, secondKey}, 80 // [00b0 to 0bf0]: where both are before firstkey. Should return firstKey (even though it's out of bounds) 81 {4000, root, common.HexToHash("0x00b0000000000000000000000000000000000000000000000000000000000000"), common.HexToHash("0x00bf100000000000000000000000000000000000000000000000000000000000"), 1, firstKey, firstKey}, 82 {4000, root, zero, zero, 1, firstKey, firstKey}, 83 {4000, root, firstKey, ffHash, 76, firstKey, common.HexToHash("0xd2669dcf3858e7f1eecb8b5fedbf22fbea3e9433848a75035f79d68422c2dcda")}, 84 {4000, root, firstKeyPlus1, ffHash, 76, secondKey, common.HexToHash("0xd28f55d3b994f16389f36944ad685b48e0fc3f8fbe86c3ca92ebecadf16a783f")}, 85 86 // Test different root hashes 87 // 88 // A stateroot that does not exist 89 {4000, common.Hash{0x13, 37}, zero, ffHash, 0, zero, zero}, 90 // The genesis stateroot (we expect it to not be served) 91 {4000, s.chain.RootAt(0), zero, ffHash, 0, zero, zero}, 92 // A 127 block old stateroot, expected to be served 93 {4000, s.chain.RootAt(999 - 127), zero, ffHash, 77, firstKey, common.HexToHash("0xe4c6fdef5dd4e789a2612390806ee840b8ec0fe52548f8b4efe41abb20c37aac")}, 94 // A root which is not actually an account root, but a storage root 95 {4000, storageRoot, zero, ffHash, 0, zero, zero}, 96 97 // And some non-sensical requests 98 // 99 // range from [0xFF to 0x00], wrong order. Expect not to be serviced 100 {4000, root, ffHash, zero, 0, zero, zero}, 101 // range from [firstkey, firstkey-1], wrong order. Expect to get first key. 102 {4000, root, firstKey, firstKeyMinus1, 1, firstKey, firstKey}, 103 // range from [firstkey, 0], wrong order. Expect to get first key. 104 {4000, root, firstKey, zero, 1, firstKey, firstKey}, 105 // Max bytes: 0. Expect to deliver one account. 106 {0, root, zero, ffHash, 1, firstKey, firstKey}, 107 } { 108 tc := tc 109 if err := s.snapGetAccountRange(t, &tc); err != nil { 110 t.Errorf("test %d \n root: %x\n range: %#x - %#x\n bytes: %d\nfailed: %v", i, tc.root, tc.origin, tc.limit, tc.nBytes, err) 111 } 112 } 113 } 114 115 type stRangesTest struct { 116 root common.Hash 117 accounts []common.Hash 118 origin []byte 119 limit []byte 120 nBytes uint64 121 122 expSlots int 123 } 124 125 // TestSnapGetStorageRanges various forms of GetStorageRanges requests. 126 func (s *Suite) TestSnapGetStorageRanges(t *utesting.T) { 127 var ( 128 ffHash = common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") 129 zero = common.Hash{} 130 firstKey = common.HexToHash("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a") 131 secondKey = common.HexToHash("0x09e47cd5056a689e708f22fe1f932709a320518e444f5f7d8d46a3da523d6606") 132 ) 133 for i, tc := range []stRangesTest{ 134 { 135 root: s.chain.RootAt(999), 136 accounts: []common.Hash{secondKey, firstKey}, 137 origin: zero[:], 138 limit: ffHash[:], 139 nBytes: 500, 140 expSlots: 0, 141 }, 142 143 /* 144 Some tests against this account: 145 { 146 "balance": "0", 147 "nonce": 1, 148 "root": "0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790", 149 "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", 150 "storage": { 151 "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace": "02", 152 "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": "01", 153 "0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b": "03" 154 }, 155 "key": "0xf493f79c43bd747129a226ad42529885a4b108aba6046b2d12071695a6627844" 156 } 157 */ 158 { // [:] -> [slot1, slot2, slot3] 159 root: s.chain.RootAt(999), 160 accounts: []common.Hash{common.HexToHash("0xf493f79c43bd747129a226ad42529885a4b108aba6046b2d12071695a6627844")}, 161 origin: zero[:], 162 limit: ffHash[:], 163 nBytes: 500, 164 expSlots: 3, 165 }, 166 { // [slot1:] -> [slot1, slot2, slot3] 167 root: s.chain.RootAt(999), 168 accounts: []common.Hash{common.HexToHash("0xf493f79c43bd747129a226ad42529885a4b108aba6046b2d12071695a6627844")}, 169 origin: common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"), 170 limit: ffHash[:], 171 nBytes: 500, 172 expSlots: 3, 173 }, 174 { // [slot1+ :] -> [slot2, slot3] 175 root: s.chain.RootAt(999), 176 accounts: []common.Hash{common.HexToHash("0xf493f79c43bd747129a226ad42529885a4b108aba6046b2d12071695a6627844")}, 177 origin: common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf"), 178 limit: ffHash[:], 179 nBytes: 500, 180 expSlots: 2, 181 }, 182 { // [slot1:slot2] -> [slot1, slot2] 183 root: s.chain.RootAt(999), 184 accounts: []common.Hash{common.HexToHash("0xf493f79c43bd747129a226ad42529885a4b108aba6046b2d12071695a6627844")}, 185 origin: common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"), 186 limit: common.FromHex("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"), 187 nBytes: 500, 188 expSlots: 2, 189 }, 190 { // [slot1+:slot2+] -> [slot2, slot3] 191 root: s.chain.RootAt(999), 192 accounts: []common.Hash{common.HexToHash("0xf493f79c43bd747129a226ad42529885a4b108aba6046b2d12071695a6627844")}, 193 origin: common.FromHex("0x4fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 194 limit: common.FromHex("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7"), 195 nBytes: 500, 196 expSlots: 2, 197 }, 198 } { 199 tc := tc 200 if err := s.snapGetStorageRanges(t, &tc); err != nil { 201 t.Errorf("test %d \n root: %x\n range: %#x - %#x\n bytes: %d\n #accounts: %d\nfailed: %v", 202 i, tc.root, tc.origin, tc.limit, tc.nBytes, len(tc.accounts), err) 203 } 204 } 205 } 206 207 type byteCodesTest struct { 208 nBytes uint64 209 hashes []common.Hash 210 211 expHashes int 212 } 213 214 // TestSnapGetByteCodes various forms of GetByteCodes requests. 215 func (s *Suite) TestSnapGetByteCodes(t *utesting.T) { 216 // The halfchain import should yield these bytecodes 217 var hcBytecodes []common.Hash 218 for _, s := range []string{ 219 "0x200c90460d8b0063210d5f5b9918e053c8f2c024485e0f1b48be8b1fc71b1317", 220 "0x20ba67ed4ac6aff626e0d1d4db623e2fada9593daeefc4a6eb4b70e6cff986f3", 221 "0x24b5b4902cb3d897c1cee9f16be8e897d8fa277c04c6dc8214f18295fca5de44", 222 "0x320b9d0a2be39b8a1c858f9f8cb96b1df0983071681de07ded3a7c0d05db5fd6", 223 "0x48cb0d5275936a24632babc7408339f9f7b051274809de565b8b0db76e97e03c", 224 "0x67c7a6f5cdaa43b4baa0e15b2be63346d1b9ce9f2c3d7e5804e0cacd44ee3b04", 225 "0x6d8418059bdc8c3fabf445e6bfc662af3b6a4ae45999b953996e42c7ead2ab49", 226 "0x7043422e5795d03f17ee0463a37235258e609fdd542247754895d72695e3e142", 227 "0x727f9e6f0c4bac1ff8d72c2972122d9c8d37ccb37e04edde2339e8da193546f1", 228 "0x86ccd5e23c78568a8334e0cebaf3e9f48c998307b0bfb1c378cee83b4bfb29cb", 229 "0x8fc89b00d6deafd4c4279531e743365626dbfa28845ec697919d305c2674302d", 230 "0x92cfc353bcb9746bb6f9996b6b9df779c88af2e9e0eeac44879ca19887c9b732", 231 "0x941b4872104f0995a4898fcf0f615ea6bf46bfbdfcf63ea8f2fd45b3f3286b77", 232 "0xa02fe8f41159bb39d2b704c633c3d6389cf4bfcb61a2539a9155f60786cf815f", 233 "0xa4b94e0afdffcb0af599677709dac067d3145489ea7aede57672bee43e3b7373", 234 "0xaf4e64edd3234c1205b725e42963becd1085f013590bd7ed93f8d711c5eb65fb", 235 "0xb69a18fa855b742031420081999086f6fb56c3930ae8840944e8b8ae9931c51e", 236 "0xc246c217bc73ce6666c93a93a94faa5250564f50a3fdc27ea74c231c07fe2ca6", 237 "0xcd6e4ab2c3034df2a8a1dfaaeb1c4baecd162a93d22de35e854ee2945cbe0c35", 238 "0xe24b692d09d6fc2f3d1a6028c400a27c37d7cbb11511907c013946d6ce263d3b", 239 "0xe440c5f0e8603fd1ed25976eee261ccee8038cf79d6a4c0eb31b2bf883be737f", 240 "0xe6eacbc509203d21ac814b350e72934fde686b7f673c19be8cf956b0c70078ce", 241 "0xe8530de4371467b5be7ea0e69e675ab36832c426d6c1ce9513817c0f0ae1486b", 242 "0xe85d487abbbc83bf3423cf9731360cf4f5a37220e18e5add54e72ee20861196a", 243 "0xf195ea389a5eea28db0be93660014275b158963dec44af1dfa7d4743019a9a49", 244 } { 245 hcBytecodes = append(hcBytecodes, common.HexToHash(s)) 246 } 247 248 for i, tc := range []byteCodesTest{ 249 // A few stateroots 250 { 251 nBytes: 10000, hashes: []common.Hash{s.chain.RootAt(0), s.chain.RootAt(999)}, 252 expHashes: 0, 253 }, 254 { 255 nBytes: 10000, hashes: []common.Hash{s.chain.RootAt(0), s.chain.RootAt(0)}, 256 expHashes: 0, 257 }, 258 // Empties 259 { 260 nBytes: 10000, hashes: []common.Hash{types.EmptyRootHash}, 261 expHashes: 0, 262 }, 263 { 264 nBytes: 10000, hashes: []common.Hash{types.EmptyCodeHash}, 265 expHashes: 1, 266 }, 267 { 268 nBytes: 10000, hashes: []common.Hash{types.EmptyCodeHash, types.EmptyCodeHash, types.EmptyCodeHash}, 269 expHashes: 3, 270 }, 271 // The existing bytecodes 272 { 273 nBytes: 10000, hashes: hcBytecodes, 274 expHashes: len(hcBytecodes), 275 }, 276 // The existing, with limited byte arg 277 { 278 nBytes: 1, hashes: hcBytecodes, 279 expHashes: 1, 280 }, 281 { 282 nBytes: 0, hashes: hcBytecodes, 283 expHashes: 1, 284 }, 285 { 286 nBytes: 1000, hashes: []common.Hash{hcBytecodes[0], hcBytecodes[0], hcBytecodes[0], hcBytecodes[0]}, 287 expHashes: 4, 288 }, 289 } { 290 tc := tc 291 if err := s.snapGetByteCodes(t, &tc); err != nil { 292 t.Errorf("test %d \n bytes: %d\n #hashes: %d\nfailed: %v", i, tc.nBytes, len(tc.hashes), err) 293 } 294 } 295 } 296 297 type trieNodesTest struct { 298 root common.Hash 299 paths []snap.TrieNodePathSet 300 nBytes uint64 301 302 expHashes []common.Hash 303 expReject bool 304 } 305 306 func decodeNibbles(nibbles []byte, bytes []byte) { 307 for bi, ni := 0, 0; ni < len(nibbles); bi, ni = bi+1, ni+2 { 308 bytes[bi] = nibbles[ni]<<4 | nibbles[ni+1] 309 } 310 } 311 312 // hasTerm returns whether a hex key has the terminator flag. 313 func hasTerm(s []byte) bool { 314 return len(s) > 0 && s[len(s)-1] == 16 315 } 316 317 func keybytesToHex(str []byte) []byte { 318 l := len(str)*2 + 1 319 var nibbles = make([]byte, l) 320 for i, b := range str { 321 nibbles[i*2] = b / 16 322 nibbles[i*2+1] = b % 16 323 } 324 nibbles[l-1] = 16 325 return nibbles 326 } 327 328 func hexToCompact(hex []byte) []byte { 329 terminator := byte(0) 330 if hasTerm(hex) { 331 terminator = 1 332 hex = hex[:len(hex)-1] 333 } 334 buf := make([]byte, len(hex)/2+1) 335 buf[0] = terminator << 5 // the flag byte 336 if len(hex)&1 == 1 { 337 buf[0] |= 1 << 4 // odd flag 338 buf[0] |= hex[0] // first nibble is contained in the first byte 339 hex = hex[1:] 340 } 341 decodeNibbles(hex, buf[1:]) 342 return buf 343 } 344 345 // TestSnapTrieNodes various forms of GetTrieNodes requests. 346 func (s *Suite) TestSnapTrieNodes(t *utesting.T) { 347 key := common.FromHex("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a") 348 // helper function to iterate the key, and generate the compact-encoded 349 // trie paths along the way. 350 pathTo := func(length int) snap.TrieNodePathSet { 351 hex := keybytesToHex(key)[:length] 352 hex[len(hex)-1] = 0 // remove term flag 353 hKey := hexToCompact(hex) 354 return snap.TrieNodePathSet{hKey} 355 } 356 var accPaths []snap.TrieNodePathSet 357 for i := 1; i <= 65; i++ { 358 accPaths = append(accPaths, pathTo(i)) 359 } 360 empty := types.EmptyCodeHash 361 for i, tc := range []trieNodesTest{ 362 { 363 root: s.chain.RootAt(999), 364 paths: nil, 365 nBytes: 500, 366 expHashes: nil, 367 }, 368 { 369 root: s.chain.RootAt(999), 370 paths: []snap.TrieNodePathSet{ 371 {}, // zero-length pathset should 'abort' and kick us off 372 {[]byte{0}}, 373 }, 374 nBytes: 5000, 375 expHashes: []common.Hash{}, 376 expReject: true, 377 }, 378 { 379 root: s.chain.RootAt(999), 380 paths: []snap.TrieNodePathSet{ 381 {[]byte{0}}, 382 {[]byte{1}, []byte{0}}, 383 }, 384 nBytes: 5000, 385 //0x6b3724a41b8c38b46d4d02fba2bb2074c47a507eb16a9a4b978f91d32e406faf 386 expHashes: []common.Hash{s.chain.RootAt(999)}, 387 }, 388 { // nonsensically long path 389 root: s.chain.RootAt(999), 390 paths: []snap.TrieNodePathSet{ 391 {[]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, 392 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}}, 393 }, 394 nBytes: 5000, 395 expHashes: []common.Hash{common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")}, 396 }, 397 { 398 root: s.chain.RootAt(0), 399 paths: []snap.TrieNodePathSet{ 400 {[]byte{0}}, 401 {[]byte{1}, []byte{0}}, 402 }, 403 nBytes: 5000, 404 expHashes: []common.Hash{ 405 common.HexToHash("0x1ee1bb2fbac4d46eab331f3e8551e18a0805d084ed54647883aa552809ca968d"), 406 }, 407 }, 408 { 409 // The leaf is only a couple of levels down, so the continued trie traversal causes lookup failures. 410 root: s.chain.RootAt(999), 411 paths: accPaths, 412 nBytes: 5000, 413 expHashes: []common.Hash{ 414 common.HexToHash("0xbcefee69b37cca1f5bf3a48aebe08b35f2ea1864fa958bb0723d909a0e0d28d8"), 415 common.HexToHash("0x4fb1e4e2391e4b4da471d59641319b8fa25d76c973d4bec594d7b00a69ae5135"), 416 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 417 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 418 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 419 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 420 empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, 421 empty, empty, empty}, 422 }, 423 { 424 // Basically the same as above, with different ordering 425 root: s.chain.RootAt(999), 426 paths: []snap.TrieNodePathSet{ 427 accPaths[10], accPaths[1], accPaths[0], 428 }, 429 nBytes: 5000, 430 expHashes: []common.Hash{ 431 empty, 432 common.HexToHash("0x4fb1e4e2391e4b4da471d59641319b8fa25d76c973d4bec594d7b00a69ae5135"), 433 common.HexToHash("0xbcefee69b37cca1f5bf3a48aebe08b35f2ea1864fa958bb0723d909a0e0d28d8"), 434 }, 435 }, 436 { 437 /* 438 A test against this account, requesting trie nodes for the storage trie 439 { 440 "balance": "0", 441 "nonce": 1, 442 "root": "0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790", 443 "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", 444 "storage": { 445 "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace": "02", 446 "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": "01", 447 "0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b": "03" 448 }, 449 "key": "0xf493f79c43bd747129a226ad42529885a4b108aba6046b2d12071695a6627844" 450 } 451 */ 452 root: s.chain.RootAt(999), 453 paths: []snap.TrieNodePathSet{ 454 { 455 common.FromHex("0xf493f79c43bd747129a226ad42529885a4b108aba6046b2d12071695a6627844"), 456 []byte{0}, 457 }, 458 }, 459 nBytes: 5000, 460 expHashes: []common.Hash{ 461 common.HexToHash("0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790"), 462 }, 463 }, 464 }[7:] { 465 tc := tc 466 if err := s.snapGetTrieNodes(t, &tc); err != nil { 467 t.Errorf("test %d \n #hashes %x\n root: %#x\n bytes: %d\nfailed: %v", i, len(tc.expHashes), tc.root, tc.nBytes, err) 468 } 469 } 470 } 471 472 func (s *Suite) snapGetAccountRange(t *utesting.T, tc *accRangeTest) error { 473 conn, err := s.dialSnap() 474 if err != nil { 475 t.Fatalf("dial failed: %v", err) 476 } 477 defer conn.Close() 478 if err = conn.peer(s.chain, nil); err != nil { 479 t.Fatalf("peering failed: %v", err) 480 } 481 // write request 482 req := &GetAccountRange{ 483 ID: uint64(rand.Int63()), 484 Root: tc.root, 485 Origin: tc.origin, 486 Limit: tc.limit, 487 Bytes: tc.nBytes, 488 } 489 resp, err := conn.snapRequest(req, req.ID, s.chain) 490 if err != nil { 491 return fmt.Errorf("account range request failed: %v", err) 492 } 493 var res *snap.AccountRangePacket 494 if r, ok := resp.(*AccountRange); !ok { 495 return fmt.Errorf("account range response wrong: %T %v", resp, resp) 496 } else { 497 res = (*snap.AccountRangePacket)(r) 498 } 499 if exp, got := tc.expAccounts, len(res.Accounts); exp != got { 500 return fmt.Errorf("expected %d accounts, got %d", exp, got) 501 } 502 // Check that the encoding order is correct 503 for i := 1; i < len(res.Accounts); i++ { 504 if bytes.Compare(res.Accounts[i-1].Hash[:], res.Accounts[i].Hash[:]) >= 0 { 505 return fmt.Errorf("accounts not monotonically increasing: #%d [%x] vs #%d [%x]", i-1, res.Accounts[i-1].Hash[:], i, res.Accounts[i].Hash[:]) 506 } 507 } 508 var ( 509 hashes []common.Hash 510 accounts [][]byte 511 proof = res.Proof 512 ) 513 hashes, accounts, err = res.Unpack() 514 if err != nil { 515 return err 516 } 517 if len(hashes) == 0 && len(accounts) == 0 && len(proof) == 0 { 518 return nil 519 } 520 if len(hashes) > 0 { 521 if exp, got := tc.expFirst, res.Accounts[0].Hash; exp != got { 522 return fmt.Errorf("expected first account %#x, got %#x", exp, got) 523 } 524 if exp, got := tc.expLast, res.Accounts[len(res.Accounts)-1].Hash; exp != got { 525 return fmt.Errorf("expected last account %#x, got %#x", exp, got) 526 } 527 } 528 // Reconstruct a partial trie from the response and verify it 529 keys := make([][]byte, len(hashes)) 530 for i, key := range hashes { 531 keys[i] = common.CopyBytes(key[:]) 532 } 533 nodes := make(light.NodeList, len(proof)) 534 for i, node := range proof { 535 nodes[i] = node 536 } 537 proofdb := nodes.NodeSet() 538 539 var end []byte 540 if len(keys) > 0 { 541 end = keys[len(keys)-1] 542 } 543 _, err = trie.VerifyRangeProof(tc.root, tc.origin[:], end, keys, accounts, proofdb) 544 return err 545 } 546 547 func (s *Suite) snapGetStorageRanges(t *utesting.T, tc *stRangesTest) error { 548 conn, err := s.dialSnap() 549 if err != nil { 550 t.Fatalf("dial failed: %v", err) 551 } 552 defer conn.Close() 553 if err = conn.peer(s.chain, nil); err != nil { 554 t.Fatalf("peering failed: %v", err) 555 } 556 // write request 557 req := &GetStorageRanges{ 558 ID: uint64(rand.Int63()), 559 Root: tc.root, 560 Accounts: tc.accounts, 561 Origin: tc.origin, 562 Limit: tc.limit, 563 Bytes: tc.nBytes, 564 } 565 resp, err := conn.snapRequest(req, req.ID, s.chain) 566 if err != nil { 567 return fmt.Errorf("account range request failed: %v", err) 568 } 569 var res *snap.StorageRangesPacket 570 if r, ok := resp.(*StorageRanges); !ok { 571 return fmt.Errorf("account range response wrong: %T %v", resp, resp) 572 } else { 573 res = (*snap.StorageRangesPacket)(r) 574 } 575 gotSlots := 0 576 // Ensure the ranges are monotonically increasing 577 for i, slots := range res.Slots { 578 gotSlots += len(slots) 579 for j := 1; j < len(slots); j++ { 580 if bytes.Compare(slots[j-1].Hash[:], slots[j].Hash[:]) >= 0 { 581 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[:]) 582 } 583 } 584 } 585 if exp, got := tc.expSlots, gotSlots; exp != got { 586 return fmt.Errorf("expected %d slots, got %d", exp, got) 587 } 588 return nil 589 } 590 591 func (s *Suite) snapGetByteCodes(t *utesting.T, tc *byteCodesTest) error { 592 conn, err := s.dialSnap() 593 if err != nil { 594 t.Fatalf("dial failed: %v", err) 595 } 596 defer conn.Close() 597 if err = conn.peer(s.chain, nil); err != nil { 598 t.Fatalf("peering failed: %v", err) 599 } 600 // write request 601 req := &GetByteCodes{ 602 ID: uint64(rand.Int63()), 603 Hashes: tc.hashes, 604 Bytes: tc.nBytes, 605 } 606 resp, err := conn.snapRequest(req, req.ID, s.chain) 607 if err != nil { 608 return fmt.Errorf("getBytecodes request failed: %v", err) 609 } 610 var res *snap.ByteCodesPacket 611 if r, ok := resp.(*ByteCodes); !ok { 612 return fmt.Errorf("bytecodes response wrong: %T %v", resp, resp) 613 } else { 614 res = (*snap.ByteCodesPacket)(r) 615 } 616 if exp, got := tc.expHashes, len(res.Codes); exp != got { 617 for i, c := range res.Codes { 618 fmt.Printf("%d. %#x\n", i, c) 619 } 620 return fmt.Errorf("expected %d bytecodes, got %d", exp, got) 621 } 622 // Cross reference the requested bytecodes with the response to find gaps 623 // that the serving node is missing 624 var ( 625 bytecodes = res.Codes 626 hasher = sha3.NewLegacyKeccak256().(crypto.KeccakState) 627 hash = make([]byte, 32) 628 codes = make([][]byte, len(req.Hashes)) 629 ) 630 631 for i, j := 0, 0; i < len(bytecodes); i++ { 632 // Find the next hash that we've been served, leaving misses with nils 633 hasher.Reset() 634 hasher.Write(bytecodes[i]) 635 hasher.Read(hash) 636 637 for j < len(req.Hashes) && !bytes.Equal(hash, req.Hashes[j][:]) { 638 j++ 639 } 640 if j < len(req.Hashes) { 641 codes[j] = bytecodes[i] 642 j++ 643 continue 644 } 645 // We've either ran out of hashes, or got unrequested data 646 return errors.New("unexpected bytecode") 647 } 648 649 return nil 650 } 651 652 func (s *Suite) snapGetTrieNodes(t *utesting.T, tc *trieNodesTest) error { 653 conn, err := s.dialSnap() 654 if err != nil { 655 t.Fatalf("dial failed: %v", err) 656 } 657 defer conn.Close() 658 if err = conn.peer(s.chain, nil); err != nil { 659 t.Fatalf("peering failed: %v", err) 660 } 661 // write request 662 req := &GetTrieNodes{ 663 ID: uint64(rand.Int63()), 664 Root: tc.root, 665 Paths: tc.paths, 666 Bytes: tc.nBytes, 667 } 668 resp, err := conn.snapRequest(req, req.ID, s.chain) 669 if err != nil { 670 if tc.expReject { 671 return nil 672 } 673 return fmt.Errorf("trienodes request failed: %v", err) 674 } 675 var res *snap.TrieNodesPacket 676 if r, ok := resp.(*TrieNodes); !ok { 677 return fmt.Errorf("trienodes response wrong: %T %v", resp, resp) 678 } else { 679 res = (*snap.TrieNodesPacket)(r) 680 } 681 682 // Check the correctness 683 684 // Cross reference the requested trienodes with the response to find gaps 685 // that the serving node is missing 686 hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) 687 hash := make([]byte, 32) 688 trienodes := res.Nodes 689 if got, want := len(trienodes), len(tc.expHashes); got != want { 690 return fmt.Errorf("wrong trienode count, got %d, want %d\n", got, want) 691 } 692 for i, trienode := range trienodes { 693 hasher.Reset() 694 hasher.Write(trienode) 695 hasher.Read(hash) 696 if got, want := hash, tc.expHashes[i]; !bytes.Equal(got, want[:]) { 697 fmt.Printf("hash %d wrong, got %#x, want %#x\n", i, got, want) 698 err = fmt.Errorf("hash %d wrong, got %#x, want %#x", i, got, want) 699 } 700 } 701 return err 702 }