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
4 changes: 4 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import (
upgrades "github.com/LumeraProtocol/lumera/app/upgrades"
appParams "github.com/LumeraProtocol/lumera/app/upgrades/params"
actionmodulekeeper "github.com/LumeraProtocol/lumera/x/action/v1/keeper"
auditmodulekeeper "github.com/LumeraProtocol/lumera/x/audit/v1/keeper"
claimmodulekeeper "github.com/LumeraProtocol/lumera/x/claim/keeper"
lumeraidmodulekeeper "github.com/LumeraProtocol/lumera/x/lumeraid/keeper"
sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types"
Expand Down Expand Up @@ -147,6 +148,7 @@ type App struct {
LumeraidKeeper lumeraidmodulekeeper.Keeper
ClaimKeeper claimmodulekeeper.Keeper
SupernodeKeeper sntypes.SupernodeKeeper
AuditKeeper auditmodulekeeper.Keeper
ActionKeeper actionmodulekeeper.Keeper
// this line is used by starport scaffolding # stargate/app/keeperDeclaration

Expand Down Expand Up @@ -248,6 +250,7 @@ func New(
&app.LumeraidKeeper,
&app.ClaimKeeper,
&app.SupernodeKeeper,
&app.AuditKeeper,
&app.ActionKeeper,
// this line is used by starport scaffolding # stargate/app/keeperDefinition
); err != nil {
Expand Down Expand Up @@ -328,6 +331,7 @@ func (app *App) setupUpgrades() {
SupernodeKeeper: app.SupernodeKeeper,
ParamsKeeper: &app.ParamsKeeper,
ConsensusParamsKeeper: &app.ConsensusParamsKeeper,
AuditKeeper: &app.AuditKeeper,
}

allUpgrades := upgrades.AllUpgrades(params)
Expand Down
9 changes: 9 additions & 0 deletions app/app_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import (
upgradetypes "cosmossdk.io/x/upgrade/types"
actionmodulev1 "github.com/LumeraProtocol/lumera/x/action/v1/module"
actionmoduletypes "github.com/LumeraProtocol/lumera/x/action/v1/types"
auditmodulev1 "github.com/LumeraProtocol/lumera/x/audit/v1/module"
auditmoduletypes "github.com/LumeraProtocol/lumera/x/audit/v1/types"
claimmodulev1 "github.com/LumeraProtocol/lumera/x/claim/module"
claimmoduletypes "github.com/LumeraProtocol/lumera/x/claim/types"
lumeraidmodulev1 "github.com/LumeraProtocol/lumera/x/lumeraid/module"
Expand Down Expand Up @@ -117,6 +119,7 @@ var (
wasmtypes.ModuleName,
claimmoduletypes.ModuleName,
supernodemoduletypes.ModuleName,
auditmoduletypes.ModuleName,
actionmoduletypes.ModuleName,
// this line is used by starport scaffolding # stargate/app/initGenesis
}
Expand Down Expand Up @@ -145,6 +148,7 @@ var (
wasmtypes.ModuleName,
claimmoduletypes.ModuleName,
supernodemoduletypes.ModuleName,
auditmoduletypes.ModuleName,
actionmoduletypes.ModuleName,
// this line is used by starport scaffolding # stargate/app/beginBlockers
}
Expand All @@ -166,6 +170,7 @@ var (
wasmtypes.ModuleName,
claimmoduletypes.ModuleName,
supernodemoduletypes.ModuleName,
auditmoduletypes.ModuleName,
actionmoduletypes.ModuleName,
// this line is used by starport scaffolding # stargate/app/endBlockers
}
Expand Down Expand Up @@ -333,6 +338,10 @@ var (
Name: supernodemoduletypes.ModuleName,
Config: appconfig.WrapAny(&supernodemodulev1.Module{}),
},
{
Name: auditmoduletypes.ModuleName,
Config: appconfig.WrapAny(&auditmodulev1.Module{}),
},
{
Name: actionmoduletypes.ModuleName,
Config: appconfig.WrapAny(&actionmodulev1.Module{}),
Expand Down
2 changes: 2 additions & 0 deletions app/upgrades/params/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper"

actionmodulekeeper "github.com/LumeraProtocol/lumera/x/action/v1/keeper"
auditmodulekeeper "github.com/LumeraProtocol/lumera/x/audit/v1/keeper"
sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types"
)

Expand All @@ -24,4 +25,5 @@ type AppUpgradeParams struct {
SupernodeKeeper sntypes.SupernodeKeeper
ParamsKeeper *paramskeeper.Keeper
ConsensusParamsKeeper *consensuskeeper.Keeper
AuditKeeper *auditmodulekeeper.Keeper
}
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_11_0 "github.com/LumeraProtocol/lumera/app/upgrades/v1_11_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.11.0 | custom | add audit store | Initializes audit params with dynamic epoch_zero_height
// =================================================================================================================================

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_11_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_11_0.UpgradeName:
return UpgradeConfig{
StoreUpgrade: &upgrade_v1_11_0.StoreUpgrades,
Handler: upgrade_v1_11_0.CreateUpgradeHandler(params),
}, true

// add future upgrades here
default:
Expand Down
8 changes: 5 additions & 3 deletions app/upgrades/upgrades_test.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_11_0 "github.com/LumeraProtocol/lumera/app/upgrades/v1_11_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 @@ func TestUpgradeNamesOrder(t *testing.T) {
upgradeNameV191,
upgrade_v1_10_0.UpgradeName,
upgrade_v1_10_1.UpgradeName,
upgrade_v1_11_0.UpgradeName,
}
require.Equal(t, expected, upgradeNames, "upgradeNames should stay in ascending order")
}
Expand Down Expand Up @@ -76,9 +78,9 @@ func TestSetupUpgradesAndHandlers(t *testing.T) {
continue
}

// v1.9.0 requires full keeper wiring; exercising it here would require
// v1.9.0 and v1.11.0 require full keeper wiring; exercising them 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_11_0.UpgradeName {
continue
}

Expand Down Expand Up @@ -123,7 +125,7 @@ func expectStoreUpgrade(upgradeName, chainID string) bool {
return IsMainnet(chainID)
case upgrade_v1_10_0.UpgradeName:
return true
case upgrade_v1_10_1.UpgradeName:
case upgrade_v1_10_1.UpgradeName, upgrade_v1_11_0.UpgradeName:
return true
default:
return false
Expand Down
92 changes: 92 additions & 0 deletions app/upgrades/v1_11_0/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package v1_11_0

import (
"context"
"fmt"

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

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

appParams "github.com/LumeraProtocol/lumera/app/upgrades/params"
audittypes "github.com/LumeraProtocol/lumera/x/audit/v1/types"
)

// Storage challenge feature toggle at activation time.
//
// This is set exactly once during the upgrade; thereafter, params are governed by MsgUpdateParams.
// All other parameter defaults are owned by the audit module (types.DefaultParams()).
const auditScEnabled = true

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

// StoreUpgrades declares store additions/deletions for this upgrade.
//
// Audit is introduced for the first time on-chain, so its KV store must be added.
var StoreUpgrades = storetypes.StoreUpgrades{
Added: []string{
audittypes.StoreKey, // "audit"
},
}

// CreateUpgradeHandler creates an upgrade handler for v1.11.0.
//
// This upgrade introduces the audit module and initializes its params in a way
// that requires no hard-coded epoch_zero_height for existing networks:
// - epoch_zero_height is set to the upgrade block height (the first block the
// new binary processes).
// - epoch_length_blocks remains its default unless governance later changes it
// (epoch cadence fields are immutable after initialization).
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)

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.")

if p.AuditKeeper == nil {
return nil, fmt.Errorf("%s upgrade requires audit keeper to be wired", UpgradeName)
}

// Initialize audit genesis state with an automatically chosen epoch_zero_height.
// Using the current block height ensures that the audit BeginBlocker will create
// the epoch-0 anchor immediately at the epoch start height.
gs := audittypes.DefaultGenesis()
params := gs.Params.WithDefaults()

// For an already-running chain, epoch zero must be chosen dynamically at the upgrade height.
// This is set exactly once here; thereafter it is immutable.
params.EpochZeroHeight = uint64(ctx.BlockHeight())

// Feature gate for SC evidence validation/acceptance.
params.ScEnabled = auditScEnabled

gs.Params = params

if err := p.AuditKeeper.InitGenesis(ctx, *gs); err != nil {
return nil, fmt.Errorf("init audit module: %w", err)
}

// Create epoch-0 anchor immediately, so audit reporting can begin in the same upgrade block
// without depending on BeginBlock ordering assumptions.
epochID := uint64(0)
epochStart := ctx.BlockHeight()
epochEnd := epochStart + int64(params.EpochLengthBlocks) - 1
if err := p.AuditKeeper.CreateEpochAnchorIfNeeded(ctx, epochID, epochStart, epochEnd, params); err != nil {
return nil, fmt.Errorf("create audit epoch anchor: %w", err)
}

p.Logger.Info(fmt.Sprintf("Successfully completed upgrade %s", UpgradeName))
return newVM, nil
}
}
2 changes: 1 addition & 1 deletion config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ genesis:
max_processing_time: 1h0m0s
expiration_duration: 24h0m0s
claim:
total_claimable_amount: '18749999991853'
total_claimable_amount: '18749999981413'
params:
claim_end_time: '1767225600' # Jan 1 2026, 00:00:00
crisis:
Expand Down
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/audit/module/v1/module.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
syntax = "proto3";
package lumera.audit.module.v1;

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

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/audit/v1"
};

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

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

