Skip to content

fix(aptos): publish the version lower bound on the slot axis - #381

Merged
msizov merged 2 commits into
mainfrom
aptos-slot-lower-bound
Sep 22, 2026
Merged

msizov merged 2 commits into
mainfrom
aptos-slot-lower-bound

Conversation

@msizov

@msizov msizov commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

In production, aggregator_upstream_providers_lower_bounds{chain="aptos"} has only type="lower_block" — no version bound at all. The live upstream description confirms it:

lower_bounds:{k:-0  b:1.049154233e+09  key:LOWER_BOUND_BLOCK}
status:{current_height:1053521899  slot:7256690171  availability:AVAIL_OK}

That left dproxy rejecting every version-addressed aptos request (/v1/blocks/by_version, /v1/transactions/by_version) for having no bound data — 100% failure for a customer running Chainlink.

Cause

internal/protocol/upstream_state_events.go:35

if head := state.HeadData.Height; l.Data.Type != SlotBound && head > 0 && l.Data.Bound > int64(head) {
    return true // "Same" -> event skipped, bound never applied
}

The detector published oldest_ledger_version (~7.23e9) as StateBound, but HeadData.Height for aptos is the block height (~1.05e9). Ledger versions run ~7x ahead, so every publish was discarded as a bound above the head.

Fix

Publish it as SlotBound, the one type exempt from that comparison, and the axis the head already carries — GetLatestBlock passes the ledger version as the block's Slot (aptos_chain_specific.go). This matches how solana already splits its two bounds. BlockBound is unchanged.

Verification

Patched nodecore against a drpc aptos fullnode (fornex-eu-bcn-20), reading the chain-status stream a gRPC client sees:

chain=CHAIN_APTOS__MAINNET LOWER BOUNDS:
  type=LOWER_BOUND_SLOT  value=7230467940
  type=LOWER_BOUND_BLOCK value=1049154233
chain=CHAIN_APTOS__MAINNET HEAD height=1053709036 slot=7258271398

Both match the node's own oldest_ledger_version / oldest_block_height, and the slot bound now survives even though 7.23e9 ≫ the head height.

Notes

  • Ship together with drpcorg/dproxy#2958, which routes aptos version requests on the slot axis. Landing this first would break archive-backed aptos upstreams: they previously published StateBound=1, which is below the head and so survived the guard, and would publish nothing until the dproxy side lands. No such upstream exists today, but don't rely on that.
  • This removes the last sanity check on the bound — SlotBound is exempt from the above-head comparison and there is no slot-axis equivalent, while Same rejects decreases unless the value is exactly 1. A bogus oversized oldest_ledger_version would now stick until restart. Worth a HeadData.Slot guard as a follow-up.

The aptos detector published oldest_ledger_version as StateBound, but
HeadData.Height for aptos is the block height. Ledger versions run about
7x ahead of block heights, so LowerBoundUpstreamStateEvent.Same discarded
every publish as a bound above the head and the router never saw it.

In production this left aptos with only LOWER_BOUND_BLOCK, which made
dproxy reject every version-addressed request for having no bound data.

SlotBound is the one type exempt from that comparison, and slot is the
axis the head already carries for aptos (GetLatestBlock passes the ledger
version as the block's slot). BlockBound is unchanged.

Verified against a drpc aptos fullnode: the upstream now publishes
LOWER_BOUND_SLOT=7230467940 alongside LOWER_BOUND_BLOCK=1049154233,
matching the node's oldest_ledger_version and oldest_block_height.
@msizov
msizov merged commit 00c6a54 into main Sep 22, 2026
5 checks passed
@msizov
msizov deleted the aptos-slot-lower-bound branch September 22, 2026 11:13
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.

2 participants