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  }