github.com/klaytn/klaytn@v1.10.2/snapshot/difflayer_test.go (about)

     1  // Modifications Copyright 2021 The klaytn Authors
     2  // Copyright 2019 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from core/state/snapshot/difflayer_test.go (2021/10/21).
    19  // Modified and improved for the klaytn development.
    20  
    21  package snapshot
    22  
    23  import (
    24  	"bytes"
    25  	"math/rand"
    26  	"testing"
    27  
    28  	"github.com/VictoriaMetrics/fastcache"
    29  	"github.com/klaytn/klaytn/common"
    30  	"github.com/klaytn/klaytn/storage/database"
    31  )
    32  
    33  func copyDestructs(destructs map[common.Hash]struct{}) map[common.Hash]struct{} {
    34  	copy := make(map[common.Hash]struct{})
    35  	for hash := range destructs {
    36  		copy[hash] = struct{}{}
    37  	}
    38  	return copy
    39  }
    40  
    41  func copyAccounts(accounts map[common.Hash][]byte) map[common.Hash][]byte {
    42  	copy := make(map[common.Hash][]byte)
    43  	for hash, blob := range accounts {
    44  		copy[hash] = blob
    45  	}
    46  	return copy
    47  }
    48  
    49  func copyStorage(storage map[common.Hash]map[common.Hash][]byte) map[common.Hash]map[common.Hash][]byte {
    50  	copy := make(map[common.Hash]map[common.Hash][]byte)
    51  	for accHash, slots := range storage {
    52  		copy[accHash] = make(map[common.Hash][]byte)
    53  		for slotHash, blob := range slots {
    54  			copy[accHash][slotHash] = blob
    55  		}
    56  	}
    57  	return copy
    58  }
    59  
    60  // TestMergeBasics tests some simple merges
    61  func TestMergeBasics(t *testing.T) {
    62  	var (
    63  		destructs = make(map[common.Hash]struct{})
    64  		accounts  = make(map[common.Hash][]byte)
    65  		storage   = make(map[common.Hash]map[common.Hash][]byte)
    66  	)
    67  	// Fill up a parent
    68  	for i := 0; i < 100; i++ {
    69  		h := randomHash()
    70  		data := randomAccount()
    71  
    72  		accounts[h] = data
    73  		if rand.Intn(4) == 0 {
    74  			destructs[h] = struct{}{}
    75  		}
    76  		if rand.Intn(2) == 0 {
    77  			accStorage := make(map[common.Hash][]byte)
    78  			value := make([]byte, 32)
    79  			rand.Read(value)
    80  			accStorage[randomHash()] = value
    81  			storage[h] = accStorage
    82  		}
    83  	}
    84  	// Add some (identical) layers on top
    85  	parent := newDiffLayer(emptyLayer(), common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage))
    86  	child := newDiffLayer(parent, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage))
    87  	child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage))
    88  	child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage))
    89  	child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage))
    90  	// And flatten
    91  	merged := (child.flatten()).(*diffLayer)
    92  
    93  	{ // Check account lists
    94  		if have, want := len(merged.accountList), 0; have != want {
    95  			t.Errorf("accountList wrong: have %v, want %v", have, want)
    96  		}
    97  		if have, want := len(merged.AccountList()), len(accounts); have != want {
    98  			t.Errorf("AccountList() wrong: have %v, want %v", have, want)
    99  		}
   100  		if have, want := len(merged.accountList), len(accounts); have != want {
   101  			t.Errorf("accountList [2] wrong: have %v, want %v", have, want)
   102  		}
   103  	}
   104  	{ // Check account drops
   105  		if have, want := len(merged.destructSet), len(destructs); have != want {
   106  			t.Errorf("accountDrop wrong: have %v, want %v", have, want)
   107  		}
   108  	}
   109  	{ // Check storage lists
   110  		i := 0
   111  		for aHash, sMap := range storage {
   112  			if have, want := len(merged.storageList), i; have != want {
   113  				t.Errorf("[1] storageList wrong: have %v, want %v", have, want)
   114  			}
   115  			list, _ := merged.StorageList(aHash)
   116  			if have, want := len(list), len(sMap); have != want {
   117  				t.Errorf("[2] StorageList() wrong: have %v, want %v", have, want)
   118  			}
   119  			if have, want := len(merged.storageList[aHash]), len(sMap); have != want {
   120  				t.Errorf("storageList wrong: have %v, want %v", have, want)
   121  			}
   122  			i++
   123  		}
   124  	}
   125  }
   126  
   127  // TestMergeDelete tests some deletion
   128  func TestMergeDelete(t *testing.T) {
   129  	storage := make(map[common.Hash]map[common.Hash][]byte)
   130  	// Fill up a parent
   131  	h1 := common.HexToHash("0x01")
   132  	h2 := common.HexToHash("0x02")
   133  
   134  	flipDrops := func() map[common.Hash]struct{} {
   135  		return map[common.Hash]struct{}{
   136  			h2: {},
   137  		}
   138  	}
   139  	flipAccs := func() map[common.Hash][]byte {
   140  		return map[common.Hash][]byte{
   141  			h1: randomAccount(),
   142  		}
   143  	}
   144  	flopDrops := func() map[common.Hash]struct{} {
   145  		return map[common.Hash]struct{}{
   146  			h1: {},
   147  		}
   148  	}
   149  	flopAccs := func() map[common.Hash][]byte {
   150  		return map[common.Hash][]byte{
   151  			h2: randomAccount(),
   152  		}
   153  	}
   154  	// Add some flipAccs-flopping layers on top
   155  	parent := newDiffLayer(emptyLayer(), common.Hash{}, flipDrops(), flipAccs(), storage)
   156  	child := parent.Update(common.Hash{}, flopDrops(), flopAccs(), storage)
   157  	child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage)
   158  	child = child.Update(common.Hash{}, flopDrops(), flopAccs(), storage)
   159  	child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage)
   160  	child = child.Update(common.Hash{}, flopDrops(), flopAccs(), storage)
   161  	child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage)
   162  
   163  	if data, _ := child.Account(h1); data == nil {
   164  		t.Errorf("last diff layer: expected %x account to be non-nil", h1)
   165  	}
   166  	if data, _ := child.Account(h2); data != nil {
   167  		t.Errorf("last diff layer: expected %x account to be nil", h2)
   168  	}
   169  	if _, ok := child.destructSet[h1]; ok {
   170  		t.Errorf("last diff layer: expected %x drop to be missing", h1)
   171  	}
   172  	if _, ok := child.destructSet[h2]; !ok {
   173  		t.Errorf("last diff layer: expected %x drop to be present", h1)
   174  	}
   175  	// And flatten
   176  	merged := (child.flatten()).(*diffLayer)
   177  
   178  	if data, _ := merged.Account(h1); data == nil {
   179  		t.Errorf("merged layer: expected %x account to be non-nil", h1)
   180  	}
   181  	if data, _ := merged.Account(h2); data != nil {
   182  		t.Errorf("merged layer: expected %x account to be nil", h2)
   183  	}
   184  	if _, ok := merged.destructSet[h1]; !ok { // Note, drops stay alive until persisted to disk!
   185  		t.Errorf("merged diff layer: expected %x drop to be present", h1)
   186  	}
   187  	if _, ok := merged.destructSet[h2]; !ok { // Note, drops stay alive until persisted to disk!
   188  		t.Errorf("merged diff layer: expected %x drop to be present", h1)
   189  	}
   190  	// If we add more granular metering of memory, we can enable this again,
   191  	// but it's not implemented for now
   192  	//if have, want := merged.memory, child.memory; have != want {
   193  	//	t.Errorf("mem wrong: have %d, want %d", have, want)
   194  	//}
   195  }
   196  
   197  // This tests that if we create a new account, and set a slot, and then merge
   198  // it, the lists will be correct.
   199  func TestInsertAndMerge(t *testing.T) {
   200  	// Fill up a parent
   201  	var (
   202  		acc    = common.HexToHash("0x01")
   203  		slot   = common.HexToHash("0x02")
   204  		parent *diffLayer
   205  		child  *diffLayer
   206  	)
   207  	{
   208  		var (
   209  			destructs = make(map[common.Hash]struct{})
   210  			accounts  = make(map[common.Hash][]byte)
   211  			storage   = make(map[common.Hash]map[common.Hash][]byte)
   212  		)
   213  		parent = newDiffLayer(emptyLayer(), common.Hash{}, destructs, accounts, storage)
   214  	}
   215  	{
   216  		var (
   217  			destructs = make(map[common.Hash]struct{})
   218  			accounts  = make(map[common.Hash][]byte)
   219  			storage   = make(map[common.Hash]map[common.Hash][]byte)
   220  		)
   221  		accounts[acc] = randomAccount()
   222  		storage[acc] = make(map[common.Hash][]byte)
   223  		storage[acc][slot] = []byte{0x01}
   224  		child = newDiffLayer(parent, common.Hash{}, destructs, accounts, storage)
   225  	}
   226  	// And flatten
   227  	merged := (child.flatten()).(*diffLayer)
   228  	{ // Check that slot value is present
   229  		have, _ := merged.Storage(acc, slot)
   230  		if want := []byte{0x01}; !bytes.Equal(have, want) {
   231  			t.Errorf("merged slot value wrong: have %x, want %x", have, want)
   232  		}
   233  	}
   234  }
   235  
   236  func emptyLayer() *diskLayer {
   237  	return &diskLayer{
   238  		diskdb: database.NewMemoryDBManager(),
   239  		cache:  fastcache.New(500 * 1024),
   240  	}
   241  }