bor: spanID calculation refactoring (#9040)

This commit is contained in:
battlmonstr 2023-12-21 09:52:00 +01:00 committed by GitHub
parent 9eb9151be4
commit 55d37b938c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 89 additions and 74 deletions

View File

@ -55,8 +55,6 @@ const (
) )
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 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 inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory
inmemorySignatures = 4096 // Number of recent block signatures 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 // where it fetches producers internally. As we fetch data from span
// in Erigon, use directly the `GetCurrentProducers` function. // in Erigon, use directly the `GetCurrentProducers` function.
if isSprintStart(number+1, c.config.CalculateSprint(number)) { if isSprintStart(number+1, c.config.CalculateSprint(number)) {
var spanID uint64 spanID := SpanIDAt(number + 1)
if number+1 > zerothSpanEnd {
spanID = 1 + (number+1-zerothSpanEnd-1)/spanLength
}
newValidators, err := c.spanner.GetCurrentProducers(spanID, c.authorizedSigner.Load().signer, chain) newValidators, err := c.spanner.GetCurrentProducers(spanID, c.authorizedSigner.Load().signer, chain)
if err != nil { if err != nil {
return errUnknownValidators return errUnknownValidators

20
consensus/bor/span_id.go Normal file
View File

@ -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
}

View File

@ -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))
}

View File

@ -43,11 +43,6 @@ import (
"github.com/ledgerwatch/erigon/rlp" "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. // ReadCanonicalHash retrieves the hash assigned to a canonical block number.
func ReadCanonicalHash(db kv.Getter, number uint64) (common.Hash, error) { func ReadCanonicalHash(db kv.Getter, number uint64) (common.Hash, error) {
data, err := db.GetOne(kv.HeaderCanonical, hexutility.EncodeTs(number)) 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) // keeps genesis in db: [1, to)
// doesn't change sequences of kv.EthTx and kv.NonCanonicalTxs // doesn't change sequences of kv.EthTx and kv.NonCanonicalTxs
// doesn't delete Receipts, Senders, Canonical markers, TotalDifficulty // 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) c, err := tx.Cursor(kv.BorEventNums)
if err != nil { if err != nil {
return err return err
@ -1109,10 +1104,7 @@ func PruneBorBlocks(tx kv.RwTx, blockTo uint64, blocksDeleteLimit int) error {
if err != nil { if err != nil {
return err return err
} }
var firstSpanToKeep uint64 firstSpanToKeep := spanIDAt(blockTo)
if blockTo > zerothSpanEnd {
firstSpanToKeep = 1 + (blockTo-zerothSpanEnd-1)/spanLength
}
c2, err := tx.RwCursor(kv.BorSpans) c2, err := tx.RwCursor(kv.BorSpans)
if err != nil { if err != nil {
return err return err

View File

@ -114,6 +114,6 @@ func (w *BlockWriter) PruneBlocks(ctx context.Context, tx kv.RwTx, blockTo uint6
// keeps genesis in db // keeps genesis in db
// doesn't change sequences of kv.EthTx and kv.NonCanonicalTxs // doesn't change sequences of kv.EthTx and kv.NonCanonicalTxs
// doesn't delete Receipts, Senders, Canonical markers, TotalDifficulty // doesn't delete Receipts, Senders, Canonical markers, TotalDifficulty
func (w *BlockWriter) PruneBorBlocks(ctx context.Context, tx kv.RwTx, blockTo uint64, blocksDeleteLimit int) error { 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) return rawdb.PruneBorBlocks(tx, blockTo, blocksDeleteLimit, spanIDAt)
} }

View File

@ -38,8 +38,6 @@ import (
) )
const ( 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 inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory
inmemorySignatures = 4096 // Number of recent block signatures 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 snapshotPersistInterval = 1024 // Number of blocks after which to persist the vote snapshot to the database
@ -215,8 +213,8 @@ func BorHeimdallForward(
nextSpanId = lastSpanId + 1 nextSpanId = lastSpanId + 1
} }
var endSpanID uint64 var endSpanID uint64
if headNumber > zerothSpanEnd { if bor.SpanIDAt(headNumber) > 0 {
endSpanID = 2 + (headNumber-zerothSpanEnd)/spanLength endSpanID = bor.SpanIDAt(headNumber+1) + 1
} }
lastBlockNum := s.BlockNumber lastBlockNum := s.BlockNumber
@ -312,7 +310,8 @@ func BorHeimdallForward(
if !mine { if !mine {
sprintLength := cfg.chainConfig.Bor.CalculateSprint(blockNum) 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 { if err = checkHeaderExtraData(u, ctx, chain, blockNum, header, cfg.chainConfig.Bor); err != nil {
return err return err
} }
@ -344,10 +343,7 @@ func checkHeaderExtraData(
header *types.Header, header *types.Header,
config *chain.BorConfig, config *chain.BorConfig,
) error { ) error {
var spanID uint64 spanID := bor.SpanIDAt(blockNum + 1)
if blockNum+1 > zerothSpanEnd {
spanID = 1 + (blockNum+1-zerothSpanEnd-1)/spanLength
}
spanBytes := chain.BorSpan(spanID) spanBytes := chain.BorSpan(spanID)
var sp span.HeimdallSpan var sp span.HeimdallSpan
if err := json.Unmarshal(spanBytes, &sp); err != nil { 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 return err
} }
defer spanCursor.Close() defer spanCursor.Close()
var lastSpanToKeep uint64 lastSpanToKeep := bor.SpanIDAt(u.UnwindPoint)
if u.UnwindPoint > zerothSpanEnd {
lastSpanToKeep = 1 + (u.UnwindPoint-zerothSpanEnd-1)/spanLength
}
var spanIdBytes [8]byte var spanIdBytes [8]byte
binary.BigEndian.PutUint64(spanIdBytes[:], lastSpanToKeep+1) binary.BigEndian.PutUint64(spanIdBytes[:], lastSpanToKeep+1)
for k, _, err = spanCursor.Seek(spanIdBytes[:]); err == nil && k != nil; k, _, err = spanCursor.Next() { for k, _, err = spanCursor.Seek(spanIdBytes[:]); err == nil && k != nil; k, _, err = spanCursor.Next() {

View File

@ -3,20 +3,23 @@ package sync
import ( import (
"context" "context"
"errors" "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"
"github.com/ledgerwatch/erigon/consensus/bor/heimdall/checkpoint" "github.com/ledgerwatch/erigon/consensus/bor/heimdall/checkpoint"
"github.com/ledgerwatch/erigon/consensus/bor/heimdall/milestone" "github.com/ledgerwatch/erigon/consensus/bor/heimdall/milestone"
"github.com/ledgerwatch/erigon/consensus/bor/heimdall/span" "github.com/ledgerwatch/erigon/consensus/bor/heimdall/span"
"github.com/ledgerwatch/log/v3"
"math/big"
"time"
) )
// Heimdall is a wrapper of Heimdall HTTP API // Heimdall is a wrapper of Heimdall HTTP API
type Heimdall interface { type Heimdall interface {
FetchCheckpoints(ctx context.Context, start uint64) ([]*checkpoint.Checkpoint, error) FetchCheckpoints(ctx context.Context, start uint64) ([]*checkpoint.Checkpoint, error)
FetchMilestones(ctx context.Context, start uint64) ([]*milestone.Milestone, 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 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 return milestones, nil
} }
func (impl *HeimdallImpl) FetchSpan(ctx context.Context) (*span.HeimdallSpan, error) { func (impl *HeimdallImpl) FetchSpan(ctx context.Context, start uint64) (*span.HeimdallSpan, error) {
// TODO: calc last spanID return impl.client.Span(ctx, bor.SpanIDAt(start))
return impl.client.Span(ctx, 0)
} }
func (impl *HeimdallImpl) OnMilestoneEvent(ctx context.Context, callback func(*milestone.Milestone)) error { func (impl *HeimdallImpl) OnMilestoneEvent(ctx context.Context, callback func(*milestone.Milestone)) error {

View File

@ -2,18 +2,21 @@ package sync
import ( import (
"context" "context"
"math/big"
"testing"
"time"
"github.com/golang/mock/gomock" "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" heimdallclient "github.com/ledgerwatch/erigon/consensus/bor/heimdall"
"github.com/ledgerwatch/erigon/consensus/bor/heimdall/checkpoint" "github.com/ledgerwatch/erigon/consensus/bor/heimdall/checkpoint"
"github.com/ledgerwatch/erigon/consensus/bor/heimdall/milestone" "github.com/ledgerwatch/erigon/consensus/bor/heimdall/milestone"
heimdallmock "github.com/ledgerwatch/erigon/consensus/bor/heimdall/mock" 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 { func makeCheckpoint(start uint64, len uint) *checkpoint.Checkpoint {
c := checkpoint.Checkpoint{ c := checkpoint.Checkpoint{

View File

@ -5,6 +5,7 @@ import (
"context" "context"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/ledgerwatch/erigon/consensus/bor"
"math" "math"
"sort" "sort"
@ -1115,18 +1116,18 @@ func (r *BlockReader) LastFrozenSpanID() uint64 {
if lastSegment == nil { if lastSegment == nil {
return 0 return 0
} }
var lastSpanID uint64
if lastSegment.ranges.to > zerothSpanEnd { lastSpanID := bor.SpanIDAt(lastSegment.ranges.to)
lastSpanID = (lastSegment.ranges.to - zerothSpanEnd - 1) / spanLength if lastSpanID > 0 {
lastSpanID--
} }
return lastSpanID return lastSpanID
} }
func (r *BlockReader) Span(ctx context.Context, tx kv.Getter, spanId uint64) ([]byte, error) { func (r *BlockReader) Span(ctx context.Context, tx kv.Getter, spanId uint64) ([]byte, error) {
// Compute starting block of the span
var endBlock uint64 var endBlock uint64
if spanId > 0 { if spanId > 0 {
endBlock = (spanId)*spanLength + zerothSpanEnd endBlock = bor.SpanEndBlockNum(spanId)
} }
var buf [8]byte var buf [8]byte
binary.BigEndian.PutUint64(buf[:], spanId) 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 { if sn.idx == nil {
continue continue
} }
var spanFrom uint64 spanFrom := bor.SpanIDAt(sn.ranges.from)
if sn.ranges.from > zerothSpanEnd {
spanFrom = 1 + (sn.ranges.from-zerothSpanEnd-1)/spanLength
}
if spanId < spanFrom { if spanId < spanFrom {
continue continue
} }
var spanTo uint64 spanTo := bor.SpanIDAt(sn.ranges.to)
if sn.ranges.to > zerothSpanEnd {
spanTo = 1 + (sn.ranges.to-zerothSpanEnd-1)/spanLength
}
if spanId >= spanTo { if spanId >= spanTo {
continue continue
} }

View File

@ -7,6 +7,7 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"github.com/ledgerwatch/erigon/consensus/bor"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@ -1328,7 +1329,7 @@ func (br *BlockRetire) PruneAncientBlocks(tx kv.RwTx, limit int) error {
includeBor := br.chainConfig.Bor != nil includeBor := br.chainConfig.Bor != nil
if includeBor { if includeBor {
canDeleteTo := CanDeleteTo(currentProgress, br.blockReader.FrozenBorBlocks()) 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 return err
} }
} }

View File

@ -6,6 +6,7 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"github.com/ledgerwatch/erigon/consensus/bor"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@ -36,11 +37,6 @@ import (
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
const (
spanLength = 6400 // Number of blocks in a span
zerothSpanEnd = 255 // End block of 0th span
)
type BorEventSegment struct { type BorEventSegment struct {
seg *compress.Decompressor // value: event_rlp seg *compress.Decompressor // value: event_rlp
IdxBorTxnHash *recsplit.Index // bor_transaction_hash -> bor_event_segment_offset 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 { 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) logEvery := time.NewTicker(20 * time.Second)
defer logEvery.Stop() defer logEvery.Stop()
var spanFrom, spanTo uint64 spanFrom := bor.SpanIDAt(blockFrom)
if blockFrom > zerothSpanEnd { spanTo := bor.SpanIDAt(blockTo)
spanFrom = 1 + (blockFrom-zerothSpanEnd-1)/spanLength
}
if blockTo > zerothSpanEnd {
spanTo = 1 + (blockTo-zerothSpanEnd-1)/spanLength
}
from := hexutility.EncodeTs(spanFrom) from := hexutility.EncodeTs(spanFrom)
if err := kv.BigChunks(db, kv.BorSpans, from, func(tx kv.Tx, spanIdBytes, spanBytes []byte) (bool, error) { if err := kv.BigChunks(db, kv.BorSpans, from, func(tx kv.Tx, spanIdBytes, spanBytes []byte) (bool, error) {
spanId := binary.BigEndian.Uint64(spanIdBytes) spanId := binary.BigEndian.Uint64(spanIdBytes)
@ -511,10 +502,7 @@ func BorSpansIdx(ctx context.Context, segmentFilePath string, blockFrom, blockTo
g := d.MakeGetter() g := d.MakeGetter()
var idxFilePath = filepath.Join(snapDir, snaptype.IdxFileName(blockFrom, blockTo, snaptype.BorSpans.String())) var idxFilePath = filepath.Join(snapDir, snaptype.IdxFileName(blockFrom, blockTo, snaptype.BorSpans.String()))
var baseSpanId uint64 baseSpanId := bor.SpanIDAt(blockFrom)
if blockFrom > zerothSpanEnd {
baseSpanId = 1 + (blockFrom-zerothSpanEnd-1)/spanLength
}
rs, err := recsplit.NewRecSplit(recsplit.RecSplitArgs{ rs, err := recsplit.NewRecSplit(recsplit.RecSplitArgs{
KeyCount: d.Count(), KeyCount: d.Count(),