mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
triedb/pathdb: fix trienode history gap when newly enabled on existing node
When enabling trienode history (--history.trienode=0) on a node that already has state at block N, repairHistory() returns a fatal error: "gap between state [#N] and trienode history [#0]" This happens because the newly created trienode freezer has 0 entries while state is at block N. The gap check on line 427 treats this as a data corruption error, but the function's own comments document that it should "detect and resolve such gaps" for the optional trienode history. Fix by detecting the newly-enabled case (empty freezer + non-zero stateID) and skipping both the gap check and the head truncation. An empty freezer with head=0 would also fail truncateFromHead because ohead(0) < nhead(stateID) is outside the valid range. The trienode history will begin accumulating naturally from the current state forward, which is the expected behavior documented in the v1.17.0 release notes. Fixes ethereum/go-ethereum#33907
This commit is contained in:
parent
723aae2b4e
commit
eabbd68c19
1 changed files with 22 additions and 7 deletions
|
|
@ -419,17 +419,27 @@ func repairHistory(db ethdb.Database, isVerkle bool, readOnly bool, stateID uint
|
|||
if stateID > head {
|
||||
return nil, nil, fmt.Errorf("gap between state [#%d] and state history [#%d]", stateID, head)
|
||||
}
|
||||
// Track whether trienode history is newly enabled (empty freezer on an
|
||||
// existing node). In that case, skip gap checks and truncation — history
|
||||
// will begin accumulating from the current state forward.
|
||||
trienodeNewlyEnabled := false
|
||||
if trienodes != nil {
|
||||
th, err := trienodes.Ancients()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if stateID > th {
|
||||
return nil, nil, fmt.Errorf("gap between state [#%d] and trienode history [#%d]", stateID, th)
|
||||
}
|
||||
if th != head {
|
||||
log.Info("Histories are not aligned with each other", "state", head, "trienode", th)
|
||||
head = min(head, th)
|
||||
if th == 0 && stateID > 0 {
|
||||
// Trienode history is newly enabled on an existing node.
|
||||
log.Info("Trienode history newly enabled, will start from current state", "state", stateID)
|
||||
trienodeNewlyEnabled = true
|
||||
} else {
|
||||
if stateID > th {
|
||||
return nil, nil, fmt.Errorf("gap between state [#%d] and trienode history [#%d]", stateID, th)
|
||||
}
|
||||
if th != head {
|
||||
log.Info("Histories are not aligned with each other", "state", head, "trienode", th)
|
||||
head = min(head, th)
|
||||
}
|
||||
}
|
||||
}
|
||||
head = min(head, stateID)
|
||||
|
|
@ -449,6 +459,11 @@ func repairHistory(db ethdb.Database, isVerkle bool, readOnly bool, stateID uint
|
|||
}
|
||||
}
|
||||
truncate(states, typeStateHistory, head)
|
||||
truncate(trienodes, typeTrienodeHistory, head)
|
||||
// Only truncate trienode history if it already has data. A newly enabled
|
||||
// (empty) trienode freezer would cause truncateFromHead to error because
|
||||
// ohead(0) < nhead(stateID) falls outside the valid range.
|
||||
if !trienodeNewlyEnabled {
|
||||
truncate(trienodes, typeTrienodeHistory, head)
|
||||
}
|
||||
return states, trienodes, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue