fix: TransactionMessage.decompile() now counts the correct number of unsigned, writable accounts (#28990)
* Test that `TransactionMessage.decompile()` can decompile a legacy `Message` * `TransactionMessage.decompile()` now correctly accounts for the number of writable unsigned accounts
This commit is contained in:
parent
b6dce6cf3b
commit
491d4f3331
|
@ -49,7 +49,9 @@ export class TransactionMessage {
|
||||||
assert(numWritableSignedAccounts > 0, 'Message header is invalid');
|
assert(numWritableSignedAccounts > 0, 'Message header is invalid');
|
||||||
|
|
||||||
const numWritableUnsignedAccounts =
|
const numWritableUnsignedAccounts =
|
||||||
message.staticAccountKeys.length - numReadonlyUnsignedAccounts;
|
message.staticAccountKeys.length -
|
||||||
|
numRequiredSignatures -
|
||||||
|
numReadonlyUnsignedAccounts;
|
||||||
assert(numWritableUnsignedAccounts >= 0, 'Message header is invalid');
|
assert(numWritableUnsignedAccounts >= 0, 'Message header is invalid');
|
||||||
|
|
||||||
const accountKeys = message.getAccountKeys(args);
|
const accountKeys = message.getAccountKeys(args);
|
||||||
|
|
|
@ -3,12 +3,13 @@ import {expect} from 'chai';
|
||||||
import {sha256} from '@noble/hashes/sha256';
|
import {sha256} from '@noble/hashes/sha256';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
Transaction,
|
||||||
TransactionInstruction,
|
TransactionInstruction,
|
||||||
TransactionMessage,
|
TransactionMessage,
|
||||||
} from '../../src/transaction';
|
} from '../../src/transaction';
|
||||||
import {PublicKey} from '../../src/publickey';
|
import {PublicKey} from '../../src/publickey';
|
||||||
import {AddressLookupTableAccount} from '../../src/programs';
|
import {AddressLookupTableAccount} from '../../src/programs';
|
||||||
import {MessageV0} from '../../src/message';
|
import {Message, MessageV0} from '../../src/message';
|
||||||
|
|
||||||
function createTestKeys(count: number): Array<PublicKey> {
|
function createTestKeys(count: number): Array<PublicKey> {
|
||||||
return new Array(count).fill(0).map(() => PublicKey.unique());
|
return new Array(count).fill(0).map(() => PublicKey.unique());
|
||||||
|
@ -31,7 +32,77 @@ function createTestLookupTable(
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('TransactionMessage', () => {
|
describe('TransactionMessage', () => {
|
||||||
it('decompile', () => {
|
it('decompiles a legacy message', () => {
|
||||||
|
const keys = createTestKeys(7);
|
||||||
|
const recentBlockhash = bs58.encode(sha256('test'));
|
||||||
|
const payerKey = keys[0];
|
||||||
|
const instructions = [
|
||||||
|
new TransactionInstruction({
|
||||||
|
programId: keys[5],
|
||||||
|
keys: [
|
||||||
|
{pubkey: keys[0], isSigner: true, isWritable: true},
|
||||||
|
{pubkey: keys[6], isSigner: false, isWritable: false},
|
||||||
|
{pubkey: keys[1], isSigner: false, isWritable: true},
|
||||||
|
{pubkey: keys[3], isSigner: false, isWritable: false},
|
||||||
|
{pubkey: keys[4], isSigner: false, isWritable: false},
|
||||||
|
{pubkey: keys[2], isSigner: false, isWritable: false},
|
||||||
|
],
|
||||||
|
data: Buffer.alloc(1),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const message = Message.compile({
|
||||||
|
instructions,
|
||||||
|
payerKey,
|
||||||
|
recentBlockhash,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(() => TransactionMessage.decompile(message)).not.to.throw(
|
||||||
|
'Failed to get account keys because address table lookups were not resolved',
|
||||||
|
);
|
||||||
|
|
||||||
|
const decompiledMessage = TransactionMessage.decompile(message);
|
||||||
|
|
||||||
|
expect(decompiledMessage.payerKey).to.eql(payerKey);
|
||||||
|
expect(decompiledMessage.recentBlockhash).to.eq(recentBlockhash);
|
||||||
|
expect(decompiledMessage.instructions).to.eql(instructions);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Regression test for https://github.com/solana-labs/solana/issues/28900
|
||||||
|
it('decompiles a legacy message the same way as the old API', () => {
|
||||||
|
const accountKeys = createTestKeys(7);
|
||||||
|
const legacyMessage = new Message({
|
||||||
|
header: {
|
||||||
|
numRequiredSignatures: 1,
|
||||||
|
numReadonlySignedAccounts: 0,
|
||||||
|
numReadonlyUnsignedAccounts: 5,
|
||||||
|
},
|
||||||
|
recentBlockhash: bs58.encode(sha256('test')),
|
||||||
|
accountKeys,
|
||||||
|
instructions: [
|
||||||
|
{
|
||||||
|
accounts: [0, 6, 1, 3, 4, 2],
|
||||||
|
data: '',
|
||||||
|
programIdIndex: 5,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const transactionFromLegacyAPI = Transaction.populate(legacyMessage);
|
||||||
|
const transactionMessage = TransactionMessage.decompile(legacyMessage);
|
||||||
|
|
||||||
|
expect(transactionMessage.payerKey).to.eql(
|
||||||
|
transactionFromLegacyAPI.feePayer,
|
||||||
|
);
|
||||||
|
expect(transactionMessage.instructions).to.eql(
|
||||||
|
transactionFromLegacyAPI.instructions,
|
||||||
|
);
|
||||||
|
expect(transactionMessage.recentBlockhash).to.eql(
|
||||||
|
transactionFromLegacyAPI.recentBlockhash,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('decompiles a V0 message', () => {
|
||||||
const keys = createTestKeys(7);
|
const keys = createTestKeys(7);
|
||||||
const recentBlockhash = bs58.encode(sha256('test'));
|
const recentBlockhash = bs58.encode(sha256('test'));
|
||||||
const payerKey = keys[0];
|
const payerKey = keys[0];
|
||||||
|
|
Loading…
Reference in New Issue