github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/trie/zk_trie_test.go (about) 1 // Copyright 2015 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 trie 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "io/ioutil" 23 "os" 24 "runtime" 25 "sync" 26 "testing" 27 28 "github.com/stretchr/testify/assert" 29 30 zkt "github.com/scroll-tech/zktrie/types" 31 32 "github.com/scroll-tech/go-ethereum/common" 33 "github.com/scroll-tech/go-ethereum/ethdb/leveldb" 34 "github.com/scroll-tech/go-ethereum/ethdb/memorydb" 35 ) 36 37 func newEmptyZkTrie() *ZkTrie { 38 trie, _ := NewZkTrie( 39 common.Hash{}, 40 &ZktrieDatabase{ 41 db: NewDatabaseWithConfig(memorydb.New(), 42 &Config{Preimages: true}), 43 prefix: []byte{}, 44 }, 45 ) 46 return trie 47 } 48 49 // makeTestSecureTrie creates a large enough secure trie for testing. 50 func makeTestZkTrie() (*ZktrieDatabase, *ZkTrie, map[string][]byte) { 51 // Create an empty trie 52 triedb := NewZktrieDatabase(memorydb.New()) 53 trie, _ := NewZkTrie(common.Hash{}, triedb) 54 55 // Fill it with some arbitrary data 56 content := make(map[string][]byte) 57 for i := byte(0); i < 255; i++ { 58 // Map the same data under multiple keys 59 key, val := common.LeftPadBytes([]byte{1, i}, 32), bytes.Repeat([]byte{i}, 32) 60 content[string(key)] = val 61 trie.Update(key, val) 62 63 key, val = common.LeftPadBytes([]byte{2, i}, 32), bytes.Repeat([]byte{i}, 32) 64 content[string(key)] = val 65 trie.Update(key, val) 66 67 // Add some other data to inflate the trie 68 for j := byte(3); j < 13; j++ { 69 key, val = common.LeftPadBytes([]byte{j, i}, 32), bytes.Repeat([]byte{j, i}, 16) 70 content[string(key)] = val 71 trie.Update(key, val) 72 } 73 } 74 trie.Commit(nil) 75 76 // Return the generated trie 77 return triedb, trie, content 78 } 79 80 func TestZktrieDelete(t *testing.T) { 81 t.Skip("var-len kv not supported") 82 trie := newEmptyZkTrie() 83 vals := []struct{ k, v string }{ 84 {"do", "verb"}, 85 {"ether", "wookiedoo"}, 86 {"horse", "stallion"}, 87 {"shaman", "horse"}, 88 {"doge", "coin"}, 89 {"ether", ""}, 90 {"dog", "puppy"}, 91 {"shaman", ""}, 92 } 93 for _, val := range vals { 94 if val.v != "" { 95 trie.Update([]byte(val.k), []byte(val.v)) 96 } else { 97 trie.Delete([]byte(val.k)) 98 } 99 } 100 hash := trie.Hash() 101 exp := common.HexToHash("29b235a58c3c25ab83010c327d5932bcf05324b7d6b1185e650798034783ca9d") 102 if hash != exp { 103 t.Errorf("expected %x got %x", exp, hash) 104 } 105 } 106 107 func TestZktrieGetKey(t *testing.T) { 108 trie := newEmptyZkTrie() 109 key := []byte("0a1b2c3d4e5f6g7h8i9j0a1b2c3d4e5f") 110 value := []byte("9j8i7h6g5f4e3d2c1b0a9j8i7h6g5f4e") 111 trie.Update(key, value) 112 113 kPreimage := zkt.NewByte32FromBytesPaddingZero(key) 114 kHash, err := kPreimage.Hash() 115 assert.Nil(t, err) 116 117 if !bytes.Equal(trie.Get(key), value) { 118 t.Errorf("Get did not return bar") 119 } 120 if k := trie.GetKey(kHash.Bytes()); !bytes.Equal(k, key) { 121 t.Errorf("GetKey returned %q, want %q", k, key) 122 } 123 } 124 125 func TestZkTrieConcurrency(t *testing.T) { 126 // Create an initial trie and copy if for concurrent access 127 _, trie, _ := makeTestZkTrie() 128 129 threads := runtime.NumCPU() 130 tries := make([]*ZkTrie, threads) 131 for i := 0; i < threads; i++ { 132 cpy := *trie 133 tries[i] = &cpy 134 } 135 // Start a batch of goroutines interactng with the trie 136 pend := new(sync.WaitGroup) 137 pend.Add(threads) 138 for i := 0; i < threads; i++ { 139 go func(index int) { 140 defer pend.Done() 141 142 for j := byte(0); j < 255; j++ { 143 // Map the same data under multiple keys 144 key, val := common.LeftPadBytes([]byte{byte(index), 1, j}, 32), bytes.Repeat([]byte{j}, 32) 145 tries[index].Update(key, val) 146 147 key, val = common.LeftPadBytes([]byte{byte(index), 2, j}, 32), bytes.Repeat([]byte{j}, 32) 148 tries[index].Update(key, val) 149 150 // Add some other data to inflate the trie 151 for k := byte(3); k < 13; k++ { 152 key, val = common.LeftPadBytes([]byte{byte(index), k, j}, 32), bytes.Repeat([]byte{k, j}, 16) 153 tries[index].Update(key, val) 154 } 155 } 156 tries[index].Commit(nil) 157 }(i) 158 } 159 // Wait for all threads to finish 160 pend.Wait() 161 } 162 163 func tempDBZK(b *testing.B) (string, *Database) { 164 dir, err := ioutil.TempDir("", "zktrie-bench") 165 assert.NoError(b, err) 166 167 diskdb, err := leveldb.New(dir, 256, 0, "", false) 168 assert.NoError(b, err) 169 config := &Config{Cache: 256, Preimages: true, Zktrie: true} 170 return dir, NewDatabaseWithConfig(diskdb, config) 171 } 172 173 const benchElemCountZk = 10000 174 175 func BenchmarkZkTrieGet(b *testing.B) { 176 _, tmpdb := tempDBZK(b) 177 zkTrie, _ := NewZkTrie(common.Hash{}, NewZktrieDatabaseFromTriedb(tmpdb)) 178 defer func() { 179 ldb := zkTrie.db.db.diskdb.(*leveldb.Database) 180 ldb.Close() 181 os.RemoveAll(ldb.Path()) 182 }() 183 184 k := make([]byte, 32) 185 for i := 0; i < benchElemCountZk; i++ { 186 binary.LittleEndian.PutUint64(k, uint64(i)) 187 188 err := zkTrie.TryUpdate(k, k) 189 assert.NoError(b, err) 190 } 191 192 zkTrie.db.db.Commit(common.Hash{}, true, nil) 193 b.ResetTimer() 194 for i := 0; i < b.N; i++ { 195 binary.LittleEndian.PutUint64(k, uint64(i)) 196 _, err := zkTrie.TryGet(k) 197 assert.NoError(b, err) 198 } 199 b.StopTimer() 200 } 201 202 func BenchmarkZkTrieUpdate(b *testing.B) { 203 _, tmpdb := tempDBZK(b) 204 zkTrie, _ := NewZkTrie(common.Hash{}, NewZktrieDatabaseFromTriedb(tmpdb)) 205 defer func() { 206 ldb := zkTrie.db.db.diskdb.(*leveldb.Database) 207 ldb.Close() 208 os.RemoveAll(ldb.Path()) 209 }() 210 211 k := make([]byte, 32) 212 v := make([]byte, 32) 213 b.ReportAllocs() 214 215 for i := 0; i < benchElemCountZk; i++ { 216 binary.LittleEndian.PutUint64(k, uint64(i)) 217 err := zkTrie.TryUpdate(k, k) 218 assert.NoError(b, err) 219 } 220 binary.LittleEndian.PutUint64(k, benchElemCountZk/2) 221 222 //zkTrie.Commit(nil) 223 zkTrie.db.db.Commit(common.Hash{}, true, nil) 224 b.ResetTimer() 225 for i := 0; i < b.N; i++ { 226 binary.LittleEndian.PutUint64(k, uint64(i)) 227 binary.LittleEndian.PutUint64(v, 0xffffffff+uint64(i)) 228 err := zkTrie.TryUpdate(k, v) 229 assert.NoError(b, err) 230 } 231 b.StopTimer() 232 } 233 234 func TestZkTrieDelete(t *testing.T) { 235 key := make([]byte, 32) 236 value := make([]byte, 32) 237 trie1 := newEmptyZkTrie() 238 239 var count int = 6 240 var hashes []common.Hash 241 hashes = append(hashes, trie1.Hash()) 242 for i := 0; i < count; i++ { 243 binary.LittleEndian.PutUint64(key, uint64(i)) 244 binary.LittleEndian.PutUint64(value, uint64(i)) 245 err := trie1.TryUpdate(key, value) 246 assert.NoError(t, err) 247 hashes = append(hashes, trie1.Hash()) 248 } 249 250 // binary.LittleEndian.PutUint64(key, uint64(0xffffff)) 251 // err := trie1.TryDelete(key) 252 // assert.Equal(t, err, zktrie.ErrKeyNotFound) 253 254 trie1.Commit(nil) 255 256 for i := count - 1; i >= 0; i-- { 257 258 binary.LittleEndian.PutUint64(key, uint64(i)) 259 v, err := trie1.TryGet(key) 260 assert.NoError(t, err) 261 assert.NotEmpty(t, v) 262 err = trie1.TryDelete(key) 263 assert.NoError(t, err) 264 hash := trie1.Hash() 265 assert.Equal(t, hashes[i].Hex(), hash.Hex()) 266 } 267 }