Search Apps Documentation Source Content File Folder Download Copy Actions Download

staker_delegation_snapshot.gno

5.35 Kb ยท 182 lines
  1package v1
  2
  3import (
  4	"chain"
  5	"chain/runtime"
  6	"math"
  7
  8	"gno.land/r/gnoswap/access"
  9	"gno.land/r/gnoswap/gov/staker"
 10	"gno.land/r/gnoswap/halt"
 11)
 12
 13// SetUnDelegationLockupPeriodByAdmin sets the undelegation lockup period.
 14// This administrative function configures the time period that undelegated tokens
 15// must wait before they can be collected by users.
 16//
 17// The lockup period serves as a security mechanism to:
 18// - Prevent rapid delegation/undelegation cycles
 19// - Provide time for governance decisions to take effect
 20// - Maintain system stability during volatile periods
 21//
 22// Parameters:
 23//   - period: lockup period in seconds (must be non-negative)
 24//
 25// Panics:
 26//   - if caller is not admin
 27//   - if period is negative
 28//
 29// Note: This change affects all future undelegation operations
 30func (gs *govStakerV1) SetUnDelegationLockupPeriodByAdmin(period int64) {
 31	halt.AssertIsNotHaltedGovStaker()
 32
 33	previousRealm := runtime.PreviousRealm()
 34	caller := previousRealm.Address()
 35	access.AssertIsAdmin(caller)
 36
 37	if period < 0 {
 38		panic("period must be greater than 0")
 39	}
 40
 41	gs.setUnDelegationLockupPeriod(period)
 42
 43	chain.Emit(
 44		"SetUnDelegationLockupPeriod",
 45		"prevAddr", previousRealm.Address().String(),
 46		"prevRealm", previousRealm.PkgPath(),
 47		"period", formatInt(period),
 48	)
 49}
 50
 51// CleanStakerDelegationSnapshotByAdmin cleans old delegation history records.
 52// This administrative function removes delegation history records older than the specified threshold
 53// to prevent unlimited growth of historical data and optimize storage usage.
 54//
 55// The cleanup process:
 56// 1. Validates the snapshot time is within allowed range
 57// 2. Checks that no active proposals need data older than the cleanup threshold
 58// 3. Filters delegation history to keep only records after cutoff time
 59// 4. Updates the delegation history with filtered records
 60//
 61// Parameters:
 62//   - snapshotTime: cutoff timestamp (records older than this will be removed)
 63//
 64// Panics:
 65//   - if caller is not admin
 66//   - if snapshotTime is invalid (negative or too recent)
 67//   - if active proposals have snapshotTime older than the cleanup threshold
 68//
 69// Note: This operation is irreversible and will permanently remove historical data
 70func (gs *govStakerV1) CleanStakerDelegationSnapshotByAdmin(snapshotTime int64) {
 71	halt.AssertIsNotHaltedGovStaker()
 72
 73	previousRealm := runtime.PreviousRealm()
 74	caller := previousRealm.Address()
 75	access.AssertIsAdmin(caller)
 76
 77	assertIsValidSnapshotTime(snapshotTime)
 78	assertIsAvailableCleanupSnapshotTime(snapshotTime)
 79
 80	// Clean total delegation history
 81	gs.cleanTotalDelegationHistory(snapshotTime)
 82
 83	// Clean user delegation history
 84	gs.cleanUserDelegationHistory(snapshotTime)
 85
 86	chain.Emit(
 87		"CleanStakerDelegationSnapshot",
 88		"prevAddr", previousRealm.Address().String(),
 89		"prevRealm", previousRealm.PkgPath(),
 90		"snapshotTime", formatInt(snapshotTime),
 91	)
 92}
 93
 94// cleanTotalDelegationHistory removes total delegation history entries older than cutoff time.
 95// Keeps the most recent entry before cutoff to preserve state continuity.
 96func (gs *govStakerV1) cleanTotalDelegationHistory(cutoffTimestamp int64) {
 97	history := gs.store.GetTotalDelegationHistory()
 98
 99	toTimestamp := cutoffTimestamp
100	if cutoffTimestamp < math.MaxInt64 {
101		toTimestamp = safeAddInt64(toTimestamp, 1)
102	}
103
104	// First, find the most recent entry before cutoff to preserve state
105	var lastValue any
106
107	hasLastValue := false
108
109	history.ReverseIterate(0, toTimestamp, func(timestamp int64, value any) bool {
110		lastValue = value
111		hasLastValue = true
112
113		return true // stop after first (most recent)
114	})
115
116	// If there was a value before cutoff, set it at cutoff time to preserve continuity
117	if hasLastValue {
118		history.Set(cutoffTimestamp, lastValue)
119	}
120
121	history.Iterate(0, cutoffTimestamp, func(timestamp int64, _ any) bool {
122		history.Remove(timestamp)
123
124		return false // continue
125	})
126
127	if err := gs.store.SetTotalDelegationHistory(history); err != nil {
128		panic(err)
129	}
130}
131
132// cleanUserDelegationHistory removes user delegation history entries older than cutoff time.
133// Structure: address -> *UintTree[timestamp -> int64]
134// Keeps the most recent entry before cutoff for each user to preserve state continuity.
135func (gs *govStakerV1) cleanUserDelegationHistory(cutoffTimestamp int64) {
136	history := gs.store.GetUserDelegationHistory()
137
138	// Iterate over all users and clean each user's history
139	history.Iterate("", "", func(addrStr string, value any) bool {
140		userHistory := value.(*staker.UintTree)
141
142		toTimestamp := cutoffTimestamp
143		if cutoffTimestamp < math.MaxInt64 {
144			toTimestamp = safeAddInt64(toTimestamp, 1)
145		}
146
147		// Find the most recent entry before cutoff to preserve state
148		var lastValue any
149
150		hasLastValue := false
151
152		userHistory.ReverseIterate(0, toTimestamp, func(_ int64, val any) bool {
153			lastValue = val
154			hasLastValue = true
155
156			return true // stop after first (most recent)
157		})
158
159		// If there was a value before cutoff, set it at cutoff time to preserve continuity
160		if hasLastValue {
161			userHistory.Set(cutoffTimestamp, lastValue)
162		}
163
164		// Copy all entries at or after cutoff time
165		userHistory.Iterate(0, cutoffTimestamp, func(key int64, val any) bool {
166			userHistory.Remove(key)
167
168			return false // continue
169		})
170
171		// Only keep users with history entries
172		if userHistory.Size() > 0 {
173			history.Set(addrStr, userHistory)
174		}
175
176		return false // continue to next user
177	})
178
179	if err := gs.store.SetUserDelegationHistory(history); err != nil {
180		panic(err)
181	}
182}