Skip to content

fix: always advance past 32-byte authority field in DeserializeLookupTable#197

Open
prasanna-anchorage wants to merge 1 commit into
blocto:mainfrom
anchorageoss:fix/address-lookup-table-authority-none-offset
Open

fix: always advance past 32-byte authority field in DeserializeLookupTable#197
prasanna-anchorage wants to merge 1 commit into
blocto:mainfrom
anchorageoss:fix/address-lookup-table-authority-none-offset

Conversation

@prasanna-anchorage
Copy link
Copy Markdown

Summary

DeserializeLookupTable incorrectly parses Address Lookup Tables when Authority is None. The on-chain format always writes 32 bytes for the Option<Pubkey> authority field (zeros when None), but the current code only advances the offset when the option flag is 1 (Some).

This causes:

  • An extra phantom address (SystemProgram / all zeros) at index 0
  • All real addresses shifted by +1 position
  • N+1 addresses parsed instead of N

Root Cause

// state.go:75-81
some := bool(data[current] == 1)
current += 1
if some {
    pubkey := common.PublicKeyFromBytes(data[current : current+32])
    current += 32  // ← only advances when Some
    addressLookupTable.Authority = &pubkey
}

When some == false, the 32-byte authority field is not skipped, so current is at offset 22 instead of 54. The subsequent padding read and address parsing all start from wrong offsets.

Fix

Unconditionally advance current by 32 after reading the option flag, matching the on-chain layout where LOOKUP_TABLE_META_SIZE is always 56 bytes:

some := bool(data[current] == 1)
current += 1
if some {
    pubkey := common.PublicKeyFromBytes(data[current : current+32])
    addressLookupTable.Authority = &pubkey
}
current += 32  // always advance past the 32-byte authority field

This is consistent with how other Go Solana SDKs handle this (e.g., gagliardetto/solana-go calls decoder.Discard(32) in the None branch).

Testing

  • Added authority_none test case to TestDeserializeLookupTable
  • All existing tests continue to pass
  • Verified against real mainnet ALT 7Vyx1y8vG9e9Q1MedmXpopRC6ZhVaZzGcvYh5Z3Cs75i (Orca Whirlpool, 254 entries, Authority=None)

Impact

Any V0 transaction using an ALT where Authority is None will have its addresses misresolved. This affects DeFi protocols (Orca, Jupiter, etc.) where ALTs commonly have no authority set.

…Table

The on-chain Solana Address Lookup Table format always writes 32 bytes
for the Option<Pubkey> authority field, regardless of whether it is
Some or None. When None, the 32 bytes are zeros.

Previously, DeserializeLookupTable only advanced the offset past the
32-byte authority pubkey when the option flag was 1 (Some). When the
flag was 0 (None), the offset was not advanced, causing all subsequent
fields (padding and addresses) to be read from the wrong position.

This resulted in:
- An extra phantom address (the zero-padded authority field) at index 0
- All real addresses shifted by +1 position
- One extra address parsed (N+1 instead of N)

The fix unconditionally advances the offset by 32 bytes after reading
the authority option flag, matching the on-chain layout where
LOOKUP_TABLE_META_SIZE is always 56 bytes.

Added a test case for Authority=None to prevent regression.
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