github.com/Unheilbar/quorum@v1.0.0/core/state/snapshot/generate_test.go (about)

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