Skip to content

Commit fac91f2

Browse files
committed
fix(x/oracle): update latest ids when source is removed from list
Signed-off-by: Artur Troian <troian@users.noreply.github.com>
1 parent 3069d99 commit fac91f2

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

x/oracle/keeper/abci.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ func (k *keeper) EndBlocker(ctx context.Context) error {
4242
twapDuration := params.TwapWindow
4343
twapStart := now.Add(-twapDuration)
4444

45+
// Build a set of currently-authorized source IDs from params.Sources.
46+
// Only these sources should participate in aggregation; latestPriceID
47+
// entries for removed sources are ignored.
48+
activeSourceIDs := make(map[uint32]bool, len(params.Sources))
49+
for _, source := range params.Sources {
50+
if id, err := k.sourceID.Get(sctx, source); err == nil {
51+
activeSourceIDs[id] = true
52+
}
53+
}
54+
4555
// Phase 1: walk latestPriceID to discover sources per denom and their latest timestamps.
4656
// latestByDenom maps DataID → list of (source, latestTimestamp) pairs.
4757
type sourceInfo struct {
@@ -52,6 +62,11 @@ func (k *keeper) EndBlocker(ctx context.Context) error {
5262
latestByDenom := make(map[types.DataID][]sourceInfo)
5363

5464
err = k.latestPriceID.Walk(sctx, nil, func(key types.PriceDataID, state types.PriceLatestDataState) (bool, error) {
65+
// Skip sources that are no longer in params.Sources.
66+
if !activeSourceIDs[key.Source] {
67+
return false, nil
68+
}
69+
5570
did := types.DataID{
5671
Denom: key.Denom,
5772
BaseDenom: key.BaseDenom,

x/oracle/keeper/keeper.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,13 @@ func (k *keeper) SetParams(ctx sdk.Context, p types.Params) error {
389389
return err
390390
}
391391

392+
// Determine which sources are being removed so we can clean up their
393+
// latestPriceID entries. Without this cleanup the EndBlocker would
394+
// continue to discover (and skip) stale entries every block, and — more
395+
// critically — the orphaned latestPriceID state prevents the aggregator
396+
// from recovering after a remove-then-re-add cycle.
397+
oldParams, oldErr := k.Params.Get(ctx)
398+
392399
if err := k.Params.Set(ctx, p); err != nil {
393400
return err
394401
}
@@ -423,6 +430,34 @@ func (k *keeper) SetParams(ctx sdk.Context, p types.Params) error {
423430
}
424431
}
425432
}
433+
434+
// Clean up latestPriceID entries for sources that were removed.
435+
// This prevents orphaned state from polluting the EndBlocker walk
436+
// and ensures a re-added source starts fresh.
437+
if oldErr == nil {
438+
newSourceSet := make(map[string]struct{}, len(p.Sources))
439+
for _, s := range p.Sources {
440+
newSourceSet[s] = struct{}{}
441+
}
442+
443+
for _, s := range oldParams.Sources {
444+
if _, ok := newSourceSet[s]; ok {
445+
continue
446+
}
447+
448+
// Source was removed — resolve its ID and delete latestPriceID entries.
449+
sID, err := k.sourceID.Get(ctx, s)
450+
if err != nil {
451+
// No sourceID mapping means no latestPriceID to clean up.
452+
continue
453+
}
454+
455+
if err := k.removeSourceLatestPriceIDs(ctx, sID); err != nil {
456+
return err
457+
}
458+
}
459+
}
460+
426461
// call hooks
427462
for _, hook := range k.hooks.onSetParams {
428463
hook(ctx, p)
@@ -431,6 +466,31 @@ func (k *keeper) SetParams(ctx sdk.Context, p types.Params) error {
431466
return nil
432467
}
433468

469+
// removeSourceLatestPriceIDs deletes all latestPriceID entries for the given
470+
// source ID. This is called when a source is removed from params.Sources so
471+
// that the EndBlocker no longer discovers stale entries
472+
func (k *keeper) removeSourceLatestPriceIDs(ctx sdk.Context, sourceID uint32) error {
473+
var toDelete []types.PriceDataID
474+
475+
err := k.latestPriceID.Walk(ctx, nil, func(key types.PriceDataID, _ types.PriceLatestDataState) (bool, error) {
476+
if key.Source == sourceID {
477+
toDelete = append(toDelete, key)
478+
}
479+
return false, nil
480+
})
481+
if err != nil {
482+
return err
483+
}
484+
485+
for _, key := range toDelete {
486+
if err := k.latestPriceID.Remove(ctx, key); err != nil {
487+
return err
488+
}
489+
}
490+
491+
return nil
492+
}
493+
434494
// GetParams returns the current x/oracle module parameters.
435495
func (k *keeper) GetParams(ctx sdk.Context) (types.Params, error) {
436496
return k.Params.Get(ctx)

0 commit comments

Comments
 (0)