Skip to content

fix(hermes): share VAA bytes across a slot's proofs via Arc#3795

Open
sunoj wants to merge 1 commit into
pyth-network:mainfrom
sunoj:fix/hermes-vaa-arc-memory
Open

fix(hermes): share VAA bytes across a slot's proofs via Arc#3795
sunoj wants to merge 1 commit into
pyth-network:mainfrom
sunoj:fix/hermes-vaa-arc-memory

Conversation

@sunoj

@sunoj sunoj commented Jun 5, 2026

Copy link
Copy Markdown

Problem

construct_message_states_proofs clones the full VAA (~1–2 KB) into the WormholeMerkleMessageProof of every message in a slot. A slot contains all price feeds, so the same VAA is duplicated across ~6000 MessageStates per slot, and each is then retained cache-size-slots deep in the message cache.

With the default cache-size-slots = 1600, a Hermes instance subscribed to all Pythnet mainnet feeds grew to ~20 GB resident and kept climbing until OOM. The duplicated VAA bytes accounted for the bulk of that.

Fix

Store the VAA behind Arc<VaaBytes> so every proof in a slot shares a single allocation (a refcount bump instead of a deep copy). The bytes are cloned once, lazily, when building update data for an API response — a per-request read cost rather than a stored, per-feed cost.

No public API or wire-format change; WormholeMerkleMessageProof only derives Clone/PartialEq/Debug, all of which Arc<Vec<u8>> satisfies.

Measurement

On a node subscribed to all mainnet feeds, cache-size-slots = 1600:

build resident memory
before ~20 GB, still climbing
after plateaus at ~6.5 GB

(At cache-size-slots = 64 the patched build plateaus at ~2.4 GB and is stable.)

cargo build --release and the existing state::cache / wormhole_merkle tests pass.


Open in Devin Review

`construct_message_states_proofs` cloned the full VAA (~1-2KB) into the
`WormholeMerkleMessageProof` of every message in a slot. Since a slot
contains all price feeds (~6000), the same VAA was duplicated ~6000x per
slot and then retained `cache-size-slots` deep in the message cache.

With the default `cache-size-slots = 1600` this dominated memory: a Hermes
instance subscribed to all Pythnet feeds grew to ~20GB of resident memory
(and kept climbing). The VAA bytes accounted for the bulk of it.

Store the VAA behind an `Arc<VaaBytes>` so every proof in a slot shares a
single allocation (refcount bump instead of a deep copy). The bytes are
cloned once when building update data for an API response, which is a
read-time/per-request cost rather than a stored, per-feed cost.

Measured on a node subscribed to all mainnet feeds (cache-size-slots=1600):
resident memory plateaued at ~6.5GB instead of climbing past 20GB.
@vercel

vercel Bot commented Jun 5, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the Pyth Network Team on Vercel.

A member of the Team first needs to authorize it.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 1 additional finding in Devin Review.

Open in Devin Review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚩 Version bump not included for hermes server

Per REVIEW.md guidelines on version bumps: the hermes server crate (apps/hermes/server/Cargo.toml) version is 0.12.0 and was not bumped in this PR. Since this is an internal memory optimization with no public API change and no behavioral change, a version bump is arguably not required — but the reviewer should confirm whether the project's release process expects a bump for internal-only changes.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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.

1 participant