Skip to content

Commit ede177e

Browse files
committed
Merge commit '615d29f7c2d5aed84cf8c7ec952d9f9a9f706e4b' into merge_v1.15.11
2 parents 5b6de15 + 615d29f commit ede177e

18 files changed

+214
-179
lines changed

core/blockchain_reader.go

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -270,42 +270,20 @@ func (bc *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, max
270270
// GetTransactionLookup retrieves the lookup along with the transaction
271271
// itself associate with the given transaction hash.
272272
//
273-
// An error will be returned if the transaction is not found, and background
274-
// indexing for transactions is still in progress. The transaction might be
275-
// reachable shortly once it's indexed.
276-
//
277-
// A null will be returned in the transaction is not found and background
278-
// transaction indexing is already finished. The transaction is not existent
279-
// from the node's perspective.
280-
func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLookupEntry, *types.Transaction, error) {
273+
// A null will be returned if the transaction is not found. This can be due to
274+
// the transaction indexer not being finished. The caller must explicitly check
275+
// the indexer progress.
276+
func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLookupEntry, *types.Transaction) {
281277
bc.txLookupLock.RLock()
282278
defer bc.txLookupLock.RUnlock()
283279

284280
// Short circuit if the txlookup already in the cache, retrieve otherwise
285281
if item, exist := bc.txLookupCache.Get(hash); exist {
286-
return item.lookup, item.transaction, nil
282+
return item.lookup, item.transaction
287283
}
288284
tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(bc.db, hash)
289285
if tx == nil {
290-
progress, err := bc.TxIndexProgress()
291-
if err != nil {
292-
// No error is returned if the transaction indexing progress is unreachable
293-
// due to unexpected internal errors. In such cases, it is impossible to
294-
// determine whether the transaction does not exist or has simply not been
295-
// indexed yet without a progress marker.
296-
//
297-
// In such scenarios, the transaction is treated as unreachable, though
298-
// this is clearly an unintended and unexpected situation.
299-
return nil, nil, nil
300-
}
301-
// The transaction indexing is not finished yet, returning an
302-
// error to explicitly indicate it.
303-
if !progress.Done() {
304-
return nil, nil, errors.New("transaction indexing still in progress")
305-
}
306-
// The transaction is already indexed, the transaction is either
307-
// not existent or not in the range of index, returning null.
308-
return nil, nil, nil
286+
return nil, nil
309287
}
310288
lookup := &rawdb.LegacyTxLookupEntry{
311289
BlockHash: blockHash,
@@ -316,7 +294,23 @@ func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLoo
316294
lookup: lookup,
317295
transaction: tx,
318296
})
319-
return lookup, tx, nil
297+
return lookup, tx
298+
}
299+
300+
// TxIndexDone returns true if the transaction indexer has finished indexing.
301+
func (bc *BlockChain) TxIndexDone() bool {
302+
progress, err := bc.TxIndexProgress()
303+
if err != nil {
304+
// No error is returned if the transaction indexing progress is unreachable
305+
// due to unexpected internal errors. In such cases, it is impossible to
306+
// determine whether the transaction does not exist or has simply not been
307+
// indexed yet without a progress marker.
308+
//
309+
// In such scenarios, the transaction is treated as unreachable, though
310+
// this is clearly an unintended and unexpected situation.
311+
return true
312+
}
313+
return progress.Done()
320314
}
321315

322316
// HasState checks if state trie is fully present in the database or not.
@@ -412,7 +406,7 @@ func (bc *BlockChain) TxIndexProgress() (TxIndexProgress, error) {
412406
if bc.txIndexer == nil {
413407
return TxIndexProgress{}, errors.New("tx indexer is not enabled")
414408
}
415-
return bc.txIndexer.txIndexProgress()
409+
return bc.txIndexer.txIndexProgress(), nil
416410
}
417411

418412
// HistoryPruningCutoff returns the configured history pruning point.

core/filtermaps/chain_view.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,6 @@ func (cv *ChainView) SharedRange(cv2 *ChainView) common.Range[uint64] {
135135
return common.NewRange(0, sharedLen)
136136
}
137137

