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  }