Documentation
¶
Index ¶
- Constants
- Variables
- func NewMsgServer(k Keeper) types.MsgServer
- func NewQueryServer(k Keeper) types.QueryServer
- type HeightPower
- type Hooks
- func (h Hooks) AfterDelegationModified(ctx context.Context, delAddr sdk.AccAddress, _ sdk.ValAddress) error
- func (Hooks) AfterUnbondingInitiated(_ context.Context, _ uint64) error
- func (h Hooks) AfterValidatorBeginUnbonding(ctx context.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) error
- func (h Hooks) AfterValidatorBonded(ctx context.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) error
- func (Hooks) AfterValidatorCreated(_ context.Context, _ sdk.ValAddress) error
- func (h Hooks) AfterValidatorRemoved(ctx context.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) error
- func (Hooks) BeforeDelegationCreated(_ context.Context, _ sdk.AccAddress, _ sdk.ValAddress) error
- func (h Hooks) BeforeDelegationRemoved(ctx context.Context, delAddr sdk.AccAddress, _ sdk.ValAddress) error
- func (Hooks) BeforeDelegationSharesModified(_ context.Context, _ sdk.AccAddress, _ sdk.ValAddress) error
- func (Hooks) BeforeValidatorModified(_ context.Context, _ sdk.ValAddress) error
- func (h Hooks) BeforeValidatorSlashed(ctx context.Context, valAddr sdk.ValAddress, _ math.LegacyDec) error
- type Keeper
- func (k Keeper) Authority() string
- func (k Keeper) BackfillFromStaking(ctx context.Context) error
- func (k Keeper) EndBlocker(ctx context.Context) error
- func (k Keeper) ExportGenesis(ctx context.Context) (*types.GenesisState, error)
- func (k Keeper) Hooks() Hooks
- func (k Keeper) InitGenesis(ctx context.Context, gs *types.GenesisState) error
- func (k Keeper) IsLST(ctx context.Context, addr sdk.AccAddress) (bool, error)
- func (Keeper) Logger(ctx context.Context) log.Logger
- func (k Keeper) Prune(ctx context.Context) error
- func (k Keeper) TotalVotingPowerAt(ctx context.Context, height int64) (math.Int, error)
- func (k Keeper) VotingPowerAt(ctx context.Context, del sdk.AccAddress, height int64) (math.Int, error)
- func (k Keeper) VotingPowerOverRange(ctx context.Context, del sdk.AccAddress, fromHeight, toHeight int64) ([]HeightPower, error)
- func (k Keeper) VotingPowerOverRangeCapped(ctx context.Context, del sdk.AccAddress, fromHeight, toHeight int64) ([]HeightPower, error)
- type MsgServer
- type QueryServer
- func (q *QueryServer) Params(ctx context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error)
- func (q *QueryServer) TotalVotingPowerAt(ctx context.Context, req *types.QueryTotalVotingPowerAtRequest) (*types.QueryTotalVotingPowerAtResponse, error)
- func (q *QueryServer) VotingPowerAt(ctx context.Context, req *types.QueryVotingPowerAtRequest) (*types.QueryVotingPowerAtResponse, error)
- func (q *QueryServer) VotingPowerOverRange(ctx context.Context, req *types.QueryVotingPowerOverRangeRequest) (*types.QueryVotingPowerOverRangeResponse, error)
Constants ¶
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.
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.
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 ¶
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 NewQueryServer ¶
func NewQueryServer(k Keeper) types.QueryServer
Types ¶
type HeightPower ¶
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) 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) 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) BeforeValidatorSlashed ¶
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) BackfillFromStaking ¶
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 ¶
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 ¶
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) InitGenesis ¶
func (Keeper) IsLST ¶
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) Prune ¶
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 ¶
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 ¶
func (m *MsgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error)
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 ¶
func (q *QueryServer) Params(ctx context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error)
func (*QueryServer) TotalVotingPowerAt ¶
func (q *QueryServer) TotalVotingPowerAt(ctx context.Context, req *types.QueryTotalVotingPowerAtRequest) (*types.QueryTotalVotingPowerAtResponse, error)
func (*QueryServer) VotingPowerAt ¶
func (q *QueryServer) VotingPowerAt(ctx context.Context, req *types.QueryVotingPowerAtRequest) (*types.QueryVotingPowerAtResponse, error)
func (*QueryServer) VotingPowerOverRange ¶
func (q *QueryServer) VotingPowerOverRange(ctx context.Context, req *types.QueryVotingPowerOverRangeRequest) (*types.QueryVotingPowerOverRangeResponse, error)