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