feat: add transaction signature verification

This commit is contained in:
Tyera Eulberg 2020-03-03 13:39:00 -07:00 committed by Michael Vines
parent fd00571b0a
commit d9a271742f
3 changed files with 104 additions and 3 deletions

View File

@ -8,13 +8,17 @@ declare module "tweetnacl" {
(): KeyPair,
fromSecretKey(secretKey: Buffer): KeyPair,
fromSeed(seed: Uint8Array): KeyPair,
};
declare type DetachedFunc = {
(text: Buffer, secretKey: Buffer): Buffer,
verify(message: Buffer, signature: Buffer|null, publicKey: Buffer): bool,
};
declare module.exports: {
sign: {
keyPair: KeypairFunc;
detached(text: Buffer, secretKey: Buffer): Buffer;
detached: DetachedFunc;
};
};
}

View File

@ -411,6 +411,22 @@ export class Transaction {
this.signatures[index].signature = Buffer.from(signature);
}
/**
* Verify signatures of a complete, signed Transaction
*/
verifySignatures(): boolean {
let verified = true;
const signData = this._getSignData();
for (const {signature, publicKey} of this.signatures) {
if (
!nacl.sign.detached.verify(signData, signature, publicKey.toBuffer())
) {
verified = false;
}
}
return verified;
}
/**
* Serialize the Transaction in the wire format.
*

View File

@ -0,0 +1,81 @@
// @flow
import {Account} from '../src/account';
import {SystemProgram} from '../src/system-program';
import {Transaction} from '../src/transaction';
test('verify getConfirmedBlock', () => {
const account0 = new Account();
const account1 = new Account();
const account2 = new Account();
const account3 = new Account();
const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
// Create a couple signed transactions
const transfer0 = SystemProgram.transfer(
account0.publicKey,
account1.publicKey,
123,
);
const transaction0 = new Transaction({recentBlockhash}).add(transfer0);
transaction0.sign(account0);
const transfer1 = SystemProgram.transfer(
account2.publicKey,
account3.publicKey,
456,
);
let transaction1 = new Transaction({recentBlockhash}).add(transfer1);
transaction1.sign(account2);
// Build ConfirmedBlock, with dummy data for blockhashes, balances
const confirmedBlock = {
blockhash: recentBlockhash,
previousBlockhash: recentBlockhash,
transactions: [
{
transaction: transaction0,
meta: {
fee: 0,
preBalances: [100000, 100000, 1, 1, 1],
postBalances: [99877, 100123, 1, 1, 1],
status: {Ok: 'null'},
},
},
{
transaction: transaction1,
meta: {
fee: 0,
preBalances: [100000, 100000, 1, 1, 1],
postBalances: [99544, 100456, 1, 1, 1],
status: {Ok: 'null'},
},
},
],
rewards: [],
};
// Verify signatures in ConfirmedBlock
for (const transactionWithMeta of confirmedBlock.transactions) {
expect(transactionWithMeta.transaction.verifySignatures()).toBe(true);
}
const bogusSignature = {
signature: Buffer.alloc(64, 9),
publicKey: account2.publicKey,
};
transaction1.signatures[0] = bogusSignature;
let badConfirmedBlock = confirmedBlock;
badConfirmedBlock.transactions[1].transaction = transaction1;
// Verify signatures in ConfirmedBlock
const verifications = badConfirmedBlock.transactions.map(
transactionWithMeta => transactionWithMeta.transaction.verifySignatures(),
);
expect(
verifications.reduce(
(accumulator, currentValue) => accumulator && currentValue,
),
).toBe(false);
});