Skip to content

Commit 7f0377b

Browse files
authored
Merge branch 'main' into julien/atomic
2 parents 4f4085b + b646e66 commit 7f0377b

8 files changed

Lines changed: 263 additions & 19 deletions

File tree

.github/workflows/dependabot-auto-fix.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
- uses: actions/setup-go@v6
2222
with:
2323
go-version: "1.22"
24+
check-latest: true
2425

2526
- name: Install make (if missing)
2627
run: sudo apt-get update && sudo apt-get install -y make

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ jobs:
134134
- uses: actions/setup-go@v6
135135
with:
136136
go-version-file: ./go.mod
137-
- run: make tidy-all
137+
- run: make deps
138138
- name: check for diff
139139
run: git diff --exit-code
140140

execution/evm/test/go.mod

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ require (
3232
github.com/beorn7/perks v1.0.1 // indirect
3333
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
3434
github.com/bits-and-blooms/bitset v1.20.0 // indirect
35-
github.com/btcsuite/btcd/btcec/v2 v2.3.5 // indirect
3635
github.com/celestiaorg/go-square/v3 v3.0.0 // indirect
3736
github.com/cespare/xxhash/v2 v2.3.0 // indirect
3837
github.com/cockroachdb/errors v1.11.3 // indirect
@@ -41,14 +40,14 @@ require (
4140
github.com/cockroachdb/pebble v1.1.5 // indirect
4241
github.com/cockroachdb/redact v1.1.5 // indirect
4342
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
44-
github.com/cometbft/cometbft v0.38.12 // indirect
43+
github.com/cometbft/cometbft v0.38.17 // indirect
4544
github.com/cometbft/cometbft-db v0.14.1 // indirect
4645
github.com/consensys/gnark-crypto v0.18.0 // indirect
4746
github.com/containerd/errdefs v1.0.0 // indirect
4847
github.com/cosmos/btcutil v1.0.5 // indirect
4948
github.com/cosmos/cosmos-db v1.1.1 // indirect
5049
github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect
51-
github.com/cosmos/cosmos-sdk v0.50.9 // indirect
50+
github.com/cosmos/cosmos-sdk v0.50.14 // indirect
5251
github.com/cosmos/go-bip39 v1.0.0 // indirect
5352
github.com/cosmos/gogoproto v1.7.0 // indirect
5453
github.com/cosmos/iavl v1.2.2 // indirect

execution/evm/test/go.sum

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ github.com/btcsuite/btcd/btcec/v2 v2.3.5 h1:dpAlnAwmT1yIBm3exhT1/8iUSD98RDJM5vqJ
6262
github.com/btcsuite/btcd/btcec/v2 v2.3.5/go.mod h1:m22FrOAiuxl/tht9wIqAoGHcbnCCaPWyauO8y2LGGtQ=
6363
github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c=
6464
github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE=
65-
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
66-
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
6765
github.com/celestiaorg/go-square/v3 v3.0.0 h1:ivLUUuVr7SpkvPiPLPvuH8/Vrm+iw9X3QL8gX25j+Sk=
6866
github.com/celestiaorg/go-square/v3 v3.0.0/go.mod h1:IROQinUbHNyFWW1J5idanVLOSLHaK1wWwVmuVSfiCVo=
6967
github.com/celestiaorg/tastora v0.5.0 h1:Cu7cIBxO3bjKiX6pdML0/9itAEO8Wfk3VSIoVeLzd7g=
@@ -98,8 +96,8 @@ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwP
9896
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
9997
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
10098
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
101-
github.com/cometbft/cometbft v0.38.12 h1:OWsLZN2KcSSFe8bet9xCn07VwhBnavPea3VyPnNq1bg=
102-
github.com/cometbft/cometbft v0.38.12/go.mod h1:GPHp3/pehPqgX1930HmK1BpBLZPxB75v/dZg8Viwy+o=
99+
github.com/cometbft/cometbft v0.38.17 h1:FkrQNbAjiFqXydeAO81FUzriL4Bz0abYxN/eOHrQGOk=
100+
github.com/cometbft/cometbft v0.38.17/go.mod h1:5l0SkgeLRXi6bBfQuevXjKqML1jjfJJlvI1Ulp02/o4=
103101
github.com/cometbft/cometbft-db v0.14.1 h1:SxoamPghqICBAIcGpleHbmoPqy+crij/++eZz3DlerQ=
104102
github.com/cometbft/cometbft-db v0.14.1/go.mod h1:KHP1YghilyGV/xjD5DP3+2hyigWx0WTp9X+0Gnx0RxQ=
105103
github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0=
@@ -115,8 +113,8 @@ github.com/cosmos/cosmos-db v1.1.1 h1:FezFSU37AlBC8S98NlSagL76oqBRWq/prTPvFcEJNC
115113
github.com/cosmos/cosmos-db v1.1.1/go.mod h1:AghjcIPqdhSLP/2Z0yha5xPH3nLnskz81pBx3tcVSAw=
116114
github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA=
117115
github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec=
118-
github.com/cosmos/cosmos-sdk v0.50.9 h1:gt2usjz0H0qW6KwAxWw7ZJ3XU8uDwmhN+hYG3nTLeSg=
119-
github.com/cosmos/cosmos-sdk v0.50.9/go.mod h1:TMH6wpoYBcg7Cp5BEg8fneLr+8XloNQkf2MRNF9V6JE=
116+
github.com/cosmos/cosmos-sdk v0.50.14 h1:G8CtGHFWbExa+ZpVOVAb4kFmko/R30igsYOwyzRMtgY=
117+
github.com/cosmos/cosmos-sdk v0.50.14/go.mod h1:hrWEFMU1eoXqLJeE6VVESpJDQH67FS1nnMrQIjO2daw=
120118
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
121119
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=
122120
github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE=

test/e2e/go.mod

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ require (
4242
github.com/beorn7/perks v1.0.1 // indirect
4343
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
4444
github.com/bits-and-blooms/bitset v1.20.0 // indirect
45-
github.com/btcsuite/btcd/btcec/v2 v2.3.5 // indirect
4645
github.com/celestiaorg/go-header v0.7.3 // indirect
4746
github.com/celestiaorg/go-square/v3 v3.0.1 // indirect
4847
github.com/cespare/xxhash/v2 v2.3.0 // indirect
@@ -52,14 +51,14 @@ require (
5251
github.com/cockroachdb/pebble v1.1.5 // indirect
5352
github.com/cockroachdb/redact v1.1.5 // indirect
5453
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
55-
github.com/cometbft/cometbft v0.38.12 // indirect
54+
github.com/cometbft/cometbft v0.38.17 // indirect
5655
github.com/cometbft/cometbft-db v0.14.1 // indirect
5756
github.com/consensys/gnark-crypto v0.18.0 // indirect
5857
github.com/containerd/errdefs v1.0.0 // indirect
5958
github.com/cosmos/btcutil v1.0.5 // indirect
6059
github.com/cosmos/cosmos-db v1.1.1 // indirect
6160
github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect
62-
github.com/cosmos/cosmos-sdk v0.50.9 // indirect
61+
github.com/cosmos/cosmos-sdk v0.50.14 // indirect
6362
github.com/cosmos/go-bip39 v1.0.0 // indirect
6463
github.com/cosmos/gogoproto v1.7.0 // indirect
6564
github.com/cosmos/iavl v1.2.2 // indirect

test/e2e/go.sum

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,6 @@ github.com/btcsuite/btcd/btcec/v2 v2.3.5 h1:dpAlnAwmT1yIBm3exhT1/8iUSD98RDJM5vqJ
6868
github.com/btcsuite/btcd/btcec/v2 v2.3.5/go.mod h1:m22FrOAiuxl/tht9wIqAoGHcbnCCaPWyauO8y2LGGtQ=
6969
github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c=
7070
github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE=
71-
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
72-
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
7371
github.com/celestiaorg/go-header v0.7.3 h1:3+kIa+YXT789gPGRh3a55qmdYq3yTTBIqTyum26AvN0=
7472
github.com/celestiaorg/go-header v0.7.3/go.mod h1:eX9iTSPthVEAlEDLux40ZT/olXPGhpxHd+mEzJeDhd0=
7573
github.com/celestiaorg/go-square/v3 v3.0.1 h1:44xnE3AUiZn/3q/uJ0c20AezFS0lywFTGG2lE/9jYKA=
@@ -106,8 +104,8 @@ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwP
106104
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
107105
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
108106
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
109-
github.com/cometbft/cometbft v0.38.12 h1:OWsLZN2KcSSFe8bet9xCn07VwhBnavPea3VyPnNq1bg=
110-
github.com/cometbft/cometbft v0.38.12/go.mod h1:GPHp3/pehPqgX1930HmK1BpBLZPxB75v/dZg8Viwy+o=
107+
github.com/cometbft/cometbft v0.38.17 h1:FkrQNbAjiFqXydeAO81FUzriL4Bz0abYxN/eOHrQGOk=
108+
github.com/cometbft/cometbft v0.38.17/go.mod h1:5l0SkgeLRXi6bBfQuevXjKqML1jjfJJlvI1Ulp02/o4=
111109
github.com/cometbft/cometbft-db v0.14.1 h1:SxoamPghqICBAIcGpleHbmoPqy+crij/++eZz3DlerQ=
112110
github.com/cometbft/cometbft-db v0.14.1/go.mod h1:KHP1YghilyGV/xjD5DP3+2hyigWx0WTp9X+0Gnx0RxQ=
113111
github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0=
@@ -123,8 +121,8 @@ github.com/cosmos/cosmos-db v1.1.1 h1:FezFSU37AlBC8S98NlSagL76oqBRWq/prTPvFcEJNC
123121
github.com/cosmos/cosmos-db v1.1.1/go.mod h1:AghjcIPqdhSLP/2Z0yha5xPH3nLnskz81pBx3tcVSAw=
124122
github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA=
125123
github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec=
126-
github.com/cosmos/cosmos-sdk v0.50.9 h1:gt2usjz0H0qW6KwAxWw7ZJ3XU8uDwmhN+hYG3nTLeSg=
127-
github.com/cosmos/cosmos-sdk v0.50.9/go.mod h1:TMH6wpoYBcg7Cp5BEg8fneLr+8XloNQkf2MRNF9V6JE=
124+
github.com/cosmos/cosmos-sdk v0.50.14 h1:G8CtGHFWbExa+ZpVOVAb4kFmko/R30igsYOwyzRMtgY=
125+
github.com/cosmos/cosmos-sdk v0.50.14/go.mod h1:hrWEFMU1eoXqLJeE6VVESpJDQH67FS1nnMrQIjO2daw=
128126
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
129127
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=
130128
github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE=

tools/cache-analyzer/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Cache Analyzer
2+
3+
> The cache analyzer only works currently for sync nodes.
4+
5+
This small program is designed to analyze the cache of a sync node.
6+
It is useful to debug when the sync node is downloading from DA but not advancing.
7+
This usually means the `DA_START_HEIGHT` is too late. This tool allows clearly to identify the first height fetched from DA.
8+
9+
## Usage
10+
11+
```sh
12+
go install github.com/evstack/ev-node/tools/cache-analyzer@main
13+
cache-analyzer -data-dir ~/.appd/data/ -summary
14+
cache-analyzer -data-dir ~/.appd/data/ -limit 50
15+
```

tools/cache-analyzer/main.go

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"encoding/gob"
6+
"flag"
7+
"fmt"
8+
"os"
9+
"path/filepath"
10+
"sort"
11+
"strings"
12+
13+
"github.com/evstack/ev-node/types"
14+
)
15+
16+
// DataHashForEmptyTxs is the hash of an empty block data.
17+
var DataHashForEmptyTxs = []byte{110, 52, 11, 156, 255, 179, 122, 152, 156, 165, 68, 230, 187, 120, 10, 44, 120, 144, 29, 63, 179, 55, 56, 118, 133, 17, 163, 6, 23, 175, 160, 29}
18+
19+
const (
20+
pendingEventsCacheDir = "cache/pending_da_events"
21+
itemsByHeightFilename = "items_by_height.gob"
22+
)
23+
24+
// DAHeightEvent represents a DA event for caching (copied from internal package)
25+
type DAHeightEvent struct {
26+
Header *types.SignedHeader
27+
Data *types.Data
28+
// DaHeight corresponds to the highest DA included height between the Header and Data.
29+
DaHeight uint64
30+
}
31+
32+
// registerGobTypes registers types needed for decoding
33+
func registerGobTypes() {
34+
gob.Register(&types.SignedHeader{})
35+
gob.Register(&types.Data{})
36+
gob.Register(&DAHeightEvent{})
37+
}
38+
39+
// loadEventsFromDisk loads pending events from the cache directory
40+
func loadEventsFromDisk(dataDir string) (map[uint64]*DAHeightEvent, error) {
41+
registerGobTypes()
42+
43+
cachePath := filepath.Join(dataDir, pendingEventsCacheDir, itemsByHeightFilename)
44+
45+
file, err := os.Open(cachePath)
46+
if err != nil {
47+
if os.IsNotExist(err) {
48+
return make(map[uint64]*DAHeightEvent), nil
49+
}
50+
return nil, fmt.Errorf("failed to open cache file %s: %w", cachePath, err)
51+
}
52+
defer file.Close()
53+
54+
var events map[uint64]*DAHeightEvent
55+
decoder := gob.NewDecoder(file)
56+
if err := decoder.Decode(&events); err != nil {
57+
return nil, fmt.Errorf("failed to decode cache file: %w", err)
58+
}
59+
60+
return events, nil
61+
}
62+
63+
// formatTable creates a formatted table string
64+
func formatTable(events []eventEntry) string {
65+
if len(events) == 0 {
66+
return "No pending events found.\n"
67+
}
68+
69+
var sb strings.Builder
70+
71+
// Header
72+
sb.WriteString("┌─────────────┬──────────────┬─────────────────────────────────────────────────────────────────────┐\n")
73+
sb.WriteString("│ Height │ DA Height │ Hash/Details │\n")
74+
sb.WriteString("├─────────────┼──────────────┼─────────────────────────────────────────────────────────────────────┤\n")
75+
76+
for _, entry := range events {
77+
heightStr := fmt.Sprintf("%d", entry.Height)
78+
daHeightStr := fmt.Sprintf("%d", entry.DAHeight)
79+
80+
// Format each row
81+
sb.WriteString(fmt.Sprintf("│ %-11s │ %-12s │ %-67s │\n",
82+
heightStr, daHeightStr, truncateString(entry.Details, 67)))
83+
}
84+
85+
sb.WriteString("└─────────────┴──────────────┴─────────────────────────────────────────────────────────────────────┘\n")
86+
87+
return sb.String()
88+
}
89+
90+
// truncateString truncates a string to maxLen, adding "..." if needed
91+
func truncateString(s string, maxLen int) string {
92+
if len(s) <= maxLen {
93+
return s
94+
}
95+
if maxLen <= 3 {
96+
return "..."
97+
}
98+
return s[:maxLen-3] + "..."
99+
}
100+
101+
// eventEntry represents a table row
102+
type eventEntry struct {
103+
Height uint64
104+
DAHeight uint64
105+
Details string
106+
}
107+
108+
// analyzeEvents processes the events and creates table entries
109+
func analyzeEvents(events map[uint64]*DAHeightEvent, limit int) []eventEntry {
110+
var entries []eventEntry
111+
112+
// Convert map to sorted slice by height
113+
heights := make([]uint64, 0, len(events))
114+
for height := range events {
115+
heights = append(heights, height)
116+
}
117+
sort.Slice(heights, func(i, j int) bool {
118+
return heights[i] < heights[j]
119+
})
120+
121+
// Apply limit
122+
if limit > 0 && len(heights) > limit {
123+
heights = heights[:limit]
124+
}
125+
126+
for _, height := range heights {
127+
event := events[height]
128+
if event == nil {
129+
continue
130+
}
131+
132+
headerHash := "N/A"
133+
if event.Header.Hash() != nil {
134+
headerHash = fmt.Sprintf("%.8x", event.Header.Hash())
135+
}
136+
dataHash := "N/A"
137+
if event.Data.DACommitment() != nil {
138+
if bytes.Equal(event.Data.DACommitment(), DataHashForEmptyTxs) {
139+
dataHash = "Hash for empty transactions"
140+
} else {
141+
dataHash = fmt.Sprintf("%.8x", event.Data.DACommitment())
142+
}
143+
}
144+
txCount := 0
145+
if event.Data.Txs != nil {
146+
txCount = len(event.Data.Txs)
147+
}
148+
details := fmt.Sprintf("H:%s D:%s TxCount:%d", headerHash, dataHash, txCount)
149+
150+
entries = append(entries, eventEntry{
151+
Height: height,
152+
DAHeight: event.DaHeight,
153+
Details: details,
154+
})
155+
}
156+
157+
return entries
158+
}
159+
160+
// printSummary prints a summary of the cache contents
161+
func printSummary(events map[uint64]*DAHeightEvent) {
162+
if len(events) == 0 {
163+
fmt.Println("Cache Summary: No events found")
164+
return
165+
}
166+
167+
var minHeight, maxHeight uint64
168+
var minDaHeight, maxDaHeight uint64
169+
first := true
170+
171+
for height, event := range events {
172+
if first {
173+
minHeight = height
174+
maxHeight = height
175+
minDaHeight = event.DaHeight
176+
maxDaHeight = event.DaHeight
177+
first = false
178+
} else {
179+
if height < minHeight {
180+
minHeight = height
181+
minDaHeight = event.DaHeight
182+
}
183+
if height > maxHeight {
184+
maxHeight = height
185+
maxDaHeight = event.DaHeight
186+
}
187+
}
188+
189+
}
190+
191+
fmt.Printf("Cache Summary:\n")
192+
fmt.Printf(" Total Events: %d\n", len(events))
193+
fmt.Printf(" Height Range: %d - %d\n", minHeight, maxHeight)
194+
fmt.Printf(" DA Height Range: %d - %d\n", minDaHeight, maxDaHeight)
195+
fmt.Printf("\n")
196+
}
197+
198+
func main() {
199+
var (
200+
dataDir = flag.String("data-dir", "data", "Path to the data directory containing cache")
201+
limit = flag.Int("limit", 10, "Maximum number of events to display (0 for no limit)")
202+
summary = flag.Bool("summary", false, "Show only summary without table")
203+
)
204+
flag.Parse()
205+
206+
// Load events from cache
207+
events, err := loadEventsFromDisk(*dataDir)
208+
if err != nil {
209+
fmt.Fprintf(os.Stderr, "Error loading cache: %v\n", err)
210+
os.Exit(1)
211+
}
212+
213+
// Print summary
214+
printSummary(events)
215+
216+
// Exit if only summary requested
217+
if *summary {
218+
return
219+
}
220+
221+
// Analyze and display events
222+
entries := analyzeEvents(events, *limit)
223+
224+
if len(entries) == 0 {
225+
fmt.Println("No pending events to display.")
226+
return
227+
}
228+
229+
if *limit > 0 && len(events) > *limit {
230+
fmt.Printf("Showing first %d of %d events:\n\n", len(entries), len(events))
231+
}
232+
233+
fmt.Print(formatTable(entries))
234+
}

0 commit comments

Comments
 (0)