fix: non-deterministic writeable account order (#21724)

This commit is contained in:
Noah Prince 2022-01-07 23:38:58 -06:00 committed by GitHub
parent 6d76db1de5
commit 81a10e649f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 2 deletions

View File

@ -259,9 +259,12 @@ export class Transaction {
// Sort. Prioritizing first by signer, then by writable
accountMetas.sort(function (x, y) {
const pubkeySorting = x.pubkey
.toBase58()
.localeCompare(y.pubkey.toBase58());
const checkSigner = x.isSigner === y.isSigner ? 0 : x.isSigner ? -1 : 1;
const checkWritable =
x.isWritable === y.isWritable ? 0 : x.isWritable ? -1 : 1;
x.isWritable === y.isWritable ? pubkeySorting : x.isWritable ? -1 : 1;
return checkSigner || checkWritable;
});

View File

@ -5,7 +5,7 @@ import {expect} from 'chai';
import {Keypair} from '../src/keypair';
import {PublicKey} from '../src/publickey';
import {Transaction} from '../src/transaction';
import {Transaction, TransactionInstruction} from '../src/transaction';
import {StakeProgram} from '../src/stake-program';
import {SystemProgram} from '../src/system-program';
import {Message} from '../src/message';
@ -505,4 +505,86 @@ describe('Transaction', () => {
tx.addSignature(from.publicKey, toBuffer(signature));
expect(tx.verifySignatures()).to.be.true;
});
it('can serialize, deserialize, and reserialize with a partial signer', () => {
const signer = Keypair.generate();
const acc0Writable = Keypair.generate();
const acc1Writable = Keypair.generate();
const acc2Writable = Keypair.generate();
const t0 = new Transaction({
recentBlockhash: 'HZaTsZuhN1aaz9WuuimCFMyH7wJ5xiyMUHFCnZSMyguH',
feePayer: signer.publicKey,
});
t0.add(
new TransactionInstruction({
keys: [
{
pubkey: signer.publicKey,
isWritable: true,
isSigner: true,
},
{
pubkey: acc0Writable.publicKey,
isWritable: true,
isSigner: false,
},
],
programId: Keypair.generate().publicKey,
}),
);
t0.add(
new TransactionInstruction({
keys: [
{
pubkey: acc1Writable.publicKey,
isWritable: false,
isSigner: false,
},
],
programId: Keypair.generate().publicKey,
}),
);
t0.add(
new TransactionInstruction({
keys: [
{
pubkey: acc2Writable.publicKey,
isWritable: true,
isSigner: false,
},
],
programId: Keypair.generate().publicKey,
}),
);
t0.add(
new TransactionInstruction({
keys: [
{
pubkey: signer.publicKey,
isWritable: true,
isSigner: true,
},
{
pubkey: acc0Writable.publicKey,
isWritable: false,
isSigner: false,
},
{
pubkey: acc2Writable.publicKey,
isWritable: false,
isSigner: false,
},
{
pubkey: acc1Writable.publicKey,
isWritable: true,
isSigner: false,
},
],
programId: Keypair.generate().publicKey,
}),
);
t0.partialSign(signer);
const t1 = Transaction.from(t0.serialize());
t1.serialize();
});
});