feat: add transaction signature verification
This commit is contained in:
committed by
Michael Vines
parent
fd00571b0a
commit
d9a271742f
10
web3.js/flow-typed/tweetnacl.js
vendored
10
web3.js/flow-typed/tweetnacl.js
vendored
@ -8,13 +8,17 @@ declare module "tweetnacl" {
|
|||||||
(): KeyPair,
|
(): KeyPair,
|
||||||
fromSecretKey(secretKey: Buffer): KeyPair,
|
fromSecretKey(secretKey: Buffer): KeyPair,
|
||||||
fromSeed(seed: Uint8Array): 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: {
|
declare module.exports: {
|
||||||
sign: {
|
sign: {
|
||||||
keyPair: KeypairFunc;
|
keyPair: KeypairFunc;
|
||||||
detached(text: Buffer, secretKey: Buffer): Buffer;
|
detached: DetachedFunc;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,6 +411,22 @@ export class Transaction {
|
|||||||
this.signatures[index].signature = Buffer.from(signature);
|
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.
|
* Serialize the Transaction in the wire format.
|
||||||
*
|
*
|
||||||
|
81
web3.js/test/get-confirmed-block.test.js
Normal file
81
web3.js/test/get-confirmed-block.test.js
Normal 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);
|
||||||
|
});
|
Reference in New Issue
Block a user