github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/trie/sync_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 trie 18 19 import ( 20 "bytes" 21 "fmt" 22 "maps" 23 "math/rand" 24 "testing" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/core/rawdb" 28 "github.com/ethereum/go-ethereum/core/types" 29 "github.com/ethereum/go-ethereum/crypto" 30 "github.com/ethereum/go-ethereum/ethdb" 31 "github.com/ethereum/go-ethereum/ethdb/memorydb" 32 "github.com/ethereum/go-ethereum/trie/trienode" 33 ) 34 35 // makeTestTrie create a sample test trie to test node-wise reconstruction. 36 func makeTestTrie(scheme string) (ethdb.Database, *testDb, *StateTrie, map[string][]byte) { 37 // Create an empty trie 38 db := rawdb.NewMemoryDatabase() 39 triedb := newTestDatabase(db, scheme) 40 trie, _ := NewStateTrie(TrieID(types.EmptyRootHash), triedb) 41 42 // Fill it with some arbitrary data 43 content := make(map[string][]byte) 44 for i := byte(0); i < 255; i++ { 45 // Map the same data under multiple keys 46 key, val := common.LeftPadBytes([]byte{1, i}, 32), []byte{i} 47 content[string(key)] = val 48 trie.MustUpdate(key, val) 49 50 key, val = common.LeftPadBytes([]byte{2, i}, 32), []byte{i} 51 content[string(key)] = val 52 trie.MustUpdate(key, val) 53 54 // Add some other data to inflate the trie 55 for j := byte(3); j < 13; j++ { 56 key, val = common.LeftPadBytes([]byte{j, i}, 32), []byte{j, i} 57 content[string(key)] = val 58 trie.MustUpdate(key, val) 59 } 60 } 61 root, nodes, _ := trie.Commit(false) 62 if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil { 63 panic(fmt.Errorf("failed to commit db %v", err)) 64 } 65 if err := triedb.Commit(root); err != nil { 66 panic(err) 67 } 68 // Re-create the trie based on the new state 69 trie, _ = NewStateTrie(TrieID(root), triedb) 70 return db, triedb, trie, content 71 } 72 73 // checkTrieContents cross references a reconstructed trie with an expected data 74 // content map. 75 func checkTrieContents(t *testing.T, db ethdb.Database, scheme string, root []byte, content map[string][]byte, rawTrie bool) { 76 // Check root availability and trie contents 77 ndb := newTestDatabase(db, scheme) 78 if err := checkTrieConsistency(db, scheme, common.BytesToHash(root), rawTrie); err != nil { 79 t.Fatalf("inconsistent trie at %x: %v", root, err) 80 } 81 type reader interface { 82 MustGet(key []byte) []byte 83 } 84 var r reader 85 if rawTrie { 86 trie, err := New(TrieID(common.BytesToHash(root)), ndb) 87 if err != nil { 88 t.Fatalf("failed to create trie at %x: %v", root, err) 89 } 90 r = trie 91 } else { 92 trie, err := NewStateTrie(TrieID(common.BytesToHash(root)), ndb) 93 if err != nil { 94 t.Fatalf("failed to create trie at %x: %v", root, err) 95 } 96 r = trie 97 } 98 for key, val := range content { 99 if have := r.MustGet([]byte(key)); !bytes.Equal(have, val) { 100 t.Errorf("entry %x: content mismatch: have %x, want %x", key, have, val) 101 } 102 } 103 } 104 105 // checkTrieConsistency checks that all nodes in a trie are indeed present. 106 func checkTrieConsistency(db ethdb.Database, scheme string, root common.Hash, rawTrie bool) error { 107 ndb := newTestDatabase(db, scheme) 108 var it NodeIterator 109 if rawTrie { 110 trie, err := New(TrieID(root), ndb) 111 if err != nil { 112 return nil // Consider a non existent state consistent 113 } 114 it = trie.MustNodeIterator(nil) 115 } else { 116 trie, err := NewStateTrie(TrieID(root), ndb) 117 if err != nil { 118 return nil // Consider a non existent state consistent 119 } 120 it = trie.MustNodeIterator(nil) 121 } 122 for it.Next(true) { 123 } 124 return it.Error() 125 } 126 127 // trieElement represents the element in the state trie(bytecode or trie node). 128 type trieElement struct { 129 path string 130 hash common.Hash 131 syncPath SyncPath 132 } 133 134 // Tests that an empty trie is not scheduled for syncing. 135 func TestEmptySync(t *testing.T) { 136 dbA := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 137 dbB := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 138 dbC := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.PathScheme) 139 dbD := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.PathScheme) 140 141 emptyA := NewEmpty(dbA) 142 emptyB, _ := New(TrieID(types.EmptyRootHash), dbB) 143 emptyC := NewEmpty(dbC) 144 emptyD, _ := New(TrieID(types.EmptyRootHash), dbD) 145 146 for i, trie := range []*Trie{emptyA, emptyB, emptyC, emptyD} { 147 sync := NewSync(trie.Hash(), memorydb.New(), nil, []*testDb{dbA, dbB, dbC, dbD}[i].Scheme()) 148 if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { 149 t.Errorf("test %d: content requested for empty trie: %v, %v, %v", i, paths, nodes, codes) 150 } 151 } 152 } 153 154 // Tests that given a root hash, a trie can sync iteratively on a single thread, 155 // requesting retrieval tasks and returning all of them in one go. 156 func TestIterativeSync(t *testing.T) { 157 testIterativeSync(t, 1, false, rawdb.HashScheme) 158 testIterativeSync(t, 100, false, rawdb.HashScheme) 159 testIterativeSync(t, 1, true, rawdb.HashScheme) 160 testIterativeSync(t, 100, true, rawdb.HashScheme) 161 testIterativeSync(t, 1, false, rawdb.PathScheme) 162 testIterativeSync(t, 100, false, rawdb.PathScheme) 163 testIterativeSync(t, 1, true, rawdb.PathScheme) 164 testIterativeSync(t, 100, true, rawdb.PathScheme) 165 } 166 167 func testIterativeSync(t *testing.T, count int, bypath bool, scheme string) { 168 // Create a random trie to copy 169 _, srcDb, srcTrie, srcData := makeTestTrie(scheme) 170 171 // Create a destination trie and sync with the scheduler 172 diskdb := rawdb.NewMemoryDatabase() 173 sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) 174 175 // The code requests are ignored here since there is no code 176 // at the testing trie. 177 paths, nodes, _ := sched.Missing(count) 178 var elements []trieElement 179 for i := 0; i < len(paths); i++ { 180 elements = append(elements, trieElement{ 181 path: paths[i], 182 hash: nodes[i], 183 syncPath: NewSyncPath([]byte(paths[i])), 184 }) 185 } 186 reader, err := srcDb.Reader(srcTrie.Hash()) 187 if err != nil { 188 t.Fatalf("State is not available %x", srcTrie.Hash()) 189 } 190 for len(elements) > 0 { 191 results := make([]NodeSyncResult, len(elements)) 192 if !bypath { 193 for i, element := range elements { 194 owner, inner := ResolvePath([]byte(element.path)) 195 data, err := reader.Node(owner, inner, element.hash) 196 if err != nil { 197 t.Fatalf("failed to retrieve node data for hash %x: %v", element.hash, err) 198 } 199 results[i] = NodeSyncResult{element.path, data} 200 } 201 } else { 202 for i, element := range elements { 203 data, _, err := srcTrie.GetNode(element.syncPath[len(element.syncPath)-1]) 204 if err != nil { 205 t.Fatalf("failed to retrieve node data for path %x: %v", element.path, err) 206 } 207 results[i] = NodeSyncResult{element.path, data} 208 } 209 } 210 for _, result := range results { 211 if err := sched.ProcessNode(result); err != nil { 212 t.Fatalf("failed to process result %v", err) 213 } 214 } 215 batch := diskdb.NewBatch() 216 if err := sched.Commit(batch); err != nil { 217 t.Fatalf("failed to commit data: %v", err) 218 } 219 batch.Write() 220 221 paths, nodes, _ = sched.Missing(count) 222 elements = elements[:0] 223 for i := 0; i < len(paths); i++ { 224 elements = append(elements, trieElement{ 225 path: paths[i], 226 hash: nodes[i], 227 syncPath: NewSyncPath([]byte(paths[i])), 228 }) 229 } 230 } 231 // Cross check that the two tries are in sync 232 checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData, false) 233 } 234 235 // Tests that the trie scheduler can correctly reconstruct the state even if only 236 // partial results are returned, and the others sent only later. 237 func TestIterativeDelayedSync(t *testing.T) { 238 testIterativeDelayedSync(t, rawdb.HashScheme) 239 testIterativeDelayedSync(t, rawdb.PathScheme) 240 } 241 242 func testIterativeDelayedSync(t *testing.T, scheme string) { 243 // Create a random trie to copy 244 _, srcDb, srcTrie, srcData := makeTestTrie(scheme) 245 246 // Create a destination trie and sync with the scheduler 247 diskdb := rawdb.NewMemoryDatabase() 248 sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) 249 250 // The code requests are ignored here since there is no code 251 // at the testing trie. 252 paths, nodes, _ := sched.Missing(10000) 253 var elements []trieElement 254 for i := 0; i < len(paths); i++ { 255 elements = append(elements, trieElement{ 256 path: paths[i], 257 hash: nodes[i], 258 syncPath: NewSyncPath([]byte(paths[i])), 259 }) 260 } 261 reader, err := srcDb.Reader(srcTrie.Hash()) 262 if err != nil { 263 t.Fatalf("State is not available %x", srcTrie.Hash()) 264 } 265 for len(elements) > 0 { 266 // Sync only half of the scheduled nodes 267 results := make([]NodeSyncResult, len(elements)/2+1) 268 for i, element := range elements[:len(results)] { 269 owner, inner := ResolvePath([]byte(element.path)) 270 data, err := reader.Node(owner, inner, element.hash) 271 if err != nil { 272 t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) 273 } 274 results[i] = NodeSyncResult{element.path, data} 275 } 276 for _, result := range results { 277 if err := sched.ProcessNode(result); err != nil { 278 t.Fatalf("failed to process result %v", err) 279 } 280 } 281 batch := diskdb.NewBatch() 282 if err := sched.Commit(batch); err != nil { 283 t.Fatalf("failed to commit data: %v", err) 284 } 285 batch.Write() 286 287 paths, nodes, _ = sched.Missing(10000) 288 elements = elements[len(results):] 289 for i := 0; i < len(paths); i++ { 290 elements = append(elements, trieElement{ 291 path: paths[i], 292 hash: nodes[i], 293 syncPath: NewSyncPath([]byte(paths[i])), 294 }) 295 } 296 } 297 // Cross check that the two tries are in sync 298 checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData, false) 299 } 300 301 // Tests that given a root hash, a trie can sync iteratively on a single thread, 302 // requesting retrieval tasks and returning all of them in one go, however in a 303 // random order. 304 func TestIterativeRandomSyncIndividual(t *testing.T) { 305 testIterativeRandomSync(t, 1, rawdb.HashScheme) 306 testIterativeRandomSync(t, 100, rawdb.HashScheme) 307 testIterativeRandomSync(t, 1, rawdb.PathScheme) 308 testIterativeRandomSync(t, 100, rawdb.PathScheme) 309 } 310 311 func testIterativeRandomSync(t *testing.T, count int, scheme string) { 312 // Create a random trie to copy 313 _, srcDb, srcTrie, srcData := makeTestTrie(scheme) 314 315 // Create a destination trie and sync with the scheduler 316 diskdb := rawdb.NewMemoryDatabase() 317 sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) 318 319 // The code requests are ignored here since there is no code 320 // at the testing trie. 321 paths, nodes, _ := sched.Missing(count) 322 queue := make(map[string]trieElement) 323 for i, path := range paths { 324 queue[path] = trieElement{ 325 path: paths[i], 326 hash: nodes[i], 327 syncPath: NewSyncPath([]byte(paths[i])), 328 } 329 } 330 reader, err := srcDb.Reader(srcTrie.Hash()) 331 if err != nil { 332 t.Fatalf("State is not available %x", srcTrie.Hash()) 333 } 334 for len(queue) > 0 { 335 // Fetch all the queued nodes in a random order 336 results := make([]NodeSyncResult, 0, len(queue)) 337 for path, element := range queue { 338 owner, inner := ResolvePath([]byte(element.path)) 339 data, err := reader.Node(owner, inner, element.hash) 340 if err != nil { 341 t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) 342 } 343 results = append(results, NodeSyncResult{path, data}) 344 } 345 // Feed the retrieved results back and queue new tasks 346 for _, result := range results { 347 if err := sched.ProcessNode(result); err != nil { 348 t.Fatalf("failed to process result %v", err) 349 } 350 } 351 batch := diskdb.NewBatch() 352 if err := sched.Commit(batch); err != nil { 353 t.Fatalf("failed to commit data: %v", err) 354 } 355 batch.Write() 356 357 paths, nodes, _ = sched.Missing(count) 358 queue = make(map[string]trieElement) 359 for i, path := range paths { 360 queue[path] = trieElement{ 361 path: path, 362 hash: nodes[i], 363 syncPath: NewSyncPath([]byte(path)), 364 } 365 } 366 } 367 // Cross check that the two tries are in sync 368 checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData, false) 369 } 370 371 // Tests that the trie scheduler can correctly reconstruct the state even if only 372 // partial results are returned (Even those randomly), others sent only later. 373 func TestIterativeRandomDelayedSync(t *testing.T) { 374 testIterativeRandomDelayedSync(t, rawdb.HashScheme) 375 testIterativeRandomDelayedSync(t, rawdb.PathScheme) 376 } 377 378 func testIterativeRandomDelayedSync(t *testing.T, scheme string) { 379 // Create a random trie to copy 380 _, srcDb, srcTrie, srcData := makeTestTrie(scheme) 381 382 // Create a destination trie and sync with the scheduler 383 diskdb := rawdb.NewMemoryDatabase() 384 sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) 385 386 // The code requests are ignored here since there is no code 387 // at the testing trie. 388 paths, nodes, _ := sched.Missing(10000) 389 queue := make(map[string]trieElement) 390 for i, path := range paths { 391 queue[path] = trieElement{ 392 path: path, 393 hash: nodes[i], 394 syncPath: NewSyncPath([]byte(path)), 395 } 396 } 397 reader, err := srcDb.Reader(srcTrie.Hash()) 398 if err != nil { 399 t.Fatalf("State is not available %x", srcTrie.Hash()) 400 } 401 for len(queue) > 0 { 402 // Sync only half of the scheduled nodes, even those in random order 403 results := make([]NodeSyncResult, 0, len(queue)/2+1) 404 for path, element := range queue { 405 owner, inner := ResolvePath([]byte(element.path)) 406 data, err := reader.Node(owner, inner, element.hash) 407 if err != nil { 408 t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) 409 } 410 results = append(results, NodeSyncResult{path, data}) 411 412 if len(results) >= cap(results) { 413 break 414 } 415 } 416 // Feed the retrieved results back and queue new tasks 417 for _, result := range results { 418 if err := sched.ProcessNode(result); err != nil { 419 t.Fatalf("failed to process result %v", err) 420 } 421 } 422 batch := diskdb.NewBatch() 423 if err := sched.Commit(batch); err != nil { 424 t.Fatalf("failed to commit data: %v", err) 425 } 426 batch.Write() 427 for _, result := range results { 428 delete(queue, result.Path) 429 } 430 paths, nodes, _ = sched.Missing(10000) 431 for i, path := range paths { 432 queue[path] = trieElement{ 433 path: path, 434 hash: nodes[i], 435 syncPath: NewSyncPath([]byte(path)), 436 } 437 } 438 } 439 // Cross check that the two tries are in sync 440 checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData, false) 441 } 442 443 // Tests that a trie sync will not request nodes multiple times, even if they 444 // have such references. 445 func TestDuplicateAvoidanceSync(t *testing.T) { 446 testDuplicateAvoidanceSync(t, rawdb.HashScheme) 447 testDuplicateAvoidanceSync(t, rawdb.PathScheme) 448 } 449 450 func testDuplicateAvoidanceSync(t *testing.T, scheme string) { 451 // Create a random trie to copy 452 _, srcDb, srcTrie, srcData := makeTestTrie(scheme) 453 454 // Create a destination trie and sync with the scheduler 455 diskdb := rawdb.NewMemoryDatabase() 456 sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) 457 458 // The code requests are ignored here since there is no code 459 // at the testing trie. 460 paths, nodes, _ := sched.Missing(0) 461 var elements []trieElement 462 for i := 0; i < len(paths); i++ { 463 elements = append(elements, trieElement{ 464 path: paths[i], 465 hash: nodes[i], 466 syncPath: NewSyncPath([]byte(paths[i])), 467 }) 468 } 469 reader, err := srcDb.Reader(srcTrie.Hash()) 470 if err != nil { 471 t.Fatalf("State is not available %x", srcTrie.Hash()) 472 } 473 requested := make(map[common.Hash]struct{}) 474 for len(elements) > 0 { 475 results := make([]NodeSyncResult, len(elements)) 476 for i, element := range elements { 477 owner, inner := ResolvePath([]byte(element.path)) 478 data, err := reader.Node(owner, inner, element.hash) 479 if err != nil { 480 t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) 481 } 482 if _, ok := requested[element.hash]; ok { 483 t.Errorf("hash %x already requested once", element.hash) 484 } 485 requested[element.hash] = struct{}{} 486 487 results[i] = NodeSyncResult{element.path, data} 488 } 489 for _, result := range results { 490 if err := sched.ProcessNode(result); err != nil { 491 t.Fatalf("failed to process result %v", err) 492 } 493 } 494 batch := diskdb.NewBatch() 495 if err := sched.Commit(batch); err != nil { 496 t.Fatalf("failed to commit data: %v", err) 497 } 498 batch.Write() 499 500 paths, nodes, _ = sched.Missing(0) 501 elements = elements[:0] 502 for i := 0; i < len(paths); i++ { 503 elements = append(elements, trieElement{ 504 path: paths[i], 505 hash: nodes[i], 506 syncPath: NewSyncPath([]byte(paths[i])), 507 }) 508 } 509 } 510 // Cross check that the two tries are in sync 511 checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData, false) 512 } 513 514 // Tests that at any point in time during a sync, only complete sub-tries are in 515 // the database. 516 func TestIncompleteSyncHash(t *testing.T) { 517 testIncompleteSync(t, rawdb.HashScheme) 518 testIncompleteSync(t, rawdb.PathScheme) 519 } 520 521 func testIncompleteSync(t *testing.T, scheme string) { 522 // Create a random trie to copy 523 _, srcDb, srcTrie, _ := makeTestTrie(scheme) 524 525 // Create a destination trie and sync with the scheduler 526 diskdb := rawdb.NewMemoryDatabase() 527 sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) 528 529 // The code requests are ignored here since there is no code 530 // at the testing trie. 531 var ( 532 addedKeys []string 533 addedHashes []common.Hash 534 elements []trieElement 535 root = srcTrie.Hash() 536 ) 537 paths, nodes, _ := sched.Missing(1) 538 for i := 0; i < len(paths); i++ { 539 elements = append(elements, trieElement{ 540 path: paths[i], 541 hash: nodes[i], 542 syncPath: NewSyncPath([]byte(paths[i])), 543 }) 544 } 545 reader, err := srcDb.Reader(srcTrie.Hash()) 546 if err != nil { 547 t.Fatalf("State is not available %x", srcTrie.Hash()) 548 } 549 for len(elements) > 0 { 550 // Fetch a batch of trie nodes 551 results := make([]NodeSyncResult, len(elements)) 552 for i, element := range elements { 553 owner, inner := ResolvePath([]byte(element.path)) 554 data, err := reader.Node(owner, inner, element.hash) 555 if err != nil { 556 t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) 557 } 558 results[i] = NodeSyncResult{element.path, data} 559 } 560 // Process each of the trie nodes 561 for _, result := range results { 562 if err := sched.ProcessNode(result); err != nil { 563 t.Fatalf("failed to process result %v", err) 564 } 565 } 566 batch := diskdb.NewBatch() 567 if err := sched.Commit(batch); err != nil { 568 t.Fatalf("failed to commit data: %v", err) 569 } 570 batch.Write() 571 572 for _, result := range results { 573 hash := crypto.Keccak256Hash(result.Data) 574 if hash != root { 575 addedKeys = append(addedKeys, result.Path) 576 addedHashes = append(addedHashes, hash) 577 } 578 } 579 // Fetch the next batch to retrieve 580 paths, nodes, _ = sched.Missing(1) 581 elements = elements[:0] 582 for i := 0; i < len(paths); i++ { 583 elements = append(elements, trieElement{ 584 path: paths[i], 585 hash: nodes[i], 586 syncPath: NewSyncPath([]byte(paths[i])), 587 }) 588 } 589 } 590 // Sanity check that removing any node from the database is detected 591 for i, path := range addedKeys { 592 if rand.Int31n(100) > 5 { 593 // Only check 5 percent of added keys as a sanity check 594 continue 595 } 596 owner, inner := ResolvePath([]byte(path)) 597 nodeHash := addedHashes[i] 598 value := rawdb.ReadTrieNode(diskdb, owner, inner, nodeHash, scheme) 599 rawdb.DeleteTrieNode(diskdb, owner, inner, nodeHash, scheme) 600 if err := checkTrieConsistency(diskdb, srcDb.Scheme(), root, false); err == nil { 601 t.Fatalf("trie inconsistency not caught, missing: %x", path) 602 } 603 rawdb.WriteTrieNode(diskdb, owner, inner, nodeHash, value, scheme) 604 } 605 } 606 607 // Tests that trie nodes get scheduled lexicographically when having the same 608 // depth. 609 func TestSyncOrdering(t *testing.T) { 610 testSyncOrdering(t, rawdb.HashScheme) 611 testSyncOrdering(t, rawdb.PathScheme) 612 } 613 614 func testSyncOrdering(t *testing.T, scheme string) { 615 // Create a random trie to copy 616 _, srcDb, srcTrie, srcData := makeTestTrie(scheme) 617 618 // Create a destination trie and sync with the scheduler, tracking the requests 619 diskdb := rawdb.NewMemoryDatabase() 620 sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) 621 622 // The code requests are ignored here since there is no code 623 // at the testing trie. 624 var ( 625 reqs []SyncPath 626 elements []trieElement 627 ) 628 paths, nodes, _ := sched.Missing(1) 629 for i := 0; i < len(paths); i++ { 630 elements = append(elements, trieElement{ 631 path: paths[i], 632 hash: nodes[i], 633 syncPath: NewSyncPath([]byte(paths[i])), 634 }) 635 reqs = append(reqs, NewSyncPath([]byte(paths[i]))) 636 } 637 reader, err := srcDb.Reader(srcTrie.Hash()) 638 if err != nil { 639 t.Fatalf("State is not available %x", srcTrie.Hash()) 640 } 641 for len(elements) > 0 { 642 results := make([]NodeSyncResult, len(elements)) 643 for i, element := range elements { 644 owner, inner := ResolvePath([]byte(element.path)) 645 data, err := reader.Node(owner, inner, element.hash) 646 if err != nil { 647 t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) 648 } 649 results[i] = NodeSyncResult{element.path, data} 650 } 651 for _, result := range results { 652 if err := sched.ProcessNode(result); err != nil { 653 t.Fatalf("failed to process result %v", err) 654 } 655 } 656 batch := diskdb.NewBatch() 657 if err := sched.Commit(batch); err != nil { 658 t.Fatalf("failed to commit data: %v", err) 659 } 660 batch.Write() 661 662 paths, nodes, _ = sched.Missing(1) 663 elements = elements[:0] 664 for i := 0; i < len(paths); i++ { 665 elements = append(elements, trieElement{ 666 path: paths[i], 667 hash: nodes[i], 668 syncPath: NewSyncPath([]byte(paths[i])), 669 }) 670 reqs = append(reqs, NewSyncPath([]byte(paths[i]))) 671 } 672 } 673 // Cross check that the two tries are in sync 674 checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData, false) 675 676 // Check that the trie nodes have been requested path-ordered 677 for i := 0; i < len(reqs)-1; i++ { 678 if len(reqs[i]) > 1 || len(reqs[i+1]) > 1 { 679 // In the case of the trie tests, there's no storage so the tuples 680 // must always be single items. 2-tuples should be tested in state. 681 t.Errorf("Invalid request tuples: len(%v) or len(%v) > 1", reqs[i], reqs[i+1]) 682 } 683 if bytes.Compare(compactToHex(reqs[i][0]), compactToHex(reqs[i+1][0])) > 0 { 684 t.Errorf("Invalid request order: %v before %v", compactToHex(reqs[i][0]), compactToHex(reqs[i+1][0])) 685 } 686 } 687 } 688 func syncWith(t *testing.T, root common.Hash, db ethdb.Database, srcDb *testDb) { 689 syncWithHookWriter(t, root, db, srcDb, nil) 690 } 691 692 func syncWithHookWriter(t *testing.T, root common.Hash, db ethdb.Database, srcDb *testDb, hookWriter ethdb.KeyValueWriter) { 693 // Create a destination trie and sync with the scheduler 694 sched := NewSync(root, db, nil, srcDb.Scheme()) 695 696 // The code requests are ignored here since there is no code 697 // at the testing trie. 698 paths, nodes, _ := sched.Missing(0) 699 var elements []trieElement 700 for i := 0; i < len(paths); i++ { 701 elements = append(elements, trieElement{ 702 path: paths[i], 703 hash: nodes[i], 704 syncPath: NewSyncPath([]byte(paths[i])), 705 }) 706 } 707 reader, err := srcDb.Reader(root) 708 if err != nil { 709 t.Fatalf("State is not available %x", root) 710 } 711 for len(elements) > 0 { 712 results := make([]NodeSyncResult, len(elements)) 713 for i, element := range elements { 714 owner, inner := ResolvePath([]byte(element.path)) 715 data, err := reader.Node(owner, inner, element.hash) 716 if err != nil { 717 t.Fatalf("failed to retrieve node data for hash %x: %v", element.hash, err) 718 } 719 results[i] = NodeSyncResult{element.path, data} 720 } 721 for index, result := range results { 722 if err := sched.ProcessNode(result); err != nil { 723 t.Fatalf("failed to process result[%d][%v] data %v %v", index, []byte(result.Path), result.Data, err) 724 } 725 } 726 batch := db.NewBatch() 727 if err := sched.Commit(batch); err != nil { 728 t.Fatalf("failed to commit data: %v", err) 729 } 730 if hookWriter != nil { 731 batch.Replay(hookWriter) 732 } else { 733 batch.Write() 734 } 735 paths, nodes, _ = sched.Missing(0) 736 elements = elements[:0] 737 for i := 0; i < len(paths); i++ { 738 elements = append(elements, trieElement{ 739 path: paths[i], 740 hash: nodes[i], 741 syncPath: NewSyncPath([]byte(paths[i])), 742 }) 743 } 744 } 745 } 746 747 // Tests that the syncing target is keeping moving which may overwrite the stale 748 // states synced in the last cycle. 749 func TestSyncMovingTarget(t *testing.T) { 750 testSyncMovingTarget(t, rawdb.HashScheme) 751 testSyncMovingTarget(t, rawdb.PathScheme) 752 } 753 754 func testSyncMovingTarget(t *testing.T, scheme string) { 755 // Create a random trie to copy 756 _, srcDb, srcTrie, srcData := makeTestTrie(scheme) 757 758 // Create a destination trie and sync with the scheduler 759 diskdb := rawdb.NewMemoryDatabase() 760 syncWith(t, srcTrie.Hash(), diskdb, srcDb) 761 checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData, false) 762 763 // Push more modifications into the src trie, to see if dest trie can still 764 // sync with it(overwrite stale states) 765 var ( 766 preRoot = srcTrie.Hash() 767 diff = make(map[string][]byte) 768 ) 769 for i := byte(0); i < 10; i++ { 770 key, val := randBytes(32), randBytes(32) 771 srcTrie.MustUpdate(key, val) 772 diff[string(key)] = val 773 } 774 root, nodes, _ := srcTrie.Commit(false) 775 if err := srcDb.Update(root, preRoot, trienode.NewWithNodeSet(nodes)); err != nil { 776 panic(err) 777 } 778 if err := srcDb.Commit(root); err != nil { 779 panic(err) 780 } 781 preRoot = root 782 srcTrie, _ = NewStateTrie(TrieID(root), srcDb) 783 784 syncWith(t, srcTrie.Hash(), diskdb, srcDb) 785 checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), diff, false) 786 787 // Revert added modifications from the src trie, to see if dest trie can still 788 // sync with it(overwrite reverted states) 789 var reverted = make(map[string][]byte) 790 for k := range diff { 791 srcTrie.MustDelete([]byte(k)) 792 reverted[k] = nil 793 } 794 for k := range srcData { 795 val := randBytes(32) 796 srcTrie.MustUpdate([]byte(k), val) 797 reverted[k] = val 798 } 799 root, nodes, _ = srcTrie.Commit(false) 800 if err := srcDb.Update(root, preRoot, trienode.NewWithNodeSet(nodes)); err != nil { 801 panic(err) 802 } 803 if err := srcDb.Commit(root); err != nil { 804 panic(err) 805 } 806 srcTrie, _ = NewStateTrie(TrieID(root), srcDb) 807 808 syncWith(t, srcTrie.Hash(), diskdb, srcDb) 809 checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), reverted, false) 810 } 811 812 // Tests if state syncer can correctly catch up the pivot move. 813 func TestPivotMove(t *testing.T) { 814 testPivotMove(t, rawdb.HashScheme, true) 815 testPivotMove(t, rawdb.HashScheme, false) 816 testPivotMove(t, rawdb.PathScheme, true) 817 testPivotMove(t, rawdb.PathScheme, false) 818 } 819 820 func testPivotMove(t *testing.T, scheme string, tiny bool) { 821 var ( 822 srcDisk = rawdb.NewMemoryDatabase() 823 srcTrieDB = newTestDatabase(srcDisk, scheme) 824 srcTrie, _ = New(TrieID(types.EmptyRootHash), srcTrieDB) 825 826 deleteFn = func(key []byte, tr *Trie, states map[string][]byte) { 827 tr.Delete(key) 828 delete(states, string(key)) 829 } 830 writeFn = func(key []byte, val []byte, tr *Trie, states map[string][]byte) { 831 if val == nil { 832 if tiny { 833 val = randBytes(4) 834 } else { 835 val = randBytes(32) 836 } 837 } 838 tr.Update(key, val) 839 states[string(key)] = common.CopyBytes(val) 840 } 841 ) 842 stateA := make(map[string][]byte) 843 writeFn([]byte{0x01, 0x23}, nil, srcTrie, stateA) 844 writeFn([]byte{0x01, 0x24}, nil, srcTrie, stateA) 845 writeFn([]byte{0x12, 0x33}, nil, srcTrie, stateA) 846 writeFn([]byte{0x12, 0x34}, nil, srcTrie, stateA) 847 writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateA) 848 writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateA) 849 850 rootA, nodesA, _ := srcTrie.Commit(false) 851 if err := srcTrieDB.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)); err != nil { 852 panic(err) 853 } 854 if err := srcTrieDB.Commit(rootA); err != nil { 855 panic(err) 856 } 857 // Create a destination trie and sync with the scheduler 858 destDisk := rawdb.NewMemoryDatabase() 859 syncWith(t, rootA, destDisk, srcTrieDB) 860 checkTrieContents(t, destDisk, scheme, srcTrie.Hash().Bytes(), stateA, true) 861 862 // Delete element to collapse trie 863 stateB := maps.Clone(stateA) 864 srcTrie, _ = New(TrieID(rootA), srcTrieDB) 865 deleteFn([]byte{0x02, 0x34}, srcTrie, stateB) 866 deleteFn([]byte{0x13, 0x44}, srcTrie, stateB) 867 writeFn([]byte{0x01, 0x24}, nil, srcTrie, stateB) 868 869 rootB, nodesB, _ := srcTrie.Commit(false) 870 if err := srcTrieDB.Update(rootB, rootA, trienode.NewWithNodeSet(nodesB)); err != nil { 871 panic(err) 872 } 873 if err := srcTrieDB.Commit(rootB); err != nil { 874 panic(err) 875 } 876 syncWith(t, rootB, destDisk, srcTrieDB) 877 checkTrieContents(t, destDisk, scheme, srcTrie.Hash().Bytes(), stateB, true) 878 879 // Add elements to expand trie 880 stateC := maps.Clone(stateB) 881 srcTrie, _ = New(TrieID(rootB), srcTrieDB) 882 883 writeFn([]byte{0x01, 0x24}, stateA[string([]byte{0x01, 0x24})], srcTrie, stateC) 884 writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateC) 885 writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateC) 886 887 rootC, nodesC, _ := srcTrie.Commit(false) 888 if err := srcTrieDB.Update(rootC, rootB, trienode.NewWithNodeSet(nodesC)); err != nil { 889 panic(err) 890 } 891 if err := srcTrieDB.Commit(rootC); err != nil { 892 panic(err) 893 } 894 syncWith(t, rootC, destDisk, srcTrieDB) 895 checkTrieContents(t, destDisk, scheme, srcTrie.Hash().Bytes(), stateC, true) 896 } 897 898 func TestSyncAbort(t *testing.T) { 899 testSyncAbort(t, rawdb.PathScheme) 900 testSyncAbort(t, rawdb.HashScheme) 901 } 902 903 type hookWriter struct { 904 db ethdb.KeyValueStore 905 filter func(key []byte, value []byte) bool 906 } 907 908 // Put inserts the given value into the key-value data store. 909 func (w *hookWriter) Put(key []byte, value []byte) error { 910 if w.filter != nil && w.filter(key, value) { 911 return nil 912 } 913 return w.db.Put(key, value) 914 } 915 916 // Delete removes the key from the key-value data store. 917 func (w *hookWriter) Delete(key []byte) error { 918 return w.db.Delete(key) 919 } 920 921 func testSyncAbort(t *testing.T, scheme string) { 922 var ( 923 srcDisk = rawdb.NewMemoryDatabase() 924 srcTrieDB = newTestDatabase(srcDisk, scheme) 925 srcTrie, _ = New(TrieID(types.EmptyRootHash), srcTrieDB) 926 927 deleteFn = func(key []byte, tr *Trie, states map[string][]byte) { 928 tr.Delete(key) 929 delete(states, string(key)) 930 } 931 writeFn = func(key []byte, val []byte, tr *Trie, states map[string][]byte) { 932 if val == nil { 933 val = randBytes(32) 934 } 935 tr.Update(key, val) 936 states[string(key)] = common.CopyBytes(val) 937 } 938 ) 939 var ( 940 stateA = make(map[string][]byte) 941 key = randBytes(32) 942 val = randBytes(32) 943 ) 944 for i := 0; i < 256; i++ { 945 writeFn(randBytes(32), nil, srcTrie, stateA) 946 } 947 writeFn(key, val, srcTrie, stateA) 948 949 rootA, nodesA, _ := srcTrie.Commit(false) 950 if err := srcTrieDB.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)); err != nil { 951 panic(err) 952 } 953 if err := srcTrieDB.Commit(rootA); err != nil { 954 panic(err) 955 } 956 // Create a destination trie and sync with the scheduler 957 destDisk := rawdb.NewMemoryDatabase() 958 syncWith(t, rootA, destDisk, srcTrieDB) 959 checkTrieContents(t, destDisk, scheme, srcTrie.Hash().Bytes(), stateA, true) 960 961 // Delete the element from the trie 962 stateB := maps.Clone(stateA) 963 srcTrie, _ = New(TrieID(rootA), srcTrieDB) 964 deleteFn(key, srcTrie, stateB) 965 966 rootB, nodesB, _ := srcTrie.Commit(false) 967 if err := srcTrieDB.Update(rootB, rootA, trienode.NewWithNodeSet(nodesB)); err != nil { 968 panic(err) 969 } 970 if err := srcTrieDB.Commit(rootB); err != nil { 971 panic(err) 972 } 973 974 // Sync the new state, but never persist the new root node. Before the 975 // fix #28595, the original old root node will still be left in database 976 // which breaks the next healing cycle. 977 syncWithHookWriter(t, rootB, destDisk, srcTrieDB, &hookWriter{db: destDisk, filter: func(key []byte, value []byte) bool { 978 if scheme == rawdb.HashScheme { 979 return false 980 } 981 if len(value) == 0 { 982 return false 983 } 984 ok, path := rawdb.ResolveAccountTrieNodeKey(key) 985 return ok && len(path) == 0 986 }}) 987 988 // Add elements to expand trie 989 stateC := maps.Clone(stateB) 990 srcTrie, _ = New(TrieID(rootB), srcTrieDB) 991 992 writeFn(key, val, srcTrie, stateC) 993 rootC, nodesC, _ := srcTrie.Commit(false) 994 if err := srcTrieDB.Update(rootC, rootB, trienode.NewWithNodeSet(nodesC)); err != nil { 995 panic(err) 996 } 997 if err := srcTrieDB.Commit(rootC); err != nil { 998 panic(err) 999 } 1000 syncWith(t, rootC, destDisk, srcTrieDB) 1001 checkTrieContents(t, destDisk, scheme, srcTrie.Hash().Bytes(), stateC, true) 1002 }