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