keeper

package
v30.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// MaxVotingPowerRangeWidth bounds the queryable window to ~1 week of
	// blocks. Wider analytics belong off-chain (indexer), not in
	// consensus-metered queries.
	MaxVotingPowerRangeWidth int64 = 100_800
	// MaxVotingPowerRangeRows bounds the number of returned snapshots.
	// Exceeding it is an error (not a silent truncation) — callers must
	// narrow the range so they never act on partial data.
	MaxVotingPowerRangeRows = 1024
)

Query caps for VotingPowerOverRangeCapped. Applied at the wasmbinding and gRPC layers so a contract or client cannot induce an unbounded store scan.

View Source
const MaxDelegatorsPerSnapshotWalk = 10_000

MaxDelegatorsPerSnapshotWalk is the advisory bound on a single validator-delegation walk (slash / bond-status change). Juno's largest validator carries ~6k delegators, so 10k is headroom. The walk is never truncated — dropping a delegator would freeze stale voting power in state — but crossing this threshold is logged so operators can see the block-time cost coming.

View Source
const MaxPruneDeletionsPerRun = 10_000

MaxPruneDeletionsPerRun bounds how many snapshot keys a single prune sweep may delete (per collection). A run that hits the cap logs and leaves the remainder for the next interval — never a silent drop of data a read still needs (the keep-most-recent-below-cutoff guard is applied before the cap, so capping only defers deletion of already stale keys).

Variables

View Source
var (
	ErrRangeTooWide     = fmt.Errorf("voting power range too wide: max %d blocks", MaxVotingPowerRangeWidth)
	ErrRangeTooManyRows = fmt.Errorf("voting power range matched too many snapshots: max %d rows, narrow the range", MaxVotingPowerRangeRows)
)

Sentinel errors for the capped range query. The gRPC layer maps these to InvalidArgument / ResourceExhausted; the wasmbinding surfaces them verbatim to the calling contract.

Functions

func NewMsgServer

func NewMsgServer(k Keeper) types.MsgServer

func NewQueryServer

func NewQueryServer(k Keeper) types.QueryServer

Types

type HeightPower

type HeightPower struct {
	Height int64
	Power  math.Int
}

HeightPower is one (height, power) pair returned by VotingPowerOverRange.

type Hooks

type Hooks struct {
	// contains filtered or unexported fields
}

func (Hooks) AfterDelegationModified

func (h Hooks) AfterDelegationModified(ctx context.Context, delAddr sdk.AccAddress, _ sdk.ValAddress) error

func (Hooks) AfterUnbondingInitiated

func (Hooks) AfterUnbondingInitiated(_ context.Context, _ uint64) error

func (Hooks) AfterValidatorBeginUnbonding

func (h Hooks) AfterValidatorBeginUnbonding(ctx context.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) error

func (Hooks) AfterValidatorBonded

func (h Hooks) AfterValidatorBonded(ctx context.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) error

func (Hooks) AfterValidatorCreated

func (Hooks) AfterValidatorCreated(_ context.Context, _ sdk.ValAddress) error

func (Hooks) AfterValidatorRemoved

func (h Hooks) AfterValidatorRemoved(ctx context.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) error

func (Hooks) BeforeDelegationCreated

func (Hooks) BeforeDelegationCreated(_ context.Context, _ sdk.AccAddress, _ sdk.ValAddress) error

func (Hooks) BeforeDelegationRemoved

func (h Hooks) BeforeDelegationRemoved(ctx context.Context, delAddr sdk.AccAddress, _ sdk.ValAddress) error

func (Hooks) BeforeDelegationSharesModified

func (Hooks) BeforeDelegationSharesModified(_ context.Context, _ sdk.AccAddress, _ sdk.ValAddress) error

func (Hooks) BeforeValidatorModified

func (Hooks) BeforeValidatorModified(_ context.Context, _ sdk.ValAddress) error

func (Hooks) BeforeValidatorSlashed

func (h Hooks) BeforeValidatorSlashed(ctx context.Context, valAddr sdk.ValAddress, _ math.LegacyDec) error

