fix: add Nonce transaction construction option

This commit is contained in:
Tyera Eulberg 2020-01-06 18:12:04 -07:00 committed by Michael Vines
parent 600a295b11
commit bd0a9348f4
2 changed files with 73 additions and 0 deletions

View File

@ -96,9 +96,22 @@ type SignaturePubkeyPair = {|
*/
type TransactionCtorFields = {|
recentBlockhash?: Blockhash | null,
nonceInfo?: NonceInformation | null,
signatures?: Array<SignaturePubkeyPair>,
|};
/**
* NonceInformation to be used to build a Transaction.
*
* @typedef {Object} NonceInformation
* @property {nonce} The current Nonce blockhash
* @property {nonceInstruction} The NonceAdvance Instruction
*/
type NonceInformation = {|
nonce: Blockhash,
nonceInstruction: TransactionInstruction,
|};
/**
* Transaction class
*/
@ -129,6 +142,12 @@ export class Transaction {
*/
recentBlockhash: Blockhash | null;
/**
* Optional Nonce information. If populated, transaction will use a durable
* Nonce hash instead of a recentBlockhash. Must be populated by the caller
*/
nonceInfo: NonceInformation | null;
/**
* Construct an empty Transaction
*/
@ -164,6 +183,11 @@ export class Transaction {
* @private
*/
_getSignData(): Buffer {
const {nonceInfo} = this;
if (nonceInfo) {
this.recentBlockhash = nonceInfo.nonce;
this.instructions.unshift(nonceInfo.nonceInstruction);
}
const {recentBlockhash} = this;
if (!recentBlockhash) {
throw new Error('Transaction recentBlockhash required');

View File

@ -4,6 +4,7 @@ import nacl from 'tweetnacl';
import {Account} from '../src/account';
import {PublicKey} from '../src/publickey';
import {Transaction} from '../src/transaction';
import {StakeProgram} from '../src/stake-program';
import {SystemProgram} from '../src/system-program';
test('signPartial', () => {
@ -78,6 +79,54 @@ test('dedup signatures', () => {
orgTransaction.sign(account1);
});
test('use nonce', () => {
const account1 = new Account();
const account2 = new Account();
const nonceAccount = new Account();
const nonce = account2.publicKey.toBase58(); // Fake Nonce hash
const nonceInfo = {
nonce,
nonceInstruction: SystemProgram.nonceAdvance(
nonceAccount.publicKey,
account1.publicKey,
),
};
const transferTransaction = new Transaction({nonceInfo}).add(
SystemProgram.transfer(account1.publicKey, account2.publicKey, 123),
);
transferTransaction.sign(account1);
let expectedData = Buffer.alloc(4);
expectedData.writeInt32LE(4, 0);
expect(transferTransaction.instructions).toHaveLength(2);
expect(transferTransaction.instructions[0].programId).toEqual(
SystemProgram.programId,
);
expect(transferTransaction.instructions[0].data).toEqual(expectedData);
expect(transferTransaction.recentBlockhash).toEqual(nonce);
const stakeAccount = new Account();
const voteAccount = new Account();
const stakeTransaction = new Transaction({nonceInfo}).add(
StakeProgram.delegate(
stakeAccount.publicKey,
account1.publicKey,
voteAccount.publicKey,
),
);
stakeTransaction.sign(account1);
expect(stakeTransaction.instructions).toHaveLength(2);
expect(stakeTransaction.instructions[0].programId).toEqual(
SystemProgram.programId,
);
expect(stakeTransaction.instructions[0].data).toEqual(expectedData);
expect(stakeTransaction.recentBlockhash).toEqual(nonce);
});
test('parse wire format and serialize', () => {
const keypair = nacl.sign.keyPair.fromSeed(
Uint8Array.from(Array(32).fill(8)),