From ca6e2d141b14e67d2ba826c6213e9e413148b6ec Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 9 Sep 2025 20:39:54 +0800 Subject: [PATCH] triedb/pathdb: sync ancient store before journal (#32557) This pull request addresses the corrupted path database with log indicating: `history head truncation out of range, tail: 122557, head: 212208, target: 212557` This is a rare edge case where the in-memory layers, including the write buffer in the disk layer, are fully persisted (e.g., written to file), but the state history freezer is not properly closed (e.g., Geth is terminated after journaling but before freezer.Close). In this situation, the recent state history writes will be truncated on the next startup, while the in-memory layers resolve correctly. As a result, the state history falls behind the disk layer (including the write buffer). In this pull request, the state history freezer is always synced before journal, ensuring the state history writes are always persisted before the others. Edit: It's confirmed that devops team has 10s container termination setting. It explains why Geth didn't finish the entire termination without state history being closed. https://github.com/ethpandaops/fusaka-devnets/pull/63/files --- triedb/pathdb/journal.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/triedb/pathdb/journal.go b/triedb/pathdb/journal.go index 7a634dc974..02bdef5d34 100644 --- a/triedb/pathdb/journal.go +++ b/triedb/pathdb/journal.go @@ -333,7 +333,16 @@ func (db *Database) Journal(root common.Hash) error { if db.readOnly { return errDatabaseReadOnly } - + // Forcibly sync the ancient store before persisting the in-memory layers. + // This prevents an edge case where the in-memory layers are persisted + // but the ancient store is not properly closed, resulting in recent writes + // being lost. After a restart, the ancient store would then be misaligned + // with the disk layer, causing data corruption. + if db.stateFreezer != nil { + if err := db.stateFreezer.SyncAncient(); err != nil { + return err + } + } // Store the journal into the database and return var ( file *os.File