Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,15 @@ build/

*.swagger.json

.roo/
.agents/
.claude/
.codex
AGENTS.md
CLAUDE.md
docs/plans/
docs/context.json
docs/decisions.md
docs/human-playbook.md
docs/requirements.json
.bridgeinclude
7 changes: 5 additions & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ import (
appParams "github.com/LumeraProtocol/lumera/app/upgrades/params"
actionmodulekeeper "github.com/LumeraProtocol/lumera/x/action/v1/keeper"
claimmodulekeeper "github.com/LumeraProtocol/lumera/x/claim/keeper"
everlightkeeper "github.com/LumeraProtocol/lumera/x/everlight/v1/keeper"
lumeraidmodulekeeper "github.com/LumeraProtocol/lumera/x/lumeraid/keeper"
sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types"

Expand Down Expand Up @@ -146,8 +147,9 @@ type App struct {

LumeraidKeeper lumeraidmodulekeeper.Keeper
ClaimKeeper claimmodulekeeper.Keeper
SupernodeKeeper sntypes.SupernodeKeeper
ActionKeeper actionmodulekeeper.Keeper
SupernodeKeeper sntypes.SupernodeKeeper
ActionKeeper actionmodulekeeper.Keeper
EverlightKeeper everlightkeeper.Keeper
// this line is used by starport scaffolding # stargate/app/keeperDeclaration

// simulation manager
Expand Down Expand Up @@ -249,6 +251,7 @@ func New(
&app.ClaimKeeper,
&app.SupernodeKeeper,
&app.ActionKeeper,
&app.EverlightKeeper,
// this line is used by starport scaffolding # stargate/app/keeperDefinition
); err != nil {
panic(err)
Expand Down
10 changes: 10 additions & 0 deletions app/app_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import (
claimmoduletypes "github.com/LumeraProtocol/lumera/x/claim/types"
lumeraidmodulev1 "github.com/LumeraProtocol/lumera/x/lumeraid/module"
lumeraidmoduletypes "github.com/LumeraProtocol/lumera/x/lumeraid/types"
everlightmodulev1 "github.com/LumeraProtocol/lumera/x/everlight/v1/module"
everlightmoduletypes "github.com/LumeraProtocol/lumera/x/everlight/v1/types"
supernodemodulev1 "github.com/LumeraProtocol/lumera/x/supernode/v1/module"
supernodemoduletypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types"
_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import for side-effects
Expand Down Expand Up @@ -118,6 +120,7 @@ var (
claimmoduletypes.ModuleName,
supernodemoduletypes.ModuleName,
actionmoduletypes.ModuleName,
everlightmoduletypes.ModuleName,
// this line is used by starport scaffolding # stargate/app/initGenesis
}

Expand All @@ -129,6 +132,7 @@ var (
beginBlockers = []string{
// cosmos sdk modules
minttypes.ModuleName,
everlightmoduletypes.ModuleName, // Must run before distrtypes to skim fee collector
distrtypes.ModuleName,
slashingtypes.ModuleName,
evidencetypes.ModuleName,
Expand Down Expand Up @@ -167,6 +171,7 @@ var (
claimmoduletypes.ModuleName,
supernodemoduletypes.ModuleName,
actionmoduletypes.ModuleName,
everlightmoduletypes.ModuleName,
// this line is used by starport scaffolding # stargate/app/endBlockers
}

Expand All @@ -192,6 +197,7 @@ var (
{Account: claimmoduletypes.ModuleName, Permissions: []string{authtypes.Minter, authtypes.Burner, authtypes.Staking}},
{Account: supernodemoduletypes.ModuleName, Permissions: []string{authtypes.Minter, authtypes.Burner, authtypes.Staking}},
{Account: actionmoduletypes.ModuleName, Permissions: []string{authtypes.Minter, authtypes.Burner, authtypes.Staking}},
{Account: everlightmoduletypes.ModuleName, Permissions: []string{authtypes.Burner}},
// this line is used by starport scaffolding # stargate/app/maccPerms
}

Expand Down Expand Up @@ -337,6 +343,10 @@ var (
Name: actionmoduletypes.ModuleName,
Config: appconfig.WrapAny(&actionmodulev1.Module{}),
},
{
Name: everlightmoduletypes.ModuleName,
Config: appconfig.WrapAny(&everlightmodulev1.Module{}),
},
// this line is used by starport scaffolding # stargate/app/moduleConfig
},
})
Expand Down
8 changes: 8 additions & 0 deletions app/upgrades/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
appParams "github.com/LumeraProtocol/lumera/app/upgrades/params"
upgrade_v1_10_0 "github.com/LumeraProtocol/lumera/app/upgrades/v1_10_0"
upgrade_v1_10_1 "github.com/LumeraProtocol/lumera/app/upgrades/v1_10_1"
upgrade_v1_15_0 "github.com/LumeraProtocol/lumera/app/upgrades/v1_15_0"
upgrade_v1_6_1 "github.com/LumeraProtocol/lumera/app/upgrades/v1_6_1"
upgrade_v1_8_0 "github.com/LumeraProtocol/lumera/app/upgrades/v1_8_0"
upgrade_v1_8_4 "github.com/LumeraProtocol/lumera/app/upgrades/v1_8_4"
Expand All @@ -33,6 +34,7 @@ import (
// | v1.9.1 | standard | none | Migrations only
// | v1.10.0 | custom | drop crisis | Migrate consensus params from x/params to x/consensus; remove x/crisis
// | v1.10.1 | custom | drop crisis (if not already) | Ensure consensus params are present in x/consensus
// | v1.15.0 | custom | add everlight | Adds Everlight store; InitGenesis sets default params
// =================================================================================================================================

type UpgradeConfig struct {
Expand Down Expand Up @@ -60,6 +62,7 @@ var upgradeNames = []string{
upgradeNameV191,
upgrade_v1_10_0.UpgradeName,
upgrade_v1_10_1.UpgradeName,
upgrade_v1_15_0.UpgradeName,
}

var NoUpgradeConfig = UpgradeConfig{
Expand Down Expand Up @@ -124,6 +127,11 @@ func SetupUpgrades(upgradeName string, params appParams.AppUpgradeParams) (Upgra
StoreUpgrade: &upgrade_v1_10_1.StoreUpgrades,
Handler: upgrade_v1_10_1.CreateUpgradeHandler(params),
}, true
case upgrade_v1_15_0.UpgradeName:
return UpgradeConfig{
StoreUpgrade: &upgrade_v1_15_0.StoreUpgrades,
Handler: upgrade_v1_15_0.CreateUpgradeHandler(params),
}, true

// add future upgrades here
default:
Expand Down
11 changes: 10 additions & 1 deletion app/upgrades/upgrades_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import (
appParams "github.com/LumeraProtocol/lumera/app/upgrades/params"
upgrade_v1_10_0 "github.com/LumeraProtocol/lumera/app/upgrades/v1_10_0"
upgrade_v1_10_1 "github.com/LumeraProtocol/lumera/app/upgrades/v1_10_1"
upgrade_v1_15_0 "github.com/LumeraProtocol/lumera/app/upgrades/v1_15_0"
upgrade_v1_6_1 "github.com/LumeraProtocol/lumera/app/upgrades/v1_6_1"
upgrade_v1_8_0 "github.com/LumeraProtocol/lumera/app/upgrades/v1_8_0"
upgrade_v1_8_4 "github.com/LumeraProtocol/lumera/app/upgrades/v1_8_4"
upgrade_v1_9_0 "github.com/LumeraProtocol/lumera/app/upgrades/v1_9_0"
actiontypes "github.com/LumeraProtocol/lumera/x/action/v1/types"
everlighttypes "github.com/LumeraProtocol/lumera/x/everlight/v1/types"
crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types"
)

Expand All @@ -33,6 +35,7 @@ func TestUpgradeNamesOrder(t *testing.T) {
upgradeNameV191,
upgrade_v1_10_0.UpgradeName,
upgrade_v1_10_1.UpgradeName,
upgrade_v1_15_0.UpgradeName,
}
require.Equal(t, expected, upgradeNames, "upgradeNames should stay in ascending order")
}
Expand Down Expand Up @@ -72,13 +75,17 @@ func TestSetupUpgradesAndHandlers(t *testing.T) {
require.Contains(t, config.StoreUpgrade.Deleted, crisistypes.StoreKey, "v1.10.0 should delete crisis store key")
}

if upgradeName == upgrade_v1_15_0.UpgradeName && config.StoreUpgrade != nil {
require.Contains(t, config.StoreUpgrade.Added, everlighttypes.StoreKey, "v1.15.0 should add everlight store key")
}

if config.Handler == nil {
continue
}

// v1.9.0 requires full keeper wiring; exercising it here would require
// a full app harness. This test only verifies registration and gating.
if upgradeName == upgrade_v1_9_0.UpgradeName || upgradeName == upgrade_v1_10_0.UpgradeName || upgradeName == upgrade_v1_10_1.UpgradeName {
if upgradeName == upgrade_v1_9_0.UpgradeName || upgradeName == upgrade_v1_10_0.UpgradeName || upgradeName == upgrade_v1_10_1.UpgradeName || upgradeName == upgrade_v1_15_0.UpgradeName {
continue
}

Expand Down Expand Up @@ -125,6 +132,8 @@ func expectStoreUpgrade(upgradeName, chainID string) bool {
return true
case upgrade_v1_10_1.UpgradeName:
return true
case upgrade_v1_15_0.UpgradeName:
return true
default:
return false
}
Expand Down
12 changes: 12 additions & 0 deletions app/upgrades/v1_15_0/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package v1_15_0

import (
storetypes "cosmossdk.io/store/types"
everlighttypes "github.com/LumeraProtocol/lumera/x/everlight/v1/types"
)

// StoreUpgrades defines store changes for v1.15.0.
// Adds the x/everlight module store.
var StoreUpgrades = storetypes.StoreUpgrades{
Added: []string{everlighttypes.StoreKey},
}
44 changes: 44 additions & 0 deletions app/upgrades/v1_15_0/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package v1_15_0

import (
"context"
"fmt"

upgradetypes "cosmossdk.io/x/upgrade/types"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"

consensusparams "github.com/LumeraProtocol/lumera/app/upgrades/internal/consensusparams"
appParams "github.com/LumeraProtocol/lumera/app/upgrades/params"
)

// UpgradeName is the on-chain name used for this upgrade.
const UpgradeName = "v1.15.0"

// CreateUpgradeHandler adds the Everlight store and initializes its params
// via RunMigrations (the module's InitGenesis sets default params automatically).
func CreateUpgradeHandler(p appParams.AppUpgradeParams) upgradetypes.UpgradeHandler {
return func(goCtx context.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
p.Logger.Info(fmt.Sprintf("Starting upgrade %s...", UpgradeName))

ctx := sdk.UnwrapSDKContext(goCtx)

if err := consensusparams.EnsurePresent(ctx, p, UpgradeName); err != nil {
return nil, err
}

// Run all module migrations after consensus params have been verified.
// This triggers Everlight's InitGenesis which sets default params.
p.Logger.Info("Running module migrations...")
newVM, err := p.ModuleManager.RunMigrations(ctx, p.Configurator, fromVM)
if err != nil {
p.Logger.Error("Failed to run migrations", "error", err)
return nil, fmt.Errorf("failed to run migrations: %w", err)
}
p.Logger.Info("Module migrations completed.")

p.Logger.Info(fmt.Sprintf("Successfully completed upgrade %s", UpgradeName))
return newVM, nil
}
}
83 changes: 83 additions & 0 deletions app/upgrades/v1_15_0/upgrade_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package v1_15_0

import (
"regexp"
"testing"

appParams "github.com/LumeraProtocol/lumera/app/upgrades/params"
everlighttypes "github.com/LumeraProtocol/lumera/x/everlight/v1/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// ---------------------------------------------------------------------------
// AT42: Upgrade handler initializes Everlight store and params with defaults
// ---------------------------------------------------------------------------

func TestUpgradeName(t *testing.T) {
require.Equal(t, "v1.15.0", UpgradeName)
}

func TestUpgradeNameFollowsSemverPattern(t *testing.T) {
// UpgradeName must be a valid semver-style string "vMAJOR.MINOR.PATCH".
matched, err := regexp.MatchString(`^v\d+\.\d+\.\d+$`, UpgradeName)
require.NoError(t, err)
require.True(t, matched,
"UpgradeName %q should match the semver pattern vX.Y.Z", UpgradeName)
}

func TestStoreUpgradesAddsEverlight(t *testing.T) {
require.Contains(t, StoreUpgrades.Added, everlighttypes.StoreKey,
"StoreUpgrades.Added should contain the everlight store key")
}

func TestStoreUpgradesAddedContainsOnlyEverlight(t *testing.T) {
// Exactly one store key is added — the everlight module and nothing else.
require.Len(t, StoreUpgrades.Added, 1,
"StoreUpgrades.Added should contain exactly one entry")
require.Equal(t, everlighttypes.StoreKey, StoreUpgrades.Added[0],
"The sole added store key should be the everlight store key")
}

func TestStoreUpgradesDeletedIsEmpty(t *testing.T) {
require.Empty(t, StoreUpgrades.Deleted,
"StoreUpgrades.Deleted should be empty — no existing stores are removed")
}

// ---------------------------------------------------------------------------
// AT43: Existing SN states and actions unaffected by Everlight upgrade
// ---------------------------------------------------------------------------

func TestStoreUpgradesDoesNotDeleteExistingModules(t *testing.T) {
// The Deleted list must NOT contain any of the pre-existing module store
// keys. This provides executable evidence that the upgrade preserves all
// existing module stores.
protectedKeys := []string{
"supernode",
"action",
"claim",
"lumeraid",
"bank",
"staking",
"distribution",
}

for _, key := range protectedKeys {
assert.NotContains(t, StoreUpgrades.Deleted, key,
"StoreUpgrades.Deleted must not contain %q — existing stores must be preserved", key)
}
}

func TestStoreUpgradesDoesNotRenameExistingModules(t *testing.T) {
// Renamed list should be empty (or at least not reference any existing stores).
require.Empty(t, StoreUpgrades.Renamed,
"StoreUpgrades.Renamed should be empty — no existing stores are renamed")
}

func TestCreateUpgradeHandlerReturnsNonNil(t *testing.T) {
// Verify that CreateUpgradeHandler can be called with a zero-value params
// struct without panicking, and that it returns a non-nil handler function.
handler := CreateUpgradeHandler(appParams.AppUpgradeParams{})
require.NotNil(t, handler,
"CreateUpgradeHandler should return a non-nil upgrade handler function")
}
8 changes: 4 additions & 4 deletions buf.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ deps:
commit: 04467658e59e44bbb22fe568206e1f70
digest: b5:8058c0aadbee8c9af67a9cefe86492c6c0b0bd5b4526b0ec820507b91fc9b0b5efbebca97331854576d2d279b0b3f5ed6a7abb0640cb640c4186532239c48fc4
- name: buf.build/cosmos/cosmos-sdk
commit: 650cd9ad7f7a468e8e19975269958658
digest: b5:652a0cd9aa3c220bb12b558f29b30ca5c248b994420472c9c2a54eed3d33356b1307e51687c1909ea4f535a2a1e180895b8cda83b58a4697003009d17fdbc154
commit: 65fa41963e6a41dd95a35934239029df
digest: b5:45c2788f1c8ca1c0e72f643d51dba37c3b25d113ee166277cd60dfd49404e713a178e177beaa7d6d016f3853722d77f8fbf40e9444e173cd3d89754d39ca0427
- name: buf.build/cosmos/gogo-proto
commit: 88ef6483f90f478fb938c37dde52ece3
digest: b5:f0c69202c9bca9672dc72a9737ea9bc83744daaed2b3da77e3a95b0e53b86dee76b5a7405b993181d6c863fd64afaca0976a302f700d6c4912eb1692a1782c0a
Expand All @@ -23,5 +23,5 @@ deps:
commit: 004180b77378443887d3b55cabc00384
digest: b5:e8f475fe3330f31f5fd86ac689093bcd274e19611a09db91f41d637cb9197881ce89882b94d13a58738e53c91c6e4bae7dc1feba85f590164c975a89e25115dc
- name: buf.build/protocolbuffers/wellknowntypes
commit: 4e1ccfa6827947beb55974645a315b8d
digest: b5:eb5228b1abd02064d6ff0248918500c1ec1ce7df69126af3f220c0b67d81ff45bdf9f016a8e66cd9c1e534f18afc6d8e090d400604c5331d551a68d05f7e7be9
commit: 9d16d599a978406980f6e2f081331a93
digest: b5:dd06e497a5c52f5ddf6ec02b3c7d289cc6c0432093fc2f6bf7a4fb5fae786c3e4c893e55d2759ffb6833268daf3de0bce303a406fed15725790528f2c27dc219
2 changes: 1 addition & 1 deletion docs/static/openapi.yml

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions proto/lumera/everlight/module/v1/module.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
syntax = "proto3";
package lumera.everlight.module.v1;

option go_package = "x/everlight/v1/module;everlight";

import "cosmos/app/v1alpha1/module.proto";

// Module is the config object for the module.
message Module {
option (cosmos.app.v1alpha1.module) = {
go_import: "github.com/LumeraProtocol/lumera/x/everlight/v1"
};

// authority defines the custom module authority. If not set, defaults to the governance module.
string authority = 1;
}
20 changes: 20 additions & 0 deletions proto/lumera/everlight/v1/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
syntax = "proto3";
package lumera.everlight.v1;

option go_package = "x/everlight/v1/types";

import "amino/amino.proto";
import "gogoproto/gogo.proto";
import "lumera/everlight/v1/params.proto";

// GenesisState defines the everlight module's genesis state.
message GenesisState {
// params defines all the parameters of the module.
Params params = 1 [
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true
];

// last_distribution_height is the block height of the last distribution.
int64 last_distribution_height = 2;
}
Loading
Loading