fix: inconsistent tx message compilation accounting

This commit is contained in:
Trent Nelson 2020-07-01 20:26:36 -06:00 committed by Trent Nelson
parent 40800e257c
commit a8b1d71ae6
1 changed files with 66 additions and 22 deletions

View File

@ -210,9 +210,6 @@ export class Transaction {
let numReadonlySignedAccounts = 0;
let numReadonlyUnsignedAccounts = 0;
const accountKeys = this.signatures.map(({publicKey}) =>
publicKey.toString(),
);
const programIds: string[] = [];
const accountMetas: AccountMeta[] = [];
this.instructions.forEach(instruction => {
@ -226,6 +223,18 @@ export class Transaction {
}
});
// Append programID account metas
programIds.forEach(programId => {
accountMetas.push({
pubkey: new PublicKey(programId),
isSigner: false,
isWritable: false,
});
});
// Prefix accountMetas with feePayer here whenever that gets implemented
// Sort. Prioritizing first by signer, then by writable
accountMetas.sort(function (x, y) {
const checkSigner = x.isSigner === y.isSigner ? 0 : x.isSigner ? -1 : 1;
const checkWritable =
@ -233,31 +242,66 @@ export class Transaction {
return checkSigner || checkWritable;
});
accountMetas.forEach(({pubkey, isSigner, isWritable}) => {
const keyStr = pubkey.toString();
if (!accountKeys.includes(keyStr)) {
accountKeys.push(keyStr);
if (isSigner) {
this.signatures.push({
signature: null,
publicKey: pubkey,
// Cull duplicate account metas
const uniqueMetas: AccountMeta[] = [];
accountMetas.forEach(accountMeta => {
const pubkeyString = accountMeta.pubkey.toString();
const uniqueIndex = uniqueMetas.findIndex(x => {
return x.pubkey.toString() === pubkeyString;
});
if (!isWritable) {
if (uniqueIndex > -1) {
uniqueMetas[uniqueIndex].isWritable =
uniqueMetas[uniqueIndex].isWritable || accountMeta.isWritable;
} else {
uniqueMetas.push(accountMeta);
}
});
this.signatures.forEach(signature => {
const sigPubkeyString = signature.publicKey.toString();
const uniqueIndex = uniqueMetas.findIndex(x => {
return x.pubkey.toString() === sigPubkeyString;
});
if (uniqueIndex > -1) {
uniqueMetas[uniqueIndex].isSigner = true;
} else {
uniqueMetas.unshift({
pubkey: new PublicKey(sigPubkeyString),
isSigner: true,
isWritable: true,
});
}
});
// Split out signing from nonsigning keys and count readonlys
const signedKeys: string[] = [];
const unsignedKeys: string[] = [];
uniqueMetas.forEach(({pubkey, isSigner, isWritable}) => {
if (isSigner) {
// Promote the first signer to writable as it is the fee payer
const first = signedKeys.length === 0;
signedKeys.push(pubkey.toString());
if (!first && !isWritable) {
numReadonlySignedAccounts += 1;
}
} else if (!isWritable) {
} else {
unsignedKeys.push(pubkey.toString());
if (!isWritable) {
numReadonlyUnsignedAccounts += 1;
}
}
});
programIds.forEach(programId => {
if (!accountKeys.includes(programId)) {
accountKeys.push(programId);
numReadonlyUnsignedAccounts += 1;
}
// Initialize signature array, if needed
if (this.signatures.length === 0) {
const signatures: Array<SignaturePubkeyPair> = [];
signedKeys.forEach(pubkey => {
signatures.push({signature: null, publicKey: new PublicKey(pubkey)});
});
this.signatures = signatures;
}
const accountKeys = signedKeys.concat(unsignedKeys);
const instructions: CompiledInstruction[] = this.instructions.map(
instruction => {
const {data, programId} = instruction;