mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 22:26:42 +00:00
feat&perf: reversed bit of key when persisting zktrie (#410)
* bit reverse when persisting zktrie * fix according to review * Update version.go --------- Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
This commit is contained in:
parent
a677ee3ccf
commit
134e1b8f92
3 changed files with 132 additions and 4 deletions
|
|
@ -23,8 +23,8 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
VersionMajor = 4 // Major version component of the current release
|
VersionMajor = 4 // Major version component of the current release
|
||||||
VersionMinor = 2 // Minor version component of the current release
|
VersionMinor = 3 // Minor version component of the current release
|
||||||
VersionPatch = 11 // Patch 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
|
VersionMeta = "sepolia" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,13 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/ethdb"
|
"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 {
|
type ZktrieDatabase struct {
|
||||||
db *Database
|
db *Database
|
||||||
prefix []byte
|
prefix []byte
|
||||||
|
|
@ -29,6 +35,7 @@ func NewZktrieDatabaseFromTriedb(db *Database) *ZktrieDatabase {
|
||||||
|
|
||||||
// Put saves a key:value into the Storage
|
// Put saves a key:value into the Storage
|
||||||
func (l *ZktrieDatabase) Put(k, v []byte) error {
|
func (l *ZktrieDatabase) Put(k, v []byte) error {
|
||||||
|
k = bitReverse(k)
|
||||||
l.db.lock.Lock()
|
l.db.lock.Lock()
|
||||||
l.db.rawDirties.Put(Concat(l.prefix, k[:]), v)
|
l.db.rawDirties.Put(Concat(l.prefix, k[:]), v)
|
||||||
l.db.lock.Unlock()
|
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
|
// Get retrieves a value from a key in the Storage
|
||||||
func (l *ZktrieDatabase) Get(key []byte) ([]byte, error) {
|
func (l *ZktrieDatabase) Get(key []byte) ([]byte, error) {
|
||||||
|
key = bitReverse(key)
|
||||||
concatKey := Concat(l.prefix, key[:])
|
concatKey := Concat(l.prefix, key[:])
|
||||||
l.db.lock.RLock()
|
l.db.lock.RLock()
|
||||||
value, ok := l.db.rawDirties.Get(concatKey)
|
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)
|
iter := l.db.diskdb.NewIterator(l.prefix, nil)
|
||||||
defer iter.Release()
|
defer iter.Release()
|
||||||
for iter.Next() {
|
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 {
|
if cont, err := f(localKey, iter.Value()); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if !cont {
|
} else if !cont {
|
||||||
|
|
@ -109,3 +117,54 @@ func (l *ZktrieDatabase) List(limit int) ([]KV, error) {
|
||||||
})
|
})
|
||||||
return ret, err
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
69
trie/zk_trie_database_test.go
Normal file
69
trie/zk_trie_database_test.go
Normal file
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue