Skip to content

Commit 05de3d2

Browse files
committed
feat: implement resource reclamation
Signed-off-by: Artur Troian <troian@users.noreply.github.com>
1 parent 711b4e1 commit 05de3d2

25 files changed

Lines changed: 1391 additions & 58 deletions

File tree

.agents/skills/guidelines/SKILL.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
name: guidelines
3+
description: Behavioral guidelines to reduce common LLM coding mistakes. Use when writing, reviewing, or refactoring code to avoid overcomplication, make surgical changes, surface assumptions, and define verifiable success criteria.
4+
license: MIT
5+
---
6+
7+
# Guidelines
8+
9+
**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment.
10+
11+
## 1. Think Before Coding
12+
13+
**Don't assume. Don't hide confusion. Surface tradeoffs.**
14+
15+
Before implementing:
16+
- State your assumptions explicitly. If uncertain, ask.
17+
- If multiple interpretations exist, present them - don't pick silently.
18+
- If a simpler approach exists, say so. Push back when warranted.
19+
- If something is unclear, stop. Name what's confusing. Ask.
20+
21+
## 2. Simplicity First
22+
23+
**Minimum code that solves the problem. Nothing speculative.**
24+
25+
- No features beyond what was asked.
26+
- No abstractions for single-use code.
27+
- No "flexibility" or "configurability" that wasn't requested.
28+
- No error handling for impossible scenarios.
29+
- If you write 200 lines and it could be 50, rewrite it.
30+
31+
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
32+
33+
## 3. Surgical Changes
34+
35+
**Touch only what you must. Clean up only your own mess.**
36+
37+
When editing existing code:
38+
- Don't "improve" adjacent code, comments, or formatting.
39+
- Don't refactor things that aren't broken.
40+
- Match existing style, even if you'd do it differently.
41+
- If you notice unrelated dead code, mention it - don't delete it.
42+
43+
When your changes create orphans:
44+
- Remove imports/variables/functions that YOUR changes made unused.
45+
- Don't remove pre-existing dead code unless asked.
46+
47+
The test: Every changed line should trace directly to the user's request.
48+
49+
## 4. Goal-Driven Execution
50+
51+
**Define success criteria. Loop until verified.**
52+
53+
Transform tasks into verifiable goals:
54+
- "Add validation" → "Write tests for invalid inputs, then make them pass"
55+
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
56+
- "Refactor X" → "Ensure tests pass before and after"
57+
58+
For multi-step tasks, state a brief plan:
59+
```
60+
1. [Step] → verify: [check]
61+
2. [Step] → verify: [check]
62+
3. [Step] → verify: [check]
63+
```
64+
65+
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
---
2+
name: upgrade-changelog
3+
description: "Generates CHANGELOG.md entries for upgrade versions found in upgrades/software/ by parsing init.go and upgrade.go"
4+
---
5+
# Instructions
6+
7+
Generate changelog entries in `upgrades/CHANGELOG.md` for any upgrade version under `upgrades/software/` that doesn't already have an entry.
8+
9+
## Steps
10+
11+
1. **Find semver directories** — list all directories under `upgrades/software/` whose names match `v<major>.<minor>.<patch>` (e.g., `v2.0.0`, `v1.0.0`).
12+
13+
2. **Read `upgrades/CHANGELOG.md`** — identify which versions already have entries by scanning for `##### vX.Y.Z` headings. If a version already has a heading, skip it entirely.
14+
15+
3. **For each new version** (no existing heading), gather data from two files:
16+
17+
### 3a. Parse `upgrades/software/<version>/init.go`
18+
19+
Find all `utypes.RegisterMigration(...)` calls. Each call has the form:
20+
```go
21+
utypes.RegisterMigration(moduleName, version, handlerFn)
22+
```
23+
- `moduleName` is a Go constant (e.g., `dv1.ModuleName`). Resolve it:
24+
1. Find the import alias (e.g., `dv1 "pkg.akt.dev/go/node/deployment/v1"`)
25+
2. Search the imported package for `ModuleName` constant definition to get the actual string value
26+
- `version` is a `uint64` — this is the **from** version. The **to** version is `version + 1`.
27+
- Record each migration as: `moduleName version -> version+1`
28+
29+
### 3b. Parse `upgrades/software/<version>/upgrade.go`
30+
31+
Find the `StoreLoader()` method. It returns a `*storetypes.StoreUpgrades` struct with optional fields:
32+
- `Added: []string{...}` — new stores
33+
- `Renamed: []storetypes.StoreRename{...}` — renamed stores
34+
- `Deleted: []string{...}` — removed stores
35+
36+
If `StoreLoader()` returns `nil`, there are no store changes.
37+
38+
For each store key constant (e.g., `epochstypes.StoreKey`, `ttypes.ModuleName`):
39+
1. Find the import alias in the file
40+
2. Search the imported package for the constant definition to get the actual string value
41+
42+
4. **Insert the new entry** in `upgrades/CHANGELOG.md` immediately after the line:
43+
```
44+
Add new upgrades after this line based on the template above
45+
```
46+
followed by `-----`.
47+
48+
Use this format (newest entries go first, right after the delimiter):
49+
50+
```markdown
51+
52+
##### vX.Y.Z
53+
54+
###### Description
55+
56+
- Stores
57+
- added
58+
- `storeName`: brief description if available
59+
- renamed
60+
- `oldName` -> `newName`
61+
- deleted
62+
- `storeName`: brief description if available
63+
64+
- Migrations
65+
- moduleName `from -> to`
66+
```
67+
68+
**Omission rules** (match existing CHANGELOG style):
69+
- Omit the entire `Stores` section if there are no added, renamed, or deleted stores
70+
- Omit `added`/`renamed`/`deleted` subsections individually if empty
71+
- Omit the entire `Migrations` section if there are no migrations
72+
- Always include the `###### Description` heading (leave it for the user to fill in)
73+
74+
5. **Report results** — list each version processed and what was added. For skipped versions (already in CHANGELOG), mention they were skipped.
75+
76+
## Important notes
77+
78+
- Store key constants may be named `StoreKey` or `ModuleName` — both are used as store identifiers. Resolve whichever constant appears in the code.
79+
- When resolving Go constants from external packages, search under the Go module cache or use `go doc` if needed. The packages typically follow the pattern `pkg.akt.dev/go/node/<module>/<version>`.
80+
- If a constant cannot be resolved, use the raw Go expression as a placeholder (e.g., `` `epochstypes.StoreKey` ``) and warn the user.
81+
- Multiple versions may need entries — process them all in one run, inserting newest first after the delimiter.

app/app.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ import (
5353
transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types"
5454
ibchost "github.com/cosmos/ibc-go/v10/modules/core/exported"
5555

56+
gogogrpc "github.com/cosmos/gogoproto/grpc"
57+
5658
cflags "pkg.akt.dev/go/cli/flags"
59+
aclient "pkg.akt.dev/go/node/client"
5760
epochstypes "pkg.akt.dev/go/node/epochs/v1beta1"
5861
"pkg.akt.dev/go/sdkutil"
5962

@@ -532,6 +535,11 @@ func (app *AkashApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIC
532535
// Register node gRPC service for grpc-gateway.
533536
nodeservice.RegisterGRPCGatewayRoutes(cctx, apiSvr.GRPCGatewayRouter)
534537

538+
// Register Akash Discovery gRPC-Gateway route for REST access at GET /akash/discovery/v1/info.
539+
if err := aclient.RegisterDiscoveryHandlerServer(cctx.CmdContext, apiSvr.GRPCGatewayRouter, aclient.NewDiscoveryServer(aclient.GetRegistry())); err != nil {
540+
panic(fmt.Errorf("failed to register discovery gRPC-Gateway routes: %w", err))
541+
}
542+
535543
// register swagger API from root so that other applications can override easily
536544
if apiConfig.Swagger {
537545
RegisterSwaggerAPI(cctx, apiSvr.Router)
@@ -557,6 +565,18 @@ func (app *AkashApp) RegisterNodeService(cctx client.Context, cfg config.Config)
557565
nodeservice.RegisterNodeService(cctx, app.GRPCQueryRouter(), cfg)
558566
}
559567

568+
// RegisterGRPCServerWithSkipCheckHeader registers all gRPC services including
569+
// the Akash Discovery service for version negotiation.
570+
func (app *AkashApp) RegisterGRPCServerWithSkipCheckHeader(server gogogrpc.Server, skipCheckHeader bool) {
571+
// Register all standard Cosmos SDK module query services.
572+
app.BaseApp.RegisterGRPCServerWithSkipCheckHeader(server, skipCheckHeader)
573+
574+
// Register Akash Discovery service directly on the gRPC server.
575+
// This enables version discovery for clients via gRPC at akash.discovery.v1.Discovery/GetInfo
576+
// and via REST through gRPC-Gateway at GET /akash/discovery/v1/info.
577+
aclient.RegisterDiscoveryService(server, aclient.GetRegistry())
578+
}
579+
560580
// RegisterSwaggerAPI registers swagger route with API Server
561581
func RegisterSwaggerAPI(_ client.Context, rtr *mux.Router) {
562582
statikFS, err := fs.New()

cmd/akash/cmd/app_creator.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ import (
1919
sdkserver "github.com/cosmos/cosmos-sdk/server"
2020
servertypes "github.com/cosmos/cosmos-sdk/server/types"
2121

22+
"github.com/cosmos/cosmos-sdk/version"
23+
2224
cflags "pkg.akt.dev/go/cli/flags"
25+
aclient "pkg.akt.dev/go/node/client"
2326
"pkg.akt.dev/go/sdkutil"
2427

2528
akash "pkg.akt.dev/node/v2/app"
@@ -81,6 +84,14 @@ func (a appCreator) newApp(
8184
cast.ToUint32(appOpts.Get(cflags.FlagStateSyncSnapshotKeepRecent)),
8285
)
8386

87+
// Configure version discovery registry with chain metadata.
88+
// This is used by the CometBFT JSON-RPC "akash" route (automatic via init())
89+
// and the gRPC Discovery service (registered in AkashApp.RegisterGRPCServerWithSkipCheckHeader).
90+
aclient.SetRegistry(aclient.DefaultRegistry(
91+
aclient.WithChainID(chainID),
92+
aclient.WithNodeVersion(version.Version),
93+
))
94+
8495
baseAppOptions := []func(*baseapp.BaseApp){
8596
baseapp.SetChainID(chainID),
8697
baseapp.SetPruning(pruningOpts),

go.mod

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module pkg.akt.dev/node/v2
22

3-
go 1.25.9
3+
go 1.26.2
44

55
require (
66
cosmossdk.io/api v0.9.2
@@ -48,7 +48,7 @@ require (
4848
google.golang.org/grpc v1.76.0
4949
gopkg.in/yaml.v3 v3.0.1
5050
gotest.tools/v3 v3.5.2
51-
pkg.akt.dev/go v0.2.9
51+
pkg.akt.dev/go v0.2.10
5252
pkg.akt.dev/go/cli v0.2.2
5353
pkg.akt.dev/go/sdl v0.2.0
5454
)
@@ -59,7 +59,7 @@ replace (
5959
// use cosmos fork of keyring
6060
github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0
6161

62-
github.com/bytedance/sonic => github.com/bytedance/sonic v1.14.2
62+
github.com/bytedance/sonic => github.com/bytedance/sonic v1.15.0
6363

6464
// use akash fork of cometbft
6565
github.com/cometbft/cometbft => github.com/akash-network/cometbft v0.38.21-akash.1
@@ -119,7 +119,7 @@ require (
119119
github.com/blang/semver/v4 v4.0.0 // indirect
120120
github.com/bytedance/gopkg v0.1.3 // indirect
121121
github.com/bytedance/sonic v1.14.2 // indirect
122-
github.com/bytedance/sonic/loader v0.4.0 // indirect
122+
github.com/bytedance/sonic/loader v0.5.0 // indirect
123123
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
124124
github.com/cespare/xxhash/v2 v2.3.0 // indirect
125125
github.com/chzyer/readline v1.5.1 // indirect

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,10 +1346,10 @@ github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/
13461346
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
13471347
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
13481348
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
1349-
github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE=
1350-
github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980=
1351-
github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o=
1352-
github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
1349+
github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE=
1350+
github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k=
1351+
github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE=
1352+
github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
13531353
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
13541354
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
13551355
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
@@ -3293,8 +3293,8 @@ nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y=
32933293
nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
32943294
pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA=
32953295
pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
3296-
pkg.akt.dev/go v0.2.9 h1:2oU971PeW/f9UY2pBL4tmFTrsk4CvSroGlTQ38uKQjY=
3297-
pkg.akt.dev/go v0.2.9/go.mod h1:x9Cku9yibLk4aGLTE/Yy7eEkkda0uOSRWmYwQeFw23o=
3296+
pkg.akt.dev/go v0.2.10 h1:oRrzQIaolZiaL3+U9fgpfod9E7NT2OzHMs+7fPEB+Dc=
3297+
pkg.akt.dev/go v0.2.10/go.mod h1:6yV8oyP8xFm4ocyuf+9nx8S3T4mJz3e64Cl7ln/BczM=
32983298
pkg.akt.dev/go/cli v0.2.2 h1:PWDAAeHkVtcZ9qE76yh4IhJ2J/42ekhwSyrGWLPGi/g=
32993299
pkg.akt.dev/go/cli v0.2.2/go.mod h1:MHm9lU8hb+xQ8BX3b9c9S1pMyZKUob5tVjHXQ4T1uwU=
33003300
pkg.akt.dev/go/sdl v0.2.0 h1:hY74GjN4itV92REf8HqGt1rQDtXsruzE/iIzd/FpUB8=
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Docker Compose for Akash Local Development with Pyth Oracle
2+
#
3+
# This setup includes:
4+
# - akash-node: Single-node validator with Wormhole and Pyth contracts
5+
# - hermes-client: Price relayer that submits Pyth prices to the oracle
6+
#
7+
# Prerequisites:
8+
# - Build contracts first: cd contracts && make build
9+
# - Hermes repo at ../../hermes (relative to node repo)
10+
#
11+
# Usage:
12+
# docker-compose -f _build/docker-compose.yaml up -d # Start all services
13+
# docker-compose -f _build/docker-compose.yaml logs -f # View all logs
14+
# docker-compose -f _build/docker-compose.yaml logs -f validator # View node logs
15+
# docker-compose -f _build/docker-compose.yaml logs -f hermes-client # View hermes logs
16+
# docker-compose -f _build/docker-compose.yaml down # Stop services
17+
# docker-compose -f _build/docker-compose.yaml down -v # Stop and clean volumes
18+
#
19+
# Verify:
20+
# curl http://localhost:26657/status # Check node status
21+
# curl http://localhost:1317/cosmos/base/tendermint/v1beta1/blocks/latest # Check latest block
22+
#
23+
---
24+
services:
25+
# =============================================================================
26+
# Hermes Price Relayer
27+
# =============================================================================
28+
hermes-client:
29+
image: ghcr.io/akash-network/hermes:latest
30+
container_name: hermes-client
31+
hostname: hermes-client
32+
network_mode: "host"
33+
environment:
34+
# RPC endpoint (internal docker network)
35+
- RPC_ENDPOINT=http://host.docker.internal:26657
36+
# Pyth Hermes API
37+
- HERMES_ENDPOINT=https://hermes.pyth.network
38+
# Update interval (1 minute for testing, use 5+ minutes in production)
39+
- UPDATE_INTERVAL_MS=10000
40+
# Gas configuration
41+
- GAS_PRICE=0.025uakt
42+
- DENOM=uakt
43+
- NODE_ENV=development
44+
env_file:
45+
- ${AKASH_RUN_DIR}/hermes.env
46+
ports:
47+
- "3000:3000"
48+
entrypoint: ["/bin/sh", "-c"]
49+
command:
50+
- |
51+
echo "================================================"
52+
echo "Hermes Price Relayer - Waiting for configuration"
53+
echo "================================================"
54+
55+
echo "Contract address: $$CONTRACT_ADDRESS"
56+
echo "Starting Hermes daemon..."
57+
echo ""
58+
59+
# Run the hermes daemon
60+
exec node dist/cli.js daemon
61+
restart: unless-stopped
62+
logging:
63+
driver: json-file
64+
options:
65+
max-size: "10m"
66+
max-file: "3"

testutil/network/rpc.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,7 @@ func NewLocalRPCClient(lc *local.Local) *LocalRPCClient {
2222
}
2323

2424
// Akash implements the RPCClient interface required by chain-sdk.
25-
// Returns client info with the current API version.
25+
// Returns version discovery info from the global registry.
2626
func (c *LocalRPCClient) Akash(_ context.Context) (*aclient.Akash, error) {
27-
return &aclient.Akash{
28-
ClientInfo: aclient.ClientInfo{
29-
ApiVersion: "v1beta3",
30-
},
31-
}, nil
27+
return aclient.GetRegistry().ToAkash(), nil
3228
}

testutil/network/util.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import (
2727
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
2828
"github.com/cosmos/cosmos-sdk/x/genutil"
2929
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
30+
31+
aclient "pkg.akt.dev/go/node/client"
3032
)
3133

3234
func startInProcess(cfg Config, val *Validator) error {
@@ -46,6 +48,10 @@ func startInProcess(cfg Config, val *Validator) error {
4648
app := cfg.AppConstructor(*val)
4749
val.app = app
4850

51+
aclient.SetRegistry(aclient.DefaultRegistry(
52+
aclient.WithChainID(cfg.ChainID),
53+
))
54+
4955
appGenesisProvider := func() (node.ChecksummedGenesisDoc, error) {
5056
appGenesis, err := genutiltypes.AppGenesisFromFile(cmtCfg.GenesisFile())
5157
if err != nil {

upgrades/software/v2.1.0/init.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package v2_1_0
44

55
import (
66
dv1 "pkg.akt.dev/go/node/deployment/v1"
7+
mv1 "pkg.akt.dev/go/node/market/v1"
78
otypes "pkg.akt.dev/go/node/oracle/v2"
89

910
utypes "pkg.akt.dev/node/v2/upgrades/types"
@@ -14,4 +15,5 @@ func init() {
1415

1516
utypes.RegisterMigration(otypes.ModuleName, 1, newOracleMigration)
1617
utypes.RegisterMigration(dv1.ModuleName, 7, newDeploymentMigration)
18+
utypes.RegisterMigration(mv1.ModuleName, 8, newMarketMigration)
1719
}

0 commit comments

Comments
 (0)