Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Commitment: do not use cell getter function to fold the row #13509

Merged
merged 14 commits into from
Feb 5, 2025
225 changes: 80 additions & 145 deletions erigon-lib/commitment/commitment.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,12 @@ import (
"github.com/google/btree"
"golang.org/x/crypto/sha3"

"github.com/erigontech/erigon-lib/common"
"github.com/erigontech/erigon-lib/common/cryptozerocopy"
"github.com/erigontech/erigon-lib/common/length"
"github.com/erigontech/erigon-lib/etl"
"github.com/erigontech/erigon-lib/log/v3"
"github.com/erigontech/erigon-lib/metrics"
"github.com/erigontech/erigon-lib/types"

"github.com/erigontech/erigon-lib/common/length"
"github.com/erigontech/erigon-lib/etl"
)

var (
Expand Down Expand Up @@ -137,7 +135,7 @@ func InitializeTrieAndUpdates(tv TrieVariant, mode Mode, tmpdir string) (Trie, *
fallthrough
default:

trie := NewHexPatriciaHashed(length.Addr, nil, tmpdir)
trie := NewHexPatriciaHashed(length.Addr, nil)
tree := NewUpdates(mode, tmpdir, KeyToHexNibbleHash)
return trie, tree
}
Expand Down Expand Up @@ -177,110 +175,110 @@ type BranchEncoder struct {
buf *bytes.Buffer
bitmapBuf [binary.MaxVarintLen64]byte
merger *BranchMerger
updates *etl.Collector
tmpdir string
}

func NewBranchEncoder(sz uint64, tmpdir string) *BranchEncoder {
be := &BranchEncoder{
func NewBranchEncoder(sz uint64) *BranchEncoder {
return &BranchEncoder{
buf: bytes.NewBuffer(make([]byte, sz)),
tmpdir: tmpdir,
merger: NewHexBranchMerger(sz / 2),
}
//be.initCollector()
return be
}

func (be *BranchEncoder) initCollector() {
if be.updates != nil {
be.updates.Close()
func (be *BranchEncoder) putUvarAndVal(size uint64, val []byte) error {
n := binary.PutUvarint(be.bitmapBuf[:], size)
if _, err := be.buf.Write(be.bitmapBuf[:n]); err != nil {
return err
}
be.updates = etl.NewCollector("commitment.BranchEncoder", be.tmpdir, etl.NewOldestEntryBuffer(etl.BufferOptimalSize/4), log.Root().New("branch-encoder"))
be.updates.LogLvl(log.LvlDebug)
be.updates.SortAndFlushInBackground(true)
if _, err := be.buf.Write(val); err != nil {
return err
}
return nil
}

func (be *BranchEncoder) Load(pc PatriciaContext, args etl.TransformArgs) error {
// do not collect them at least now. Write them at CollectUpdate into pc
if be.updates == nil {
return nil
func (cell *cell) EncodeInto(be *BranchEncoder) error {
var fields cellFields
if cell.extLen > 0 && cell.storageAddrLen == 0 {
fields |= fieldExtension
}

if err := be.updates.Load(nil, "", func(prefix, update []byte, table etl.CurrentTableReader, next etl.LoadNextFunc) error {
stateValue, stateStep, err := pc.Branch(prefix)
if err != nil {
if cell.accountAddrLen > 0 {
fields |= fieldAccountAddr
}
if cell.storageAddrLen > 0 {
fields |= fieldStorageAddr
}
if cell.hashLen > 0 {
fields |= fieldHash
}
if cell.stateHashLen == 32 && (cell.accountAddrLen > 0 || cell.storageAddrLen > 0) {
fields |= fieldStateHash
}
if err := be.buf.WriteByte(byte(fields)); err != nil {
return err
}
if fields&fieldExtension != 0 {
if err := be.putUvarAndVal(uint64(cell.extLen), cell.extension[:cell.extLen]); err != nil {
return err
}

cp, cu := common.Copy(prefix), common.Copy(update) // has to copy :(
if err = pc.PutBranch(cp, cu, stateValue, stateStep); err != nil {
}
if fields&fieldAccountAddr != 0 {
if err := be.putUvarAndVal(uint64(cell.accountAddrLen), cell.accountAddr[:cell.accountAddrLen]); err != nil {
return err
}
mxTrieBranchesUpdated.Inc()
return nil
}, args); err != nil {
return err
}
be.initCollector()
return nil
}

func (be *BranchEncoder) CollectUpdate(
ctx PatriciaContext,
prefix []byte,
bitmap, touchMap, afterMap uint16,
readCell func(nibble int, skip bool) (*cell, error),
) (lastNibble int, err error) {

prev, prevStep, err := ctx.Branch(prefix)
if err != nil {
return 0, err
}
update, lastNibble, err := be.EncodeBranch(bitmap, touchMap, afterMap, readCell)
if err != nil {
return 0, err
}

if len(prev) > 0 {
if bytes.Equal(prev, update) {
//fmt.Printf("skip collectBranchUpdate [%x]\n", prefix)
return lastNibble, nil // do not write the same data for prefix
if fields&fieldStorageAddr != 0 {
if err := be.putUvarAndVal(uint64(cell.storageAddrLen), cell.storageAddr[:cell.storageAddrLen]); err != nil {
return err
}
update, err = be.merger.Merge(prev, update)
if err != nil {
return 0, err
}
if fields&fieldHash != 0 {
if err := be.putUvarAndVal(uint64(cell.hashLen), cell.hash[:cell.hashLen]); err != nil {
return err
}
}
//fmt.Printf("\ncollectBranchUpdate [%x] -> %s\n", prefix, BranchData(update).String())
// has to copy :(
if err = ctx.PutBranch(common.Copy(prefix), common.Copy(update), prev, prevStep); err != nil {
return 0, err
if fields&fieldStateHash != 0 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can add method fields.Has(fieldStateHash)

if err := be.putUvarAndVal(uint64(cell.stateHashLen), cell.stateHash[:cell.stateHashLen]); err != nil {
return err
}
}
return lastNibble, nil
return nil
}

func (be *BranchEncoder) putUvarAndVal(size uint64, val []byte) error {
n := binary.PutUvarint(be.bitmapBuf[:], size)
if _, err := be.buf.Write(be.bitmapBuf[:n]); err != nil {
return err
// EncodeDelete encodes deleted branch with given touchMap.
// Returned slice is valid until next call to encodeMaps/Reset()
func (be *BranchEncoder) EncodeDelete(tm uint16) ([]byte, error) {
if err := be.encodeMaps(tm, 0); err != nil {
return nil, err
}
if _, err := be.buf.Write(val); err != nil {
return be.EncodedBranch(), nil
}

// Each branch begins with 4 bytes bitmap (touchMap, afterMap).
// encodeMaps resets be.buf and encodes them into be.buf
func (be *BranchEncoder) encodeMaps(touchMap, afterMap uint16) error {
binary.BigEndian.PutUint16(be.bitmapBuf[:], touchMap)
binary.BigEndian.PutUint16(be.bitmapBuf[2:], afterMap)

be.buf.Reset()

if _, err := be.buf.Write(be.bitmapBuf[:4]); err != nil {
be.buf.Reset()
return err
}
return nil
}

// Cells in branch comes one by one without mentionting the nibble
func (be *BranchEncoder) encodeCell(c *cell) error { return c.EncodeInto(be) }

// Returned slice is valid until next call to encodeMaps/be.Reset()
func (be *BranchEncoder) EncodedBranch() []byte { return be.buf.Bytes() }

func (be *BranchEncoder) Reset() { be.buf.Reset() }

// Encoded result should be copied before next call to EncodeBranch, underlying slice is reused
// DEPRECATED
func (be *BranchEncoder) EncodeBranch(bitmap, touchMap, afterMap uint16, readCell func(nibble int, skip bool) (*cell, error)) (BranchData, int, error) {
be.buf.Reset()

var encoded [2]byte
binary.BigEndian.PutUint16(encoded[:], touchMap)
if _, err := be.buf.Write(encoded[:]); err != nil {
return nil, 0, err
}
binary.BigEndian.PutUint16(encoded[:], afterMap)
if _, err := be.buf.Write(encoded[:]); err != nil {
if err := be.encodeMaps(touchMap, afterMap); err != nil {
return nil, 0, err
}

Expand All @@ -301,59 +299,16 @@ func (be *BranchEncoder) EncodeBranch(bitmap, touchMap, afterMap uint16, readCel
}

if bitmap&bit != 0 {
var fields cellFields
if cell.extLen > 0 && cell.storageAddrLen == 0 {
fields |= fieldExtension
}
if cell.accountAddrLen > 0 {
fields |= fieldAccountAddr
}
if cell.storageAddrLen > 0 {
fields |= fieldStorageAddr
}
if cell.hashLen > 0 {
fields |= fieldHash
}
if cell.stateHashLen == 32 && (cell.accountAddrLen > 0 || cell.storageAddrLen > 0) {
fields |= fieldStateHash
}
if err := be.buf.WriteByte(byte(fields)); err != nil {
if err := cell.EncodeInto(be); err != nil {
return nil, 0, err
}
if fields&fieldExtension != 0 {
if err := be.putUvarAndVal(uint64(cell.extLen), cell.extension[:cell.extLen]); err != nil {
return nil, 0, err
}
}
if fields&fieldAccountAddr != 0 {
if err := be.putUvarAndVal(uint64(cell.accountAddrLen), cell.accountAddr[:cell.accountAddrLen]); err != nil {
return nil, 0, err
}
}
if fields&fieldStorageAddr != 0 {
if err := be.putUvarAndVal(uint64(cell.storageAddrLen), cell.storageAddr[:cell.storageAddrLen]); err != nil {
return nil, 0, err
}
}
if fields&fieldHash != 0 {
if err := be.putUvarAndVal(uint64(cell.hashLen), cell.hash[:cell.hashLen]); err != nil {
return nil, 0, err
}
}
if fields&fieldStateHash != 0 {
if err := be.putUvarAndVal(uint64(cell.stateHashLen), cell.stateHash[:cell.stateHashLen]); err != nil {
return nil, 0, err
}
}
}
bitset ^= bit
}
//fmt.Printf("EncodeBranch [%x] size: %d\n", be.buf.Bytes(), be.buf.Len())
return be.buf.Bytes(), lastNibble, nil
return be.EncodedBranch(), lastNibble, nil
}

func RetrieveCellNoop(nibble int, skip bool) (*cell, error) { return nil, nil }

type BranchData []byte

func (branchData BranchData) String() string {
Expand All @@ -380,27 +335,7 @@ func (branchData BranchData) String() string {
// This is used for test output, so ok to panic
panic(err)
}
sb.WriteString("{")
var comma string
if cell.hashedExtLen > 0 {
fmt.Fprintf(&sb, "hashedExtension=[%x]", cell.hashedExtension[:cell.hashedExtLen])
comma = ","
}
if cell.accountAddrLen > 0 {
fmt.Fprintf(&sb, "%saccountAddr=[%x]", comma, cell.accountAddr[:cell.accountAddrLen])
comma = ","
}
if cell.storageAddrLen > 0 {
fmt.Fprintf(&sb, "%sstorageAddr=[%x]", comma, cell.storageAddr[:cell.storageAddrLen])
comma = ","
}
if cell.hashLen > 0 {
fmt.Fprintf(&sb, "%shash=[%x]", comma, cell.hash[:cell.hashLen])
}
if cell.stateHashLen > 0 {
fmt.Fprintf(&sb, "%sleafHash=[%x]", comma, cell.stateHash[:cell.stateHashLen])
}
sb.WriteString("}\n")
sb.WriteString(cell.String())
}
bitset ^= bit
}
Expand Down
4 changes: 2 additions & 2 deletions erigon-lib/commitment/commitment_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func BenchmarkBranchMerger_Merge(b *testing.B) {
b.StopTimer()
row, bm := generateCellRow(b, 16)

be := NewBranchEncoder(1024, b.TempDir())
be := NewBranchEncoder(1024)
enc, _, err := be.EncodeBranch(bm, bm, bm, func(i int, skip bool) (*cell, error) {
return row[i], nil
})
Expand Down Expand Up @@ -89,7 +89,7 @@ func BenchmarkBranchData_ReplacePlainKeys(b *testing.B) {
return row[nibble], nil
}

be := NewBranchEncoder(1024, b.TempDir())
be := NewBranchEncoder(1024)
enc, _, err := be.EncodeBranch(bm, bm, bm, cg)
require.NoError(b, err)

Expand Down
8 changes: 4 additions & 4 deletions erigon-lib/commitment/commitment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func TestBranchData_MergeHexBranches2(t *testing.T) {
t.Parallel()
row, bm := generateCellRow(t, 16)

be := NewBranchEncoder(1024, t.TempDir())
be := NewBranchEncoder(1024)
enc, _, err := be.EncodeBranch(bm, bm, bm, func(i int, skip bool) (*cell, error) {
return row[i], nil
})
Expand Down Expand Up @@ -152,7 +152,7 @@ func TestDecodeBranchWithLeafHashes(t *testing.T) {
}
}

be := NewBranchEncoder(1024, t.TempDir())
be := NewBranchEncoder(1024)
enc, _, err := be.EncodeBranch(bm, bm, bm, func(i int, skip bool) (*cell, error) {
return row[i], nil
})
Expand Down Expand Up @@ -213,7 +213,7 @@ func TestBranchData_ReplacePlainKeys(t *testing.T) {
return row[nibble], nil
}

be := NewBranchEncoder(1024, t.TempDir())
be := NewBranchEncoder(1024)
enc, _, err := be.EncodeBranch(bm, bm, bm, cg)
require.NoError(t, err)

Expand Down Expand Up @@ -262,7 +262,7 @@ func TestBranchData_ReplacePlainKeys_WithEmpty(t *testing.T) {
return row[nibble], nil
}

be := NewBranchEncoder(1024, t.TempDir())
be := NewBranchEncoder(1024)
enc, _, err := be.EncodeBranch(bm, bm, bm, cg)
require.NoError(t, err)

Expand Down
Loading
Loading