type Keeper

type Keeper struct {
	Schema collections.Schema
	Params collections.Item[types.Params]
	// VotingPower indexes a delegator's bonded stake per snapshot height.
	// Only delegations to validators in Bonded status count (matching the
	// TotalBondedTokens basis). LST-allowlisted delegators write zero and
	// their stake is symmetrically excluded from TotalPower.
	VotingPower collections.Map[collections.Pair[[]byte, int64], math.Int]
	// TotalPower indexes the chain's total voting power per snapshot
	// height: staking.TotalBondedTokens minus the bonded stake held by
	// LST-allowlisted addresses. This keeps the numerator/denominator
	// bases aligned so Σ VotingPower[d,h] <= TotalPower[h] (up to
	// shares-rounding dust). DAO designers can compute quorum as
	// Σ votes / TotalPower directly.
	TotalPower collections.Map[int64, math.Int]

	// TransientSchema and the collections below live in the module's
	// transient store (reset on every commit). They carry the set of
	// delegators whose power changed within the current block from the
	// staking hooks to the EndBlocker drain.
	TransientSchema collections.Schema
	DirtyDelegators collections.KeySet[[]byte]
	TotalDirty      collections.Item[bool]
	// contains filtered or unexported fields
}

Keeper holds the event-driven voting-power index for staked JUNO.

Per planning/05-staking-snapshot.md (option 2): staking hooks mark affected delegators dirty in a transient store, and the module EndBlocker (ordered after staking in app/modules.go) recomputes and writes their snapshots once all staking mutations for the block have settled. Reads return the latest snapshot at-or-before the requested height — caller-side semantics line up with proposal-vote tallying ("what was X's power at proposal-open height?").

Writing from EndBlock instead of inside the hooks is load-bearing for correctness: several staking hooks (BeforeDelegationRemoved, BeforeValidatorSlashed) fire while the store still holds the pre-mutation state, so an in-hook recompute records stale power.

func NewKeeper

func NewKeeper(
	cdc codec.BinaryCodec,
	storeService corestore.KVStoreService,
	stakingKeeper types.StakingKeeper,
	authority string,
	transientService corestore.KVStoreService,
) Keeper

func (Keeper) Authority

func (k Keeper) Authority() string

func (Keeper) BackfillFromStaking

func (k Keeper) BackfillFromStaking(ctx context.Context) error

BackfillFromStaking writes a snapshot of every active delegator's bonded power and the total voting power at the current block height. Used in the v30 upgrade handler so contracts querying VotingPowerAt(height >= upgrade) get real data immediately rather than zeros until the next delegation event.

Walks all delegations once and caches validator bond status so the upgrade block does not do a second per-delegator delegation walk. Writes remain sorted by delegator address for deterministic IAVL write order.

func (Keeper) EndBlocker

func (k Keeper) EndBlocker(ctx context.Context) error

EndBlocker drains the transient dirty-delegator set: for each dirty delegator it recomputes bonded power from (now fully settled) staking state and writes the snapshot at the current height; if the total is dirty it recomputes and writes TotalPower. Runs after staking's EndBlocker (see orderEndBlockers in app/modules.go), so slashes, undelegations, and validator bond-status transitions from this block are all reflected.

Determinism: dirty keys are collected from an ordered store iterator and explicitly sorted before any state write (mirrors backfill.go) — no Go-map iteration feeds state.

func (Keeper) ExportGenesis

func (k Keeper) ExportGenesis(ctx context.Context) (*types.GenesisState, error)

ExportGenesis exports Params only — the snapshot index (VotingPower / TotalPower maps) is intentionally NOT exported.

This is a documented in-place-upgrade-only assumption: Juno upgrades via x/upgrade in-place migrations, so the snapshot history never needs to round-trip through genesis JSON (it can be millions of rows). If the chain is ever restarted from an exported genesis, InitGenesis's BackfillFromStaking reseeds every delegator's power and the total at the restart height from live staking state — current voting power is correct immediately; only pre-restart *history* is lost, which matches what proposals opened before a hard restart can expect.

