How To Use Address Lookup Tables in Solana

Antematter
3 min readJul 16, 2022

--

Problem Statement

Solana, the famed permission-less blockchain, relies on a crafty transaction processing engine known as the Sealevel runtime. Sealevel allows hyper-parallelized processing of transactions submitted to the chain, in turn enabling a high TPS (Transactions Per Second) figure.

Parallel processing of transactions??? What??? Is that possible???

Yes. But if and only if each transaction specifies up front what state (read: accounts) they’ll read and write during execution. So far so good.

Oh but there’s a catch. Solana devs, in their desire for an even higher TPS, have limited the transaction size to the IPv6 MTU size. Small messages, fast messages.

Tough luck for us at Antematter though, we want a transaction composed of like a trillion instructions with a bazillion account inputs. After accounting for signatures and other transaction metadata, a transaction can at most only have 35 account inputs and still be under the MTU size of 1280 bytes.

Oh but fret not! I present to you …. *drum rolls* …. the Address Lookup Table Program. Long story short, you can create lookup tables on-chain and stuff them up with all your account inputs (at max 256). And then you’ll use a revised transaction format which utilizes u8 indices into the lookup table to specify the account inputs.

But…we were early to the party. The feature was not up yet. Even though the core was implemented, some accessory components were missing. And we were hankering after this feature.

So we decided to implement the missing @solana/web3.js SDK bindings to interact with the Address Lookup Table Program.

Web3 Instruction Bindings

The nerds in our group sat together and scoured through the codebase, understanding the conventions of the SDK. We were to implement bindings for the following instructions.

  • CreateLookupTable
  • FreezeLookupTable
  • ExtendLookupTable
  • DeactivateLookupTable
  • CloseLookupTable

The SDK already provides a TransactionInstruction class, which is just an aggregation of the programID (which is a rustic value of AddressLookupTab1e1111111111111111111111111), the keys and a raw data buffer. keys is just a list of objects with the following type

export type AccountMeta = {
/** An account’s public key */
pubkey: PublicKey;
/** True if an instruction requires a transaction signature matching `pubkey` */
isSigner: boolean;
/** True if the `pubkey` can be loaded as a read-write account. */
isWritable: boolean;
};

Inspecting the Rust program, one can easily determine the account inputs needed for each instruction. Hence, constructing the keys object for each instruction was trivial. Here’s what the keys look like for CreateLookupTable.

Each lookup table has an authority, which is essentially God over that lookup table. Only the authority can extend, freeze, close or deactivate a table. payer is used to fund the table creation. (or reallocation for ExtendLookupTable).

The raw data buffer is a sequence of u8 values encoding the instruction to be executed (a u32 value) and the data required precisely by that instruction. For instance, to create a lookup table, you need to provide a recentSlot (a u64) and a bumpSeed (a u8 value returned by PublicKey.findProgramAddressSync, used to derive the address of the lookup table).

No instruction data is needed for freezing, extending, deactivating or closing the lookup tables. Anyway, we coded away the bindings for each instruction, the instruction layouts, the decoding logic for each instruction etc.

NOTE: The Web3 bindings for Address Lookup Table program have been merged. You can find the pertinent documentation here.

Usage

The usage is congruous with how the rest of the Web3 SDK functions.

  • Create a Transaction instance.
  • Use AddressLookupTableProgram.CreateLookupTable or other static functions to create instances of TransactionInstruction.
  • Use the Transaction.add method to add instructions to the transaction instance.
  • Set the feePayer property on the transaction instance.
  • Use the sendAndConfirmTransaction method to submit the transaction.

A snippet from the tests we authored for the bindings is pasted below for reference.

Credits

All credits go to Soban Raza and Muhammad Saad, our valuable team members, for bringing on the big bren and making it possible.

Visit our website at : Antematter.io

References

--

--

Antematter

The world moves fast, your software should move faster. We develop and improve cutting-edge solutions using Blockchain & AI with maximum performance