From 55d37b938cbfd063dc41bdb161e82728d9379805 Mon Sep 17 00:00:00 2001 From: battlmonstr Date: Thu, 21 Dec 2023 09:52:00 +0100 Subject: [PATCH] bor: spanID calculation refactoring (#9040) --- consensus/bor/bor.go | 7 +---- consensus/bor/span_id.go | 20 ++++++++++++++ consensus/bor/span_id_test.go | 26 +++++++++++++++++++ core/rawdb/accessors_chain.go | 12 ++------- core/rawdb/blockio/block_writer.go | 4 +-- eth/stagedsync/stage_bor_heimdall.go | 19 +++++--------- polygon/sync/heimdall.go | 16 +++++++----- polygon/sync/heimdall_test.go | 15 ++++++----- .../snapshotsync/freezeblocks/block_reader.go | 21 ++++++--------- .../freezeblocks/block_snapshots.go | 3 ++- .../freezeblocks/bor_snapshots.go | 20 +++----------- 11 files changed, 89 insertions(+), 74 deletions(-) create mode 100644 consensus/bor/span_id.go create mode 100644 consensus/bor/span_id_test.go diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go index fe913ed77..cb86b4a5e 100644 --- a/consensus/bor/bor.go +++ b/consensus/bor/bor.go @@ -55,8 +55,6 @@ const ( ) const ( - spanLength = 6400 // Number of blocks in a span - zerothSpanEnd = 255 // End block of 0th span snapshotPersistInterval = 1024 // Number of blocks after which to persist the vote snapshot to the database inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory inmemorySignatures = 4096 // Number of recent block signatures to keep in memory @@ -926,10 +924,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header, s // where it fetches producers internally. As we fetch data from span // in Erigon, use directly the `GetCurrentProducers` function. if isSprintStart(number+1, c.config.CalculateSprint(number)) { - var spanID uint64 - if number+1 > zerothSpanEnd { - spanID = 1 + (number+1-zerothSpanEnd-1)/spanLength - } + spanID := SpanIDAt(number + 1) newValidators, err := c.spanner.GetCurrentProducers(spanID, c.authorizedSigner.Load().signer, chain) if err != nil { return errUnknownValidators diff --git a/consensus/bor/span_id.go b/consensus/bor/span_id.go new file mode 100644 index 000000000..699e7fef9 --- /dev/null +++ b/consensus/bor/span_id.go @@ -0,0 +1,20 @@ +package bor + +const ( + spanLength = 6400 // Number of blocks in a span + zerothSpanEnd = 255 // End block of 0th span +) + +func SpanIDAt(number uint64) uint64 { + if number > zerothSpanEnd { + return 1 + (number-zerothSpanEnd-1)/spanLength + } + return 0 +} + +func SpanEndBlockNum(spanID uint64) uint64 { + if spanID > 0 { + return spanID*spanLength + zerothSpanEnd + } + return zerothSpanEnd +} diff --git a/consensus/bor/span_id_test.go b/consensus/bor/span_id_test.go new file mode 100644 index 000000000..62c82d96c --- /dev/null +++ b/consensus/bor/span_id_test.go @@ -0,0 +1,26 @@ +package bor + +import "testing" +import "github.com/stretchr/testify/assert" + +func TestSpanIDAt(t *testing.T) { + assert.Equal(t, uint64(0), SpanIDAt(0)) + assert.Equal(t, uint64(0), SpanIDAt(1)) + assert.Equal(t, uint64(0), SpanIDAt(2)) + assert.Equal(t, uint64(0), SpanIDAt(zerothSpanEnd)) + assert.Equal(t, uint64(1), SpanIDAt(zerothSpanEnd+1)) + assert.Equal(t, uint64(1), SpanIDAt(zerothSpanEnd+2)) + assert.Equal(t, uint64(1), SpanIDAt(6655)) + assert.Equal(t, uint64(2), SpanIDAt(6656)) + assert.Equal(t, uint64(2), SpanIDAt(6657)) + assert.Equal(t, uint64(2), SpanIDAt(13055)) + assert.Equal(t, uint64(3), SpanIDAt(13056)) + assert.Equal(t, uint64(6839), SpanIDAt(43763456)) +} + +func TestSpanEndBlockNum(t *testing.T) { + assert.Equal(t, uint64(zerothSpanEnd), SpanEndBlockNum(0)) + assert.Equal(t, uint64(6655), SpanEndBlockNum(1)) + assert.Equal(t, uint64(13055), SpanEndBlockNum(2)) + assert.Equal(t, uint64(43769855), SpanEndBlockNum(6839)) +} diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index c15de0e3d..905643429 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -43,11 +43,6 @@ import ( "github.com/ledgerwatch/erigon/rlp" ) -const ( - spanLength = 6400 // Number of blocks in a span - zerothSpanEnd = 255 // End block of 0th span -) - // ReadCanonicalHash retrieves the hash assigned to a canonical block number. func ReadCanonicalHash(db kv.Getter, number uint64) (common.Hash, error) { data, err := db.GetOne(kv.HeaderCanonical, hexutility.EncodeTs(number)) @@ -1074,7 +1069,7 @@ func PruneBlocks(tx kv.RwTx, blockTo uint64, blocksDeleteLimit int) error { // keeps genesis in db: [1, to) // doesn't change sequences of kv.EthTx and kv.NonCanonicalTxs // doesn't delete Receipts, Senders, Canonical markers, TotalDifficulty -func PruneBorBlocks(tx kv.RwTx, blockTo uint64, blocksDeleteLimit int) error { +func PruneBorBlocks(tx kv.RwTx, blockTo uint64, blocksDeleteLimit int, spanIDAt func(number uint64) uint64) error { c, err := tx.Cursor(kv.BorEventNums) if err != nil { return err @@ -1109,10 +1104,7 @@ func PruneBorBlocks(tx kv.RwTx, blockTo uint64, blocksDeleteLimit int) error { if err != nil { return err } - var firstSpanToKeep uint64 - if blockTo > zerothSpanEnd { - firstSpanToKeep = 1 + (blockTo-zerothSpanEnd-1)/spanLength - } + firstSpanToKeep := spanIDAt(blockTo) c2, err := tx.RwCursor(kv.BorSpans) if err != nil { return err diff --git a/core/rawdb/blockio/block_writer.go b/core/rawdb/blockio/block_writer.go index 73264cda1..096f1dd0f 100644 --- a/core/rawdb/blockio/block_writer.go +++ b/core/rawdb/blockio/block_writer.go @@ -114,6 +114,6 @@ func (w *BlockWriter) PruneBlocks(ctx context.Context, tx kv.RwTx, blockTo uint6 // keeps genesis in db // doesn't change sequences of kv.EthTx and kv.NonCanonicalTxs // doesn't delete Receipts, Senders, Canonical markers, TotalDifficulty -func (w *BlockWriter) PruneBorBlocks(ctx context.Context, tx kv.RwTx, blockTo uint64, blocksDeleteLimit int) error { - return rawdb.PruneBorBlocks(tx, blockTo, blocksDeleteLimit) +func (w *BlockWriter) PruneBorBlocks(ctx context.Context, tx kv.RwTx, blockTo uint64, blocksDeleteLimit int, spanIDAt func(number uint64) uint64) error { + return rawdb.PruneBorBlocks(tx, blockTo, blocksDeleteLimit, spanIDAt) } diff --git a/eth/stagedsync/stage_bor_heimdall.go b/eth/stagedsync/stage_bor_heimdall.go index 61b936ab6..2b7d8b39e 100644 --- a/eth/stagedsync/stage_bor_heimdall.go +++ b/eth/stagedsync/stage_bor_heimdall.go @@ -38,8 +38,6 @@ import ( ) const ( - spanLength = 6400 // Number of blocks in a span - zerothSpanEnd = 255 // End block of 0th span inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory inmemorySignatures = 4096 // Number of recent block signatures to keep in memory snapshotPersistInterval = 1024 // Number of blocks after which to persist the vote snapshot to the database @@ -215,8 +213,8 @@ func BorHeimdallForward( nextSpanId = lastSpanId + 1 } var endSpanID uint64 - if headNumber > zerothSpanEnd { - endSpanID = 2 + (headNumber-zerothSpanEnd)/spanLength + if bor.SpanIDAt(headNumber) > 0 { + endSpanID = bor.SpanIDAt(headNumber+1) + 1 } lastBlockNum := s.BlockNumber @@ -312,7 +310,8 @@ func BorHeimdallForward( if !mine { sprintLength := cfg.chainConfig.Bor.CalculateSprint(blockNum) - if blockNum > zerothSpanEnd && ((blockNum+1)%sprintLength == 0) { + spanID := bor.SpanIDAt(blockNum) + if (spanID > 0) && ((blockNum+1)%sprintLength == 0) { if err = checkHeaderExtraData(u, ctx, chain, blockNum, header, cfg.chainConfig.Bor); err != nil { return err } @@ -344,10 +343,7 @@ func checkHeaderExtraData( header *types.Header, config *chain.BorConfig, ) error { - var spanID uint64 - if blockNum+1 > zerothSpanEnd { - spanID = 1 + (blockNum+1-zerothSpanEnd-1)/spanLength - } + spanID := bor.SpanIDAt(blockNum + 1) spanBytes := chain.BorSpan(spanID) var sp span.HeimdallSpan if err := json.Unmarshal(spanBytes, &sp); err != nil { @@ -795,10 +791,7 @@ func BorHeimdallUnwind(u *UnwindState, ctx context.Context, s *StageState, tx kv return err } defer spanCursor.Close() - var lastSpanToKeep uint64 - if u.UnwindPoint > zerothSpanEnd { - lastSpanToKeep = 1 + (u.UnwindPoint-zerothSpanEnd-1)/spanLength - } + lastSpanToKeep := bor.SpanIDAt(u.UnwindPoint) var spanIdBytes [8]byte binary.BigEndian.PutUint64(spanIdBytes[:], lastSpanToKeep+1) for k, _, err = spanCursor.Seek(spanIdBytes[:]); err == nil && k != nil; k, _, err = spanCursor.Next() { diff --git a/polygon/sync/heimdall.go b/polygon/sync/heimdall.go index 31617924c..59a9d22b5 100644 --- a/polygon/sync/heimdall.go +++ b/polygon/sync/heimdall.go @@ -3,20 +3,23 @@ package sync import ( "context" "errors" + "math/big" + "time" + + "github.com/ledgerwatch/log/v3" + + "github.com/ledgerwatch/erigon/consensus/bor" "github.com/ledgerwatch/erigon/consensus/bor/heimdall" "github.com/ledgerwatch/erigon/consensus/bor/heimdall/checkpoint" "github.com/ledgerwatch/erigon/consensus/bor/heimdall/milestone" "github.com/ledgerwatch/erigon/consensus/bor/heimdall/span" - "github.com/ledgerwatch/log/v3" - "math/big" - "time" ) // Heimdall is a wrapper of Heimdall HTTP API type Heimdall interface { FetchCheckpoints(ctx context.Context, start uint64) ([]*checkpoint.Checkpoint, error) FetchMilestones(ctx context.Context, start uint64) ([]*milestone.Milestone, error) - FetchSpan(ctx context.Context) (*span.HeimdallSpan, error) + FetchSpan(ctx context.Context, start uint64) (*span.HeimdallSpan, error) OnMilestoneEvent(ctx context.Context, callback func(*milestone.Milestone)) error } @@ -131,9 +134,8 @@ func (impl *HeimdallImpl) FetchMilestones(ctx context.Context, start uint64) ([] return milestones, nil } -func (impl *HeimdallImpl) FetchSpan(ctx context.Context) (*span.HeimdallSpan, error) { - // TODO: calc last spanID - return impl.client.Span(ctx, 0) +func (impl *HeimdallImpl) FetchSpan(ctx context.Context, start uint64) (*span.HeimdallSpan, error) { + return impl.client.Span(ctx, bor.SpanIDAt(start)) } func (impl *HeimdallImpl) OnMilestoneEvent(ctx context.Context, callback func(*milestone.Milestone)) error { diff --git a/polygon/sync/heimdall_test.go b/polygon/sync/heimdall_test.go index 2c337a117..0286e6895 100644 --- a/polygon/sync/heimdall_test.go +++ b/polygon/sync/heimdall_test.go @@ -2,18 +2,21 @@ package sync import ( "context" + "math/big" + "testing" + "time" + "github.com/golang/mock/gomock" + + "github.com/ledgerwatch/log/v3" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + heimdallclient "github.com/ledgerwatch/erigon/consensus/bor/heimdall" "github.com/ledgerwatch/erigon/consensus/bor/heimdall/checkpoint" "github.com/ledgerwatch/erigon/consensus/bor/heimdall/milestone" heimdallmock "github.com/ledgerwatch/erigon/consensus/bor/heimdall/mock" - "github.com/ledgerwatch/log/v3" - "github.com/stretchr/testify/assert" - "math/big" - "testing" - "time" ) -import "github.com/stretchr/testify/require" func makeCheckpoint(start uint64, len uint) *checkpoint.Checkpoint { c := checkpoint.Checkpoint{ diff --git a/turbo/snapshotsync/freezeblocks/block_reader.go b/turbo/snapshotsync/freezeblocks/block_reader.go index bd6662266..cb9dfc3f0 100644 --- a/turbo/snapshotsync/freezeblocks/block_reader.go +++ b/turbo/snapshotsync/freezeblocks/block_reader.go @@ -5,6 +5,7 @@ import ( "context" "encoding/binary" "fmt" + "github.com/ledgerwatch/erigon/consensus/bor" "math" "sort" @@ -1115,18 +1116,18 @@ func (r *BlockReader) LastFrozenSpanID() uint64 { if lastSegment == nil { return 0 } - var lastSpanID uint64 - if lastSegment.ranges.to > zerothSpanEnd { - lastSpanID = (lastSegment.ranges.to - zerothSpanEnd - 1) / spanLength + + lastSpanID := bor.SpanIDAt(lastSegment.ranges.to) + if lastSpanID > 0 { + lastSpanID-- } return lastSpanID } func (r *BlockReader) Span(ctx context.Context, tx kv.Getter, spanId uint64) ([]byte, error) { - // Compute starting block of the span var endBlock uint64 if spanId > 0 { - endBlock = (spanId)*spanLength + zerothSpanEnd + endBlock = bor.SpanEndBlockNum(spanId) } var buf [8]byte binary.BigEndian.PutUint64(buf[:], spanId) @@ -1149,17 +1150,11 @@ func (r *BlockReader) Span(ctx context.Context, tx kv.Getter, spanId uint64) ([] if sn.idx == nil { continue } - var spanFrom uint64 - if sn.ranges.from > zerothSpanEnd { - spanFrom = 1 + (sn.ranges.from-zerothSpanEnd-1)/spanLength - } + spanFrom := bor.SpanIDAt(sn.ranges.from) if spanId < spanFrom { continue } - var spanTo uint64 - if sn.ranges.to > zerothSpanEnd { - spanTo = 1 + (sn.ranges.to-zerothSpanEnd-1)/spanLength - } + spanTo := bor.SpanIDAt(sn.ranges.to) if spanId >= spanTo { continue } diff --git a/turbo/snapshotsync/freezeblocks/block_snapshots.go b/turbo/snapshotsync/freezeblocks/block_snapshots.go index e1ae94d08..0e1305fe7 100644 --- a/turbo/snapshotsync/freezeblocks/block_snapshots.go +++ b/turbo/snapshotsync/freezeblocks/block_snapshots.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "errors" "fmt" + "github.com/ledgerwatch/erigon/consensus/bor" "os" "path" "path/filepath" @@ -1328,7 +1329,7 @@ func (br *BlockRetire) PruneAncientBlocks(tx kv.RwTx, limit int) error { includeBor := br.chainConfig.Bor != nil if includeBor { canDeleteTo := CanDeleteTo(currentProgress, br.blockReader.FrozenBorBlocks()) - if err := br.blockWriter.PruneBorBlocks(context.Background(), tx, canDeleteTo, limit); err != nil { + if err := br.blockWriter.PruneBorBlocks(context.Background(), tx, canDeleteTo, limit, bor.SpanIDAt); err != nil { return err } } diff --git a/turbo/snapshotsync/freezeblocks/bor_snapshots.go b/turbo/snapshotsync/freezeblocks/bor_snapshots.go index 7c2a6f306..72574c7ee 100644 --- a/turbo/snapshotsync/freezeblocks/bor_snapshots.go +++ b/turbo/snapshotsync/freezeblocks/bor_snapshots.go @@ -6,6 +6,7 @@ import ( "encoding/binary" "errors" "fmt" + "github.com/ledgerwatch/erigon/consensus/bor" "os" "path" "path/filepath" @@ -36,11 +37,6 @@ import ( "golang.org/x/exp/slices" ) -const ( - spanLength = 6400 // Number of blocks in a span - zerothSpanEnd = 255 // End block of 0th span -) - type BorEventSegment struct { seg *compress.Decompressor // value: event_rlp IdxBorTxnHash *recsplit.Index // bor_transaction_hash -> bor_event_segment_offset @@ -374,13 +370,8 @@ func DumpBorEvents(ctx context.Context, db kv.RoDB, blockFrom, blockTo uint64, w func DumpBorSpans(ctx context.Context, db kv.RoDB, blockFrom, blockTo uint64, workers int, lvl log.Lvl, logger log.Logger, collect func([]byte) error) error { logEvery := time.NewTicker(20 * time.Second) defer logEvery.Stop() - var spanFrom, spanTo uint64 - if blockFrom > zerothSpanEnd { - spanFrom = 1 + (blockFrom-zerothSpanEnd-1)/spanLength - } - if blockTo > zerothSpanEnd { - spanTo = 1 + (blockTo-zerothSpanEnd-1)/spanLength - } + spanFrom := bor.SpanIDAt(blockFrom) + spanTo := bor.SpanIDAt(blockTo) from := hexutility.EncodeTs(spanFrom) if err := kv.BigChunks(db, kv.BorSpans, from, func(tx kv.Tx, spanIdBytes, spanBytes []byte) (bool, error) { spanId := binary.BigEndian.Uint64(spanIdBytes) @@ -511,10 +502,7 @@ func BorSpansIdx(ctx context.Context, segmentFilePath string, blockFrom, blockTo g := d.MakeGetter() var idxFilePath = filepath.Join(snapDir, snaptype.IdxFileName(blockFrom, blockTo, snaptype.BorSpans.String())) - var baseSpanId uint64 - if blockFrom > zerothSpanEnd { - baseSpanId = 1 + (blockFrom-zerothSpanEnd-1)/spanLength - } + baseSpanId := bor.SpanIDAt(blockFrom) rs, err := recsplit.NewRecSplit(recsplit.RecSplitArgs{ KeyCount: d.Count(),