Skip to content

Conversation

@tejasbadadare
Copy link
Contributor

@tejasbadadare tejasbadadare commented Apr 17, 2025

Summary

This PR fixes the "atomic" subscription update guarantee (ensuring all feeds in a subscription are updated together,) by using slots instead of timestamps for the validation.

Rationale

Use slots instead of timestamps

The main motivation for this is that timestamps (publishTime) can be misleading for validating an "atomic" subscription update as one or more assets might have closed markets, and will retain timestamps from their last trading period.
Thus, we use Pythnet slots for the atomicity validation since they are consistent across all assets regardless of market status.

  • We still use timestamps to validate the heartbeat update condition. We now take the max of all passed in timestamps (rather than the first) to ensure that if any of the feeds need updating, we perform the update.

Get the slots data from the Pyth parse functions

Pythnet slot number is available in the AccumulatorUpdate, but unfortunately Pyth.parsePriceFeedUpdates doesn't return them, just the Price[] structs. Thus, we add parsePriceFeedUpdatesWithSlots to the Pyth contract to expose slot information, and we consume this from the Scheduler contract.

  • All the updates in a single WhMerkle message have the same slot, so technically we could have returned a slots array of len(updateData) rather than len(priceFeedIds), but I chose to return parallel arrays of Price[] feeds and uint64[] slots to keep things coherent for the user, especially if len(updateData) > 1.
  • It turns out that parsePriceUpdatesInternal was already very close to the stack depth limit, and adding a slots array took it (quite far) over the line. Thus, this PR also contains significant refactors to that method to split it up into helper methods to reduce stack frame size. We also use structs to pass arguments instead of local variables for the same reason, since passing many arguments to functions takes up lots of stack space.

Misc

  • Expanded timestamp validity periods to 1 hour in the past and 10 seconds in the future and extracted them out to constants.

Note to reviewers

I'd start in Pyth.sol first with the changes to parsePriceFeedUpdatesInternal. Then Scheduler.sol since it is downstream. The rest is somewhat mechanical fallout. Some of the motivations behind the changes are nonobvious, see below for the rationale.

How has this been tested?

  • Current tests cover my changes
    • All existing tests were updated to work with slot-based validation
  • Added new tests
    • New tests were added to verify correct slot validation behavior and Pyth.parsePriceFeedUpdatesWithSlots behavior
  • Manually tested the code

@vercel
Copy link

vercel bot commented Apr 17, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
api-reference ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 17, 2025 5:03pm
5 Skipped Deployments
Name Status Preview Comments Updated (UTC)
component-library ⬜️ Ignored (Inspect) Visit Preview Apr 17, 2025 5:03pm
entropy-debugger ⬜️ Ignored (Inspect) Visit Preview Apr 17, 2025 5:03pm
insights ⬜️ Ignored (Inspect) Visit Preview Apr 17, 2025 5:03pm
proposals ⬜️ Ignored (Inspect) Visit Preview Apr 17, 2025 5:03pm
staking ⬜️ Ignored (Inspect) Visit Preview Apr 17, 2025 5:03pm

@tejasbadadare tejasbadadare changed the title Tb/pulse scheduler/validate update has matching slots fix(pulse-scheduler): validate atomic subscription updates using slots instead of timestamps Apr 17, 2025
Copy link
Collaborator

@ali-behjati ali-behjati left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This overall looks good to me. I like to know the code size and gas consumption changes before merging though. Another concern that I have is whether we should audit the Pyth contract now that's changed more.

@tejasbadadare
Copy link
Contributor Author

tejasbadadare commented Apr 17, 2025

This overall looks good to me. I like to know the code size and gas consumption changes before merging though. Another concern that I have is whether we should audit the Pyth contract now that's changed more.

Yeah good callouts. Will test both and get back to you. If we can get the Pyth contract included in the scope that would be great :) I will reach out.

@tejasbadadare
Copy link
Contributor Author

@ali-bahjati
Gas impact looks minimal (~1%), see this diff vs main

As for the contract size, we're juuust slim enough at 24,125 bytes :) See here

Will merge, lmk if you have any concerns

@tejasbadadare tejasbadadare merged commit 7642a39 into main Apr 17, 2025
10 checks passed
@tejasbadadare tejasbadadare deleted the tb/pulse-scheduler/validate-update-has-matching-slots branch April 17, 2025 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants