diff --git a/cmd/rpcdaemon/rpcservices/eth_backend.go b/cmd/rpcdaemon/rpcservices/eth_backend.go index 44f1d91e6..aa4f8192e 100644 --- a/cmd/rpcdaemon/rpcservices/eth_backend.go +++ b/cmd/rpcdaemon/rpcservices/eth_backend.go @@ -271,6 +271,9 @@ func (back *RemoteBackend) EventLookup(ctx context.Context, tx kv.Getter, txnHas func (back *RemoteBackend) EventsByBlock(ctx context.Context, tx kv.Tx, hash common.Hash, blockNum uint64) ([]rlp.RawValue, error) { return back.blockReader.EventsByBlock(ctx, tx, hash, blockNum) } +func (back *RemoteBackend) Span(ctx context.Context, tx kv.Getter, spanId uint64) ([]byte, error) { + return back.blockReader.Span(ctx, tx, spanId) +} func (back *RemoteBackend) NodeInfo(ctx context.Context, limit uint32) ([]p2p.NodeInfo, error) { nodes, err := back.remoteEthBackend.NodeInfo(ctx, &remote.NodesInfoRequest{Limit: limit}) diff --git a/cmd/state/exec3/state.go b/cmd/state/exec3/state.go index a5f61b03b..4e3297219 100644 --- a/cmd/state/exec3/state.go +++ b/cmd/state/exec3/state.go @@ -286,6 +286,7 @@ func (cr ChainReader) HasBlock(hash libcommon.Hash, number uint64) bool { func (cr ChainReader) BorEventsByBlock(hash libcommon.Hash, number uint64) []rlp.RawValue { panic("") } +func (cr ChainReader) BorSpan(spanId uint64) []byte { panic("") } func NewWorkersPool(lock sync.Locker, ctx context.Context, background bool, chainDb kv.RoDB, rs *state.StateV3, in *exec22.QueueWithRetry, blockReader services.FullBlockReader, chainConfig *chain.Config, genesis *types.Genesis, engine consensus.Engine, workerCount int) (reconWorkers []*Worker, applyWorker *Worker, rws *exec22.ResultsQueue, clear func(), wait func()) { reconWorkers = make([]*Worker, workerCount) diff --git a/consensus/bor/bor_test.go b/consensus/bor/bor_test.go index 937868cab..d5572cbd7 100644 --- a/consensus/bor/bor_test.go +++ b/consensus/bor/bor_test.go @@ -2,6 +2,7 @@ package bor_test import ( "context" + "encoding/json" "fmt" "math/big" "testing" @@ -173,6 +174,11 @@ func (r headerReader) GetTd(libcommon.Hash, uint64) *big.Int { return nil } +func (r headerReader) BorSpan(spanId uint64) []byte { + b, _ := json.Marshal(&r.validator.heimdall.currentSpan) + return b +} + type spanner struct { *span.ChainSpanner currentSpan span.Span diff --git a/consensus/chain_reader.go b/consensus/chain_reader.go index 795e2a856..f79de40c4 100644 --- a/consensus/chain_reader.go +++ b/consensus/chain_reader.go @@ -78,3 +78,11 @@ func (cr ChainReaderImpl) GetTd(hash libcommon.Hash, number uint64) *big.Int { func (cr ChainReaderImpl) FrozenBlocks() uint64 { return cr.BlockReader.FrozenBlocks() } + +func (cr ChainReaderImpl) BorSpan(spanId uint64) []byte { + spanBytes, err := cr.BlockReader.Span(context.Background(), cr.Db, spanId) + if err != nil { + log.Error("BorSpan failed", "err", err) + } + return spanBytes +} diff --git a/consensus/consensus.go b/consensus/consensus.go index 1165c95bb..0a98706fa 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -55,6 +55,9 @@ type ChainHeaderReader interface { // Number of blocks frozen in the block snapshots FrozenBlocks() uint64 + + // Byte string representation of a bor span with given ID + BorSpan(spanId uint64) []byte } // ChainReader defines a small collection of methods needed to access the local diff --git a/consensus/merge/merge_test.go b/consensus/merge/merge_test.go index bf0558211..aee7810cd 100644 --- a/consensus/merge/merge_test.go +++ b/consensus/merge/merge_test.go @@ -41,6 +41,10 @@ func (r readerMock) FrozenBlocks() uint64 { return 0 } +func (r readerMock) BorSpan(spanId uint64) []byte { + return nil +} + // The thing only that changes beetwen normal ethash checks other than POW, is difficulty // and nonce so we are gonna test those func TestVerifyHeaderDifficulty(t *testing.T) { diff --git a/core/chain_makers.go b/core/chain_makers.go index a2d7221e2..25a96626b 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -653,3 +653,4 @@ func (cr *FakeChainReader) FrozenBlocks() uint64 func (cr *FakeChainReader) BorEventsByBlock(hash libcommon.Hash, number uint64) []rlp.RawValue { return nil } +func (cr *FakeChainReader) BorSpan(spanId uint64) []byte { return nil } diff --git a/eth/stagedsync/chain_reader.go b/eth/stagedsync/chain_reader.go index d86f7c3f2..862cae571 100644 --- a/eth/stagedsync/chain_reader.go +++ b/eth/stagedsync/chain_reader.go @@ -84,3 +84,7 @@ func (cr ChainReader) FrozenBlocks() uint64 { func (cr ChainReader) BorEventsByBlock(hash libcommon.Hash, number uint64) []rlp.RawValue { panic("") } + +func (cr ChainReader) BorSpan(spanId uint64) []byte { + panic("") +} diff --git a/eth/stagedsync/stage_headers.go b/eth/stagedsync/stage_headers.go index ea99b6c39..5126aa9a5 100644 --- a/eth/stagedsync/stage_headers.go +++ b/eth/stagedsync/stage_headers.go @@ -568,3 +568,11 @@ func (cr ChainReaderImpl) BorEventsByBlock(hash libcommon.Hash, number uint64) [ } return events } +func (cr ChainReaderImpl) BorSpan(spanId uint64) []byte { + span, err := cr.blockReader.Span(context.Background(), cr.tx, spanId) + if err != nil { + cr.logger.Error("BorSpan failed", "err", err) + return nil + } + return span +} diff --git a/turbo/services/interfaces.go b/turbo/services/interfaces.go index 2b86e736f..4fbe8a7c3 100644 --- a/turbo/services/interfaces.go +++ b/turbo/services/interfaces.go @@ -38,6 +38,10 @@ type BorEventReader interface { EventsByBlock(ctx context.Context, tx kv.Tx, hash common.Hash, blockNum uint64) ([]rlp.RawValue, error) } +type BorSpanReader interface { + Span(ctx context.Context, tx kv.Getter, spanNum uint64) ([]byte, error) +} + type CanonicalReader interface { CanonicalHash(ctx context.Context, tx kv.Getter, blockNum uint64) (common.Hash, error) BadHeaderNumber(ctx context.Context, tx kv.Getter, hash common.Hash) (blockHeight *uint64, err error) @@ -71,6 +75,7 @@ type FullBlockReader interface { BodyReader HeaderReader BorEventReader + BorSpanReader TxnReader CanonicalReader diff --git a/turbo/snapshotsync/freezeblocks/block_reader.go b/turbo/snapshotsync/freezeblocks/block_reader.go index 430e9f5ab..d1b67cc64 100644 --- a/turbo/snapshotsync/freezeblocks/block_reader.go +++ b/turbo/snapshotsync/freezeblocks/block_reader.go @@ -235,6 +235,10 @@ func (r *RemoteBlockReader) EventsByBlock(ctx context.Context, tx kv.Tx, hash co return result, nil } +func (r *RemoteBlockReader) Span(ctx context.Context, tx kv.Getter, spanId uint64) ([]byte, error) { + return nil, nil +} + // BlockReader can read blocks from db and snapshots type BlockReader struct { sn *RoSnapshots @@ -1078,6 +1082,73 @@ func (r *BlockReader) LastFrozenEventID() uint64 { return lastEventID } +func (r *BlockReader) LastFrozenSpanID() uint64 { + view := r.borSn.View() + defer view.Close() + segments := view.Spans() + if len(segments) == 0 { + return 0 + } + lastSegment := segments[len(segments)-1] + var lastSpanID uint64 + if lastSegment.ranges.to > zerothSpanEnd { + lastSpanID = (lastSegment.ranges.to - zerothSpanEnd - 1) / spanLength + } + 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 + } + var buf [8]byte + binary.BigEndian.PutUint64(buf[:], spanId) + if endBlock >= r.FrozenBorBlocks() { + v, err := tx.GetOne(kv.BorSpans, buf[:]) + if err != nil { + return nil, err + } + if v == nil { + return nil, fmt.Errorf("span %d not found (db)", spanId) + } + return common.Copy(v), nil + } + view := r.borSn.View() + defer view.Close() + segments := view.Spans() + for i := len(segments) - 1; i >= 0; i-- { + sn := segments[i] + if sn.idx == nil { + continue + } + var spanFrom uint64 + if sn.ranges.from > zerothSpanEnd { + spanFrom = 1 + (sn.ranges.from-zerothSpanEnd-1)/spanLength + } + if spanId < spanFrom { + continue + } + var spanTo uint64 + if sn.ranges.to > zerothSpanEnd { + spanTo = 1 + (sn.ranges.to-zerothSpanEnd-1)/spanLength + } + if spanId >= spanTo { + continue + } + if sn.idx.KeyCount() == 0 { + continue + } + offset := sn.idx.OrdinalLookup(spanId - sn.idx.BaseDataID()) + gg := sn.seg.MakeGetter() + gg.Reset(offset) + result, _ := gg.Next(nil) + return common.Copy(result), nil + } + return nil, fmt.Errorf("span %d not found (snapshots)", spanId) +} + // ---- Data Integrity part ---- func (r *BlockReader) ensureHeaderNumber(n uint64, seg *HeaderSegment) error {