feat: allow setting explicit fee payer for transaction (#13129)

This commit is contained in:
Justin Starry
2020-10-25 09:59:38 +08:00
committed by GitHub
parent 0cc9c94c43
commit 6e13dbe206
7 changed files with 225 additions and 90 deletions

View File

@ -176,7 +176,7 @@ describe('load BPF Rust program', () => {
);
});
test('simulate transaction without signature verification', async () => {
test('deprecated - simulate transaction without signature verification', async () => {
const simulatedTransaction = new Transaction().add({
keys: [
{pubkey: payerAccount.publicKey, isSigner: true, isWritable: true},
@ -202,6 +202,33 @@ describe('load BPF Rust program', () => {
);
});
test('simulate transaction without signature verification', async () => {
const simulatedTransaction = new Transaction({
feePayer: payerAccount.publicKey,
}).add({
keys: [
{pubkey: payerAccount.publicKey, isSigner: true, isWritable: true},
],
programId: program.publicKey,
});
const {err, logs} = (
await connection.simulateTransaction(simulatedTransaction)
).value;
expect(err).toBeNull();
if (logs === null) {
expect(logs).not.toBeNull();
return;
}
expect(logs.length).toBeGreaterThanOrEqual(2);
expect(logs[0]).toEqual(`Call BPF program ${program.publicKey.toBase58()}`);
expect(logs[logs.length - 1]).toEqual(
`BPF program ${program.publicKey.toBase58()} success`,
);
});
test('simulate transaction with bad programId', async () => {
const simulatedTransaction = new Transaction().add({
keys: [

View File

@ -198,8 +198,8 @@ test('get program accounts', async () => {
},
]);
if (transaction.recentBlockhash === null) {
expect(transaction.recentBlockhash).not.toBeNull();
if (!transaction.recentBlockhash) {
expect(transaction.recentBlockhash).toBeTruthy();
return;
}

View File

@ -86,19 +86,22 @@ describe('compileMessage', () => {
expect(() => {
transaction.compileMessage();
}).toThrow('Transaction feePayer required');
transaction.setSigners(payer.publicKey);
expect(() => {
transaction.compileMessage();
}).toThrow('missing signer');
}).toThrow('Transaction fee payer required');
transaction.setSigners(payer.publicKey, new Account().publicKey);
expect(() => {
transaction.compileMessage();
}).toThrow('unknown signer');
// Expect compile to succeed with implicit fee payer from signers
transaction.setSigners(payer.publicKey);
transaction.compileMessage();
// Expect compile to succeed with fee payer and no signers
transaction.signatures = [];
transaction.feePayer = payer.publicKey;
transaction.compileMessage();
});
test('payer is writable', () => {
@ -260,6 +263,7 @@ test('transfer signatures', () => {
const newTransaction = new Transaction({
recentBlockhash: orgTransaction.recentBlockhash,
feePayer: orgTransaction.feePayer,
signatures: orgTransaction.signatures,
}).add(transfer1, transfer2);
@ -354,7 +358,10 @@ test('parse wire format and serialize', () => {
toPubkey: recipient,
lamports: 49,
});
const expectedTransaction = new Transaction({recentBlockhash}).add(transfer);
const expectedTransaction = new Transaction({
recentBlockhash,
feePayer: sender.publicKey,
}).add(transfer);
expectedTransaction.sign(sender);
const wireTransaction = Buffer.from(
@ -423,21 +430,38 @@ test('serialize unsigned transaction', () => {
expect(expectedTransaction.signatures.length).toBe(0);
expect(() => {
expectedTransaction.serialize();
}).toThrow(Error);
}).toThrow('Transaction fee payer required');
expect(() => {
expectedTransaction.serialize({verifySignatures: false});
}).toThrow(Error);
}).toThrow('Transaction fee payer required');
expect(() => {
expectedTransaction.serializeMessage();
}).toThrow('Transaction feePayer required');
}).toThrow('Transaction fee payer required');
expectedTransaction.feePayer = sender.publicKey;
// Transactions with missing signatures will fail sigverify.
expect(() => {
expectedTransaction.serialize();
}).toThrow('Signature verification failed');
// Serializing without signatures is allowed if sigverify disabled.
expectedTransaction.serialize({verifySignatures: false});
// Serializing the message is allowed when signature array has null signatures
expectedTransaction.serializeMessage();
expectedTransaction.feePayer = null;
expectedTransaction.setSigners(sender.publicKey);
expect(expectedTransaction.signatures.length).toBe(1);
// Signature array populated with null signatures fails.
// Transactions with missing signatures will fail sigverify.
expect(() => {
expectedTransaction.serialize();
}).toThrow(Error);
}).toThrow('Signature verification failed');
// Serializing without signatures is allowed if sigverify disabled.
expectedTransaction.serialize({verifySignatures: false});
// Serializing the message is allowed when signature array has null signatures
expectedTransaction.serializeMessage();
@ -468,7 +492,7 @@ test('serialize unsigned transaction', () => {
expect(expectedTransaction.signatures.length).toBe(1);
});
test('externally signed stake delegate', () => {
test('deprecated - externally signed stake delegate', () => {
const from_keypair = nacl.sign.keyPair.fromSeed(
Uint8Array.from(Array(32).fill(1)),
);
@ -489,3 +513,25 @@ test('externally signed stake delegate', () => {
tx.addSignature(from.publicKey, signature);
expect(tx.verifySignatures()).toBe(true);
});
test('externally signed stake delegate', () => {
const from_keypair = nacl.sign.keyPair.fromSeed(
Uint8Array.from(Array(32).fill(1)),
);
const authority = new Account(Buffer.from(from_keypair.secretKey));
const stake = new PublicKey(2);
const recentBlockhash = new PublicKey(3).toBuffer();
const vote = new PublicKey(4);
var tx = StakeProgram.delegate({
stakePubkey: stake,
authorizedPubkey: authority.publicKey,
votePubkey: vote,
});
const from = authority;
tx.recentBlockhash = bs58.encode(recentBlockhash);
tx.feePayer = from.publicKey;
const tx_bytes = tx.serializeMessage();
const signature = nacl.sign.detached(tx_bytes, from.secretKey);
tx.addSignature(from.publicKey, signature);
expect(tx.verifySignatures()).toBe(true);
});