Skip to content

Commit 0c90e4b

Browse files
authored
all: incorporate state history indexing status into eth_syncing response (#32099)
This pull request tracks the state indexing progress in eth_syncing RPC response, i.e. we will return non-null syncing status until indexing has finished.
1 parent 36bcc24 commit 0c90e4b

File tree

11 files changed

+88
-2
lines changed

11 files changed

+88
-2
lines changed

core/blockchain_reader.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,11 @@ func (bc *BlockChain) TxIndexProgress() (TxIndexProgress, error) {
426426
return bc.txIndexer.txIndexProgress(), nil
427427
}
428428

429+
// StateIndexProgress returns the historical state indexing progress.
430+
func (bc *BlockChain) StateIndexProgress() (uint64, error) {
431+
return bc.triedb.IndexProgress()
432+
}
433+
429434
// HistoryPruningCutoff returns the configured history pruning point.
430435
// Blocks before this might not be available in the database.
431436
func (bc *BlockChain) HistoryPruningCutoff() (uint64, common.Hash) {

eth/api_backend.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,10 @@ func (b *EthAPIBackend) SyncProgress(ctx context.Context) ethereum.SyncProgress
403403
prog.TxIndexFinishedBlocks = txProg.Indexed
404404
prog.TxIndexRemainingBlocks = txProg.Remaining
405405
}
406+
remain, err := b.eth.blockchain.StateIndexProgress()
407+
if err == nil {
408+
prog.StateIndexRemaining = remain
409+
}
406410
return prog
407411
}
408412

eth/downloader/api.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ func (api *DownloaderAPI) eventLoop() {
8181
prog.TxIndexFinishedBlocks = txProg.Indexed
8282
prog.TxIndexRemainingBlocks = txProg.Remaining
8383
}
84+
remain, err := api.chain.StateIndexProgress()
85+
if err == nil {
86+
prog.StateIndexRemaining = remain
87+
}
8488
return prog
8589
}
8690
)

ethclient/ethclient.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,7 @@ type rpcProgress struct {
789789
HealingBytecode hexutil.Uint64
790790
TxIndexFinishedBlocks hexutil.Uint64
791791
TxIndexRemainingBlocks hexutil.Uint64
792+
StateIndexRemaining hexutil.Uint64
792793
}
793794

794795
func (p *rpcProgress) toSyncProgress() *ethereum.SyncProgress {
@@ -815,5 +816,6 @@ func (p *rpcProgress) toSyncProgress() *ethereum.SyncProgress {
815816
HealingBytecode: uint64(p.HealingBytecode),
816817
TxIndexFinishedBlocks: uint64(p.TxIndexFinishedBlocks),
817818
TxIndexRemainingBlocks: uint64(p.TxIndexRemainingBlocks),
819+
StateIndexRemaining: uint64(p.StateIndexRemaining),
818820
}
819821
}

graphql/graphql.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,6 +1510,9 @@ func (s *SyncState) TxIndexFinishedBlocks() hexutil.Uint64 {
15101510
func (s *SyncState) TxIndexRemainingBlocks() hexutil.Uint64 {
15111511
return hexutil.Uint64(s.progress.TxIndexRemainingBlocks)
15121512
}
1513+
func (s *SyncState) StateIndexRemaining() hexutil.Uint64 {
1514+
return hexutil.Uint64(s.progress.StateIndexRemaining)
1515+
}
15131516

15141517
// Syncing returns false in case the node is currently not syncing with the network. It can be up-to-date or has not
15151518
// yet received the latest block headers from its peers. In case it is synchronizing:

interfaces.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,17 @@ type SyncProgress struct {
124124
// "transaction indexing" fields
125125
TxIndexFinishedBlocks uint64 // Number of blocks whose transactions are already indexed
126126
TxIndexRemainingBlocks uint64 // Number of blocks whose transactions are not indexed yet
127+
128+
// "historical state indexing" fields
129+
StateIndexRemaining uint64 // Number of states remain unindexed
127130
}
128131

129132
// Done returns the indicator if the initial sync is finished or not.
130133
func (prog SyncProgress) Done() bool {
131134
if prog.CurrentBlock < prog.HighestBlock {
132135
return false
133136
}
134-
return prog.TxIndexRemainingBlocks == 0
137+
return prog.TxIndexRemainingBlocks == 0 && prog.StateIndexRemaining == 0
135138
}
136139

137140
// ChainSyncReader wraps access to the node's current sync status. If there's no

internal/ethapi/api.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ func (api *EthereumAPI) Syncing(ctx context.Context) (interface{}, error) {
170170
"healingBytecode": hexutil.Uint64(progress.HealingBytecode),
171171
"txIndexFinishedBlocks": hexutil.Uint64(progress.TxIndexFinishedBlocks),
172172
"txIndexRemainingBlocks": hexutil.Uint64(progress.TxIndexRemainingBlocks),
173+
"stateIndexRemaining": hexutil.Uint64(progress.StateIndexRemaining),
173174
}, nil
174175
}
175176

