Skip to content

Commit 3b336eb

Browse files
committed
add CI tooling, golangci-lint config, Makefile, and CLAUDE.md
- UCI reusable workflows (go-lint, stale-check, release-check, release-publish) matching the sei-chain v0.0.6 pattern - CI workflow running tests on push/PR to main - golangci-lint v2 config adapted from sei-k8s-controller - Makefile with test, lint, vet, fmt, ci targets - CLAUDE.md codifying code standards, design constraints, and conventions - Fix all lint issues: gofmt, errcheck, lll, goconst, modernize, staticcheck - Export pruning strategy constants (PruningDefault, PruningNothing, etc.) - version.json for UCI release management (v0.0.1)
1 parent 5ec9b4e commit 3b336eb

17 files changed

Lines changed: 430 additions & 144 deletions

.github/workflows/ci.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
permissions:
10+
contents: read
11+
12+
concurrency:
13+
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
test:
18+
name: Test
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
- uses: actions/setup-go@v5
23+
with:
24+
go-version-file: go.mod
25+
- run: make test

.github/workflows/uci-lint.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: UCI
2+
run-name: UCI / Go Lint
3+
4+
on:
5+
pull_request:
6+
push:
7+
branches:
8+
- main
9+
workflow_dispatch:
10+
11+
permissions:
12+
contents: read
13+
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
go-lint:
20+
name: Go
21+
uses: sei-protocol/uci/.github/workflows/go-lint.yml@v0.0.6
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: UCI
2+
run-name: UCI / Release Check
3+
4+
on:
5+
pull_request_target:
6+
paths: [ 'version.json' ]
7+
types: [ opened, synchronize, reopened, labeled, unlabeled ]
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: write
12+
pull-requests: write
13+
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
release-check:
20+
name: Release
21+
uses: sei-protocol/uci/.github/workflows/release-check.yml@v0.0.6
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: UCI
2+
run-name: UCI / Release Publish
3+
4+
on:
5+
push:
6+
paths: [ 'version.json' ]
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write
11+
12+
concurrency:
13+
group: ${{ github.workflow }}-${{ github.sha }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
releaser:
18+
name: Release
19+
uses: sei-protocol/uci/.github/workflows/release-publish.yml@v0.0.6
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: UCI
2+
run-name: UCI / Stale Check
3+
4+
on:
5+
workflow_dispatch:
6+
schedule:
7+
- cron: '0 12 * * *'
8+
9+
permissions:
10+
contents: read
11+
12+
concurrency:
13+
group: ${{ github.workflow }}-${{ github.sha }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
stale:
18+
name: Stale
19+
permissions:
20+
issues: write
21+
pull-requests: write
22+
uses: sei-protocol/uci/.github/workflows/stale-check.yml@v0.0.6
23+
with:
24+
days-before-pr-stale: 28

.golangci.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
version: "2"
2+
run:
3+
allow-parallel-runners: true
4+
linters:
5+
default: none
6+
enable:
7+
- bodyclose
8+
- copyloopvar
9+
- dupl
10+
- errcheck
11+
- goconst
12+
- gocyclo
13+
- govet
14+
- ineffassign
15+
- lll
16+
- misspell
17+
- modernize
18+
- nakedret
19+
- noctx
20+
- prealloc
21+
- revive
22+
- staticcheck
23+
- unconvert
24+
- unparam
25+
- unused
26+
settings:
27+
revive:
28+
rules:
29+
- name: comment-spacings
30+
- name: import-shadowing
31+
modernize:
32+
disable:
33+
- omitzero
34+
exclusions:
35+
generated: lax
36+
rules:
37+
- linters:
38+
- dupl
39+
path: legacy\.go
40+
paths:
41+
- third_party$
42+
- builtin$
43+
- examples$
44+
issues:
45+
max-issues-per-linter: 0
46+
max-same-issues: 0
47+
formatters:
48+
enable:
49+
- gofmt
50+
- goimports
51+
settings:
52+
goimports:
53+
local-prefixes:
54+
- github.com/sei-protocol/sei-config
55+
exclusions:
56+
generated: lax
57+
paths:
58+
- third_party$
59+
- builtin$
60+
- examples$

CLAUDE.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# sei-config
2+
3+
Shared Go library providing unified configuration types, mode-aware defaults, validation, and serialization for all Sei node components (`seid`, `seictl`, `sei-k8s-controller`).
4+
5+
## Architecture
6+
7+
- **Package**: `seiconfig` (import as `github.com/sei-protocol/sei-config`)
8+
- **Unified struct**: `SeiConfig` — single type covering all fields from both `config.toml` (Tendermint) and `app.toml` (Cosmos SDK + Sei)
9+
- **Legacy IO**: Reads/writes the existing two-file layout via intermediate legacy types in `legacy.go`; atomic writes (temp + rename) prevent corruption
10+
- **No external dependencies** beyond `github.com/BurntSushi/toml`
11+
12+
### Key Files
13+
14+
| File | Purpose |
15+
|------|---------|
16+
| `config.go` | `SeiConfig` and all sub-config struct definitions |
17+
| `types.go` | `NodeMode`, `Duration`, `WriteMode`, `ReadMode` |
18+
| `defaults.go` | `DefaultForMode()` — mode-aware baseline configs |
19+
| `validate.go` | `Validate()` — structured diagnostics (Error/Warning/Info) |
20+
| `resolve.go` | `ResolveEnv()``SEI_`/`SEID_` env var resolution via reflection |
21+
| `io.go` | `ReadConfigFromDir()`, `WriteConfigToDir()`, `ApplyOverrides()` |
22+
| `legacy.go` | Two-file TOML mapping types and `SeiConfig` ↔ legacy conversion |
23+
24+
## Code Standards
25+
26+
### Go
27+
28+
- **Idiomatic Go above all.** Prefer clarity over cleverness. Three explicit lines beat a cryptic one-liner.
29+
- **No unnecessary abstractions.** This is a leaf library — keep it flat. Don't add interfaces until there are two concrete implementations.
30+
- **Zero `panic`.** Every failure path must return an error. Callers (seid, seictl, controller) decide how to handle it.
31+
- **All code must pass `golangci-lint`** (config in `.golangci.yml`). Fix lint issues at the source — do not add `nolint` directives without a comment explaining why suppression is the only option.
32+
- **Imports grouped**: stdlib, external, then `github.com/sei-protocol/sei-config` (enforced by goimports).
33+
- **Exported types are the contract.** Every exported type, function, and constant must have a doc comment. Unexported helpers don't need them unless the logic is non-obvious.
34+
- **Struct tags are the schema.** TOML tags on `SeiConfig` define the unified `sei.toml` key names. Legacy TOML tags on `legacy*.go` types must exactly match the existing `config.toml`/`app.toml` key names — do not change them without a migration plan.
35+
- **Keep `SeiConfig` and legacy types in sync.** Every field added to `SeiConfig` must have corresponding legacy mapping in `toLegacyTendermint()`/`toLegacyApp()` and `fromLegacy()`. Tests enforce round-trip fidelity.
36+
37+
### Defaults & Modes
38+
39+
- `DefaultForMode(mode)` is the single entry point. Baseline defaults live in `baseDefaults()`, mode overrides in `apply*Overrides()`.
40+
- When adding a new field: add to `baseDefaults()` with the safe/common default, then add mode-specific values only where they differ.
41+
- Every mode's defaults must pass `Validate()` — this is enforced by `TestDefaultForMode_AllModesValid`.
42+
43+
### Validation
44+
45+
- Validation returns `*ValidationResult` with typed `Diagnostic` entries — never `error` directly.
46+
- `SeverityError` = blocks startup. `SeverityWarning` = logged. Use the right severity.
47+
- Cross-field checks go in `validateCrossField()`.
48+
49+
### Testing
50+
51+
- Tests use the `testing` package only — no assertion libraries, no test frameworks.
52+
- Run tests with `make test` before submitting changes.
53+
- Every new field should be exercised in at least one round-trip test (`WriteConfigToDir``ReadConfigFromDir`).
54+
- Test file naming: `config_test.go` for the main test file. Add `*_test.go` files when a single file grows past ~500 lines.
55+
56+
## Build & Validate
57+
58+
```bash
59+
make test # Run all tests
60+
make lint # Run golangci-lint
61+
make vet # Run go vet
62+
make fmt # Format all code (gofmt -s)
63+
make ci # lint + vet + test (what CI runs)
64+
make test-cover # Tests with coverage report
65+
```
66+
67+
## Design Constraints
68+
69+
- **This is a library, not a binary.** There is no `main` package. Consumers are `seid`, `seictl`, and `sei-k8s-controller`.
70+
- **Minimal dependencies.** Think hard before adding a new `require`. Every dependency here transitively affects three other repos.
71+
- **Phase-aware IO.** `ReadConfigFromDir`/`WriteConfigToDir` currently handle the two-file layout (Phase 2). When Phase 3 ships unified `sei.toml`, the IO layer switches internally — callers should not need to change.
72+
- **Backward compatibility matters.** The legacy types in `legacy.go` must produce TOML files that existing `seid` binaries can read. Changing a legacy TOML tag is a breaking change.

Makefile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
GOLANGCI_LINT ?= $(shell which golangci-lint 2>/dev/null || echo $(HOME)/go/bin/golangci-lint)
2+
3+
.PHONY: test lint fmt vet ci clean
4+
5+
test: ## Run tests.
6+
go test ./... -count=1
7+
8+
test-cover: ## Run tests with coverage.
9+
go test ./... -coverprofile cover.out
10+
go tool cover -func cover.out
11+
12+
lint: ## Run golangci-lint.
13+
$(GOLANGCI_LINT) run
14+
15+
fmt: ## Format code.
16+
gofmt -s -w .
17+
18+
vet: ## Run go vet.
19+
go vet ./...
20+
21+
ci: lint vet test ## Run lint, vet, and test.
22+
23+
clean: ## Clean build artifacts.
24+
rm -f cover.out

config.go

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ import "runtime"
1010
// CurrentVersion is the config schema version produced by this library.
1111
const CurrentVersion = 1
1212

13+
// Pruning strategy constants.
14+
const (
15+
PruningDefault = "default"
16+
PruningNothing = "nothing"
17+
PruningEverything = "everything"
18+
PruningCustom = "custom"
19+
)
20+
1321
// SeiConfig is the unified configuration for a Sei node, encompassing all
1422
// settings previously split across config.toml (Tendermint) and app.toml
1523
// (Cosmos SDK + Sei extensions).
@@ -90,25 +98,25 @@ type RPCConfig struct {
9098
TLSCertFile string `toml:"tls_cert_file"`
9199
TLSKeyFile string `toml:"tls_key_file"`
92100

93-
PprofListenAddress string `toml:"pprof_listen_address"`
94-
LagThreshold int64 `toml:"lag_threshold"`
101+
PprofListenAddress string `toml:"pprof_listen_address"`
102+
LagThreshold int64 `toml:"lag_threshold"`
95103
TimeoutRead Duration `toml:"timeout_read"`
96104
}
97105

98106
type P2PConfig struct {
99-
ListenAddress string `toml:"listen_address"`
107+
ListenAddress string `toml:"listen_address"`
100108
ExternalAddress string `toml:"external_address"`
101-
BootstrapPeers string `toml:"bootstrap_peers"`
109+
BootstrapPeers string `toml:"bootstrap_peers"`
102110
PersistentPeers string `toml:"persistent_peers"`
103111
BlockSyncPeers string `toml:"blocksync_peers"`
104112

105-
UPNP bool `toml:"upnp"`
106-
MaxConnections uint16 `toml:"max_connections"`
113+
UPNP bool `toml:"upnp"`
114+
MaxConnections uint16 `toml:"max_connections"`
107115
MaxIncomingConnectionAttempts uint `toml:"max_incoming_connection_attempts"`
108-
PexReactor bool `toml:"pex"`
109-
PrivatePeerIDs string `toml:"private_peer_ids"`
110-
AllowDuplicateIP bool `toml:"allow_duplicate_ip"`
111-
UnconditionalPeerIDs string `toml:"unconditional_peer_ids"`
116+
PexReactor bool `toml:"pex"`
117+
PrivatePeerIDs string `toml:"private_peer_ids"`
118+
AllowDuplicateIP bool `toml:"allow_duplicate_ip"`
119+
UnconditionalPeerIDs string `toml:"unconditional_peer_ids"`
112120

113121
FlushThrottleTimeout Duration `toml:"flush_throttle_timeout"`
114122
MaxPacketMsgPayloadSize int `toml:"max_packet_msg_payload_size"`
@@ -163,10 +171,10 @@ type MempoolConfig struct {
163171
CheckTxErrorBlacklistEnabled bool `toml:"check_tx_error_blacklist_enabled"`
164172
CheckTxErrorThreshold int `toml:"check_tx_error_threshold"`
165173

166-
PendingSize int `toml:"pending_size"`
167-
MaxPendingTxsBytes int64 `toml:"max_pending_txs_bytes"`
168-
PendingTTLDuration Duration `toml:"pending_ttl_duration"`
169-
PendingTTLNumBlocks int64 `toml:"pending_ttl_num_blocks"`
174+
PendingSize int `toml:"pending_size"`
175+
MaxPendingTxsBytes int64 `toml:"max_pending_txs_bytes"`
176+
PendingTTLDuration Duration `toml:"pending_ttl_duration"`
177+
PendingTTLNumBlocks int64 `toml:"pending_ttl_num_blocks"`
170178

171179
RemoveExpiredTxsFromQueue bool `toml:"remove_expired_txs_from_queue"`
172180
DropPriorityThreshold float64 `toml:"drop_priority_threshold"`
@@ -179,8 +187,8 @@ type MempoolConfig struct {
179187
// ---------------------------------------------------------------------------
180188

181189
type StateSyncConfig struct {
182-
Enable bool `toml:"enable"`
183-
UseP2P bool `toml:"use_p2p"`
190+
Enable bool `toml:"enable"`
191+
UseP2P bool `toml:"use_p2p"`
184192
RPCServers []string `toml:"rpc_servers"`
185193

186194
TrustHeight int64 `toml:"trust_height"`
@@ -264,7 +272,7 @@ type StateStoreConfig struct {
264272

265273
type TxIndexConfig struct {
266274
Indexer []string `toml:"indexer"`
267-
PsqlConn string `toml:"psql_conn"`
275+
PsqlConn string `toml:"psql_conn"`
268276
}
269277

270278
// ---------------------------------------------------------------------------
@@ -288,7 +296,7 @@ type EVMConfig struct {
288296
CORSOrigins string `toml:"cors_origins"`
289297
WSOrigins string `toml:"ws_origins"`
290298

291-
FilterTimeout Duration `toml:"filter_timeout"`
299+
FilterTimeout Duration `toml:"filter_timeout"`
292300
CheckTxTimeout Duration `toml:"checktx_timeout"`
293301

294302
MaxTxPoolTxs uint64 `toml:"max_tx_pool_txs"`
@@ -301,9 +309,9 @@ type EVMConfig struct {
301309
MaxSubscriptionsNewHead uint64 `toml:"max_subscriptions_new_head"`
302310
EnableTestAPI bool `toml:"enable_test_api"`
303311

304-
MaxConcurrentTraceCalls uint64 `toml:"max_concurrent_trace_calls"`
305-
MaxConcurrentSimulationCalls int `toml:"max_concurrent_simulation_calls"`
306-
MaxTraceLookbackBlocks int64 `toml:"max_trace_lookback_blocks"`
312+
MaxConcurrentTraceCalls uint64 `toml:"max_concurrent_trace_calls"`
313+
MaxConcurrentSimulationCalls int `toml:"max_concurrent_simulation_calls"`
314+
MaxTraceLookbackBlocks int64 `toml:"max_trace_lookback_blocks"`
307315
TraceTimeout Duration `toml:"trace_timeout"`
308316

309317
RPCStatsInterval Duration `toml:"rpc_stats_interval"`

0 commit comments

Comments
 (0)