github.com/ethereum/go-ethereum@v1.14.3/core/state/snapshot/generate_test.go (about)

     1  // Copyright 2019 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 snapshot
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/core/rawdb"
    27  	"github.com/ethereum/go-ethereum/core/types"
    28  	"github.com/ethereum/go-ethereum/ethdb"
    29  	"github.com/ethereum/go-ethereum/log"
    30  	"github.com/ethereum/go-ethereum/rlp"
    31  	"github.com/ethereum/go-ethereum/trie"
    32  	"github.com/ethereum/go-ethereum/trie/trienode"
    33  	"github.com/ethereum/go-ethereum/triedb"
    34  	"github.com/ethereum/go-ethereum/triedb/hashdb"
    35  	"github.com/ethereum/go-ethereum/triedb/pathdb"
    36  	"github.com/holiman/uint256"
    37  	"golang.org/x/crypto/sha3"
    38  )
    39  
    40  func hashData(input []byte) common.Hash {
    41  	var hasher = sha3.NewLegacyKeccak256()
    42  	var hash common.Hash
    43  	hasher.Reset()
    44  	hasher.Write(input)
    45  	hasher.Sum(hash[:0])
    46  	return hash
    47  }
    48  
    49  // Tests that snapshot generation from an empty database.
    50  func TestGeneration(t *testing.T) {
    51  	testGeneration(t, rawdb.HashScheme)
    52  	testGeneration(t, rawdb.PathScheme)
    53  }
    54  
    55  func testGeneration(t *testing.T, scheme string) {
    56  	// We can't use statedb to make a test trie (circular dependency), so make
    57  	// a fake one manually. We're going with a small account trie of 3 accounts,
    58  	// two of which also has the same 3-slot storage trie attached.
    59  	var helper = newHelper(scheme)
    60  	stRoot := helper.makeStorageTrie(common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, false)
    61  
    62  	helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
    63  	helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
    64  	helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
    65  
    66  	helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
    67  	helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
    68  
    69  	root, snap := helper.CommitAndGenerate()
    70  	if have, want := root, common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"); have != want {
    71  		t.Fatalf("have %#x want %#x", have, want)
    72  	}
    73  	select {
    74  	case <-snap.genPending:
    75  		// Snapshot generation succeeded
    76  
    77  	case <-time.After(3 * time.Second):
    78  		t.Errorf("Snapshot generation failed")
    79  	}
    80  	checkSnapRoot(t, snap, root)
    81  
    82  	// Signal abortion to the generator and wait for it to tear down
    83  	stop := make(chan *generatorStats)
    84  	snap.genAbort <- stop
    85  	<-stop
    86  }
    87  
    88  // Tests that snapshot generation with existent flat state.
    89  func TestGenerateExistentState(t *testing.T) {
    90  	testGenerateExistentState(t, rawdb.HashScheme)
    91  	testGenerateExistentState(t, rawdb.PathScheme)
    92  }
    93  
    94  func testGenerateExistentState(t *testing.T, scheme string) {
    95  	// We can't use statedb to make a test trie (circular dependency), so make
    96  	// a fake one manually. We're going with a small account trie of 3 accounts,
    97  	// two of which also has the same 3-slot storage trie attached.
    98  	var helper = newHelper(scheme)
    99  
   100  	stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   101  	helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   102  	helper.addSnapAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   103  	helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   104  
   105  	helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
   106  	helper.addSnapAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
   107  
   108  	stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   109  	helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   110  	helper.addSnapAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   111  	helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   112  
   113  	root, snap := helper.CommitAndGenerate()
   114  	select {
   115  	case <-snap.genPending:
   116  		// Snapshot generation succeeded
   117  
   118  	case <-time.After(3 * time.Second):
   119  		t.Errorf("Snapshot generation failed")
   120  	}
   121  	checkSnapRoot(t, snap, root)
   122  
   123  	// Signal abortion to the generator and wait for it to tear down
   124  	stop := make(chan *generatorStats)
   125  	snap.genAbort <- stop
   126  	<-stop
   127  }
   128  
   129  func checkSnapRoot(t *testing.T, snap *diskLayer, trieRoot common.Hash) {
   130  	t.Helper()
   131  
   132  	accIt := snap.AccountIterator(common.Hash{})
   133  	defer accIt.Release()
   134  
   135  	snapRoot, err := generateTrieRoot(nil, "", accIt, common.Hash{}, stackTrieGenerate,
   136  		func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) {
   137  			storageIt, _ := snap.StorageIterator(accountHash, common.Hash{})
   138  			defer storageIt.Release()
   139  
   140  			hash, err := generateTrieRoot(nil, "", storageIt, accountHash, stackTrieGenerate, nil, stat, false)
   141  			if err != nil {
   142  				return common.Hash{}, err
   143  			}
   144  			return hash, nil
   145  		}, newGenerateStats(), true)
   146  	if err != nil {
   147  		t.Fatal(err)
   148  	}
   149  	if snapRoot != trieRoot {
   150  		t.Fatalf("snaproot: %#x != trieroot #%x", snapRoot, trieRoot)
   151  	}
   152  	if err := CheckDanglingStorage(snap.diskdb); err != nil {
   153  		t.Fatalf("Detected dangling storages: %v", err)
   154  	}
   155  }
   156  
   157  type testHelper struct {
   158  	diskdb  ethdb.Database
   159  	triedb  *triedb.Database
   160  	accTrie *trie.StateTrie
   161  	nodes   *trienode.MergedNodeSet
   162  }
   163  
   164  func newHelper(scheme string) *testHelper {
   165  	diskdb := rawdb.NewMemoryDatabase()
   166  	config := &triedb.Config{}
   167  	if scheme == rawdb.PathScheme {
   168  		config.PathDB = &pathdb.Config{} // disable caching
   169  	} else {
   170  		config.HashDB = &hashdb.Config{} // disable caching
   171  	}
   172  	triedb := triedb.NewDatabase(diskdb, config)
   173  	accTrie, _ := trie.NewStateTrie(trie.StateTrieID(types.EmptyRootHash), triedb)
   174  	return &testHelper{
   175  		diskdb:  diskdb,
   176  		triedb:  triedb,
   177  		accTrie: accTrie,
   178  		nodes:   trienode.NewMergedNodeSet(),
   179  	}
   180  }
   181  
   182  func (t *testHelper) addTrieAccount(acckey string, acc *types.StateAccount) {
   183  	val, _ := rlp.EncodeToBytes(acc)
   184  	t.accTrie.MustUpdate([]byte(acckey), val)
   185  }
   186  
   187  func (t *testHelper) addSnapAccount(acckey string, acc *types.StateAccount) {
   188  	key := hashData([]byte(acckey))
   189  	rawdb.WriteAccountSnapshot(t.diskdb, key, types.SlimAccountRLP(*acc))
   190  }
   191  
   192  func (t *testHelper) addAccount(acckey string, acc *types.StateAccount) {
   193  	t.addTrieAccount(acckey, acc)
   194  	t.addSnapAccount(acckey, acc)
   195  }
   196  
   197  func (t *testHelper) addSnapStorage(accKey string, keys []string, vals []string) {
   198  	accHash := hashData([]byte(accKey))
   199  	for i, key := range keys {
   200  		rawdb.WriteStorageSnapshot(t.diskdb, accHash, hashData([]byte(key)), []byte(vals[i]))
   201  	}
   202  }
   203  
   204  func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []string, commit bool) common.Hash {
   205  	id := trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash)
   206  	stTrie, _ := trie.NewStateTrie(id, t.triedb)
   207  	for i, k := range keys {
   208  		stTrie.MustUpdate([]byte(k), []byte(vals[i]))
   209  	}
   210  	if !commit {
   211  		return stTrie.Hash()
   212  	}
   213  	root, nodes, _ := stTrie.Commit(false)
   214  	if nodes != nil {
   215  		t.nodes.Merge(nodes)
   216  	}
   217  	return root
   218  }
   219  
   220  func (t *testHelper) Commit() common.Hash {
   221  	root, nodes, _ := t.accTrie.Commit(true)
   222  	if nodes != nil {
   223  		t.nodes.Merge(nodes)
   224  	}
   225  	t.triedb.Update(root, types.EmptyRootHash, 0, t.nodes, nil)
   226  	t.triedb.Commit(root, false)
   227  	return root
   228  }
   229  
   230  func (t *testHelper) CommitAndGenerate() (common.Hash, *diskLayer) {
   231  	root := t.Commit()
   232  	snap := generateSnapshot(t.diskdb, t.triedb, 16, root)
   233  	return root, snap
   234  }
   235  
   236  // Tests that snapshot generation with existent flat state, where the flat state
   237  // contains some errors:
   238  // - the contract with empty storage root but has storage entries in the disk
   239  // - the contract with non empty storage root but empty storage slots
   240  // - the contract(non-empty storage) misses some storage slots
   241  //   - miss in the beginning
   242  //   - miss in the middle
   243  //   - miss in the end
   244  //
   245  // - the contract(non-empty storage) has wrong storage slots
   246  //   - wrong slots in the beginning
   247  //   - wrong slots in the middle
   248  //   - wrong slots in the end
   249  //
   250  // - the contract(non-empty storage) has extra storage slots
   251  //   - extra slots in the beginning
   252  //   - extra slots in the middle
   253  //   - extra slots in the end
   254  func TestGenerateExistentStateWithWrongStorage(t *testing.T) {
   255  	testGenerateExistentStateWithWrongStorage(t, rawdb.HashScheme)
   256  	testGenerateExistentStateWithWrongStorage(t, rawdb.PathScheme)
   257  }
   258  
   259  func testGenerateExistentStateWithWrongStorage(t *testing.T, scheme string) {
   260  	helper := newHelper(scheme)
   261  
   262  	// Account one, empty root but non-empty database
   263  	helper.addAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
   264  	helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   265  
   266  	// Account two, non empty root but empty database
   267  	stRoot := helper.makeStorageTrie(hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   268  	helper.addAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   269  
   270  	// Miss slots
   271  	{
   272  		// Account three, non empty root but misses slots in the beginning
   273  		helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   274  		helper.addAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   275  		helper.addSnapStorage("acc-3", []string{"key-2", "key-3"}, []string{"val-2", "val-3"})
   276  
   277  		// Account four, non empty root but misses slots in the middle
   278  		helper.makeStorageTrie(hashData([]byte("acc-4")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   279  		helper.addAccount("acc-4", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   280  		helper.addSnapStorage("acc-4", []string{"key-1", "key-3"}, []string{"val-1", "val-3"})
   281  
   282  		// Account five, non empty root but misses slots in the end
   283  		helper.makeStorageTrie(hashData([]byte("acc-5")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   284  		helper.addAccount("acc-5", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   285  		helper.addSnapStorage("acc-5", []string{"key-1", "key-2"}, []string{"val-1", "val-2"})
   286  	}
   287  
   288  	// Wrong storage slots
   289  	{
   290  		// Account six, non empty root but wrong slots in the beginning
   291  		helper.makeStorageTrie(hashData([]byte("acc-6")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   292  		helper.addAccount("acc-6", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   293  		helper.addSnapStorage("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"badval-1", "val-2", "val-3"})
   294  
   295  		// Account seven, non empty root but wrong slots in the middle
   296  		helper.makeStorageTrie(hashData([]byte("acc-7")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   297  		helper.addAccount("acc-7", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   298  		helper.addSnapStorage("acc-7", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "badval-2", "val-3"})
   299  
   300  		// Account eight, non empty root but wrong slots in the end
   301  		helper.makeStorageTrie(hashData([]byte("acc-8")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   302  		helper.addAccount("acc-8", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   303  		helper.addSnapStorage("acc-8", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "badval-3"})
   304  
   305  		// Account 9, non empty root but rotated slots
   306  		helper.makeStorageTrie(hashData([]byte("acc-9")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   307  		helper.addAccount("acc-9", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   308  		helper.addSnapStorage("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-3", "val-2"})
   309  	}
   310  
   311  	// Extra storage slots
   312  	{
   313  		// Account 10, non empty root but extra slots in the beginning
   314  		helper.makeStorageTrie(hashData([]byte("acc-10")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   315  		helper.addAccount("acc-10", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   316  		helper.addSnapStorage("acc-10", []string{"key-0", "key-1", "key-2", "key-3"}, []string{"val-0", "val-1", "val-2", "val-3"})
   317  
   318  		// Account 11, non empty root but extra slots in the middle
   319  		helper.makeStorageTrie(hashData([]byte("acc-11")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   320  		helper.addAccount("acc-11", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   321  		helper.addSnapStorage("acc-11", []string{"key-1", "key-2", "key-2-1", "key-3"}, []string{"val-1", "val-2", "val-2-1", "val-3"})
   322  
   323  		// Account 12, non empty root but extra slots in the end
   324  		helper.makeStorageTrie(hashData([]byte("acc-12")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   325  		helper.addAccount("acc-12", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   326  		helper.addSnapStorage("acc-12", []string{"key-1", "key-2", "key-3", "key-4"}, []string{"val-1", "val-2", "val-3", "val-4"})
   327  	}
   328  
   329  	root, snap := helper.CommitAndGenerate()
   330  	t.Logf("Root: %#x\n", root) // Root = 0x8746cce9fd9c658b2cfd639878ed6584b7a2b3e73bb40f607fcfa156002429a0
   331  
   332  	select {
   333  	case <-snap.genPending:
   334  		// Snapshot generation succeeded
   335  
   336  	case <-time.After(3 * time.Second):
   337  		t.Errorf("Snapshot generation failed")
   338  	}
   339  	checkSnapRoot(t, snap, root)
   340  	// Signal abortion to the generator and wait for it to tear down
   341  	stop := make(chan *generatorStats)
   342  	snap.genAbort <- stop
   343  	<-stop
   344  }
   345  
   346  // Tests that snapshot generation with existent flat state, where the flat state
   347  // contains some errors:
   348  // - miss accounts
   349  // - wrong accounts
   350  // - extra accounts
   351  func TestGenerateExistentStateWithWrongAccounts(t *testing.T) {
   352  	testGenerateExistentStateWithWrongAccounts(t, rawdb.HashScheme)
   353  	testGenerateExistentStateWithWrongAccounts(t, rawdb.PathScheme)
   354  }
   355  
   356  func testGenerateExistentStateWithWrongAccounts(t *testing.T, scheme string) {
   357  	helper := newHelper(scheme)
   358  
   359  	helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   360  	helper.makeStorageTrie(hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   361  	helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   362  	helper.makeStorageTrie(hashData([]byte("acc-4")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   363  	stRoot := helper.makeStorageTrie(hashData([]byte("acc-6")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   364  
   365  	// Trie accounts [acc-1, acc-2, acc-3, acc-4, acc-6]
   366  	// Extra accounts [acc-0, acc-5, acc-7]
   367  
   368  	// Missing accounts, only in the trie
   369  	{
   370  		helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Beginning
   371  		helper.addTrieAccount("acc-4", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Middle
   372  		helper.addTrieAccount("acc-6", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // End
   373  	}
   374  
   375  	// Wrong accounts
   376  	{
   377  		helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   378  		helper.addSnapAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: common.Hex2Bytes("0x1234")})
   379  
   380  		helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   381  		helper.addSnapAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
   382  	}
   383  
   384  	// Extra accounts, only in the snap
   385  	{
   386  		helper.addSnapAccount("acc-0", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})              // before the beginning
   387  		helper.addSnapAccount("acc-5", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: common.Hex2Bytes("0x1234")})  // Middle
   388  		helper.addSnapAccount("acc-7", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // after the end
   389  	}
   390  
   391  	root, snap := helper.CommitAndGenerate()
   392  	t.Logf("Root: %#x\n", root) // Root = 0x825891472281463511e7ebcc7f109e4f9200c20fa384754e11fd605cd98464e8
   393  
   394  	select {
   395  	case <-snap.genPending:
   396  		// Snapshot generation succeeded
   397  
   398  	case <-time.After(3 * time.Second):
   399  		t.Errorf("Snapshot generation failed")
   400  	}
   401  	checkSnapRoot(t, snap, root)
   402  
   403  	// Signal abortion to the generator and wait for it to tear down
   404  	stop := make(chan *generatorStats)
   405  	snap.genAbort <- stop
   406  	<-stop
   407  }
   408  
   409  // Tests that snapshot generation errors out correctly in case of a missing trie
   410  // node in the account trie.
   411  func TestGenerateCorruptAccountTrie(t *testing.T) {
   412  	testGenerateCorruptAccountTrie(t, rawdb.HashScheme)
   413  	testGenerateCorruptAccountTrie(t, rawdb.PathScheme)
   414  }
   415  
   416  func testGenerateCorruptAccountTrie(t *testing.T, scheme string) {
   417  	// We can't use statedb to make a test trie (circular dependency), so make
   418  	// a fake one manually. We're going with a small account trie of 3 accounts,
   419  	// without any storage slots to keep the test smaller.
   420  	helper := newHelper(scheme)
   421  
   422  	helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074
   423  	helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
   424  	helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4
   425  
   426  	root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978
   427  
   428  	// Delete an account trie node and ensure the generator chokes
   429  	targetPath := []byte{0xc}
   430  	targetHash := common.HexToHash("0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7")
   431  
   432  	rawdb.DeleteTrieNode(helper.diskdb, common.Hash{}, targetPath, targetHash, scheme)
   433  
   434  	snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root)
   435  	select {
   436  	case <-snap.genPending:
   437  		// Snapshot generation succeeded
   438  		t.Errorf("Snapshot generated against corrupt account trie")
   439  
   440  	case <-time.After(time.Second):
   441  		// Not generated fast enough, hopefully blocked inside on missing trie node fail
   442  	}
   443  	// Signal abortion to the generator and wait for it to tear down
   444  	stop := make(chan *generatorStats)
   445  	snap.genAbort <- stop
   446  	<-stop
   447  }
   448  
   449  // Tests that snapshot generation errors out correctly in case of a missing root
   450  // trie node for a storage trie. It's similar to internal corruption but it is
   451  // handled differently inside the generator.
   452  func TestGenerateMissingStorageTrie(t *testing.T) {
   453  	testGenerateMissingStorageTrie(t, rawdb.HashScheme)
   454  	testGenerateMissingStorageTrie(t, rawdb.PathScheme)
   455  }
   456  
   457  func testGenerateMissingStorageTrie(t *testing.T, scheme string) {
   458  	// We can't use statedb to make a test trie (circular dependency), so make
   459  	// a fake one manually. We're going with a small account trie of 3 accounts,
   460  	// two of which also has the same 3-slot storage trie attached.
   461  	var (
   462  		acc1   = hashData([]byte("acc-1"))
   463  		acc3   = hashData([]byte("acc-3"))
   464  		helper = newHelper(scheme)
   465  	)
   466  	stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)       // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
   467  	helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})              // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
   468  	helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
   469  	stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   470  	helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
   471  
   472  	root := helper.Commit()
   473  
   474  	// Delete storage trie root of account one and three.
   475  	rawdb.DeleteTrieNode(helper.diskdb, acc1, nil, stRoot, scheme)
   476  	rawdb.DeleteTrieNode(helper.diskdb, acc3, nil, stRoot, scheme)
   477  
   478  	snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root)
   479  	select {
   480  	case <-snap.genPending:
   481  		// Snapshot generation succeeded
   482  		t.Errorf("Snapshot generated against corrupt storage trie")
   483  
   484  	case <-time.After(time.Second):
   485  		// Not generated fast enough, hopefully blocked inside on missing trie node fail
   486  	}
   487  	// Signal abortion to the generator and wait for it to tear down
   488  	stop := make(chan *generatorStats)
   489  	snap.genAbort <- stop
   490  	<-stop
   491  }
   492  
   493  // Tests that snapshot generation errors out correctly in case of a missing trie
   494  // node in a storage trie.
   495  func TestGenerateCorruptStorageTrie(t *testing.T) {
   496  	testGenerateCorruptStorageTrie(t, rawdb.HashScheme)
   497  	testGenerateCorruptStorageTrie(t, rawdb.PathScheme)
   498  }
   499  
   500  func testGenerateCorruptStorageTrie(t *testing.T, scheme string) {
   501  	// We can't use statedb to make a test trie (circular dependency), so make
   502  	// a fake one manually. We're going with a small account trie of 3 accounts,
   503  	// two of which also has the same 3-slot storage trie attached.
   504  	helper := newHelper(scheme)
   505  
   506  	stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)       // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
   507  	helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})              // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
   508  	helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
   509  	stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   510  	helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
   511  
   512  	root := helper.Commit()
   513  
   514  	// Delete a node in the storage trie.
   515  	targetPath := []byte{0x4}
   516  	targetHash := common.HexToHash("0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371")
   517  	rawdb.DeleteTrieNode(helper.diskdb, hashData([]byte("acc-1")), targetPath, targetHash, scheme)
   518  	rawdb.DeleteTrieNode(helper.diskdb, hashData([]byte("acc-3")), targetPath, targetHash, scheme)
   519  
   520  	snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root)
   521  	select {
   522  	case <-snap.genPending:
   523  		// Snapshot generation succeeded
   524  		t.Errorf("Snapshot generated against corrupt storage trie")
   525  
   526  	case <-time.After(time.Second):
   527  		// Not generated fast enough, hopefully blocked inside on missing trie node fail
   528  	}
   529  	// Signal abortion to the generator and wait for it to tear down
   530  	stop := make(chan *generatorStats)
   531  	snap.genAbort <- stop
   532  	<-stop
   533  }
   534  
   535  // Tests that snapshot generation when an extra account with storage exists in the snap state.
   536  func TestGenerateWithExtraAccounts(t *testing.T) {
   537  	testGenerateWithExtraAccounts(t, rawdb.HashScheme)
   538  	testGenerateWithExtraAccounts(t, rawdb.PathScheme)
   539  }
   540  
   541  func testGenerateWithExtraAccounts(t *testing.T, scheme string) {
   542  	helper := newHelper(scheme)
   543  	{
   544  		// Account one in the trie
   545  		stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")),
   546  			[]string{"key-1", "key-2", "key-3", "key-4", "key-5"},
   547  			[]string{"val-1", "val-2", "val-3", "val-4", "val-5"},
   548  			true,
   549  		)
   550  		acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
   551  		val, _ := rlp.EncodeToBytes(acc)
   552  		helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
   553  
   554  		// Identical in the snap
   555  		key := hashData([]byte("acc-1"))
   556  		rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
   557  		rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-1")), []byte("val-1"))
   558  		rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-2")), []byte("val-2"))
   559  		rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-3")), []byte("val-3"))
   560  		rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-4")), []byte("val-4"))
   561  		rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-5")), []byte("val-5"))
   562  	}
   563  	{
   564  		// Account two exists only in the snapshot
   565  		stRoot := helper.makeStorageTrie(hashData([]byte("acc-2")),
   566  			[]string{"key-1", "key-2", "key-3", "key-4", "key-5"},
   567  			[]string{"val-1", "val-2", "val-3", "val-4", "val-5"},
   568  			true,
   569  		)
   570  		acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
   571  		val, _ := rlp.EncodeToBytes(acc)
   572  		key := hashData([]byte("acc-2"))
   573  		rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
   574  		rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-1")), []byte("b-val-1"))
   575  		rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-2")), []byte("b-val-2"))
   576  		rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-3")), []byte("b-val-3"))
   577  	}
   578  	root := helper.Commit()
   579  
   580  	// To verify the test: If we now inspect the snap db, there should exist extraneous storage items
   581  	if data := rawdb.ReadStorageSnapshot(helper.diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data == nil {
   582  		t.Fatalf("expected snap storage to exist")
   583  	}
   584  	snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root)
   585  	select {
   586  	case <-snap.genPending:
   587  		// Snapshot generation succeeded
   588  
   589  	case <-time.After(3 * time.Second):
   590  		t.Errorf("Snapshot generation failed")
   591  	}
   592  	checkSnapRoot(t, snap, root)
   593  
   594  	// Signal abortion to the generator and wait for it to tear down
   595  	stop := make(chan *generatorStats)
   596  	snap.genAbort <- stop
   597  	<-stop
   598  	// If we now inspect the snap db, there should exist no extraneous storage items
   599  	if data := rawdb.ReadStorageSnapshot(helper.diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil {
   600  		t.Fatalf("expected slot to be removed, got %v", string(data))
   601  	}
   602  }
   603  
   604  func enableLogging() {
   605  	log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
   606  }
   607  
   608  // Tests that snapshot generation when an extra account with storage exists in the snap state.
   609  func TestGenerateWithManyExtraAccounts(t *testing.T) {
   610  	testGenerateWithManyExtraAccounts(t, rawdb.HashScheme)
   611  	testGenerateWithManyExtraAccounts(t, rawdb.PathScheme)
   612  }
   613  
   614  func testGenerateWithManyExtraAccounts(t *testing.T, scheme string) {
   615  	if false {
   616  		enableLogging()
   617  	}
   618  	helper := newHelper(scheme)
   619  	{
   620  		// Account one in the trie
   621  		stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")),
   622  			[]string{"key-1", "key-2", "key-3"},
   623  			[]string{"val-1", "val-2", "val-3"},
   624  			true,
   625  		)
   626  		acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
   627  		val, _ := rlp.EncodeToBytes(acc)
   628  		helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
   629  
   630  		// Identical in the snap
   631  		key := hashData([]byte("acc-1"))
   632  		rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
   633  		rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-1")), []byte("val-1"))
   634  		rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-2")), []byte("val-2"))
   635  		rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-3")), []byte("val-3"))
   636  	}
   637  	{
   638  		// 100 accounts exist only in snapshot
   639  		for i := 0; i < 1000; i++ {
   640  			acc := &types.StateAccount{Balance: uint256.NewInt(uint64(i)), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}
   641  			val, _ := rlp.EncodeToBytes(acc)
   642  			key := hashData([]byte(fmt.Sprintf("acc-%d", i)))
   643  			rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
   644  		}
   645  	}
   646  	root, snap := helper.CommitAndGenerate()
   647  	select {
   648  	case <-snap.genPending:
   649  		// Snapshot generation succeeded
   650  
   651  	case <-time.After(3 * time.Second):
   652  		t.Errorf("Snapshot generation failed")
   653  	}
   654  	checkSnapRoot(t, snap, root)
   655  	// Signal abortion to the generator and wait for it to tear down
   656  	stop := make(chan *generatorStats)
   657  	snap.genAbort <- stop
   658  	<-stop
   659  }
   660  
   661  // Tests this case
   662  // maxAccountRange 3
   663  // snapshot-accounts: 01, 02, 03, 04, 05, 06, 07
   664  // trie-accounts:             03,             07
   665  //
   666  // We iterate three snapshot storage slots (max = 3) from the database. They are 0x01, 0x02, 0x03.
   667  // The trie has a lot of deletions.
   668  // So in trie, we iterate 2 entries 0x03, 0x07. We create the 0x07 in the database and abort the procedure, because the trie is exhausted.
   669  // But in the database, we still have the stale storage slots 0x04, 0x05. They are not iterated yet, but the procedure is finished.
   670  func TestGenerateWithExtraBeforeAndAfter(t *testing.T) {
   671  	testGenerateWithExtraBeforeAndAfter(t, rawdb.HashScheme)
   672  	testGenerateWithExtraBeforeAndAfter(t, rawdb.PathScheme)
   673  }
   674  
   675  func testGenerateWithExtraBeforeAndAfter(t *testing.T, scheme string) {
   676  	accountCheckRange = 3
   677  	if false {
   678  		enableLogging()
   679  	}
   680  	helper := newHelper(scheme)
   681  	{
   682  		acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}
   683  		val, _ := rlp.EncodeToBytes(acc)
   684  		helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val)
   685  		helper.accTrie.MustUpdate(common.HexToHash("0x07").Bytes(), val)
   686  
   687  		rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x01"), val)
   688  		rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x02"), val)
   689  		rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x03"), val)
   690  		rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x04"), val)
   691  		rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x05"), val)
   692  		rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x06"), val)
   693  		rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x07"), val)
   694  	}
   695  	root, snap := helper.CommitAndGenerate()
   696  	select {
   697  	case <-snap.genPending:
   698  		// Snapshot generation succeeded
   699  
   700  	case <-time.After(3 * time.Second):
   701  		t.Errorf("Snapshot generation failed")
   702  	}
   703  	checkSnapRoot(t, snap, root)
   704  	// Signal abortion to the generator and wait for it to tear down
   705  	stop := make(chan *generatorStats)
   706  	snap.genAbort <- stop
   707  	<-stop
   708  }
   709  
   710  // TestGenerateWithMalformedSnapdata tests what happes if we have some junk
   711  // in the snapshot database, which cannot be parsed back to an account
   712  func TestGenerateWithMalformedSnapdata(t *testing.T) {
   713  	testGenerateWithMalformedSnapdata(t, rawdb.HashScheme)
   714  	testGenerateWithMalformedSnapdata(t, rawdb.PathScheme)
   715  }
   716  
   717  func testGenerateWithMalformedSnapdata(t *testing.T, scheme string) {
   718  	accountCheckRange = 3
   719  	if false {
   720  		enableLogging()
   721  	}
   722  	helper := newHelper(scheme)
   723  	{
   724  		acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}
   725  		val, _ := rlp.EncodeToBytes(acc)
   726  		helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val)
   727  
   728  		junk := make([]byte, 100)
   729  		copy(junk, []byte{0xde, 0xad})
   730  		rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x02"), junk)
   731  		rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x03"), junk)
   732  		rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x04"), junk)
   733  		rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x05"), junk)
   734  	}
   735  	root, snap := helper.CommitAndGenerate()
   736  	select {
   737  	case <-snap.genPending:
   738  		// Snapshot generation succeeded
   739  
   740  	case <-time.After(3 * time.Second):
   741  		t.Errorf("Snapshot generation failed")
   742  	}
   743  	checkSnapRoot(t, snap, root)
   744  	// Signal abortion to the generator and wait for it to tear down
   745  	stop := make(chan *generatorStats)
   746  	snap.genAbort <- stop
   747  	<-stop
   748  	// If we now inspect the snap db, there should exist no extraneous storage items
   749  	if data := rawdb.ReadStorageSnapshot(helper.diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil {
   750  		t.Fatalf("expected slot to be removed, got %v", string(data))
   751  	}
   752  }
   753  
   754  func TestGenerateFromEmptySnap(t *testing.T) {
   755  	testGenerateFromEmptySnap(t, rawdb.HashScheme)
   756  	testGenerateFromEmptySnap(t, rawdb.PathScheme)
   757  }
   758  
   759  func testGenerateFromEmptySnap(t *testing.T, scheme string) {
   760  	//enableLogging()
   761  	accountCheckRange = 10
   762  	storageCheckRange = 20
   763  	helper := newHelper(scheme)
   764  	// Add 1K accounts to the trie
   765  	for i := 0; i < 400; i++ {
   766  		stRoot := helper.makeStorageTrie(hashData([]byte(fmt.Sprintf("acc-%d", i))), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   767  		helper.addTrieAccount(fmt.Sprintf("acc-%d", i),
   768  			&types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   769  	}
   770  	root, snap := helper.CommitAndGenerate()
   771  	t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4
   772  
   773  	select {
   774  	case <-snap.genPending:
   775  		// Snapshot generation succeeded
   776  
   777  	case <-time.After(3 * time.Second):
   778  		t.Errorf("Snapshot generation failed")
   779  	}
   780  	checkSnapRoot(t, snap, root)
   781  	// Signal abortion to the generator and wait for it to tear down
   782  	stop := make(chan *generatorStats)
   783  	snap.genAbort <- stop
   784  	<-stop
   785  }
   786  
   787  // Tests that snapshot generation with existent flat state, where the flat state
   788  // storage is correct, but incomplete.
   789  // The incomplete part is on the second range
   790  // snap: [ 0x01, 0x02, 0x03, 0x04] , [ 0x05, 0x06, 0x07, {missing}] (with storageCheck = 4)
   791  // trie:  0x01, 0x02, 0x03, 0x04,  0x05, 0x06, 0x07, 0x08
   792  // This hits a case where the snap verification passes, but there are more elements in the trie
   793  // which we must also add.
   794  func TestGenerateWithIncompleteStorage(t *testing.T) {
   795  	testGenerateWithIncompleteStorage(t, rawdb.HashScheme)
   796  	testGenerateWithIncompleteStorage(t, rawdb.PathScheme)
   797  }
   798  
   799  func testGenerateWithIncompleteStorage(t *testing.T, scheme string) {
   800  	storageCheckRange = 4
   801  	helper := newHelper(scheme)
   802  	stKeys := []string{"1", "2", "3", "4", "5", "6", "7", "8"}
   803  	stVals := []string{"v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"}
   804  	// We add 8 accounts, each one is missing exactly one of the storage slots. This means
   805  	// we don't have to order the keys and figure out exactly which hash-key winds up
   806  	// on the sensitive spots at the boundaries
   807  	for i := 0; i < 8; i++ {
   808  		accKey := fmt.Sprintf("acc-%d", i)
   809  		stRoot := helper.makeStorageTrie(hashData([]byte(accKey)), stKeys, stVals, true)
   810  		helper.addAccount(accKey, &types.StateAccount{Balance: uint256.NewInt(uint64(i)), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   811  		var moddedKeys []string
   812  		var moddedVals []string
   813  		for ii := 0; ii < 8; ii++ {
   814  			if ii != i {
   815  				moddedKeys = append(moddedKeys, stKeys[ii])
   816  				moddedVals = append(moddedVals, stVals[ii])
   817  			}
   818  		}
   819  		helper.addSnapStorage(accKey, moddedKeys, moddedVals)
   820  	}
   821  	root, snap := helper.CommitAndGenerate()
   822  	t.Logf("Root: %#x\n", root) // Root: 0xca73f6f05ba4ca3024ef340ef3dfca8fdabc1b677ff13f5a9571fd49c16e67ff
   823  
   824  	select {
   825  	case <-snap.genPending:
   826  		// Snapshot generation succeeded
   827  
   828  	case <-time.After(3 * time.Second):
   829  		t.Errorf("Snapshot generation failed")
   830  	}
   831  	checkSnapRoot(t, snap, root)
   832  	// Signal abortion to the generator and wait for it to tear down
   833  	stop := make(chan *generatorStats)
   834  	snap.genAbort <- stop
   835  	<-stop
   836  }
   837  
   838  func incKey(key []byte) []byte {
   839  	for i := len(key) - 1; i >= 0; i-- {
   840  		key[i]++
   841  		if key[i] != 0x0 {
   842  			break
   843  		}
   844  	}
   845  	return key
   846  }
   847  
   848  func decKey(key []byte) []byte {
   849  	for i := len(key) - 1; i >= 0; i-- {
   850  		key[i]--
   851  		if key[i] != 0xff {
   852  			break
   853  		}
   854  	}
   855  	return key
   856  }
   857  
   858  func populateDangling(disk ethdb.KeyValueStore) {
   859  	populate := func(accountHash common.Hash, keys []string, vals []string) {
   860  		for i, key := range keys {
   861  			rawdb.WriteStorageSnapshot(disk, accountHash, hashData([]byte(key)), []byte(vals[i]))
   862  		}
   863  	}
   864  	// Dangling storages of the "first" account
   865  	populate(common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   866  
   867  	// Dangling storages of the "last" account
   868  	populate(common.HexToHash("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   869  
   870  	// Dangling storages around the account 1
   871  	hash := decKey(hashData([]byte("acc-1")).Bytes())
   872  	populate(common.BytesToHash(hash), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   873  	hash = incKey(hashData([]byte("acc-1")).Bytes())
   874  	populate(common.BytesToHash(hash), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   875  
   876  	// Dangling storages around the account 2
   877  	hash = decKey(hashData([]byte("acc-2")).Bytes())
   878  	populate(common.BytesToHash(hash), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   879  	hash = incKey(hashData([]byte("acc-2")).Bytes())
   880  	populate(common.BytesToHash(hash), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   881  
   882  	// Dangling storages around the account 3
   883  	hash = decKey(hashData([]byte("acc-3")).Bytes())
   884  	populate(common.BytesToHash(hash), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   885  	hash = incKey(hashData([]byte("acc-3")).Bytes())
   886  	populate(common.BytesToHash(hash), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   887  
   888  	// Dangling storages of the random account
   889  	populate(randomHash(), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   890  	populate(randomHash(), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   891  	populate(randomHash(), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   892  }
   893  
   894  // Tests that snapshot generation with dangling storages. Dangling storage means
   895  // the storage data is existent while the corresponding account data is missing.
   896  //
   897  // This test will populate some dangling storages to see if they can be cleaned up.
   898  func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) {
   899  	testGenerateCompleteSnapshotWithDanglingStorage(t, rawdb.HashScheme)
   900  	testGenerateCompleteSnapshotWithDanglingStorage(t, rawdb.PathScheme)
   901  }
   902  
   903  func testGenerateCompleteSnapshotWithDanglingStorage(t *testing.T, scheme string) {
   904  	var helper = newHelper(scheme)
   905  
   906  	stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   907  	helper.addAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   908  	helper.addAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
   909  
   910  	helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   911  	helper.addAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   912  
   913  	helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   914  	helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
   915  
   916  	populateDangling(helper.diskdb)
   917  
   918  	root, snap := helper.CommitAndGenerate()
   919  	select {
   920  	case <-snap.genPending:
   921  		// Snapshot generation succeeded
   922  
   923  	case <-time.After(3 * time.Second):
   924  		t.Errorf("Snapshot generation failed")
   925  	}
   926  	checkSnapRoot(t, snap, root)
   927  
   928  	// Signal abortion to the generator and wait for it to tear down
   929  	stop := make(chan *generatorStats)
   930  	snap.genAbort <- stop
   931  	<-stop
   932  }
   933  
   934  // Tests that snapshot generation with dangling storages. Dangling storage means
   935  // the storage data is existent while the corresponding account data is missing.
   936  //
   937  // This test will populate some dangling storages to see if they can be cleaned up.
   938  func TestGenerateBrokenSnapshotWithDanglingStorage(t *testing.T) {
   939  	testGenerateBrokenSnapshotWithDanglingStorage(t, rawdb.HashScheme)
   940  	testGenerateBrokenSnapshotWithDanglingStorage(t, rawdb.PathScheme)
   941  }
   942  
   943  func testGenerateBrokenSnapshotWithDanglingStorage(t *testing.T, scheme string) {
   944  	var helper = newHelper(scheme)
   945  
   946  	stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   947  	helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   948  	helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
   949  
   950  	helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
   951  	helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
   952  
   953  	populateDangling(helper.diskdb)
   954  
   955  	root, snap := helper.CommitAndGenerate()
   956  	select {
   957  	case <-snap.genPending:
   958  		// Snapshot generation succeeded
   959  
   960  	case <-time.After(3 * time.Second):
   961  		t.Errorf("Snapshot generation failed")
   962  	}
   963  	checkSnapRoot(t, snap, root)
   964  
   965  	// Signal abortion to the generator and wait for it to tear down
   966  	stop := make(chan *generatorStats)
   967  	snap.genAbort <- stop
   968  	<-stop
   969  }