github.com/theQRL/go-zond@v0.1.1/core/state/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 state
    18  
    19  import (
    20  	"bytes"
    21  	"math/big"
    22  	"testing"
    23  
    24  	"github.com/theQRL/go-zond/common"
    25  	"github.com/theQRL/go-zond/core/rawdb"
    26  	"github.com/theQRL/go-zond/core/types"
    27  	"github.com/theQRL/go-zond/crypto"
    28  	"github.com/theQRL/go-zond/rlp"
    29  	"github.com/theQRL/go-zond/trie"
    30  	"github.com/theQRL/go-zond/trie/triedb/hashdb"
    31  	"github.com/theQRL/go-zond/trie/triedb/pathdb"
    32  	"github.com/theQRL/go-zond/zonddb"
    33  )
    34  
    35  // testAccount is the data associated with an account used by the state tests.
    36  type testAccount struct {
    37  	address common.Address
    38  	balance *big.Int
    39  	nonce   uint64
    40  	code    []byte
    41  }
    42  
    43  // makeTestState create a sample test state to test node-wise reconstruction.
    44  func makeTestState(scheme string) (zonddb.Database, Database, *trie.Database, common.Hash, []*testAccount) {
    45  	// Create an empty state
    46  	config := &trie.Config{Preimages: true}
    47  	if scheme == rawdb.PathScheme {
    48  		config.PathDB = pathdb.Defaults
    49  	} else {
    50  		config.HashDB = hashdb.Defaults
    51  	}
    52  	db := rawdb.NewMemoryDatabase()
    53  	nodeDb := trie.NewDatabase(db, config)
    54  	sdb := NewDatabaseWithNodeDB(db, nodeDb)
    55  	state, _ := New(types.EmptyRootHash, sdb, nil)
    56  
    57  	// Fill it with some arbitrary data
    58  	var accounts []*testAccount
    59  	for i := byte(0); i < 96; i++ {
    60  		obj := state.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
    61  		acc := &testAccount{address: common.BytesToAddress([]byte{i})}
    62  
    63  		obj.AddBalance(big.NewInt(int64(11 * i)))
    64  		acc.balance = big.NewInt(int64(11 * i))
    65  
    66  		obj.SetNonce(uint64(42 * i))
    67  		acc.nonce = uint64(42 * i)
    68  
    69  		if i%3 == 0 {
    70  			obj.SetCode(crypto.Keccak256Hash([]byte{i, i, i, i, i}), []byte{i, i, i, i, i})
    71  			acc.code = []byte{i, i, i, i, i}
    72  		}
    73  		if i%5 == 0 {
    74  			for j := byte(0); j < 5; j++ {
    75  				hash := crypto.Keccak256Hash([]byte{i, i, i, i, i, j, j})
    76  				obj.SetState(hash, hash)
    77  			}
    78  		}
    79  		accounts = append(accounts, acc)
    80  	}
    81  	root, _ := state.Commit(0, false)
    82  
    83  	// Return the generated state
    84  	return db, sdb, nodeDb, root, accounts
    85  }
    86  
    87  // checkStateAccounts cross references a reconstructed state with an expected
    88  // account array.
    89  func checkStateAccounts(t *testing.T, db zonddb.Database, scheme string, root common.Hash, accounts []*testAccount) {
    90  	var config trie.Config
    91  	if scheme == rawdb.PathScheme {
    92  		config.PathDB = pathdb.Defaults
    93  	}
    94  	// Check root availability and state contents
    95  	state, err := New(root, NewDatabaseWithConfig(db, &config), nil)
    96  	if err != nil {
    97  		t.Fatalf("failed to create state trie at %x: %v", root, err)
    98  	}
    99  	if err := checkStateConsistency(db, scheme, root); err != nil {
   100  		t.Fatalf("inconsistent state trie at %x: %v", root, err)
   101  	}
   102  	for i, acc := range accounts {
   103  		if balance := state.GetBalance(acc.address); balance.Cmp(acc.balance) != 0 {
   104  			t.Errorf("account %d: balance mismatch: have %v, want %v", i, balance, acc.balance)
   105  		}
   106  		if nonce := state.GetNonce(acc.address); nonce != acc.nonce {
   107  			t.Errorf("account %d: nonce mismatch: have %v, want %v", i, nonce, acc.nonce)
   108  		}
   109  		if code := state.GetCode(acc.address); !bytes.Equal(code, acc.code) {
   110  			t.Errorf("account %d: code mismatch: have %x, want %x", i, code, acc.code)
   111  		}
   112  	}
   113  }
   114  
   115  // checkStateConsistency checks that all data of a state root is present.
   116  func checkStateConsistency(db zonddb.Database, scheme string, root common.Hash) error {
   117  	config := &trie.Config{Preimages: true}
   118  	if scheme == rawdb.PathScheme {
   119  		config.PathDB = pathdb.Defaults
   120  	}
   121  	state, err := New(root, NewDatabaseWithConfig(db, config), nil)
   122  	if err != nil {
   123  		return err
   124  	}
   125  	it := newNodeIterator(state)
   126  	for it.Next() {
   127  	}
   128  	return it.Error
   129  }
   130  
   131  // Tests that an empty state is not scheduled for syncing.
   132  func TestEmptyStateSync(t *testing.T) {
   133  	dbA := trie.NewDatabase(rawdb.NewMemoryDatabase(), nil)
   134  	dbB := trie.NewDatabase(rawdb.NewMemoryDatabase(), &trie.Config{PathDB: pathdb.Defaults})
   135  
   136  	sync := NewStateSync(types.EmptyRootHash, rawdb.NewMemoryDatabase(), nil, dbA.Scheme())
   137  	if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 {
   138  		t.Errorf("content requested for empty state: %v, %v, %v", nodes, paths, codes)
   139  	}
   140  	sync = NewStateSync(types.EmptyRootHash, rawdb.NewMemoryDatabase(), nil, dbB.Scheme())
   141  	if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 {
   142  		t.Errorf("content requested for empty state: %v, %v, %v", nodes, paths, codes)
   143  	}
   144  }
   145  
   146  // Tests that given a root hash, a state can sync iteratively on a single thread,
   147  // requesting retrieval tasks and returning all of them in one go.
   148  func TestIterativeStateSyncIndividual(t *testing.T) {
   149  	testIterativeStateSync(t, 1, false, false, rawdb.HashScheme)
   150  	testIterativeStateSync(t, 1, false, false, rawdb.PathScheme)
   151  }
   152  func TestIterativeStateSyncBatched(t *testing.T) {
   153  	testIterativeStateSync(t, 100, false, false, rawdb.HashScheme)
   154  	testIterativeStateSync(t, 100, false, false, rawdb.PathScheme)
   155  }
   156  func TestIterativeStateSyncIndividualFromDisk(t *testing.T) {
   157  	testIterativeStateSync(t, 1, true, false, rawdb.HashScheme)
   158  	testIterativeStateSync(t, 1, true, false, rawdb.PathScheme)
   159  }
   160  func TestIterativeStateSyncBatchedFromDisk(t *testing.T) {
   161  	testIterativeStateSync(t, 100, true, false, rawdb.HashScheme)
   162  	testIterativeStateSync(t, 100, true, false, rawdb.PathScheme)
   163  }
   164  func TestIterativeStateSyncIndividualByPath(t *testing.T) {
   165  	testIterativeStateSync(t, 1, false, true, rawdb.HashScheme)
   166  	testIterativeStateSync(t, 1, false, true, rawdb.PathScheme)
   167  }
   168  func TestIterativeStateSyncBatchedByPath(t *testing.T) {
   169  	testIterativeStateSync(t, 100, false, true, rawdb.HashScheme)
   170  	testIterativeStateSync(t, 100, false, true, rawdb.PathScheme)
   171  }
   172  
   173  // stateElement represents the element in the state trie(bytecode or trie node).
   174  type stateElement struct {
   175  	path     string
   176  	hash     common.Hash
   177  	code     common.Hash
   178  	syncPath trie.SyncPath
   179  }
   180  
   181  func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, scheme string) {
   182  	// Create a random state to copy
   183  	srcDisk, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme)
   184  	if commit {
   185  		ndb.Commit(srcRoot, false)
   186  	}
   187  	srcTrie, _ := trie.New(trie.StateTrieID(srcRoot), ndb)
   188  
   189  	// Create a destination state and sync with the scheduler
   190  	dstDb := rawdb.NewMemoryDatabase()
   191  	sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme())
   192  
   193  	var (
   194  		nodeElements []stateElement
   195  		codeElements []stateElement
   196  	)
   197  	paths, nodes, codes := sched.Missing(count)
   198  	for i := 0; i < len(paths); i++ {
   199  		nodeElements = append(nodeElements, stateElement{
   200  			path:     paths[i],
   201  			hash:     nodes[i],
   202  			syncPath: trie.NewSyncPath([]byte(paths[i])),
   203  		})
   204  	}
   205  	for i := 0; i < len(codes); i++ {
   206  		codeElements = append(codeElements, stateElement{code: codes[i]})
   207  	}
   208  	reader, err := ndb.Reader(srcRoot)
   209  	if err != nil {
   210  		t.Fatalf("state is not existent, %#x", srcRoot)
   211  	}
   212  	for len(nodeElements)+len(codeElements) > 0 {
   213  		var (
   214  			nodeResults = make([]trie.NodeSyncResult, len(nodeElements))
   215  			codeResults = make([]trie.CodeSyncResult, len(codeElements))
   216  		)
   217  		for i, element := range codeElements {
   218  			data, err := srcDb.ContractCode(common.Address{}, element.code)
   219  			if err != nil {
   220  				t.Fatalf("failed to retrieve contract bytecode for hash %x", element.code)
   221  			}
   222  			codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data}
   223  		}
   224  		for i, node := range nodeElements {
   225  			if bypath {
   226  				if len(node.syncPath) == 1 {
   227  					data, _, err := srcTrie.GetNode(node.syncPath[0])
   228  					if err != nil {
   229  						t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[0], err)
   230  					}
   231  					nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data}
   232  				} else {
   233  					var acc types.StateAccount
   234  					if err := rlp.DecodeBytes(srcTrie.MustGet(node.syncPath[0]), &acc); err != nil {
   235  						t.Fatalf("failed to decode account on path %x: %v", node.syncPath[0], err)
   236  					}
   237  					id := trie.StorageTrieID(srcRoot, common.BytesToHash(node.syncPath[0]), acc.Root)
   238  					stTrie, err := trie.New(id, ndb)
   239  					if err != nil {
   240  						t.Fatalf("failed to retriev storage trie for path %x: %v", node.syncPath[1], err)
   241  					}
   242  					data, _, err := stTrie.GetNode(node.syncPath[1])
   243  					if err != nil {
   244  						t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[1], err)
   245  					}
   246  					nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data}
   247  				}
   248  			} else {
   249  				owner, inner := trie.ResolvePath([]byte(node.path))
   250  				data, err := reader.Node(owner, inner, node.hash)
   251  				if err != nil {
   252  					t.Fatalf("failed to retrieve node data for key %v", []byte(node.path))
   253  				}
   254  				nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data}
   255  			}
   256  		}
   257  		for _, result := range codeResults {
   258  			if err := sched.ProcessCode(result); err != nil {
   259  				t.Errorf("failed to process result %v", err)
   260  			}
   261  		}
   262  		for _, result := range nodeResults {
   263  			if err := sched.ProcessNode(result); err != nil {
   264  				t.Errorf("failed to process result %v", err)
   265  			}
   266  		}
   267  		batch := dstDb.NewBatch()
   268  		if err := sched.Commit(batch); err != nil {
   269  			t.Fatalf("failed to commit data: %v", err)
   270  		}
   271  		batch.Write()
   272  
   273  		paths, nodes, codes = sched.Missing(count)
   274  		nodeElements = nodeElements[:0]
   275  		for i := 0; i < len(paths); i++ {
   276  			nodeElements = append(nodeElements, stateElement{
   277  				path:     paths[i],
   278  				hash:     nodes[i],
   279  				syncPath: trie.NewSyncPath([]byte(paths[i])),
   280  			})
   281  		}
   282  		codeElements = codeElements[:0]
   283  		for i := 0; i < len(codes); i++ {
   284  			codeElements = append(codeElements, stateElement{
   285  				code: codes[i],
   286  			})
   287  		}
   288  	}
   289  	// Copy the preimages from source db in order to traverse the state.
   290  	srcDb.TrieDB().WritePreimages()
   291  	copyPreimages(srcDisk, dstDb)
   292  
   293  	// Cross check that the two states are in sync
   294  	checkStateAccounts(t, dstDb, ndb.Scheme(), srcRoot, srcAccounts)
   295  }
   296  
   297  // Tests that the trie scheduler can correctly reconstruct the state even if only
   298  // partial results are returned, and the others sent only later.
   299  func TestIterativeDelayedStateSync(t *testing.T) {
   300  	testIterativeDelayedStateSync(t, rawdb.HashScheme)
   301  	testIterativeDelayedStateSync(t, rawdb.PathScheme)
   302  }
   303  
   304  func testIterativeDelayedStateSync(t *testing.T, scheme string) {
   305  	// Create a random state to copy
   306  	srcDisk, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme)
   307  
   308  	// Create a destination state and sync with the scheduler
   309  	dstDb := rawdb.NewMemoryDatabase()
   310  	sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme())
   311  
   312  	var (
   313  		nodeElements []stateElement
   314  		codeElements []stateElement
   315  	)
   316  	paths, nodes, codes := sched.Missing(0)
   317  	for i := 0; i < len(paths); i++ {
   318  		nodeElements = append(nodeElements, stateElement{
   319  			path:     paths[i],
   320  			hash:     nodes[i],
   321  			syncPath: trie.NewSyncPath([]byte(paths[i])),
   322  		})
   323  	}
   324  	for i := 0; i < len(codes); i++ {
   325  		codeElements = append(codeElements, stateElement{code: codes[i]})
   326  	}
   327  	reader, err := ndb.Reader(srcRoot)
   328  	if err != nil {
   329  		t.Fatalf("state is not existent, %#x", srcRoot)
   330  	}
   331  	for len(nodeElements)+len(codeElements) > 0 {
   332  		// Sync only half of the scheduled nodes
   333  		var nodeProcessed int
   334  		var codeProcessed int
   335  		if len(codeElements) > 0 {
   336  			codeResults := make([]trie.CodeSyncResult, len(codeElements)/2+1)
   337  			for i, element := range codeElements[:len(codeResults)] {
   338  				data, err := srcDb.ContractCode(common.Address{}, element.code)
   339  				if err != nil {
   340  					t.Fatalf("failed to retrieve contract bytecode for %x", element.code)
   341  				}
   342  				codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data}
   343  			}
   344  			for _, result := range codeResults {
   345  				if err := sched.ProcessCode(result); err != nil {
   346  					t.Fatalf("failed to process result %v", err)
   347  				}
   348  			}
   349  			codeProcessed = len(codeResults)
   350  		}
   351  		if len(nodeElements) > 0 {
   352  			nodeResults := make([]trie.NodeSyncResult, len(nodeElements)/2+1)
   353  			for i, element := range nodeElements[:len(nodeResults)] {
   354  				owner, inner := trie.ResolvePath([]byte(element.path))
   355  				data, err := reader.Node(owner, inner, element.hash)
   356  				if err != nil {
   357  					t.Fatalf("failed to retrieve contract bytecode for %x", element.code)
   358  				}
   359  				nodeResults[i] = trie.NodeSyncResult{Path: element.path, Data: data}
   360  			}
   361  			for _, result := range nodeResults {
   362  				if err := sched.ProcessNode(result); err != nil {
   363  					t.Fatalf("failed to process result %v", err)
   364  				}
   365  			}
   366  			nodeProcessed = len(nodeResults)
   367  		}
   368  		batch := dstDb.NewBatch()
   369  		if err := sched.Commit(batch); err != nil {
   370  			t.Fatalf("failed to commit data: %v", err)
   371  		}
   372  		batch.Write()
   373  
   374  		paths, nodes, codes = sched.Missing(0)
   375  		nodeElements = nodeElements[nodeProcessed:]
   376  		for i := 0; i < len(paths); i++ {
   377  			nodeElements = append(nodeElements, stateElement{
   378  				path:     paths[i],
   379  				hash:     nodes[i],
   380  				syncPath: trie.NewSyncPath([]byte(paths[i])),
   381  			})
   382  		}
   383  		codeElements = codeElements[codeProcessed:]
   384  		for i := 0; i < len(codes); i++ {
   385  			codeElements = append(codeElements, stateElement{
   386  				code: codes[i],
   387  			})
   388  		}
   389  	}
   390  	// Copy the preimages from source db in order to traverse the state.
   391  	srcDb.TrieDB().WritePreimages()
   392  	copyPreimages(srcDisk, dstDb)
   393  
   394  	// Cross check that the two states are in sync
   395  	checkStateAccounts(t, dstDb, ndb.Scheme(), srcRoot, srcAccounts)
   396  }
   397  
   398  // Tests that given a root hash, a trie can sync iteratively on a single thread,
   399  // requesting retrieval tasks and returning all of them in one go, however in a
   400  // random order.
   401  func TestIterativeRandomStateSyncIndividual(t *testing.T) {
   402  	testIterativeRandomStateSync(t, 1, rawdb.HashScheme)
   403  	testIterativeRandomStateSync(t, 1, rawdb.PathScheme)
   404  }
   405  func TestIterativeRandomStateSyncBatched(t *testing.T) {
   406  	testIterativeRandomStateSync(t, 100, rawdb.HashScheme)
   407  	testIterativeRandomStateSync(t, 100, rawdb.PathScheme)
   408  }
   409  
   410  func testIterativeRandomStateSync(t *testing.T, count int, scheme string) {
   411  	// Create a random state to copy
   412  	srcDisk, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme)
   413  
   414  	// Create a destination state and sync with the scheduler
   415  	dstDb := rawdb.NewMemoryDatabase()
   416  	sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme())
   417  
   418  	nodeQueue := make(map[string]stateElement)
   419  	codeQueue := make(map[common.Hash]struct{})
   420  	paths, nodes, codes := sched.Missing(count)
   421  	for i, path := range paths {
   422  		nodeQueue[path] = stateElement{
   423  			path:     path,
   424  			hash:     nodes[i],
   425  			syncPath: trie.NewSyncPath([]byte(path)),
   426  		}
   427  	}
   428  	for _, hash := range codes {
   429  		codeQueue[hash] = struct{}{}
   430  	}
   431  	reader, err := ndb.Reader(srcRoot)
   432  	if err != nil {
   433  		t.Fatalf("state is not existent, %#x", srcRoot)
   434  	}
   435  	for len(nodeQueue)+len(codeQueue) > 0 {
   436  		// Fetch all the queued nodes in a random order
   437  		if len(codeQueue) > 0 {
   438  			results := make([]trie.CodeSyncResult, 0, len(codeQueue))
   439  			for hash := range codeQueue {
   440  				data, err := srcDb.ContractCode(common.Address{}, hash)
   441  				if err != nil {
   442  					t.Fatalf("failed to retrieve node data for %x", hash)
   443  				}
   444  				results = append(results, trie.CodeSyncResult{Hash: hash, Data: data})
   445  			}
   446  			for _, result := range results {
   447  				if err := sched.ProcessCode(result); err != nil {
   448  					t.Fatalf("failed to process result %v", err)
   449  				}
   450  			}
   451  		}
   452  		if len(nodeQueue) > 0 {
   453  			results := make([]trie.NodeSyncResult, 0, len(nodeQueue))
   454  			for path, element := range nodeQueue {
   455  				owner, inner := trie.ResolvePath([]byte(element.path))
   456  				data, err := reader.Node(owner, inner, element.hash)
   457  				if err != nil {
   458  					t.Fatalf("failed to retrieve node data for %x %v %v", element.hash, []byte(element.path), element.path)
   459  				}
   460  				results = append(results, trie.NodeSyncResult{Path: path, Data: data})
   461  			}
   462  			for _, result := range results {
   463  				if err := sched.ProcessNode(result); err != nil {
   464  					t.Fatalf("failed to process result %v", err)
   465  				}
   466  			}
   467  		}
   468  		batch := dstDb.NewBatch()
   469  		if err := sched.Commit(batch); err != nil {
   470  			t.Fatalf("failed to commit data: %v", err)
   471  		}
   472  		batch.Write()
   473  
   474  		nodeQueue = make(map[string]stateElement)
   475  		codeQueue = make(map[common.Hash]struct{})
   476  		paths, nodes, codes := sched.Missing(count)
   477  		for i, path := range paths {
   478  			nodeQueue[path] = stateElement{
   479  				path:     path,
   480  				hash:     nodes[i],
   481  				syncPath: trie.NewSyncPath([]byte(path)),
   482  			}
   483  		}
   484  		for _, hash := range codes {
   485  			codeQueue[hash] = struct{}{}
   486  		}
   487  	}
   488  	// Copy the preimages from source db in order to traverse the state.
   489  	srcDb.TrieDB().WritePreimages()
   490  	copyPreimages(srcDisk, dstDb)
   491  
   492  	// Cross check that the two states are in sync
   493  	checkStateAccounts(t, dstDb, ndb.Scheme(), srcRoot, srcAccounts)
   494  }
   495  
   496  // Tests that the trie scheduler can correctly reconstruct the state even if only
   497  // partial results are returned (Even those randomly), others sent only later.
   498  func TestIterativeRandomDelayedStateSync(t *testing.T) {
   499  	testIterativeRandomDelayedStateSync(t, rawdb.HashScheme)
   500  	testIterativeRandomDelayedStateSync(t, rawdb.PathScheme)
   501  }
   502  
   503  func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) {
   504  	// Create a random state to copy
   505  	srcDisk, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme)
   506  
   507  	// Create a destination state and sync with the scheduler
   508  	dstDb := rawdb.NewMemoryDatabase()
   509  	sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme())
   510  
   511  	nodeQueue := make(map[string]stateElement)
   512  	codeQueue := make(map[common.Hash]struct{})
   513  	paths, nodes, codes := sched.Missing(0)
   514  	for i, path := range paths {
   515  		nodeQueue[path] = stateElement{
   516  			path:     path,
   517  			hash:     nodes[i],
   518  			syncPath: trie.NewSyncPath([]byte(path)),
   519  		}
   520  	}
   521  	for _, hash := range codes {
   522  		codeQueue[hash] = struct{}{}
   523  	}
   524  	reader, err := ndb.Reader(srcRoot)
   525  	if err != nil {
   526  		t.Fatalf("state is not existent, %#x", srcRoot)
   527  	}
   528  	for len(nodeQueue)+len(codeQueue) > 0 {
   529  		// Sync only half of the scheduled nodes, even those in random order
   530  		if len(codeQueue) > 0 {
   531  			results := make([]trie.CodeSyncResult, 0, len(codeQueue)/2+1)
   532  			for hash := range codeQueue {
   533  				delete(codeQueue, hash)
   534  
   535  				data, err := srcDb.ContractCode(common.Address{}, hash)
   536  				if err != nil {
   537  					t.Fatalf("failed to retrieve node data for %x", hash)
   538  				}
   539  				results = append(results, trie.CodeSyncResult{Hash: hash, Data: data})
   540  
   541  				if len(results) >= cap(results) {
   542  					break
   543  				}
   544  			}
   545  			for _, result := range results {
   546  				if err := sched.ProcessCode(result); err != nil {
   547  					t.Fatalf("failed to process result %v", err)
   548  				}
   549  			}
   550  		}
   551  		if len(nodeQueue) > 0 {
   552  			results := make([]trie.NodeSyncResult, 0, len(nodeQueue)/2+1)
   553  			for path, element := range nodeQueue {
   554  				delete(nodeQueue, path)
   555  
   556  				owner, inner := trie.ResolvePath([]byte(element.path))
   557  				data, err := reader.Node(owner, inner, element.hash)
   558  				if err != nil {
   559  					t.Fatalf("failed to retrieve node data for %x", element.hash)
   560  				}
   561  				results = append(results, trie.NodeSyncResult{Path: path, Data: data})
   562  
   563  				if len(results) >= cap(results) {
   564  					break
   565  				}
   566  			}
   567  			// Feed the retrieved results back and queue new tasks
   568  			for _, result := range results {
   569  				if err := sched.ProcessNode(result); err != nil {
   570  					t.Fatalf("failed to process result %v", err)
   571  				}
   572  			}
   573  		}
   574  		batch := dstDb.NewBatch()
   575  		if err := sched.Commit(batch); err != nil {
   576  			t.Fatalf("failed to commit data: %v", err)
   577  		}
   578  		batch.Write()
   579  
   580  		paths, nodes, codes := sched.Missing(0)
   581  		for i, path := range paths {
   582  			nodeQueue[path] = stateElement{
   583  				path:     path,
   584  				hash:     nodes[i],
   585  				syncPath: trie.NewSyncPath([]byte(path)),
   586  			}
   587  		}
   588  		for _, hash := range codes {
   589  			codeQueue[hash] = struct{}{}
   590  		}
   591  	}
   592  	// Copy the preimages from source db in order to traverse the state.
   593  	srcDb.TrieDB().WritePreimages()
   594  	copyPreimages(srcDisk, dstDb)
   595  
   596  	// Cross check that the two states are in sync
   597  	checkStateAccounts(t, dstDb, ndb.Scheme(), srcRoot, srcAccounts)
   598  }
   599  
   600  // Tests that at any point in time during a sync, only complete sub-tries are in
   601  // the database.
   602  func TestIncompleteStateSync(t *testing.T) {
   603  	testIncompleteStateSync(t, rawdb.HashScheme)
   604  	testIncompleteStateSync(t, rawdb.PathScheme)
   605  }
   606  
   607  func testIncompleteStateSync(t *testing.T, scheme string) {
   608  	// Create a random state to copy
   609  	db, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme)
   610  
   611  	// isCodeLookup to save some hashing
   612  	var isCode = make(map[common.Hash]struct{})
   613  	for _, acc := range srcAccounts {
   614  		if len(acc.code) > 0 {
   615  			isCode[crypto.Keccak256Hash(acc.code)] = struct{}{}
   616  		}
   617  	}
   618  	isCode[types.EmptyCodeHash] = struct{}{}
   619  
   620  	// Create a destination state and sync with the scheduler
   621  	dstDb := rawdb.NewMemoryDatabase()
   622  	sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme())
   623  
   624  	var (
   625  		addedCodes  []common.Hash
   626  		addedPaths  []string
   627  		addedHashes []common.Hash
   628  	)
   629  	reader, err := ndb.Reader(srcRoot)
   630  	if err != nil {
   631  		t.Fatalf("state is not available %x", srcRoot)
   632  	}
   633  	nodeQueue := make(map[string]stateElement)
   634  	codeQueue := make(map[common.Hash]struct{})
   635  	paths, nodes, codes := sched.Missing(1)
   636  	for i, path := range paths {
   637  		nodeQueue[path] = stateElement{
   638  			path:     path,
   639  			hash:     nodes[i],
   640  			syncPath: trie.NewSyncPath([]byte(path)),
   641  		}
   642  	}
   643  	for _, hash := range codes {
   644  		codeQueue[hash] = struct{}{}
   645  	}
   646  	for len(nodeQueue)+len(codeQueue) > 0 {
   647  		// Fetch a batch of state nodes
   648  		if len(codeQueue) > 0 {
   649  			results := make([]trie.CodeSyncResult, 0, len(codeQueue))
   650  			for hash := range codeQueue {
   651  				data, err := srcDb.ContractCode(common.Address{}, hash)
   652  				if err != nil {
   653  					t.Fatalf("failed to retrieve node data for %x", hash)
   654  				}
   655  				results = append(results, trie.CodeSyncResult{Hash: hash, Data: data})
   656  				addedCodes = append(addedCodes, hash)
   657  			}
   658  			// Process each of the state nodes
   659  			for _, result := range results {
   660  				if err := sched.ProcessCode(result); err != nil {
   661  					t.Fatalf("failed to process result %v", err)
   662  				}
   663  			}
   664  		}
   665  		if len(nodeQueue) > 0 {
   666  			results := make([]trie.NodeSyncResult, 0, len(nodeQueue))
   667  			for path, element := range nodeQueue {
   668  				owner, inner := trie.ResolvePath([]byte(element.path))
   669  				data, err := reader.Node(owner, inner, element.hash)
   670  				if err != nil {
   671  					t.Fatalf("failed to retrieve node data for %x", element.hash)
   672  				}
   673  				results = append(results, trie.NodeSyncResult{Path: path, Data: data})
   674  
   675  				if element.hash != srcRoot {
   676  					addedPaths = append(addedPaths, element.path)
   677  					addedHashes = append(addedHashes, element.hash)
   678  				}
   679  			}
   680  			// Process each of the state nodes
   681  			for _, result := range results {
   682  				if err := sched.ProcessNode(result); err != nil {
   683  					t.Fatalf("failed to process result %v", err)
   684  				}
   685  			}
   686  		}
   687  		batch := dstDb.NewBatch()
   688  		if err := sched.Commit(batch); err != nil {
   689  			t.Fatalf("failed to commit data: %v", err)
   690  		}
   691  		batch.Write()
   692  
   693  		// Fetch the next batch to retrieve
   694  		nodeQueue = make(map[string]stateElement)
   695  		codeQueue = make(map[common.Hash]struct{})
   696  		paths, nodes, codes := sched.Missing(1)
   697  		for i, path := range paths {
   698  			nodeQueue[path] = stateElement{
   699  				path:     path,
   700  				hash:     nodes[i],
   701  				syncPath: trie.NewSyncPath([]byte(path)),
   702  			}
   703  		}
   704  		for _, hash := range codes {
   705  			codeQueue[hash] = struct{}{}
   706  		}
   707  	}
   708  	// Copy the preimages from source db in order to traverse the state.
   709  	srcDb.TrieDB().WritePreimages()
   710  	copyPreimages(db, dstDb)
   711  
   712  	// Sanity check that removing any node from the database is detected
   713  	for _, node := range addedCodes {
   714  		val := rawdb.ReadCode(dstDb, node)
   715  		rawdb.DeleteCode(dstDb, node)
   716  		if err := checkStateConsistency(dstDb, ndb.Scheme(), srcRoot); err == nil {
   717  			t.Errorf("trie inconsistency not caught, missing: %x", node)
   718  		}
   719  		rawdb.WriteCode(dstDb, node, val)
   720  	}
   721  	for i, path := range addedPaths {
   722  		owner, inner := trie.ResolvePath([]byte(path))
   723  		hash := addedHashes[i]
   724  		val := rawdb.ReadTrieNode(dstDb, owner, inner, hash, scheme)
   725  		if val == nil {
   726  			t.Error("missing trie node")
   727  		}
   728  		rawdb.DeleteTrieNode(dstDb, owner, inner, hash, scheme)
   729  		if err := checkStateConsistency(dstDb, scheme, srcRoot); err == nil {
   730  			t.Errorf("trie inconsistency not caught, missing: %v", path)
   731  		}
   732  		rawdb.WriteTrieNode(dstDb, owner, inner, hash, val, scheme)
   733  	}
   734  }
   735  
   736  func copyPreimages(srcDb, dstDb zonddb.Database) {
   737  	it := srcDb.NewIterator(rawdb.PreimagePrefix, nil)
   738  	defer it.Release()
   739  
   740  	preimages := make(map[common.Hash][]byte)
   741  	for it.Next() {
   742  		hash := it.Key()[len(rawdb.PreimagePrefix):]
   743  		preimages[common.BytesToHash(hash)] = common.CopyBytes(it.Value())
   744  	}
   745  	rawdb.WritePreimages(dstDb, preimages)
   746  }