diff --git a/params/version.go b/params/version.go index ddac51b1522c..6fc08d7b70e7 100644 --- a/params/version.go +++ b/params/version.go @@ -23,8 +23,8 @@ import ( const ( VersionMajor = 4 // Major version component of the current release - VersionMinor = 2 // Minor version component of the current release - VersionPatch = 11 // Patch version component of the current release + VersionMinor = 3 // Minor version component of the current release + VersionPatch = 0 // Patch version component of the current release VersionMeta = "sepolia" // Version metadata to append to the version string ) diff --git a/trie/zk_trie_database.go b/trie/zk_trie_database.go index 6f9d6a39852a..ea4d670ab6b2 100644 --- a/trie/zk_trie_database.go +++ b/trie/zk_trie_database.go @@ -11,7 +11,13 @@ import ( "github.com/scroll-tech/go-ethereum/ethdb" ) -// ZktrieDatabase Database adaptor imple zktrie.ZktrieDatbase +// ZktrieDatabase Database adaptor implements zktrie.ZktrieDatbase +// It also reverses the bit order of the key being persisted. +// This ensures that the adjacent leaf in zktrie maintains minimal +// distance when persisted with dictionary order in LevelDB. +// Consequently, this optimizes the snapshot operation, allowing it +// to iterate through adjacent leaves at a reduced cost. + type ZktrieDatabase struct { db *Database prefix []byte @@ -29,6 +35,7 @@ func NewZktrieDatabaseFromTriedb(db *Database) *ZktrieDatabase { // Put saves a key:value into the Storage func (l *ZktrieDatabase) Put(k, v []byte) error { + k = bitReverse(k) l.db.lock.Lock() l.db.rawDirties.Put(Concat(l.prefix, k[:]), v) l.db.lock.Unlock() @@ -37,6 +44,7 @@ func (l *ZktrieDatabase) Put(k, v []byte) error { // Get retrieves a value from a key in the Storage func (l *ZktrieDatabase) Get(key []byte) ([]byte, error) { + key = bitReverse(key) concatKey := Concat(l.prefix, key[:]) l.db.lock.RLock() value, ok := l.db.rawDirties.Get(concatKey) @@ -78,7 +86,7 @@ func (l *ZktrieDatabase) Iterate(f func([]byte, []byte) (bool, error)) error { iter := l.db.diskdb.NewIterator(l.prefix, nil) defer iter.Release() for iter.Next() { - localKey := iter.Key()[len(l.prefix):] + localKey := bitReverse(iter.Key()[len(l.prefix):]) if cont, err := f(localKey, iter.Value()); err != nil { return err } else if !cont { @@ -109,3 +117,54 @@ func (l *ZktrieDatabase) List(limit int) ([]KV, error) { }) return ret, err } + +func bitReverseForNibble(b byte) byte { + switch b { + case 0: + return 0 + case 1: + return 8 + case 2: + return 4 + case 3: + return 12 + case 4: + return 2 + case 5: + return 10 + case 6: + return 6 + case 7: + return 14 + case 8: + return 1 + case 9: + return 9 + case 10: + return 5 + case 11: + return 13 + case 12: + return 3 + case 13: + return 11 + case 14: + return 7 + case 15: + return 15 + default: + panic("unexpected input") + } +} + +func bitReverse(inp []byte) (out []byte) { + + l := len(inp) + out = make([]byte, l) + + for i, b := range inp { + out[l-i-1] = bitReverseForNibble(b&15)<<4 + bitReverseForNibble(b>>4) + } + + return +} diff --git a/trie/zk_trie_database_test.go b/trie/zk_trie_database_test.go new file mode 100644 index 000000000000..011428f9a822 --- /dev/null +++ b/trie/zk_trie_database_test.go @@ -0,0 +1,69 @@ +package trie + +import ( + "bytes" + "testing" + + "github.com/scroll-tech/go-ethereum/common" +) + +// grep from `feat/snap` +func reverseBitInPlace(b []byte) { + var v [8]uint8 + for i := 0; i < len(b); i++ { + for j := 0; j < 8; j++ { + v[j] = (b[i] >> j) & 1 + } + var tmp uint8 = 0 + for j := 0; j < 8; j++ { + tmp |= v[8-j-1] << j + } + b[i] = tmp + } +} + +func reverseBytesInPlace(b []byte) { + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] + } +} + +func TestBitReverse(t *testing.T) { + + for _, testBytes := range [][]byte{ + common.FromHex("7b908cce3bc16abb3eac5dff6c136856526f15225f74ce860a2bec47912a5492"), + common.FromHex("fac65cd2ad5e301083d0310dd701b5faaff1364cbe01cdbfaf4ec3609bb4149e"), + common.FromHex("55791f6ec2f83fee512a2d3d4b505784fdefaea89974e10440d01d62a18a298a"), + common.FromHex("5ab775b64d86a8058bb71c3c765d0f2158c14bbeb9cb32a65eda793a7e95e30f"), + common.FromHex("ccb464abf67804538908c62431b3a6788e8dc6dee62aff9bfe6b10136acfceac"), + common.FromHex("b908adff17a5aa9d6787324c39014a74b04cef7fba6a92aeb730f48da1ca665d"), + } { + + b1 := bitReverse(testBytes) + reverseBitInPlace(testBytes) + reverseBytesInPlace(testBytes) + if !bytes.Equal(b1, testBytes) { + t.Errorf("unexpected bit reversed %x vs %x", b1, testBytes) + } + } + +} + +func TestBitDoubleReverse(t *testing.T) { + + for _, testBytes := range [][]byte{ + common.FromHex("7b908cce3bc16abb3eac5dff6c136856526f15225f74ce860a2bec47912a5492"), + common.FromHex("fac65cd2ad5e301083d0310dd701b5faaff1364cbe01cdbfaf4ec3609bb4149e"), + common.FromHex("55791f6ec2f83fee512a2d3d4b505784fdefaea89974e10440d01d62a18a298a"), + common.FromHex("5ab775b64d86a8058bb71c3c765d0f2158c14bbeb9cb32a65eda793a7e95e30f"), + common.FromHex("ccb464abf67804538908c62431b3a6788e8dc6dee62aff9bfe6b10136acfceac"), + common.FromHex("b908adff17a5aa9d6787324c39014a74b04cef7fba6a92aeb730f48da1ca665d"), + } { + + b := bitReverse(bitReverse(testBytes)) + if !bytes.Equal(b, testBytes) { + t.Errorf("unexpected double bit reversed %x vs %x", b, testBytes) + } + } + +}