internal/jsre/deps/web3.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3977,6 +3977,7 @@ var outputSyncingFormatter = function(result) {
39773977
result.healingBytecode = utils.toDecimal(result.healingBytecode);
39783978
result.txIndexFinishedBlocks = utils.toDecimal(result.txIndexFinishedBlocks);
39793979
result.txIndexRemainingBlocks = utils.toDecimal(result.txIndexRemainingBlocks);
3980+
result.stateIndexRemaining = utils.toDecimal(result.stateIndexRemaining)
39803981

39813982
return result;
39823983
};

triedb/database.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,16 @@ func (db *Database) StorageIterator(root common.Hash, account common.Hash, seek
356356
return pdb.StorageIterator(root, account, seek)
357357
}
358358

359+
// IndexProgress returns the indexing progress made so far. It provides the
360+
// number of states that remain unindexed.
361+
func (db *Database) IndexProgress() (uint64, error) {
362+
pdb, ok := db.backend.(*pathdb.Database)
363+
if !ok {
364+
return 0, errors.New("not supported")
365+
}
366+
return pdb.IndexProgress()
367+
}
368+
359369
// IsVerkle returns the indicator if the database is holding a verkle tree.
360370
func (db *Database) IsVerkle() bool {
361371
return db.config.IsVerkle

triedb/pathdb/database.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,15 @@ func (db *Database) HistoryRange() (uint64, uint64, error) {
700700
return historyRange(db.freezer)
701701
}
702702

703+
// IndexProgress returns the indexing progress made so far. It provides the
704+
// number of states that remain unindexed.
705+
func (db *Database) IndexProgress() (uint64, error) {
706+
if db.indexer == nil {
707+
return 0, nil
708+
}
709+
return db.indexer.progress()
710+
}
711+
703712
// AccountIterator creates a new account iterator for the specified root hash and
704713
// seeks to a starting account hash.
705714
func (db *Database) AccountIterator(root common.Hash, seek common.Hash) (AccountIterator, error) {

triedb/pathdb/history_indexer.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,12 @@ type indexIniter struct {
305305
interrupt chan *interruptSignal
306306
done chan struct{}
307307
closed chan struct{}
308-
wg sync.WaitGroup
308+
309+
// indexing progress
310+
indexed atomic.Uint64 // the id of latest indexed state
311+
last atomic.Uint64 // the id of the target state to be indexed
312+
313+
wg sync.WaitGroup
309314
}
310315

311316
func newIndexIniter(disk ethdb.KeyValueStore, freezer ethdb.AncientStore, lastID uint64) *indexIniter {
@@ -316,6 +321,14 @@ func newIndexIniter(disk ethdb.KeyValueStore, freezer ethdb.AncientStore, lastID
316321
done: make(chan struct{}),
317322
closed: make(chan struct{}),
318323
}
324+
// Load indexing progress
325+
initer.last.Store(lastID)
326+
metadata := loadIndexMetadata(disk)
327+
if metadata != nil {
328+
initer.indexed.Store(metadata.Last)
329+
}
330+
331+
// Launch background indexer
319332
initer.wg.Add(1)
320333
go initer.run(lastID)
321334
return initer
@@ -342,6 +355,22 @@ func (i *indexIniter) inited() bool {
342355
}
343356
}
344357

358+
func (i *indexIniter) remain() uint64 {
359+
select {
360+
case <-i.closed:
361+
return 0
362+
case <-i.done:
363+
return 0
364+
default:
365+
last, indexed := i.last.Load(), i.indexed.Load()
366+
if last < indexed {
367+
log.Error("Invalid state indexing range", "last", last, "indexed", indexed)
368+
return 0
369+
}
370+
return last - indexed
371+
}
372+
}
373+
345374
func (i *indexIniter) run(lastID uint64) {
346375
defer i.wg.Done()
347376

@@ -367,6 +396,8 @@ func (i *indexIniter) run(lastID uint64) {
367396
signal.result <- fmt.Errorf("invalid history id, last: %d, got: %d", lastID, signal.newLastID)
368397
continue
369398
}
399+
i.last.Store(signal.newLastID) // update indexing range
400+
370401
// The index limit is extended by one, update the limit without
371402
// interrupting the current background process.
372403
if signal.newLastID == lastID+1 {
@@ -507,6 +538,8 @@ func (i *indexIniter) index(done chan struct{}, interrupt *atomic.Int32, lastID
507538
log.Info("Indexing state history", "processed", done, "left", left, "elapsed", common.PrettyDuration(time.Since(start)), "eta", common.PrettyDuration(eta))
508539
}
509540
}
541+
i.indexed.Store(current - 1) // update indexing progress
542+
510543
// Check interruption signal and abort process if it's fired
511544
if interrupt != nil {
512545
if signal := interrupt.Load(); signal != 0 {
@@ -617,3 +650,14 @@ func (i *historyIndexer) shorten(historyID uint64) error {
617650
return <-signal.result
618651
}
619652
}
653+
654+
// progress returns the indexing progress made so far. It provides the number
655+
// of states that remain unindexed.
656+
func (i *historyIndexer) progress() (uint64, error) {
657+
select {
658+
case <-i.initer.closed:
659+
return 0, errors.New("indexer is closed")
660+
default:
661+
return i.initer.remain(), nil
662+
}
663+
}

0 commit comments

Comments
 (0)