Skip to content

Commit e5a8da2

Browse files
authored
Merge pull request #93 from wcatz/audit/cleanup-dead-code-and-docs
refactor: audit cleanup — remove dead code, fix stake bug, consolidate helpers
2 parents 172dcb6 + 81cd57b commit e5a8da2

File tree

13 files changed

+187
-1086
lines changed

13 files changed

+187
-1086
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o goduckbot .
308308
docker pull wcatz/goduckbot:latest
309309
```
310310

311-
Multi-arch images (amd64/arm64) are published to [Docker Hub](https://hub.docker.com/r/wcatz/goduckbot) via GitHub Actions on every merge to master and tagged release.
311+
ARM64 images are published to [Docker Hub](https://hub.docker.com/r/wcatz/goduckbot) built locally and pushed on every release.
312312

313313
## Helm Chart
314314

cli.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ func cmdCLIHistory(args []string) int {
373373
if fromEpoch > 0 {
374374
startEpoch = fromEpoch
375375
} else {
376-
regEpoch, regErr := fetchPoolRegistrationEpoch(ctx, cc.bech32PoolId)
376+
regEpoch, regErr := fetchPoolRegistrationEpoch(ctx, koiosRESTBase(cc.networkMagic), cc.bech32PoolId)
377377
if regErr != nil {
378378
fmt.Fprintf(os.Stderr, "Error fetching pool registration: %v\n", regErr)
379379
return 1
@@ -474,7 +474,7 @@ func cmdCLIHistory(args []string) int {
474474
}
475475

476476
// Get OUR pool's forged slots from Koios
477-
forgedSet, fErr := fetchPoolForgedSlots(ctx, cc.bech32PoolId, epoch)
477+
forgedSet, fErr := fetchPoolForgedSlots(ctx, koiosRESTBase(cc.networkMagic), cc.bech32PoolId, epoch)
478478
if fErr != nil {
479479
log.Printf("[history] epoch %d: pool forged slots failed: %v", epoch, fErr)
480480
forgedSet = make(map[uint64]bool)

commands.go

Lines changed: 10 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ func (i *Indexer) cmdEpoch(m *telebot.Message) {
389389
i.bot.Send(m.Chat, msg)
390390
}
391391

392+
392393
func (i *Indexer) cmdLeaderlog(m *telebot.Message) {
393394
if !i.isAllowed(m) {
394395
return
@@ -417,14 +418,11 @@ func (i *Indexer) cmdLeaderlog(m *telebot.Message) {
417418

418419
// Parse argument: "next", "current", or epoch number
419420
var targetEpoch int
420-
var snapType SnapshotType
421421
switch {
422422
case args == "next":
423423
targetEpoch = i.getCurrentEpoch() + 1
424-
snapType = SnapshotMark
425424
case args == "current":
426425
targetEpoch = i.getCurrentEpoch()
427-
snapType = SnapshotSet
428426
default:
429427
parsed, err := strconv.Atoi(args)
430428
if err != nil {
@@ -460,69 +458,9 @@ func (i *Indexer) cmdLeaderlog(m *telebot.Message) {
460458
return
461459
}
462460

463-
// Try NtC first if epoch is within snapshot range (mark/set/go)
464-
var poolStake, totalStake uint64
465-
curEpoch := i.getCurrentEpoch()
466-
if i.nodeQuery != nil {
467-
var snap SnapshotType
468-
ntcAvailable := true
469-
switch targetEpoch {
470-
case curEpoch + 1:
471-
snap = SnapshotMark
472-
case curEpoch:
473-
snap = SnapshotSet
474-
case curEpoch - 1:
475-
snap = SnapshotGo
476-
default:
477-
ntcAvailable = false
478-
}
479-
if ntcAvailable {
480-
ntcCtx, ntcCancel := context.WithTimeout(ctx, 5*time.Minute)
481-
snapshots, snapErr := i.nodeQuery.QueryPoolStakeSnapshots(ntcCtx, i.bech32PoolId)
482-
ntcCancel()
483-
if snapErr != nil {
484-
log.Printf("NtC stake query for epoch %d failed: %v", targetEpoch, snapErr)
485-
} else {
486-
switch snap {
487-
case SnapshotMark:
488-
poolStake = snapshots.PoolStakeMark
489-
totalStake = snapshots.TotalStakeMark
490-
case SnapshotSet:
491-
poolStake = snapshots.PoolStakeSet
492-
totalStake = snapshots.TotalStakeSet
493-
case SnapshotGo:
494-
poolStake = snapshots.PoolStakeGo
495-
totalStake = snapshots.TotalStakeGo
496-
}
497-
}
498-
}
499-
}
500-
501-
// Koios fallback for epochs outside NtC range or NtC failure
502-
if poolStake == 0 && i.koios != nil {
503-
curEpoch := i.getCurrentEpoch()
504-
for _, tryEpoch := range []int{targetEpoch, curEpoch, curEpoch - 1, curEpoch - 2} {
505-
epochNo := koios.EpochNo(tryEpoch)
506-
poolHist, histErr := i.koios.GetPoolHistory(ctx, koios.PoolID(i.bech32PoolId), &epochNo, nil)
507-
if histErr != nil || len(poolHist.Data) == 0 {
508-
continue
509-
}
510-
poolStake = uint64(poolHist.Data[0].ActiveStake.IntPart())
511-
epochInfo, infoErr := i.koios.GetEpochInfo(ctx, &epochNo, nil)
512-
if infoErr != nil || len(epochInfo.Data) == 0 {
513-
poolStake = 0
514-
continue
515-
}
516-
totalStake = uint64(epochInfo.Data[0].ActiveStake.IntPart())
517-
if tryEpoch != targetEpoch {
518-
log.Printf("Using Koios stake fallback for /leaderlog %d (from epoch %d)", targetEpoch, tryEpoch)
519-
}
520-
break
521-
}
522-
}
523-
524-
if poolStake == 0 || totalStake == 0 {
525-
replyEpoch(fmt.Sprintf("Failed to get stake for epoch %d from NtC or Koios", targetEpoch))
461+
poolStake, totalStake, stakeErr := i.queryStakeForLeaderlog(ctx, targetEpoch)
462+
if stakeErr != nil {
463+
replyEpoch(fmt.Sprintf("Failed to get stake for epoch %d: %v", targetEpoch, stakeErr))
526464
return
527465
}
528466

@@ -576,51 +514,9 @@ func (i *Indexer) cmdLeaderlog(m *telebot.Message) {
576514
return
577515
}
578516

579-
// Try NtC first for stake data
580-
var poolStake, totalStake uint64
581-
if i.nodeQuery != nil {
582-
ntcCtx, ntcCancel := context.WithTimeout(ctx, 5*time.Minute)
583-
snapshots, snapErr := i.nodeQuery.QueryPoolStakeSnapshots(ntcCtx, i.bech32PoolId)
584-
ntcCancel()
585-
if snapErr != nil {
586-
log.Printf("NtC stake query for epoch %d failed: %v", targetEpoch, snapErr)
587-
} else {
588-
switch snapType {
589-
case SnapshotSet:
590-
poolStake = snapshots.PoolStakeSet
591-
totalStake = snapshots.TotalStakeSet
592-
default:
593-
poolStake = snapshots.PoolStakeMark
594-
totalStake = snapshots.TotalStakeMark
595-
}
596-
}
597-
}
598-
599-
// Koios fallback if NtC unavailable or failed (try recent epochs since Koios may lag)
600-
if poolStake == 0 && i.koios != nil {
601-
curEpoch := i.getCurrentEpoch()
602-
for _, tryEpoch := range []int{curEpoch, curEpoch - 1, curEpoch - 2} {
603-
epochNo := koios.EpochNo(tryEpoch)
604-
poolHist, histErr := i.koios.GetPoolHistory(ctx, koios.PoolID(i.bech32PoolId), &epochNo, nil)
605-
if histErr != nil || len(poolHist.Data) == 0 {
606-
continue
607-
}
608-
poolStake = uint64(poolHist.Data[0].ActiveStake.IntPart())
609-
epochInfo, infoErr := i.koios.GetEpochInfo(ctx, &epochNo, nil)
610-
if infoErr != nil || len(epochInfo.Data) == 0 {
611-
poolStake = 0
612-
continue
613-
}
614-
totalStake = uint64(epochInfo.Data[0].ActiveStake.IntPart())
615-
if tryEpoch != targetEpoch {
616-
log.Printf("Using Koios stake fallback for /leaderlog (from epoch %d)", tryEpoch)
617-
}
618-
break
619-
}
620-
}
621-
622-
if poolStake == 0 || totalStake == 0 {
623-
reply(fmt.Sprintf("Failed to get stake for epoch %d from NtC or Koios", targetEpoch))
517+
poolStake, totalStake, stakeErr := i.queryStakeForLeaderlog(ctx, targetEpoch)
518+
if stakeErr != nil {
519+
reply(fmt.Sprintf("Failed to get stake for epoch %d: %v", targetEpoch, stakeErr))
624520
return
625521
}
626522

@@ -994,41 +890,9 @@ func (i *Indexer) cmdNextBlock(m *telebot.Message) {
994890
return
995891
}
996892

997-
var poolStake, totalStake uint64
998-
if i.nodeQuery != nil {
999-
ntcCtx, ntcCancel := context.WithTimeout(ctx, 5*time.Minute)
1000-
snapshots, snapErr := i.nodeQuery.QueryPoolStakeSnapshots(ntcCtx, i.bech32PoolId)
1001-
ntcCancel()
1002-
if snapErr != nil {
1003-
log.Printf("NtC stake query failed, trying Koios fallback: %v", snapErr)
1004-
} else {
1005-
poolStake = snapshots.PoolStakeSet
1006-
totalStake = snapshots.TotalStakeSet
1007-
}
1008-
}
1009-
if poolStake == 0 && i.koios != nil {
1010-
// Try recent epochs (Koios may lag 1-2 epochs behind)
1011-
for _, tryEpoch := range []int{currentEpoch, currentEpoch - 1, currentEpoch - 2} {
1012-
epochNo := koios.EpochNo(tryEpoch)
1013-
poolHist, histErr := i.koios.GetPoolHistory(ctx, koios.PoolID(i.bech32PoolId), &epochNo, nil)
1014-
if histErr != nil || len(poolHist.Data) == 0 {
1015-
log.Printf("Koios GetPoolHistory(%d) empty or error: %v", tryEpoch, histErr)
1016-
continue
1017-
}
1018-
poolStake = uint64(poolHist.Data[0].ActiveStake.IntPart())
1019-
epochInfo, infoErr := i.koios.GetEpochInfo(ctx, &epochNo, nil)
1020-
if infoErr != nil || len(epochInfo.Data) == 0 {
1021-
log.Printf("Koios GetEpochInfo(%d) failed: %v", tryEpoch, infoErr)
1022-
poolStake = 0
1023-
continue
1024-
}
1025-
totalStake = uint64(epochInfo.Data[0].ActiveStake.IntPart())
1026-
log.Printf("Using Koios stake fallback for /nextblock (from epoch %d)", tryEpoch)
1027-
break
1028-
}
1029-
}
1030-
if poolStake == 0 || totalStake == 0 {
1031-
reply("No stake data available from NtC or Koios")
893+
poolStake, totalStake, stakeErr := i.queryStakeForLeaderlog(ctx, currentEpoch)
894+
if stakeErr != nil {
895+
reply(fmt.Sprintf("No stake data available: %v", stakeErr))
1032896
return
1033897
}
1034898

comprehensive_test.go

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -819,40 +819,6 @@ func TestStoreForgedSlots(t *testing.T) {
819819
}
820820
}
821821

822-
func TestStoreStreamBlockNonces(t *testing.T) {
823-
store := newTestStore(t)
824-
ctx := context.Background()
825-
826-
_, _ = store.InsertBlock(ctx, 300, 2, "h3", []byte{3}, []byte{33})
827-
_, _ = store.InsertBlock(ctx, 100, 1, "h1", []byte{1}, []byte{11})
828-
_, _ = store.InsertBlock(ctx, 200, 1, "h2", []byte{2}, []byte{22})
829-
830-
rows, err := store.StreamBlockNonces(ctx)
831-
if err != nil {
832-
t.Fatalf("StreamBlockNonces: %v", err)
833-
}
834-
defer rows.Close()
835-
836-
var slots []uint64
837-
for rows.Next() {
838-
_, slot, _, _, err := rows.Scan()
839-
if err != nil {
840-
t.Fatalf("Scan: %v", err)
841-
}
842-
slots = append(slots, slot)
843-
}
844-
if err := rows.Err(); err != nil {
845-
t.Fatalf("Err: %v", err)
846-
}
847-
848-
// Should be ordered by slot ASC
849-
if len(slots) != 3 {
850-
t.Fatalf("expected 3, got %d", len(slots))
851-
}
852-
if slots[0] != 100 || slots[1] != 200 || slots[2] != 300 {
853-
t.Fatalf("slots not in order: %v", slots)
854-
}
855-
}
856822

857823
func TestStoreStreamBlockVrfOutputs(t *testing.T) {
858824
store := newTestStore(t)

config.yaml.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ leaderlog:
4848
timezone: "America/New_York"
4949
timeFormat: "12h" # "12h" or "24h"
5050

51+
# Advanced (full mode only):
52+
# nonceIntegrityCheck: false # After nonce backfill, verify computed nonces against Koios
53+
# # and log any mismatches. Safe to enable; adds ~1 API call/epoch.
54+
# backfillSchedules: false # After nonce backfill, calculate and store leader schedules
55+
# # for all historical epochs where nonce data is available.
56+
5157
# Database configuration (only used when leaderlog.enabled is true)
5258
database:
5359
driver: "sqlite" # "sqlite" (default) or "postgres"

db.go

Lines changed: 0 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -311,15 +311,6 @@ func (s *PgStore) InsertBlockBatch(ctx context.Context, blocks []BlockData) erro
311311
return tx.Commit(ctx)
312312
}
313313

314-
func (s *PgStore) StreamBlockNonces(ctx context.Context) (BlockNonceRows, error) {
315-
rows, err := s.pool.Query(ctx,
316-
`SELECT epoch, slot, nonce_value, block_hash FROM blocks ORDER BY slot`,
317-
)
318-
if err != nil {
319-
return nil, err
320-
}
321-
return &pgBlockNonceRows{rows: rows}, nil
322-
}
323314

324315
func (s *PgStore) GetBlockByHash(ctx context.Context, hashPrefix string) ([]BlockRecord, error) {
325316
rows, err := s.pool.Query(ctx,
@@ -382,46 +373,6 @@ func (s *PgStore) GetLeaderSchedule(ctx context.Context, epoch int) (*LeaderSche
382373
}, nil
383374
}
384375

385-
// pgBlockNonceRows wraps pgx.Rows to implement BlockNonceRows.
386-
type pgBlockNonceRows struct {
387-
rows pgx.Rows
388-
epoch int
389-
slot uint64
390-
nonce []byte
391-
blockHash string
392-
err error
393-
closed bool
394-
}
395-
396-
func (r *pgBlockNonceRows) Next() bool {
397-
if r.closed {
398-
return false
399-
}
400-
if !r.rows.Next() {
401-
r.err = r.rows.Err()
402-
r.closed = true
403-
return false
404-
}
405-
var slotInt64 int64
406-
r.err = r.rows.Scan(&r.epoch, &slotInt64, &r.nonce, &r.blockHash)
407-
r.slot = uint64(slotInt64)
408-
return r.err == nil
409-
}
410-
411-
func (r *pgBlockNonceRows) Scan() (epoch int, slot uint64, nonceValue []byte, blockHash string, err error) {
412-
return r.epoch, r.slot, r.nonce, r.blockHash, r.err
413-
}
414-
415-
func (r *pgBlockNonceRows) Close() {
416-
if !r.closed {
417-
r.rows.Close()
418-
r.closed = true
419-
}
420-
}
421-
422-
func (r *pgBlockNonceRows) Err() error {
423-
return r.err
424-
}
425376

426377
func (s *PgStore) StreamBlockVrfOutputs(ctx context.Context) (BlockVrfRows, error) {
427378
rows, err := s.pool.Query(ctx,
@@ -500,24 +451,6 @@ func (s *PgStore) GetBlockCountForEpoch(ctx context.Context, epoch int) (int, er
500451
return count, err
501452
}
502453

503-
func (s *PgStore) GetNonceValuesForEpoch(ctx context.Context, epoch int) ([][]byte, error) {
504-
rows, err := s.pool.Query(ctx,
505-
`SELECT nonce_value FROM blocks WHERE epoch = $1 ORDER BY slot`, epoch)
506-
if err != nil {
507-
return nil, err
508-
}
509-
defer rows.Close()
510-
511-
var values [][]byte
512-
for rows.Next() {
513-
var nonce []byte
514-
if err := rows.Scan(&nonce); err != nil {
515-
return nil, err
516-
}
517-
values = append(values, nonce)
518-
}
519-
return values, rows.Err()
520-
}
521454

522455
func (s *PgStore) GetVrfOutputsForEpoch(ctx context.Context, epoch int) ([]VrfBlock, error) {
523456
rows, err := s.pool.Query(ctx,
@@ -548,15 +481,6 @@ func (s *PgStore) GetCandidateNonce(ctx context.Context, epoch int) ([]byte, err
548481
return nonce, nil
549482
}
550483

551-
func (s *PgStore) GetLastBlockHashForEpoch(ctx context.Context, epoch int) (string, error) {
552-
var hash string
553-
err := s.pool.QueryRow(ctx,
554-
`SELECT block_hash FROM blocks WHERE epoch = $1 ORDER BY slot DESC LIMIT 1`, epoch).Scan(&hash)
555-
if err != nil {
556-
return "", err
557-
}
558-
return hash, nil
559-
}
560484

561485
// GetPrevHashOfLastBlock returns the block hash of the second-to-last block
562486
// in the given epoch. This is the prevHash of the last block, which is what

0 commit comments

Comments
 (0)