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