gitlab.com/flarenetwork/coreth@v0.1.1/core/state/snapshot/snapshot_test.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2019 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package snapshot
    28  
    29  import (
    30  	"fmt"
    31  	"math/big"
    32  	"math/rand"
    33  	"testing"
    34  
    35  	"github.com/ethereum/go-ethereum/common"
    36  	"github.com/ethereum/go-ethereum/rlp"
    37  	"gitlab.com/flarenetwork/coreth/core/rawdb"
    38  )
    39  
    40  // randomHash generates a random blob of data and returns it as a hash.
    41  func randomHash() common.Hash {
    42  	var hash common.Hash
    43  	if n, err := rand.Read(hash[:]); n != common.HashLength || err != nil {
    44  		panic(err)
    45  	}
    46  	return hash
    47  }
    48  
    49  // randomAccount generates a random account and returns it RLP encoded.
    50  func randomAccount() []byte {
    51  	root := randomHash()
    52  	a := Account{
    53  		Balance:  big.NewInt(rand.Int63()),
    54  		Nonce:    rand.Uint64(),
    55  		Root:     root[:],
    56  		CodeHash: emptyCode[:],
    57  	}
    58  	data, _ := rlp.EncodeToBytes(a)
    59  	return data
    60  }
    61  
    62  // randomAccountSet generates a set of random accounts with the given strings as
    63  // the account address hashes.
    64  func randomAccountSet(hashes ...string) map[common.Hash][]byte {
    65  	accounts := make(map[common.Hash][]byte)
    66  	for _, hash := range hashes {
    67  		accounts[common.HexToHash(hash)] = randomAccount()
    68  	}
    69  	return accounts
    70  }
    71  
    72  // randomStorageSet generates a set of random slots with the given strings as
    73  // the slot addresses.
    74  func randomStorageSet(accounts []string, hashes [][]string, nilStorage [][]string) map[common.Hash]map[common.Hash][]byte {
    75  	storages := make(map[common.Hash]map[common.Hash][]byte)
    76  	for index, account := range accounts {
    77  		storages[common.HexToHash(account)] = make(map[common.Hash][]byte)
    78  
    79  		if index < len(hashes) {
    80  			hashes := hashes[index]
    81  			for _, hash := range hashes {
    82  				storages[common.HexToHash(account)][common.HexToHash(hash)] = randomHash().Bytes()
    83  			}
    84  		}
    85  		if index < len(nilStorage) {
    86  			nils := nilStorage[index]
    87  			for _, hash := range nils {
    88  				storages[common.HexToHash(account)][common.HexToHash(hash)] = nil
    89  			}
    90  		}
    91  	}
    92  	return storages
    93  }
    94  
    95  // Tests that if a disk layer becomes stale, no active external references will
    96  // be returned with junk data. This version of the test flattens every diff layer
    97  // to check internal corner case around the bottom-most memory accumulator.
    98  func TestDiskLayerExternalInvalidationFullFlatten(t *testing.T) {
    99  	// Create an empty base layer and a snapshot tree out of it
   100  	snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01"))
   101  	// Retrieve a reference to the base and commit a diff on top
   102  	ref := snaps.Snapshot(common.HexToHash("0xff01"))
   103  
   104  	accounts := map[common.Hash][]byte{
   105  		common.HexToHash("0xa1"): randomAccount(),
   106  	}
   107  	if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil {
   108  		t.Fatalf("failed to create a diff layer: %v", err)
   109  	}
   110  	if n := snaps.NumStateLayers(); n != 2 {
   111  		t.Errorf("pre-flatten state layer count mismatch: have %d, want %d", n, 2)
   112  	}
   113  	if n := snaps.NumBlockLayers(); n != 2 {
   114  		t.Errorf("pre-flatten block layer count mismatch: have %d, want %d", n, 2)
   115  	}
   116  	// Commit the diff layer onto the disk and ensure it's persisted
   117  	snaps.verified = true // Bypass validation of junk data
   118  	if err := snaps.Flatten(common.HexToHash("0x02")); err != nil {
   119  		t.Fatalf("failed to merge diff layer onto disk: %v", err)
   120  	}
   121  	// Since the base layer was modified, ensure that data retrieval on the external reference fail
   122  	if acc, err := ref.Account(common.HexToHash("0x01")); err != ErrSnapshotStale {
   123  		t.Errorf("stale reference returned account: %v (err: %v)", acc, err)
   124  	}
   125  	if slot, err := ref.Storage(common.HexToHash("0xa1"), common.HexToHash("0xb1")); err != ErrSnapshotStale {
   126  		t.Errorf("stale reference returned storage slot: %v (err: %v)", slot, err)
   127  	}
   128  	if n := snaps.NumStateLayers(); n != 1 {
   129  		t.Errorf("pre-flatten state layer count mismatch: have %d, want %d", n, 1)
   130  	}
   131  	if n := snaps.NumBlockLayers(); n != 1 {
   132  		t.Errorf("pre-flatten block layer count mismatch: have %d, want %d", n, 1)
   133  	}
   134  }
   135  
   136  // Tests that if a disk layer becomes stale, no active external references will
   137  // be returned with junk data. This version of the test retains the bottom diff
   138  // layer to check the usual mode of operation where the accumulator is retained.
   139  func TestDiskLayerExternalInvalidationPartialFlatten(t *testing.T) {
   140  	// Create an empty base layer and a snapshot tree out of it
   141  	snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01"))
   142  	// Retrieve a reference to the base and commit two diffs on top
   143  	ref := snaps.Snapshot(common.HexToHash("0xff01"))
   144  
   145  	accounts := map[common.Hash][]byte{
   146  		common.HexToHash("0xa1"): randomAccount(),
   147  	}
   148  	if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil {
   149  		t.Fatalf("failed to create a diff layer: %v", err)
   150  	}
   151  	if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil {
   152  		t.Fatalf("failed to create a diff layer: %v", err)
   153  	}
   154  	if n := snaps.NumBlockLayers(); n != 3 {
   155  		t.Errorf("pre-cap block layer count mismatch: have %d, want %d", n, 3)
   156  	}
   157  	if n := snaps.NumStateLayers(); n != 3 {
   158  		t.Errorf("pre-cap state layer count mismatch: have %d, want %d", n, 3)
   159  	}
   160  	// Commit the diff layer onto the disk and ensure it's persisted
   161  	defer func(memcap uint64) { aggregatorMemoryLimit = memcap }(aggregatorMemoryLimit)
   162  	aggregatorMemoryLimit = 0
   163  
   164  	snaps.verified = true // Bypass validation of junk data
   165  	if err := snaps.Flatten(common.HexToHash("0x02")); err != nil {
   166  		t.Fatalf("Failed to flatten diff layer onto disk: %v", err)
   167  	}
   168  	// Since the base layer was modified, ensure that data retrieval on the external reference fails
   169  	if acc, err := ref.Account(common.HexToHash("0x01")); err != ErrSnapshotStale {
   170  		t.Errorf("stale reference returned account: %v (err: %v)", acc, err)
   171  	}
   172  	if slot, err := ref.Storage(common.HexToHash("0xa1"), common.HexToHash("0xb1")); err != ErrSnapshotStale {
   173  		t.Errorf("stale reference returned storage slot: %#x (err: %v)", slot, err)
   174  	}
   175  	if n := snaps.NumBlockLayers(); n != 2 {
   176  		t.Errorf("pre-cap block layer count mismatch: have %d, want %d", n, 2)
   177  	}
   178  	if n := snaps.NumStateLayers(); n != 2 {
   179  		t.Errorf("pre-cap state layer count mismatch: have %d, want %d", n, 2)
   180  	}
   181  }
   182  
   183  // Tests that if a diff layer becomes stale, no active external references will
   184  // be returned with junk data. This version of the test retains the bottom diff
   185  // layer to check the usual mode of operation where the accumulator is retained.
   186  func TestDiffLayerExternalInvalidationPartialFlatten(t *testing.T) {
   187  	// Create an empty base layer and a snapshot tree out of it
   188  	snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01"))
   189  	// Commit three diffs on top and retrieve a reference to the bottommost
   190  	accounts := map[common.Hash][]byte{
   191  		common.HexToHash("0xa1"): randomAccount(),
   192  	}
   193  	if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil {
   194  		t.Fatalf("failed to create a diff layer: %v", err)
   195  	}
   196  	if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil {
   197  		t.Fatalf("failed to create a diff layer: %v", err)
   198  	}
   199  	if err := snaps.Update(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, accounts, nil); err != nil {
   200  		t.Fatalf("failed to create a diff layer: %v", err)
   201  	}
   202  	if n := snaps.NumStateLayers(); n != 4 {
   203  		t.Errorf("pre-flatten state layer count mismatch: have %d, want %d", n, 4)
   204  	}
   205  	if n := snaps.NumBlockLayers(); n != 4 {
   206  		t.Errorf("pre-flatten block layer count mismatch: have %d, want %d", n, 4)
   207  	}
   208  	ref := snaps.Snapshot(common.HexToHash("0xff02"))
   209  
   210  	snaps.verified = true // Bypass validation of junk data
   211  	if err := snaps.Flatten(common.HexToHash("0x02")); err != nil {
   212  		t.Fatal(err)
   213  	}
   214  	// Since the accumulator diff layer was modified, ensure that data retrieval on the external reference fails
   215  	if acc, err := ref.Account(common.HexToHash("0x01")); err != ErrSnapshotStale {
   216  		t.Errorf("stale reference returned account: %v (err: %v)", acc, err)
   217  	}
   218  	if slot, err := ref.Storage(common.HexToHash("0xa1"), common.HexToHash("0xb1")); err != ErrSnapshotStale {
   219  		t.Errorf("stale reference returned storage slot: %#x (err: %v)", slot, err)
   220  	}
   221  	if n := snaps.NumStateLayers(); n != 3 {
   222  		t.Errorf("pre-flatten state layer count mismatch: have %d, want %d", n, 3)
   223  	}
   224  	if n := snaps.NumBlockLayers(); n != 3 {
   225  		t.Errorf("pre-flatten block layer count mismatch: have %d, want %d", n, 3)
   226  	}
   227  }
   228  
   229  // TestPostCapBasicDataAccess tests some functionality regarding capping/flattening.
   230  func TestPostFlattenBasicDataAccess(t *testing.T) {
   231  	// setAccount is a helper to construct a random account entry and assign it to
   232  	// an account slot in a snapshot
   233  	setAccount := func(accKey string) map[common.Hash][]byte {
   234  		return map[common.Hash][]byte{
   235  			common.HexToHash(accKey): randomAccount(),
   236  		}
   237  	}
   238  	// Create a starting base layer and a snapshot tree out of it
   239  	snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01"))
   240  	// The lowest difflayer
   241  	snaps.Update(common.HexToHash("0xa1"), common.HexToHash("0xffa1"), common.HexToHash("0x01"), nil, setAccount("0xa1"), nil)
   242  	snaps.Update(common.HexToHash("0xa2"), common.HexToHash("0xffa2"), common.HexToHash("0xa1"), nil, setAccount("0xa2"), nil)
   243  	snaps.Update(common.HexToHash("0xb2"), common.HexToHash("0xffb2"), common.HexToHash("0xa1"), nil, setAccount("0xb2"), nil)
   244  
   245  	snaps.Update(common.HexToHash("0xa3"), common.HexToHash("0xffa3"), common.HexToHash("0xa2"), nil, setAccount("0xa3"), nil)
   246  	snaps.Update(common.HexToHash("0xb3"), common.HexToHash("0xffb3"), common.HexToHash("0xb2"), nil, setAccount("0xb3"), nil)
   247  
   248  	// checkExist verifies if an account exiss in a snapshot
   249  	checkExist := func(layer Snapshot, key string) error {
   250  		if data, _ := layer.Account(common.HexToHash(key)); data == nil {
   251  			return fmt.Errorf("expected %x to exist, got nil", common.HexToHash(key))
   252  		}
   253  		return nil
   254  	}
   255  	checkNotExist := func(layer Snapshot, key string) error {
   256  		if data, err := layer.Account(common.HexToHash(key)); err != nil {
   257  			return fmt.Errorf("expected %x to not error: %w", key, err)
   258  		} else if data != nil {
   259  			return fmt.Errorf("expected %x to be empty, got %v", key, data)
   260  		}
   261  		return nil
   262  	}
   263  	// shouldErr checks that an account access errors as expected
   264  	shouldErr := func(layer Snapshot, key string) error {
   265  		if data, err := layer.Account(common.HexToHash(key)); err == nil {
   266  			return fmt.Errorf("expected error, got data %v", data)
   267  		}
   268  		return nil
   269  	}
   270  	// Check basics for both snapshots 0xffa3 and 0xffb3
   271  	snap := snaps.Snapshot(common.HexToHash("0xffa3")).(*diffLayer)
   272  
   273  	// Check that the accounts that should exist are present in the snapshot
   274  	if err := checkExist(snap, "0xa1"); err != nil {
   275  		t.Error(err)
   276  	}
   277  	if err := checkExist(snap, "0xa2"); err != nil {
   278  		t.Error(err)
   279  	}
   280  	if err := checkExist(snap, "0xa1"); err != nil {
   281  		t.Error(err)
   282  	}
   283  	// Check that the accounts that should only exist in the other branch
   284  	// of the snapshot tree are not present in the snapshot.
   285  	if err := checkNotExist(snap, "0xb1"); err != nil {
   286  		t.Error(err)
   287  	}
   288  	if err := checkNotExist(snap, "0xb2"); err != nil {
   289  		t.Error(err)
   290  	}
   291  
   292  	snap = snaps.Snapshot(common.HexToHash("0xffb3")).(*diffLayer)
   293  
   294  	// Check that the accounts that should exist are present in the snapshot
   295  	if err := checkExist(snap, "0xa1"); err != nil {
   296  		t.Error(err)
   297  	}
   298  	if err := checkExist(snap, "0xb2"); err != nil {
   299  		t.Error(err)
   300  	}
   301  	if err := checkExist(snap, "0xb3"); err != nil {
   302  		t.Error(err)
   303  	}
   304  	// Check that the accounts that should only exist in the other branch
   305  	// of the snapshot tree are not present in the snapshot.
   306  	if err := checkNotExist(snap, "0xa2"); err != nil {
   307  		t.Error(err)
   308  	}
   309  
   310  	// Flatten a non-existent block should fail
   311  	if err := snaps.Flatten(common.HexToHash("0x1337")); err == nil {
   312  		t.Errorf("expected error, got none")
   313  	}
   314  
   315  	// Now, merge the a-chain layer by layer
   316  	snaps.verified = true // Bypass validation of junk data
   317  	if err := snaps.Flatten(common.HexToHash("0xa1")); err != nil {
   318  		t.Error(err)
   319  	}
   320  	if err := snaps.Flatten(common.HexToHash("0xa2")); err != nil {
   321  		t.Error(err)
   322  	}
   323  
   324  	// At this point, a2 got merged into a1. Thus, a1 is now modified, and as a1 is
   325  	// the parent of b2, b2 should no longer be able to iterate into parent.
   326  
   327  	// These should still be accessible since it doesn't require iteration into the
   328  	// disk layer. However, it's also valid for these diffLayers to be marked as stale.
   329  	if err := checkExist(snap, "0xb2"); err != nil {
   330  		t.Error(err)
   331  	}
   332  	if err := checkExist(snap, "0xb3"); err != nil {
   333  		t.Error(err)
   334  	}
   335  	// But 0xa1 would need iteration into the modified parent
   336  	// and 0xa2 and 0xa3 should never be present since they are
   337  	// on the other branch of the snapshot tree. These should strictly
   338  	// error since they're not in the diff layers and will result in
   339  	// traversing into the stale disk layer.
   340  	if err := shouldErr(snap, "0xa1"); err != nil {
   341  		t.Error(err)
   342  	}
   343  	if err := shouldErr(snap, "0xa2"); err != nil {
   344  		t.Error(err)
   345  	}
   346  	if err := shouldErr(snap, "0xa3"); err != nil {
   347  		t.Error(err)
   348  	}
   349  
   350  	snap = snaps.Snapshot(common.HexToHash("0xffa3")).(*diffLayer)
   351  	// Check that the accounts that should exist are present in the snapshot
   352  	if err := checkExist(snap, "0xa1"); err != nil {
   353  		t.Error(err)
   354  	}
   355  	if err := checkExist(snap, "0xa2"); err != nil {
   356  		t.Error(err)
   357  	}
   358  	if err := checkExist(snap, "0xa3"); err != nil {
   359  		t.Error(err)
   360  	}
   361  	// Check that the accounts that should only exist in the other branch
   362  	// of the snapshot tree are not present in the snapshot.
   363  	if err := checkNotExist(snap, "0xb1"); err != nil {
   364  		t.Error(err)
   365  	}
   366  	if err := checkNotExist(snap, "0xb2"); err != nil {
   367  		t.Error(err)
   368  	}
   369  
   370  	diskLayer := snaps.Snapshot(common.HexToHash("0xffa2"))
   371  	// Check that the accounts that should exist are present in the snapshot
   372  	if err := checkExist(diskLayer, "0xa1"); err != nil {
   373  		t.Error(err)
   374  	}
   375  	if err := checkExist(diskLayer, "0xa2"); err != nil {
   376  		t.Error(err)
   377  	}
   378  	// 0xa3 should not be included until the diffLayer built on top of
   379  	// 0xffa2.
   380  	if err := checkNotExist(diskLayer, "0xa3"); err != nil {
   381  		t.Error(err)
   382  	}
   383  	// Check that the accounts that should only exist in the other branch
   384  	// of the snapshot tree are not present in the snapshot.
   385  	if err := checkNotExist(diskLayer, "0xb1"); err != nil {
   386  		t.Error(err)
   387  	}
   388  	if err := checkNotExist(diskLayer, "0xb2"); err != nil {
   389  		t.Error(err)
   390  	}
   391  }
   392  
   393  // TestTreeFlattenDoesNotDropPendingLayers tests that Tree.Flatten correctly
   394  // retains layers built on top of the given root layer in the presence of multiple
   395  // different blocks inserted with an identical state root.
   396  // In this example, (B, C) and (D, E) share the identical state root, but were
   397  // inserted under different blocks.
   398  //    A
   399  //   /  \
   400  //  B    C
   401  //  |    |
   402  //  D    E
   403  //
   404  // `t.Flatten(C)` should result in:
   405  //
   406  //  B    C
   407  //  |    |
   408  //  D    E
   409  // With the branch D, E, hanging and relying on Discard to be called to
   410  // garbage collect the references.
   411  func TestTreeFlattenDoesNotDropPendingLayers(t *testing.T) {
   412  	var (
   413  		baseRoot      = common.HexToHash("0xffff01")
   414  		baseBlockHash = common.HexToHash("0x01")
   415  	)
   416  	snaps := NewTestTree(rawdb.NewMemoryDatabase(), baseBlockHash, baseRoot)
   417  	accounts := map[common.Hash][]byte{
   418  		common.HexToHash("0xa1"): randomAccount(),
   419  	}
   420  
   421  	// Create N layers on top of base (N+1) total
   422  	parentAHash := baseBlockHash
   423  	parentBHash := baseBlockHash
   424  	totalLayers := 10
   425  	for i := 2; i <= totalLayers; i++ {
   426  		diffBlockAHash := common.Hash{0xee, 0xee, byte(i)}
   427  		diffBlockBHash := common.Hash{0xdd, 0xdd, byte(i)}
   428  		diffBlockRoot := common.Hash{0xff, 0xff, byte(i)}
   429  		if err := snaps.Update(diffBlockAHash, diffBlockRoot, parentAHash, nil, accounts, nil); err != nil {
   430  			t.Fatalf("failed to create a diff layer: %v", err)
   431  		}
   432  		if err := snaps.Update(diffBlockBHash, diffBlockRoot, parentBHash, nil, accounts, nil); err != nil {
   433  			t.Fatalf("failed to create a diff layer: %v", err)
   434  		}
   435  
   436  		parentAHash = diffBlockAHash
   437  		parentBHash = diffBlockBHash
   438  	}
   439  
   440  	if n := snaps.NumStateLayers(); n != 10 {
   441  		t.Errorf("pre-flatten state layer count mismatch: have %d, want %d", n, 10)
   442  	}
   443  	if n := snaps.NumBlockLayers(); n != 19 {
   444  		t.Errorf("pre-flatten block layer count mismatch: have %d, want %d", n, 19)
   445  	}
   446  
   447  	snaps.verified = true // Bypass validation of junk data
   448  	if err := snaps.Flatten(common.Hash{0xee, 0xee, byte(2)}); err != nil {
   449  		t.Fatalf("failed to flatten diff layer from chain A: %v", err)
   450  	}
   451  
   452  	if n := snaps.NumStateLayers(); n != 9 {
   453  		t.Errorf("pre-flatten state layer count mismatch: have %d, want %d", n, 9)
   454  	}
   455  	if n := snaps.NumBlockLayers(); n != 18 {
   456  		t.Errorf("pre-flatten block layer count mismatch: have %d, want %d", n, 18)
   457  	}
   458  
   459  	// Attempt to flatten from chain B should error
   460  	if err := snaps.Flatten(common.Hash{0xdd, 0xdd, byte(2)}); err == nil {
   461  		t.Errorf("expected flattening abandoned chain to error")
   462  	}
   463  
   464  	for i := 2; i <= 10; i++ {
   465  		if err := snaps.Discard(common.Hash{0xdd, 0xdd, byte(i)}); err != nil {
   466  			t.Errorf("attempt to discard snapshot from abandoned chain failed: %v", err)
   467  		}
   468  	}
   469  
   470  	if n := snaps.NumStateLayers(); n != 9 {
   471  		t.Errorf("pre-flatten state layer count mismatch: have %d, want %d", n, 9)
   472  	}
   473  	if n := snaps.NumBlockLayers(); n != 9 {
   474  		t.Errorf("pre-flatten block layer count mismatch: have %d, want %d", n, 18)
   475  	}
   476  }
   477  
   478  func TestStaleOriginLayer(t *testing.T) {
   479  	var (
   480  		baseRoot       = common.HexToHash("0xffff01")
   481  		baseBlockHash  = common.HexToHash("0x01")
   482  		diffRootA      = common.HexToHash("0xff02")
   483  		diffBlockHashA = common.HexToHash("0x02")
   484  		diffRootB      = common.HexToHash("0xff03")
   485  		diffBlockHashB = common.HexToHash("0x03")
   486  		diffRootC      = common.HexToHash("0xff04")
   487  		diffBlockHashC = common.HexToHash("0x04")
   488  	)
   489  	snaps := NewTestTree(rawdb.NewMemoryDatabase(), baseBlockHash, baseRoot)
   490  	addrA := randomHash()
   491  	accountsA := map[common.Hash][]byte{
   492  		addrA: randomAccount(),
   493  	}
   494  	addrB := randomHash()
   495  	accountsB := map[common.Hash][]byte{
   496  		addrB: randomAccount(),
   497  	}
   498  	addrC := randomHash()
   499  	accountsC := map[common.Hash][]byte{
   500  		addrC: randomAccount(),
   501  	}
   502  
   503  	// Create diff layer A containing account 0xa1
   504  	if err := snaps.Update(diffBlockHashA, diffRootA, baseBlockHash, nil, accountsA, nil); err != nil {
   505  		t.Errorf("failed to create diff layer A: %v", err)
   506  	}
   507  	// Flatten account 0xa1 to disk
   508  	snaps.verified = true // Bypass validation of junk data
   509  	if err := snaps.Flatten(diffBlockHashA); err != nil {
   510  		t.Errorf("failed to flatten diff block A: %v", err)
   511  	}
   512  	// Create diff layer B containing account 0xa2
   513  	// The bloom filter should contain only 0xa2.
   514  	if err := snaps.Update(diffBlockHashB, diffRootB, diffBlockHashA, nil, accountsB, nil); err != nil {
   515  		t.Errorf("failed to create diff layer B: %v", err)
   516  	}
   517  	// Create diff layer C containing account 0xa3
   518  	// The bloom filter should contain 0xa2 and 0xa3
   519  	if err := snaps.Update(diffBlockHashC, diffRootC, diffBlockHashB, nil, accountsC, nil); err != nil {
   520  		t.Errorf("failed to create diff layer C: %v", err)
   521  	}
   522  
   523  	if err := snaps.Flatten(diffBlockHashB); err != nil {
   524  		t.Errorf("failed to flattten diff block A: %v", err)
   525  	}
   526  	snap := snaps.Snapshot(diffRootC)
   527  	if _, err := snap.Account(addrA); err != nil {
   528  		t.Errorf("expected account to exist: %v", err)
   529  	}
   530  }
   531  
   532  func TestRebloomOnFlatten(t *testing.T) {
   533  	// Create diff layers, including a level with two children, then flatten
   534  	// the layers and assert that the bloom filters are being updated correctly.
   535  	//
   536  	// Each layer will add an account which will be in the blooms for every
   537  	// following difflayer. No accesses would need to touch disk. Layers C and D
   538  	// should have all addrs in their blooms except for each others.
   539  	//
   540  	// After flattening A into the root, the remaining blooms should no longer
   541  	// have addrA but should retain all the others.
   542  	//
   543  	// After flattening B into A, blooms C and D should contain only their own
   544  	// addrs.
   545  	//
   546  	//          Initial Root (diskLayer)
   547  	//                   |
   548  	//                   A <- First diffLayer. Adds addrA
   549  	//                   |
   550  	//                   B <- Second diffLayer. Adds addrB
   551  	//                 /  \
   552  	//  Adds addrC -> C    D <- Adds addrD
   553  
   554  	var (
   555  		baseRoot       = common.HexToHash("0xff01")
   556  		baseBlockHash  = common.HexToHash("0x01")
   557  		diffRootA      = common.HexToHash("0xff02")
   558  		diffBlockHashA = common.HexToHash("0x02")
   559  		diffRootB      = common.HexToHash("0xff03")
   560  		diffBlockHashB = common.HexToHash("0x03")
   561  		diffRootC      = common.HexToHash("0xff04")
   562  		diffBlockHashC = common.HexToHash("0x04")
   563  		diffRootD      = common.HexToHash("0xff05")
   564  		diffBlockHashD = common.HexToHash("0x05")
   565  	)
   566  
   567  	snaps := NewTestTree(rawdb.NewMemoryDatabase(), baseBlockHash, baseRoot)
   568  	addrA := randomHash()
   569  	accountsA := map[common.Hash][]byte{
   570  		addrA: randomAccount(),
   571  	}
   572  	addrB := randomHash()
   573  	accountsB := map[common.Hash][]byte{
   574  		addrB: randomAccount(),
   575  	}
   576  	addrC := randomHash()
   577  	accountsC := map[common.Hash][]byte{
   578  		addrC: randomAccount(),
   579  	}
   580  	addrD := randomHash()
   581  	accountsD := map[common.Hash][]byte{
   582  		addrD: randomAccount(),
   583  	}
   584  
   585  	// Build the tree
   586  	if err := snaps.Update(diffBlockHashA, diffRootA, baseBlockHash, nil, accountsA, nil); err != nil {
   587  		t.Errorf("failed to create diff layer A: %v", err)
   588  	}
   589  	if err := snaps.Update(diffBlockHashB, diffRootB, diffBlockHashA, nil, accountsB, nil); err != nil {
   590  		t.Errorf("failed to create diff layer B: %v", err)
   591  	}
   592  	if err := snaps.Update(diffBlockHashC, diffRootC, diffBlockHashB, nil, accountsC, nil); err != nil {
   593  		t.Errorf("failed to create diff layer C: %v", err)
   594  	}
   595  	if err := snaps.Update(diffBlockHashD, diffRootD, diffBlockHashB, nil, accountsD, nil); err != nil {
   596  		t.Errorf("failed to create diff layer D: %v", err)
   597  	}
   598  
   599  	assertBlooms := func(snap Snapshot, hitsA, hitsB, hitsC, hitsD bool) {
   600  		dl, ok := snap.(*diffLayer)
   601  		if !ok {
   602  			t.Fatal("snapshot should be a diffLayer")
   603  		}
   604  
   605  		if hitsA != dl.diffed.Contains(accountBloomHasher(addrA)) {
   606  			t.Errorf("expected bloom filter to return %t but got %t", hitsA, !hitsA)
   607  		}
   608  
   609  		if hitsB != dl.diffed.Contains(accountBloomHasher(addrB)) {
   610  			t.Errorf("expected bloom filter to return %t but got %t", hitsB, !hitsB)
   611  		}
   612  
   613  		if hitsC != dl.diffed.Contains(accountBloomHasher(addrC)) {
   614  			t.Errorf("expected bloom filter to return %t but got %t", hitsC, !hitsC)
   615  		}
   616  
   617  		if hitsD != dl.diffed.Contains(accountBloomHasher(addrD)) {
   618  			t.Errorf("expected bloom filter to return %t but got %t", hitsD, !hitsD)
   619  		}
   620  	}
   621  
   622  	// First check that each layer's bloom has all current and ancestor addrs,
   623  	// but no sibling-only addrs.
   624  	assertBlooms(snaps.Snapshot(diffRootB), true, true, false, false)
   625  	assertBlooms(snaps.Snapshot(diffRootC), true, true, true, false)
   626  	assertBlooms(snaps.Snapshot(diffRootD), true, true, false, true)
   627  
   628  	// Flatten diffLayer A, making it a disk layer and trigger a rebloom on B, C
   629  	// and D. If we didn't rebloom, or didn't rebloom recursively, then blooms C
   630  	// and D would still think addrA was in the diff layers
   631  	snaps.verified = true // Bypass validation of junk data
   632  	if err := snaps.Flatten(diffBlockHashA); err != nil {
   633  		t.Errorf("failed to flattten diff block A: %v", err)
   634  	}
   635  
   636  	// Check that no blooms still have addrA, but they have all the others
   637  	assertBlooms(snaps.Snapshot(diffRootB), false, true, false, false)
   638  	assertBlooms(snaps.Snapshot(diffRootC), false, true, true, false)
   639  	assertBlooms(snaps.Snapshot(diffRootD), false, true, false, true)
   640  
   641  	// Flatten diffLayer B, making it a disk layer and trigger a rebloom on C
   642  	// and D. If we didn't rebloom, or didn't rebloom recursively, then blooms C
   643  	// and D would still think addrB was in the diff layers
   644  	if err := snaps.Flatten(diffBlockHashB); err != nil {
   645  		t.Errorf("failed to flattten diff block A: %v", err)
   646  	}
   647  
   648  	// Blooms C and D should now have only their own addrs
   649  	assertBlooms(snaps.Snapshot(diffRootC), false, false, true, false)
   650  	assertBlooms(snaps.Snapshot(diffRootD), false, false, false, true)
   651  }