From 48f5cb47a7177954155d9882d4a2c316739866c4 Mon Sep 17 00:00:00 2001 From: Simon Gellis Date: Thu, 26 Jun 2025 16:41:41 -0400 Subject: [PATCH] feat: emit logs/metrics to track forks Signed-off-by: Simon Gellis --- ledger/chainsync.go | 9 +++++++++ ledger/metrics.go | 5 +++++ ledger/state.go | 16 +++++++++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/ledger/chainsync.go b/ledger/chainsync.go index c3bc393c..2063b822 100644 --- a/ledger/chainsync.go +++ b/ledger/chainsync.go @@ -95,6 +95,10 @@ func (ls *LedgerState) handleEventBlockfetch(evt event.Event) { } func (ls *LedgerState) handleEventChainsyncRollback(e ChainsyncEvent) error { + if ls.chainsyncState == SyncingChainsyncState { + ls.config.Logger.Warn(fmt.Sprintf("ledger: rolling back to %d.%s", e.Point.Slot, hex.EncodeToString(e.Point.Hash))) + ls.chainsyncState = RollbackChainsyncState + } if err := ls.chain.Rollback(e.Point); err != nil { return fmt.Errorf("chain rollback failed: %w", err) } @@ -102,6 +106,11 @@ func (ls *LedgerState) handleEventChainsyncRollback(e ChainsyncEvent) error { } func (ls *LedgerState) handleEventChainsyncBlockHeader(e ChainsyncEvent) error { + if ls.chainsyncState == RollbackChainsyncState { + ls.config.Logger.Info(fmt.Sprintf("ledger: switched to fork at %d.%s", e.Point.Slot, hex.EncodeToString(e.Point.Hash))) + ls.metrics.forks.Add(1) + } + ls.chainsyncState = SyncingChainsyncState // Allow us to build up a few blockfetch batches worth of headers allowedHeaderCount := blockfetchBatchSize * 4 headerCount := ls.chain.HeaderCount() diff --git a/ledger/metrics.go b/ledger/metrics.go index 11f34c45..b16a18fb 100644 --- a/ledger/metrics.go +++ b/ledger/metrics.go @@ -25,6 +25,7 @@ type stateMetrics struct { epochNum prometheus.Gauge slotInEpoch prometheus.Gauge slotNum prometheus.Gauge + forks prometheus.Gauge } func (m *stateMetrics) init(promRegistry prometheus.Registerer) { @@ -50,4 +51,8 @@ func (m *stateMetrics) init(promRegistry prometheus.Registerer) { Name: "cardano_node_metrics_slotNum_int", Help: "current slot number", }) + m.forks = promautoFactory.NewGauge(prometheus.GaugeOpts{ + Name: "cardano_node_metrics_forks_int", + Help: "number of forks seen", + }) } diff --git a/ledger/state.go b/ledger/state.go index bf89968b..03b6bd5d 100644 --- a/ledger/state.go +++ b/ledger/state.go @@ -44,6 +44,14 @@ const ( validateHistoricalThreshold = 14 * (24 * time.Hour) // 2 weeks ) +type ChainsyncState string + +const ( + InitChainsyncState ChainsyncState = "init" + RollbackChainsyncState ChainsyncState = "rollback" + SyncingChainsyncState ChainsyncState = "syncing" +) + type LedgerStateConfig struct { Logger *slog.Logger Database *database.Database @@ -63,6 +71,7 @@ type BlockfetchRequestRangeFunc func(ouroboros.ConnectionId, ocommon.Point, ocom type LedgerState struct { sync.RWMutex chainsyncMutex sync.Mutex + chainsyncState ChainsyncState config LedgerStateConfig db *database.Database timerCleanupConsumedUtxos *time.Timer @@ -84,9 +93,10 @@ type LedgerState struct { func NewLedgerState(cfg LedgerStateConfig) (*LedgerState, error) { ls := &LedgerState{ - config: cfg, - db: cfg.Database, - chain: cfg.ChainManager.PrimaryChain(), + config: cfg, + chainsyncState: InitChainsyncState, + db: cfg.Database, + chain: cfg.ChainManager.PrimaryChain(), } if cfg.Logger == nil { // Create logger to throw away logs