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 }