Skip to content

Commit 54d8445

Browse files
fix: skip compressing program addresses during transaction message compression (anza-xyz#951)
* fix: skip compressing program addresses during transaction message compression * refactor: Combined programAddress with other skip conditions in a single `if` block * refactor(transaction-messages): filter out program addresses when building eligible lookup addresses * test(transaction-messages): add case to ensure program addresses are not compressed when reused as accounts * Create two-items-decide.md --------- Co-authored-by: Steven Luscher <steveluscher@users.noreply.github.com>
1 parent 22f18d0 commit 54d8445

File tree

3 files changed

+51
-3
lines changed

3 files changed

+51
-3
lines changed

.changeset/two-items-decide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@solana/transaction-messages": patch
3+
---
4+
5+
`compressTransactionMessageUsingAddressLookupTables()` will no longer convert an account to a lookup table account, if the address of that account is used as a program address anywhere in the transaction.

packages/transaction-messages/src/__tests__/compress-transaction-message-test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,4 +578,43 @@ describe('compressTransactionMessageUsingAddressLookupTables', () => {
578578

579579
expect(result.instructions[0].accounts![0]).toBeFrozenObject();
580580
});
581+
582+
it('should not replace a program address that appears as an account in another instruction', () => {
583+
const programAddressA = 'programA' as Address;
584+
const programAddressB = 'programB' as Address;
585+
const lookupTableAddress = 'lookupTableAddress' as Address;
586+
587+
// Create a transaction and append two instructions sequentially
588+
const transactionMessage = appendTransactionMessageInstructions(
589+
[
590+
{
591+
accounts: [] as AccountMeta[],
592+
programAddress: programAddressA,
593+
},
594+
{
595+
accounts: [
596+
{
597+
address: programAddressA,
598+
role: AccountRole.READONLY,
599+
},
600+
] as AccountMeta[],
601+
programAddress: programAddressB,
602+
},
603+
],
604+
createTransactionMessage({ version: 0 }),
605+
);
606+
607+
const lookupTables: AddressesByLookupTableAddress = {
608+
[lookupTableAddress]: [programAddressA],
609+
};
610+
611+
const result = compressTransactionMessageUsingAddressLookupTables(transactionMessage, lookupTables);
612+
613+
// The first instruction’s programAddressA should be excluded from compression,
614+
// even though it exists in the lookup table.
615+
expect(result.instructions[1].accounts![0]).toStrictEqual({
616+
address: programAddressA,
617+
role: AccountRole.READONLY,
618+
});
619+
});
581620
});

packages/transaction-messages/src/compress-transaction-message.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,12 @@ export function compressTransactionMessageUsingAddressLookupTables<
9393
transactionMessage: TTransactionMessage,
9494
addressesByLookupTableAddress: AddressesByLookupTableAddress,
9595
): TTransactionMessage | WidenTransactionMessageInstructions<TTransactionMessage> {
96-
const lookupTableAddresses = new Set(Object.values(addressesByLookupTableAddress).flatMap(a => a));
97-
96+
const programAddresses = new Set(transactionMessage.instructions.map(ix => ix.programAddress));
97+
const eligibleLookupAddresses = new Set(
98+
Object.values(addressesByLookupTableAddress)
99+
.flatMap(a => a)
100+
.filter(address => !programAddresses.has(address)),
101+
);
98102
const newInstructions: Instruction[] = [];
99103
let updatedAnyInstructions = false;
100104
for (const instruction of transactionMessage.instructions) {
@@ -109,7 +113,7 @@ export function compressTransactionMessageUsingAddressLookupTables<
109113
// If the address is already a lookup, is not in any lookup tables, or is a signer role, return as-is
110114
if (
111115
'lookupTableAddress' in account ||
112-
!lookupTableAddresses.has(account.address) ||
116+
!eligibleLookupAddresses.has(account.address) ||
113117
isSignerRole(account.role)
114118
) {
115119
newAccounts.push(account);

0 commit comments

Comments
 (0)