Fix cross-network block detection and remove false orphan artifacts
- Change OrphanedAt from time.Time to *time.Time so JSON omitempty correctly omits zero values (Go serializes zero time.Time as "0001-01-01T00:00:00Z" which JS treats as truthy) - Rewrite reconcileOnce with 4-pass architecture: enrichment, reorg detection via GetBlock verification, false-positive un-orphaning, and legacy block stamping - Use inferOtherChain() to stamp cross-network blocks with the correct chain identifier (testnet4 reports as "testnet4", not "test") - Move tailer startup after aggregator's first refresh so blocks are always stamped with the current chain - Add StampChain store method, debug-blocks admin endpoint, and comprehensive reconcile tests for cross-network scenarios
This commit is contained in:
@@ -287,3 +287,41 @@ func (s *BlockStore) MarkOrphaned(height int64, at time.Time) error {
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// UnmarkOrphaned clears the orphaned_at stamp set by MarkOrphaned.
|
||||
// Used to correct false positives caused by a network switch: a block
|
||||
// found on testnet is not "orphaned" when the node switches to mainnet —
|
||||
// it simply belongs to a different chain and must not be compared against
|
||||
// mainnet's canonical history.
|
||||
func (s *BlockStore) UnmarkOrphaned(height int64) error {
|
||||
_, err := s.db.Exec(
|
||||
`UPDATE blocks SET orphaned_at = 0 WHERE height = ?`,
|
||||
height,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// UnmarkOrphanedStampChain clears orphaned_at and simultaneously sets the
|
||||
// chain field. Used for legacy rows (chain == "") that were falsely orphaned
|
||||
// during a network switch: by stamping a non-mainnet chain value we prevent
|
||||
// the reconcile reorg-detection pass from re-checking the block against the
|
||||
// current chain's canonical hashes.
|
||||
func (s *BlockStore) UnmarkOrphanedStampChain(height int64, chain string) error {
|
||||
_, err := s.db.Exec(
|
||||
`UPDATE blocks SET orphaned_at = 0, chain = ? WHERE height = ?`,
|
||||
chain, height,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// StampChain sets the chain field on a block without touching orphaned_at.
|
||||
// Used when the reconcile loop determines a block belongs to a different
|
||||
// network — the block is not orphaned (a reorg), it just doesn't belong
|
||||
// to the current chain.
|
||||
func (s *BlockStore) StampChain(height int64, chain string) error {
|
||||
_, err := s.db.Exec(
|
||||
`UPDATE blocks SET chain = ? WHERE height = ?`,
|
||||
chain, height,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user