import "amino/amino.proto";
import "cosmos_proto/cosmos.proto";
import "gogoproto/gogo.proto";

enum PortState {
PORT_STATE_UNKNOWN = 0;
PORT_STATE_OPEN = 1;
PORT_STATE_CLOSED = 2;
}

// HostReport is the Supernode's self-reported host metrics and counters for an epoch.
message HostReport {
double cpu_usage_percent = 1;
double mem_usage_percent = 2;
double disk_usage_percent = 3;

repeated PortState inbound_port_states = 4;

uint32 failed_actions_count = 5;
}

// StorageChallengeObservation is a prober's reachability observation about an assigned target.
message StorageChallengeObservation {
string target_supernode_account = 1 [(cosmos_proto.scalar) = "cosmos.AccAddressString"];

// port_states[i] refers to required_open_ports[i] for the epoch.
repeated PortState port_states = 2;
}

// EpochReport is a single per-epoch report submitted by a Supernode.
message EpochReport {
string supernode_account = 1 [(cosmos_proto.scalar) = "cosmos.AccAddressString"];
uint64 epoch_id = 2;
int64 report_height = 3;

HostReport host_report = 4 [(gogoproto.nullable) = false];
repeated StorageChallengeObservation storage_challenge_observations = 5;
}
36 changes: 36 additions & 0 deletions proto/lumera/audit/v1/epoch.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
syntax = "proto3";
package lumera.audit.v1;

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

import "amino/amino.proto";
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";

// EpochAnchor is a minimal per-epoch on-chain anchor that freezes the deterministic seed
// and the eligible supernode sets used for deterministic selection off-chain.
message EpochAnchor {
option (gogoproto.equal) = true;

uint64 epoch_id = 1;
int64 epoch_start_height = 2;
int64 epoch_end_height = 3;
uint64 epoch_length_blocks = 4;

// seed is a fixed 32-byte value derived at epoch start (domain-separated).
bytes seed = 5;

// active_supernode_accounts is the sorted list of ACTIVE supernodes at epoch start.
repeated string active_supernode_accounts = 6 [(cosmos_proto.scalar) = "cosmos.AccAddressString"];

// target_supernode_accounts is the sorted list of eligible targets at epoch start:
// ACTIVE + POSTPONED supernodes.
repeated string target_supernode_accounts = 7 [(cosmos_proto.scalar) = "cosmos.AccAddressString"];

// params_commitment is a hash commitment to Params (with defaults) at epoch start.
bytes params_commitment = 8;

bytes active_set_commitment = 9;
bytes targets_set_commitment = 10;
}

Loading
Loading