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