138-
// limitedView returns a new chain view that is a truncated version of the parent view.
139-
func (cv *ChainView) limitedView(newHead uint64) *ChainView {
140-
if newHead >= cv.headNumber {
141-
return cv
142-
}
143-
return NewChainView(cv.chain, newHead, cv.BlockHash(newHead))
144-
}
145-
146138
// equalViews returns true if the two chain views are equivalent.
147139
func equalViews(cv1, cv2 *ChainView) bool {
148140
if cv1 == nil || cv2 == nil {

core/filtermaps/filtermaps.go

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ var (
5050
)
5151

5252
const (
53-
databaseVersion = 1 // reindexed if database version does not match
53+
databaseVersion = 2 // reindexed if database version does not match
5454
cachedLastBlocks = 1000 // last block of map pointers
5555
cachedLvPointers = 1000 // first log value pointer of block pointers
5656
cachedBaseRows = 100 // groups of base layer filter row data
@@ -244,6 +244,8 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, f
244244
disabledCh: make(chan struct{}),
245245
exportFileName: config.ExportFileName,
246246
Params: params,
247+
targetView: initView,
248+
indexedView: initView,
247249
indexedRange: filterMapsRange{
248250
initialized: initialized,
249251
headIndexed: rs.HeadIndexed,
@@ -265,16 +267,8 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, f
265267
baseRowsCache: lru.NewCache[uint64, [][]uint32](cachedBaseRows),
266268
renderSnapshots: lru.NewCache[uint64, *renderedMap](cachedRenderSnapshots),
267269
}
270+
f.checkRevertRange() // revert maps that are inconsistent with the current chain view
268271

269-
// Set initial indexer target.
270-
f.targetView = initView
271-
if f.indexedRange.initialized {
272-
f.indexedView = f.initChainView(f.targetView)
273-
f.indexedRange.headIndexed = f.indexedRange.blocks.AfterLast() == f.indexedView.HeadNumber()+1
274-
if !f.indexedRange.headIndexed {
275-
f.indexedRange.headDelimiter = 0
276-
}
277-
}
278272
if f.indexedRange.hasIndexedBlocks() {
279273
log.Info("Initialized log indexer",
280274
"first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(),
@@ -303,29 +297,40 @@ func (f *FilterMaps) Stop() {
303297
f.closeWg.Wait()
304298
}
305299

306-
// initChainView returns a chain view consistent with both the current target
307-
// view and the current state of the log index as found in the database, based
308-
// on the last block of stored maps.
309-
// Note that the returned view might be shorter than the existing index if
310-
// the latest maps are not consistent with targetView.
311-
func (f *FilterMaps) initChainView(chainView *ChainView) *ChainView {
312-
mapIndex := f.indexedRange.maps.AfterLast()
313-
for {
314-
var ok bool
315-
mapIndex, ok = f.lastMapBoundaryBefore(mapIndex)
316-
if !ok {
317-
break
300+
// checkRevertRange checks whether the existing index is consistent with the
301+
// current indexed view and reverts inconsistent maps if necessary.
302+
func (f *FilterMaps) checkRevertRange() {
303+
if f.indexedRange.maps.Count() == 0 {
304+
return
305+
}
306+
lastMap := f.indexedRange.maps.Last()
307+
lastBlockNumber, lastBlockId, err := f.getLastBlockOfMap(lastMap)
308+
if err != nil {
309+
log.Error("Error initializing log index database; resetting log index", "error", err)
310+
f.reset()
311+
return
312+
}
313+
for lastBlockNumber > f.indexedView.HeadNumber() || f.indexedView.BlockId(lastBlockNumber) != lastBlockId {
314+
// revert last map
315+
if f.indexedRange.maps.Count() == 1 {
316+
f.reset() // reset database if no rendered maps remained
317+
return
318318
}
319-
lastBlockNumber, lastBlockId, err := f.getLastBlockOfMap(mapIndex)
319+
lastMap--
320+
newRange := f.indexedRange
321+
newRange.maps.SetLast(lastMap)
322+
lastBlockNumber, lastBlockId, err = f.getLastBlockOfMap(lastMap)
320323
if err != nil {
321-
log.Error("Could not initialize indexed chain view", "error", err)
322-
break
323-
}
324-
if lastBlockNumber <= chainView.HeadNumber() && chainView.BlockId(lastBlockNumber) == lastBlockId {
325-
return chainView.limitedView(lastBlockNumber)
324+
log.Error("Error initializing log index database; resetting log index", "error", err)
325+
f.reset()
326+
return
326327
}
328+
newRange.blocks.SetAfterLast(lastBlockNumber) // lastBlockNumber is probably partially indexed
329+
newRange.headIndexed = false
330+
newRange.headDelimiter = 0
331+
// only shorten range and leave map data; next head render will overwrite it
332+
f.setRange(f.db, f.indexedView, newRange, false)
327333
}
328-
return chainView.limitedView(0)
329334
}
330335

331336
// reset un-initializes the FilterMaps structure and removes all related data from
@@ -662,15 +667,11 @@ func (f *FilterMaps) mapRowIndex(mapIndex, rowIndex uint32) uint64 {
662667
}
663668

664669
// getBlockLvPointer returns the starting log value index where the log values
665-
// generated by the given block are located. If blockNumber is beyond the current
666-
// head then the first unoccupied log value index is returned.
670+
// generated by the given block are located.
667671
//
668672
// Note that this function assumes that the indexer read lock is being held when
669673
// called from outside the indexerLoop goroutine.
670674
func (f *FilterMaps) getBlockLvPointer(blockNumber uint64) (uint64, error) {
671-
if blockNumber >= f.indexedRange.blocks.AfterLast() && f.indexedRange.headIndexed {
672-
return f.indexedRange.headDelimiter + 1, nil
673-
}
674675
if lvPointer, ok := f.lvPointerCache.Get(blockNumber); ok {
675676
return lvPointer, nil
676677
}

core/filtermaps/map_renderer.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -468,15 +468,25 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error {
468468
r.f.filterMapCache.Remove(mapIndex)
469469
}
470470
}
471+
var blockNumber uint64
472+
if r.finished.First() > 0 {
473+
// in order to always ensure continuous block pointers, initialize
474+
// blockNumber based on the last block of the previous map, then verify
475+
// against the first block associated with each rendered map
476+
lastBlock, _, err := r.f.getLastBlockOfMap(r.finished.First() - 1)
477+
if err != nil {
478+
return fmt.Errorf("failed to get last block of previous map %d: %v", r.finished.First()-1, err)
479+
}
480+
blockNumber = lastBlock + 1
481+
}
471482
// add or update block pointers
472-
blockNumber := r.finishedMaps[r.finished.First()].firstBlock()
473483
for mapIndex := range r.finished.Iter() {
474484
renderedMap := r.finishedMaps[mapIndex]
475-
r.f.storeLastBlockOfMap(batch, mapIndex, renderedMap.lastBlock, renderedMap.lastBlockId)
476-
checkWriteCnt()
477485
if blockNumber != renderedMap.firstBlock() {
478-
panic("non-continuous block numbers")
486+
return fmt.Errorf("non-continuous block numbers in rendered map %d (next expected: %d first rendered: %d)", mapIndex, blockNumber, renderedMap.firstBlock())
479487
}
488+
r.f.storeLastBlockOfMap(batch, mapIndex, renderedMap.lastBlock, renderedMap.lastBlockId)
489+
checkWriteCnt()
480490
for _, lvPtr := range renderedMap.blockLvPtrs {
481491
r.f.storeBlockLvPointer(batch, blockNumber, lvPtr)
482492
checkWriteCnt()

core/filtermaps/matcher_backend.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,26 @@ func (fm *FilterMapsMatcherBackend) GetFilterMapRow(ctx context.Context, mapInde
8282
}
8383

8484
// GetBlockLvPointer returns the starting log value index where the log values
85-
// generated by the given block are located. If blockNumber is beyond the current
86-
// head then the first unoccupied log value index is returned.
85+
// generated by the given block are located. If blockNumber is beyond the last
86+
// indexed block then the pointer will point right after this block, ensuring
87+
// that the matcher does not fail and can return a set of results where the
88+
// valid range is correct.
8789
// GetBlockLvPointer implements MatcherBackend.
8890
func (fm *FilterMapsMatcherBackend) GetBlockLvPointer(ctx context.Context, blockNumber uint64) (uint64, error) {
8991
fm.f.indexLock.RLock()
9092
defer fm.f.indexLock.RUnlock()
9193

94+
if blockNumber >= fm.f.indexedRange.blocks.AfterLast() {
95+
if fm.f.indexedRange.headIndexed {
96+
// return index after head block
97+
return fm.f.indexedRange.headDelimiter + 1, nil
98+
}
99+
if fm.f.indexedRange.blocks.Count() > 0 {
100+
// return index at the beginning of the last, partially indexed
101+
// block (after the last fully indexed one)
102+
blockNumber = fm.f.indexedRange.blocks.Last()
103+
}
104+
}
92105
return fm.f.getBlockLvPointer(blockNumber)
93106
}
94107

0 commit comments

Comments
 (0)