func (Keeper) Hooks

func (k Keeper) Hooks() Hooks

Hooks returns a wrapper implementing the staking hook interface.

func (Keeper) InitGenesis

func (k Keeper) InitGenesis(ctx context.Context, gs *types.GenesisState) error

func (Keeper) IsLST

func (k Keeper) IsLST(ctx context.Context, addr sdk.AccAddress) (bool, error)

IsLST reports whether the given delegator address is currently in the LST allowlist (delegators whose stake does NOT count toward voting power). Pre-genesis (params unset) returns false so staking hooks fired during InitGenesis don't error out before our InitGenesis sets params.

func (Keeper) Logger

func (Keeper) Logger(ctx context.Context) log.Logger

Logger returns a module-tagged logger derived from the context.

func (Keeper) Prune

func (k Keeper) Prune(ctx context.Context) error

Prune drops snapshots with height < (current_height - RetentionWindowHeights). Called from the module's EndBlocker. No-op if the retention window is 0 (disabled) or if the current block isn't on a prune-interval boundary.

Per-delegator the pruner preserves the most recent snapshot that is still below the cutoff (h_max_below). Without that guard a set-and-forget delegator whose last staking event predates the retention window would lose every snapshot and read zero voting power even though their stake is unchanged. TotalPower gets the same treatment for symmetry — the total only writes on staking events, not every block, so a quiet period can produce the same sparse pattern.

func (Keeper) TotalVotingPowerAt

func (k Keeper) TotalVotingPowerAt(ctx context.Context, height int64) (math.Int, error)

TotalVotingPowerAt returns the most recent total-power snapshot at-or-before `height`. Returns zero if no snapshot exists.

func (Keeper) VotingPowerAt

func (k Keeper) VotingPowerAt(ctx context.Context, del sdk.AccAddress, height int64) (math.Int, error)

VotingPowerAt returns the bonded-token voting power attributable to del as of `height`. It returns the most recent snapshot at-or-before the requested height. Returns zero if no snapshot exists (height is before backfill / module activation).

func (Keeper) VotingPowerOverRange

func (k Keeper) VotingPowerOverRange(ctx context.Context, del sdk.AccAddress, fromHeight, toHeight int64) ([]HeightPower, error)

VotingPowerOverRange returns every recorded snapshot for `del` whose height falls in [fromHeight, toHeight] (inclusive). Useful for time-decay schemes (conviction voting, plural voting) that want to integrate power over a window rather than read at a single height.

Unbounded — internal use only. Externally reachable surfaces (wasmbindings, gRPC) must call VotingPowerOverRangeCapped.

Caller-side note: pre-existing at-or-before semantics still apply for the boundaries — a delegator who didn't change stake within [fromHeight, toHeight] will produce zero rows here, and the caller should fall back to VotingPowerAt(fromHeight) to learn the constant-over-the-window value.

func (Keeper) VotingPowerOverRangeCapped

func (k Keeper) VotingPowerOverRangeCapped(ctx context.Context, del sdk.AccAddress, fromHeight, toHeight int64) ([]HeightPower, error)

VotingPowerOverRangeCapped is the externally reachable variant of VotingPowerOverRange. It rejects windows wider than MaxVotingPowerRangeWidth and result sets larger than MaxVotingPowerRangeRows — errors, never silent truncation, so callers can't mistake a partial window for the whole one.

type MsgServer

type MsgServer struct {
	// contains filtered or unexported fields
}

MsgServer adapts Keeper into the proto-generated types.MsgServer interface. Currently a single message: governance-driven UpdateParams.

func (*MsgServer) UpdateParams

type QueryServer

type QueryServer struct {
	// contains filtered or unexported fields
}

QueryServer adapts Keeper into the proto-generated types.QueryServer interface. The wasmbinding surface mirrors these methods directly; gRPC consumers (CLI, indexers, REST gateway) use this path.

func (*QueryServer) Params

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL