github.com/Debrief-BC/go-debrief@v0.0.0-20200420203408-0c26ca968123/core/state/snapshot/disklayer_test.go (about)

     1  // Copyright 2019 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package snapshot
    18  
    19  import (
    20  	"bytes"
    21  	"testing"
    22  
    23  	"github.com/VictoriaMetrics/fastcache"
    24  	"github.com/Debrief-BC/go-debrief/common"
    25  	"github.com/Debrief-BC/go-debrief/core/rawdb"
    26  	"github.com/Debrief-BC/go-debrief/ethdb/memorydb"
    27  )
    28  
    29  // reverse reverses the contents of a byte slice. It's used to update random accs
    30  // with deterministic changes.
    31  func reverse(blob []byte) []byte {
    32  	res := make([]byte, len(blob))
    33  	for i, b := range blob {
    34  		res[len(blob)-1-i] = b
    35  	}
    36  	return res
    37  }
    38  
    39  // Tests that merging something into a disk layer persists it into the database
    40  // and invalidates any previously written and cached values.
    41  func TestDiskMerge(t *testing.T) {
    42  	// Create some accounts in the disk layer
    43  	db := memorydb.New()
    44  
    45  	var (
    46  		accNoModNoCache     = common.Hash{0x1}
    47  		accNoModCache       = common.Hash{0x2}
    48  		accModNoCache       = common.Hash{0x3}
    49  		accModCache         = common.Hash{0x4}
    50  		accDelNoCache       = common.Hash{0x5}
    51  		accDelCache         = common.Hash{0x6}
    52  		conNoModNoCache     = common.Hash{0x7}
    53  		conNoModNoCacheSlot = common.Hash{0x70}
    54  		conNoModCache       = common.Hash{0x8}
    55  		conNoModCacheSlot   = common.Hash{0x80}
    56  		conModNoCache       = common.Hash{0x9}
    57  		conModNoCacheSlot   = common.Hash{0x90}
    58  		conModCache         = common.Hash{0xa}
    59  		conModCacheSlot     = common.Hash{0xa0}
    60  		conDelNoCache       = common.Hash{0xb}
    61  		conDelNoCacheSlot   = common.Hash{0xb0}
    62  		conDelCache         = common.Hash{0xc}
    63  		conDelCacheSlot     = common.Hash{0xc0}
    64  		conNukeNoCache      = common.Hash{0xd}
    65  		conNukeNoCacheSlot  = common.Hash{0xd0}
    66  		conNukeCache        = common.Hash{0xe}
    67  		conNukeCacheSlot    = common.Hash{0xe0}
    68  		baseRoot            = randomHash()
    69  		diffRoot            = randomHash()
    70  	)
    71  
    72  	rawdb.WriteAccountSnapshot(db, accNoModNoCache, accNoModNoCache[:])
    73  	rawdb.WriteAccountSnapshot(db, accNoModCache, accNoModCache[:])
    74  	rawdb.WriteAccountSnapshot(db, accModNoCache, accModNoCache[:])
    75  	rawdb.WriteAccountSnapshot(db, accModCache, accModCache[:])
    76  	rawdb.WriteAccountSnapshot(db, accDelNoCache, accDelNoCache[:])
    77  	rawdb.WriteAccountSnapshot(db, accDelCache, accDelCache[:])
    78  
    79  	rawdb.WriteAccountSnapshot(db, conNoModNoCache, conNoModNoCache[:])
    80  	rawdb.WriteStorageSnapshot(db, conNoModNoCache, conNoModNoCacheSlot, conNoModNoCacheSlot[:])
    81  	rawdb.WriteAccountSnapshot(db, conNoModCache, conNoModCache[:])
    82  	rawdb.WriteStorageSnapshot(db, conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
    83  	rawdb.WriteAccountSnapshot(db, conModNoCache, conModNoCache[:])
    84  	rawdb.WriteStorageSnapshot(db, conModNoCache, conModNoCacheSlot, conModNoCacheSlot[:])
    85  	rawdb.WriteAccountSnapshot(db, conModCache, conModCache[:])
    86  	rawdb.WriteStorageSnapshot(db, conModCache, conModCacheSlot, conModCacheSlot[:])
    87  	rawdb.WriteAccountSnapshot(db, conDelNoCache, conDelNoCache[:])
    88  	rawdb.WriteStorageSnapshot(db, conDelNoCache, conDelNoCacheSlot, conDelNoCacheSlot[:])
    89  	rawdb.WriteAccountSnapshot(db, conDelCache, conDelCache[:])
    90  	rawdb.WriteStorageSnapshot(db, conDelCache, conDelCacheSlot, conDelCacheSlot[:])
    91  
    92  	rawdb.WriteAccountSnapshot(db, conNukeNoCache, conNukeNoCache[:])
    93  	rawdb.WriteStorageSnapshot(db, conNukeNoCache, conNukeNoCacheSlot, conNukeNoCacheSlot[:])
    94  	rawdb.WriteAccountSnapshot(db, conNukeCache, conNukeCache[:])
    95  	rawdb.WriteStorageSnapshot(db, conNukeCache, conNukeCacheSlot, conNukeCacheSlot[:])
    96  
    97  	rawdb.WriteSnapshotRoot(db, baseRoot)
    98  
    99  	// Create a disk layer based on the above and cache in some data
   100  	snaps := &Tree{
   101  		layers: map[common.Hash]snapshot{
   102  			baseRoot: &diskLayer{
   103  				diskdb: db,
   104  				cache:  fastcache.New(500 * 1024),
   105  				root:   baseRoot,
   106  			},
   107  		},
   108  	}
   109  	base := snaps.Snapshot(baseRoot)
   110  	base.AccountRLP(accNoModCache)
   111  	base.AccountRLP(accModCache)
   112  	base.AccountRLP(accDelCache)
   113  	base.Storage(conNoModCache, conNoModCacheSlot)
   114  	base.Storage(conModCache, conModCacheSlot)
   115  	base.Storage(conDelCache, conDelCacheSlot)
   116  	base.Storage(conNukeCache, conNukeCacheSlot)
   117  
   118  	// Modify or delete some accounts, flatten everything onto disk
   119  	if err := snaps.Update(diffRoot, baseRoot, map[common.Hash]struct{}{
   120  		accDelNoCache:  struct{}{},
   121  		accDelCache:    struct{}{},
   122  		conNukeNoCache: struct{}{},
   123  		conNukeCache:   struct{}{},
   124  	}, map[common.Hash][]byte{
   125  		accModNoCache: reverse(accModNoCache[:]),
   126  		accModCache:   reverse(accModCache[:]),
   127  	}, map[common.Hash]map[common.Hash][]byte{
   128  		conModNoCache: {conModNoCacheSlot: reverse(conModNoCacheSlot[:])},
   129  		conModCache:   {conModCacheSlot: reverse(conModCacheSlot[:])},
   130  		conDelNoCache: {conDelNoCacheSlot: nil},
   131  		conDelCache:   {conDelCacheSlot: nil},
   132  	}); err != nil {
   133  		t.Fatalf("failed to update snapshot tree: %v", err)
   134  	}
   135  	if err := snaps.Cap(diffRoot, 0); err != nil {
   136  		t.Fatalf("failed to flatten snapshot tree: %v", err)
   137  	}
   138  	// Retrieve all the data through the disk layer and validate it
   139  	base = snaps.Snapshot(diffRoot)
   140  	if _, ok := base.(*diskLayer); !ok {
   141  		t.Fatalf("update not flattend into the disk layer")
   142  	}
   143  
   144  	// assertAccount ensures that an account matches the given blob.
   145  	assertAccount := func(account common.Hash, data []byte) {
   146  		t.Helper()
   147  		blob, err := base.AccountRLP(account)
   148  		if err != nil {
   149  			t.Errorf("account access (%x) failed: %v", account, err)
   150  		} else if !bytes.Equal(blob, data) {
   151  			t.Errorf("account access (%x) mismatch: have %x, want %x", account, blob, data)
   152  		}
   153  	}
   154  	assertAccount(accNoModNoCache, accNoModNoCache[:])
   155  	assertAccount(accNoModCache, accNoModCache[:])
   156  	assertAccount(accModNoCache, reverse(accModNoCache[:]))
   157  	assertAccount(accModCache, reverse(accModCache[:]))
   158  	assertAccount(accDelNoCache, nil)
   159  	assertAccount(accDelCache, nil)
   160  
   161  	// assertStorage ensures that a storage slot matches the given blob.
   162  	assertStorage := func(account common.Hash, slot common.Hash, data []byte) {
   163  		t.Helper()
   164  		blob, err := base.Storage(account, slot)
   165  		if err != nil {
   166  			t.Errorf("storage access (%x:%x) failed: %v", account, slot, err)
   167  		} else if !bytes.Equal(blob, data) {
   168  			t.Errorf("storage access (%x:%x) mismatch: have %x, want %x", account, slot, blob, data)
   169  		}
   170  	}
   171  	assertStorage(conNoModNoCache, conNoModNoCacheSlot, conNoModNoCacheSlot[:])
   172  	assertStorage(conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
   173  	assertStorage(conModNoCache, conModNoCacheSlot, reverse(conModNoCacheSlot[:]))
   174  	assertStorage(conModCache, conModCacheSlot, reverse(conModCacheSlot[:]))
   175  	assertStorage(conDelNoCache, conDelNoCacheSlot, nil)
   176  	assertStorage(conDelCache, conDelCacheSlot, nil)
   177  	assertStorage(conNukeNoCache, conNukeNoCacheSlot, nil)
   178  	assertStorage(conNukeCache, conNukeCacheSlot, nil)
   179  
   180  	// Retrieve all the data directly from the database and validate it
   181  
   182  	// assertDatabaseAccount ensures that an account from the database matches the given blob.
   183  	assertDatabaseAccount := func(account common.Hash, data []byte) {
   184  		t.Helper()
   185  		if blob := rawdb.ReadAccountSnapshot(db, account); !bytes.Equal(blob, data) {
   186  			t.Errorf("account database access (%x) mismatch: have %x, want %x", account, blob, data)
   187  		}
   188  	}
   189  	assertDatabaseAccount(accNoModNoCache, accNoModNoCache[:])
   190  	assertDatabaseAccount(accNoModCache, accNoModCache[:])
   191  	assertDatabaseAccount(accModNoCache, reverse(accModNoCache[:]))
   192  	assertDatabaseAccount(accModCache, reverse(accModCache[:]))
   193  	assertDatabaseAccount(accDelNoCache, nil)
   194  	assertDatabaseAccount(accDelCache, nil)
   195  
   196  	// assertDatabaseStorage ensures that a storage slot from the database matches the given blob.
   197  	assertDatabaseStorage := func(account common.Hash, slot common.Hash, data []byte) {
   198  		t.Helper()
   199  		if blob := rawdb.ReadStorageSnapshot(db, account, slot); !bytes.Equal(blob, data) {
   200  			t.Errorf("storage database access (%x:%x) mismatch: have %x, want %x", account, slot, blob, data)
   201  		}
   202  	}
   203  	assertDatabaseStorage(conNoModNoCache, conNoModNoCacheSlot, conNoModNoCacheSlot[:])
   204  	assertDatabaseStorage(conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
   205  	assertDatabaseStorage(conModNoCache, conModNoCacheSlot, reverse(conModNoCacheSlot[:]))
   206  	assertDatabaseStorage(conModCache, conModCacheSlot, reverse(conModCacheSlot[:]))
   207  	assertDatabaseStorage(conDelNoCache, conDelNoCacheSlot, nil)
   208  	assertDatabaseStorage(conDelCache, conDelCacheSlot, nil)
   209  	assertDatabaseStorage(conNukeNoCache, conNukeNoCacheSlot, nil)
   210  	assertDatabaseStorage(conNukeCache, conNukeCacheSlot, nil)
   211  }
   212  
   213  // Tests that merging something into a disk layer persists it into the database
   214  // and invalidates any previously written and cached values, discarding anything
   215  // after the in-progress generation marker.
   216  func TestDiskPartialMerge(t *testing.T) {
   217  	// Iterate the test a few times to ensure we pick various internal orderings
   218  	// for the data slots as well as the progress marker.
   219  	for i := 0; i < 1024; i++ {
   220  		// Create some accounts in the disk layer
   221  		db := memorydb.New()
   222  
   223  		var (
   224  			accNoModNoCache     = randomHash()
   225  			accNoModCache       = randomHash()
   226  			accModNoCache       = randomHash()
   227  			accModCache         = randomHash()
   228  			accDelNoCache       = randomHash()
   229  			accDelCache         = randomHash()
   230  			conNoModNoCache     = randomHash()
   231  			conNoModNoCacheSlot = randomHash()
   232  			conNoModCache       = randomHash()
   233  			conNoModCacheSlot   = randomHash()
   234  			conModNoCache       = randomHash()
   235  			conModNoCacheSlot   = randomHash()
   236  			conModCache         = randomHash()
   237  			conModCacheSlot     = randomHash()
   238  			conDelNoCache       = randomHash()
   239  			conDelNoCacheSlot   = randomHash()
   240  			conDelCache         = randomHash()
   241  			conDelCacheSlot     = randomHash()
   242  			conNukeNoCache      = randomHash()
   243  			conNukeNoCacheSlot  = randomHash()
   244  			conNukeCache        = randomHash()
   245  			conNukeCacheSlot    = randomHash()
   246  			baseRoot            = randomHash()
   247  			diffRoot            = randomHash()
   248  			genMarker           = append(randomHash().Bytes(), randomHash().Bytes()...)
   249  		)
   250  
   251  		// insertAccount injects an account into the database if it's after the
   252  		// generator marker, drops the op otherwise. This is needed to seed the
   253  		// database with a valid starting snapshot.
   254  		insertAccount := func(account common.Hash, data []byte) {
   255  			if bytes.Compare(account[:], genMarker) <= 0 {
   256  				rawdb.WriteAccountSnapshot(db, account, data[:])
   257  			}
   258  		}
   259  		insertAccount(accNoModNoCache, accNoModNoCache[:])
   260  		insertAccount(accNoModCache, accNoModCache[:])
   261  		insertAccount(accModNoCache, accModNoCache[:])
   262  		insertAccount(accModCache, accModCache[:])
   263  		insertAccount(accDelNoCache, accDelNoCache[:])
   264  		insertAccount(accDelCache, accDelCache[:])
   265  
   266  		// insertStorage injects a storage slot into the database if it's after
   267  		// the  generator marker, drops the op otherwise. This is needed to seed
   268  		// the  database with a valid starting snapshot.
   269  		insertStorage := func(account common.Hash, slot common.Hash, data []byte) {
   270  			if bytes.Compare(append(account[:], slot[:]...), genMarker) <= 0 {
   271  				rawdb.WriteStorageSnapshot(db, account, slot, data[:])
   272  			}
   273  		}
   274  		insertAccount(conNoModNoCache, conNoModNoCache[:])
   275  		insertStorage(conNoModNoCache, conNoModNoCacheSlot, conNoModNoCacheSlot[:])
   276  		insertAccount(conNoModCache, conNoModCache[:])
   277  		insertStorage(conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
   278  		insertAccount(conModNoCache, conModNoCache[:])
   279  		insertStorage(conModNoCache, conModNoCacheSlot, conModNoCacheSlot[:])
   280  		insertAccount(conModCache, conModCache[:])
   281  		insertStorage(conModCache, conModCacheSlot, conModCacheSlot[:])
   282  		insertAccount(conDelNoCache, conDelNoCache[:])
   283  		insertStorage(conDelNoCache, conDelNoCacheSlot, conDelNoCacheSlot[:])
   284  		insertAccount(conDelCache, conDelCache[:])
   285  		insertStorage(conDelCache, conDelCacheSlot, conDelCacheSlot[:])
   286  
   287  		insertAccount(conNukeNoCache, conNukeNoCache[:])
   288  		insertStorage(conNukeNoCache, conNukeNoCacheSlot, conNukeNoCacheSlot[:])
   289  		insertAccount(conNukeCache, conNukeCache[:])
   290  		insertStorage(conNukeCache, conNukeCacheSlot, conNukeCacheSlot[:])
   291  
   292  		rawdb.WriteSnapshotRoot(db, baseRoot)
   293  
   294  		// Create a disk layer based on the above using a random progress marker
   295  		// and cache in some data.
   296  		snaps := &Tree{
   297  			layers: map[common.Hash]snapshot{
   298  				baseRoot: &diskLayer{
   299  					diskdb: db,
   300  					cache:  fastcache.New(500 * 1024),
   301  					root:   baseRoot,
   302  				},
   303  			},
   304  		}
   305  		snaps.layers[baseRoot].(*diskLayer).genMarker = genMarker
   306  		base := snaps.Snapshot(baseRoot)
   307  
   308  		// assertAccount ensures that an account matches the given blob if it's
   309  		// already covered by the disk snapshot, and errors out otherwise.
   310  		assertAccount := func(account common.Hash, data []byte) {
   311  			t.Helper()
   312  			blob, err := base.AccountRLP(account)
   313  			if bytes.Compare(account[:], genMarker) > 0 && err != ErrNotCoveredYet {
   314  				t.Fatalf("test %d: post-marker (%x) account access (%x) succeeded: %x", i, genMarker, account, blob)
   315  			}
   316  			if bytes.Compare(account[:], genMarker) <= 0 && !bytes.Equal(blob, data) {
   317  				t.Fatalf("test %d: pre-marker (%x) account access (%x) mismatch: have %x, want %x", i, genMarker, account, blob, data)
   318  			}
   319  		}
   320  		assertAccount(accNoModCache, accNoModCache[:])
   321  		assertAccount(accModCache, accModCache[:])
   322  		assertAccount(accDelCache, accDelCache[:])
   323  
   324  		// assertStorage ensures that a storage slot matches the given blob if
   325  		// it's already covered by the disk snapshot, and errors out otherwise.
   326  		assertStorage := func(account common.Hash, slot common.Hash, data []byte) {
   327  			t.Helper()
   328  			blob, err := base.Storage(account, slot)
   329  			if bytes.Compare(append(account[:], slot[:]...), genMarker) > 0 && err != ErrNotCoveredYet {
   330  				t.Fatalf("test %d: post-marker (%x) storage access (%x:%x) succeeded: %x", i, genMarker, account, slot, blob)
   331  			}
   332  			if bytes.Compare(append(account[:], slot[:]...), genMarker) <= 0 && !bytes.Equal(blob, data) {
   333  				t.Fatalf("test %d: pre-marker (%x) storage access (%x:%x) mismatch: have %x, want %x", i, genMarker, account, slot, blob, data)
   334  			}
   335  		}
   336  		assertStorage(conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
   337  		assertStorage(conModCache, conModCacheSlot, conModCacheSlot[:])
   338  		assertStorage(conDelCache, conDelCacheSlot, conDelCacheSlot[:])
   339  		assertStorage(conNukeCache, conNukeCacheSlot, conNukeCacheSlot[:])
   340  
   341  		// Modify or delete some accounts, flatten everything onto disk
   342  		if err := snaps.Update(diffRoot, baseRoot, map[common.Hash]struct{}{
   343  			accDelNoCache:  struct{}{},
   344  			accDelCache:    struct{}{},
   345  			conNukeNoCache: struct{}{},
   346  			conNukeCache:   struct{}{},
   347  		}, map[common.Hash][]byte{
   348  			accModNoCache: reverse(accModNoCache[:]),
   349  			accModCache:   reverse(accModCache[:]),
   350  		}, map[common.Hash]map[common.Hash][]byte{
   351  			conModNoCache: {conModNoCacheSlot: reverse(conModNoCacheSlot[:])},
   352  			conModCache:   {conModCacheSlot: reverse(conModCacheSlot[:])},
   353  			conDelNoCache: {conDelNoCacheSlot: nil},
   354  			conDelCache:   {conDelCacheSlot: nil},
   355  		}); err != nil {
   356  			t.Fatalf("test %d: failed to update snapshot tree: %v", i, err)
   357  		}
   358  		if err := snaps.Cap(diffRoot, 0); err != nil {
   359  			t.Fatalf("test %d: failed to flatten snapshot tree: %v", i, err)
   360  		}
   361  		// Retrieve all the data through the disk layer and validate it
   362  		base = snaps.Snapshot(diffRoot)
   363  		if _, ok := base.(*diskLayer); !ok {
   364  			t.Fatalf("test %d: update not flattend into the disk layer", i)
   365  		}
   366  		assertAccount(accNoModNoCache, accNoModNoCache[:])
   367  		assertAccount(accNoModCache, accNoModCache[:])
   368  		assertAccount(accModNoCache, reverse(accModNoCache[:]))
   369  		assertAccount(accModCache, reverse(accModCache[:]))
   370  		assertAccount(accDelNoCache, nil)
   371  		assertAccount(accDelCache, nil)
   372  
   373  		assertStorage(conNoModNoCache, conNoModNoCacheSlot, conNoModNoCacheSlot[:])
   374  		assertStorage(conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
   375  		assertStorage(conModNoCache, conModNoCacheSlot, reverse(conModNoCacheSlot[:]))
   376  		assertStorage(conModCache, conModCacheSlot, reverse(conModCacheSlot[:]))
   377  		assertStorage(conDelNoCache, conDelNoCacheSlot, nil)
   378  		assertStorage(conDelCache, conDelCacheSlot, nil)
   379  		assertStorage(conNukeNoCache, conNukeNoCacheSlot, nil)
   380  		assertStorage(conNukeCache, conNukeCacheSlot, nil)
   381  
   382  		// Retrieve all the data directly from the database and validate it
   383  
   384  		// assertDatabaseAccount ensures that an account inside the database matches
   385  		// the given blob if it's already covered by the disk snapshot, and does not
   386  		// exist otherwise.
   387  		assertDatabaseAccount := func(account common.Hash, data []byte) {
   388  			t.Helper()
   389  			blob := rawdb.ReadAccountSnapshot(db, account)
   390  			if bytes.Compare(account[:], genMarker) > 0 && blob != nil {
   391  				t.Fatalf("test %d: post-marker (%x) account database access (%x) succeeded: %x", i, genMarker, account, blob)
   392  			}
   393  			if bytes.Compare(account[:], genMarker) <= 0 && !bytes.Equal(blob, data) {
   394  				t.Fatalf("test %d: pre-marker (%x) account database access (%x) mismatch: have %x, want %x", i, genMarker, account, blob, data)
   395  			}
   396  		}
   397  		assertDatabaseAccount(accNoModNoCache, accNoModNoCache[:])
   398  		assertDatabaseAccount(accNoModCache, accNoModCache[:])
   399  		assertDatabaseAccount(accModNoCache, reverse(accModNoCache[:]))
   400  		assertDatabaseAccount(accModCache, reverse(accModCache[:]))
   401  		assertDatabaseAccount(accDelNoCache, nil)
   402  		assertDatabaseAccount(accDelCache, nil)
   403  
   404  		// assertDatabaseStorage ensures that a storage slot inside the database
   405  		// matches the given blob if it's already covered by the disk snapshot,
   406  		// and does not exist otherwise.
   407  		assertDatabaseStorage := func(account common.Hash, slot common.Hash, data []byte) {
   408  			t.Helper()
   409  			blob := rawdb.ReadStorageSnapshot(db, account, slot)
   410  			if bytes.Compare(append(account[:], slot[:]...), genMarker) > 0 && blob != nil {
   411  				t.Fatalf("test %d: post-marker (%x) storage database access (%x:%x) succeeded: %x", i, genMarker, account, slot, blob)
   412  			}
   413  			if bytes.Compare(append(account[:], slot[:]...), genMarker) <= 0 && !bytes.Equal(blob, data) {
   414  				t.Fatalf("test %d: pre-marker (%x) storage database access (%x:%x) mismatch: have %x, want %x", i, genMarker, account, slot, blob, data)
   415  			}
   416  		}
   417  		assertDatabaseStorage(conNoModNoCache, conNoModNoCacheSlot, conNoModNoCacheSlot[:])
   418  		assertDatabaseStorage(conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
   419  		assertDatabaseStorage(conModNoCache, conModNoCacheSlot, reverse(conModNoCacheSlot[:]))
   420  		assertDatabaseStorage(conModCache, conModCacheSlot, reverse(conModCacheSlot[:]))
   421  		assertDatabaseStorage(conDelNoCache, conDelNoCacheSlot, nil)
   422  		assertDatabaseStorage(conDelCache, conDelCacheSlot, nil)
   423  		assertDatabaseStorage(conNukeNoCache, conNukeNoCacheSlot, nil)
   424  		assertDatabaseStorage(conNukeCache, conNukeCacheSlot, nil)
   425  	}
   426  }
   427  
   428  // Tests that merging something into a disk layer persists it into the database
   429  // and invalidates any previously written and cached values, discarding anything
   430  // after the in-progress generation marker.
   431  //
   432  // This test case is a tiny specialized case of TestDiskPartialMerge, which tests
   433  // some very specific cornercases that random tests won't ever trigger.
   434  func TestDiskMidAccountPartialMerge(t *testing.T) {
   435  }