Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

Commit

Permalink
Fix: use getBlockHeight and getLatestBlockhash to confirm transactions
Browse files Browse the repository at this point in the history
Co-authored-by: Marc Jaramillo <mnj.webdeveloper@gmail.com>
Co-authored-by: Stella Wang <stella01wang@gmail.com>
  • Loading branch information
marcnjaramillo and stellaw1 committed Apr 8, 2022
1 parent 24cc6c3 commit 9b5775f
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 16 deletions.
1 change: 1 addition & 0 deletions web3.js/src/last-valid-block-height.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type LastValidBlockHeight = number;
17 changes: 16 additions & 1 deletion web3.js/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ export type MessageArgs = {
recentBlockhash: Blockhash;
/** Instructions that will be executed in sequence and committed in one atomic transaction if all succeed. */
instructions: CompiledInstruction[];

latestBlockhash?: {
blockhash: Blockhash;
/** the last block chain can advance to before tx is declared expired */
lastValidBlockHeight: number;
};
};

const PUBKEY_LENGTH = 32;
Expand All @@ -64,6 +70,7 @@ export class Message {
accountKeys: PublicKey[];
recentBlockhash: Blockhash;
instructions: CompiledInstruction[];
lastValidBlockHeight?: number;

private indexToProgramIds: Map<number, PublicKey> = new Map<
number,
Expand All @@ -73,7 +80,15 @@ export class Message {
constructor(args: MessageArgs) {
this.header = args.header;
this.accountKeys = args.accountKeys.map(account => new PublicKey(account));
this.recentBlockhash = args.recentBlockhash;
if (
Object.prototype.hasOwnProperty.call(args, 'latestBlockhash') &&
args.latestBlockhash
) {
this.recentBlockhash = args.latestBlockhash.blockhash;
this.lastValidBlockHeight = args.latestBlockhash?.lastValidBlockHeight;
} else {
this.recentBlockhash = args.recentBlockhash;
}
this.instructions = args.instructions;
this.instructions.forEach(ix =>
this.indexToProgramIds.set(
Expand Down
47 changes: 42 additions & 5 deletions web3.js/src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {toBuffer} from './util/to-buffer';
import invariant from './util/assert';
import type {Signer} from './keypair';
import type {Blockhash} from './blockhash';
import {LastValidBlockHeight} from './last-valid-block-height';
import type {CompiledInstruction} from './message';

/**
Expand Down Expand Up @@ -104,18 +105,31 @@ export type SignaturePubkeyPair = {
};

/**
* List of Transaction object fields that may be initialized at construction
*
*/
export type TransactionCtorFields_DEPRECATED = Omit<
TransactionCtorFields,
'latestBlockhash'
> & {
recentBlockhash?: Blockhash;
};

/**
* List of Transaction object fields that may be initialized at construction
*/
export type TransactionCtorFields = {
/** A recent blockhash */
recentBlockhash?: Blockhash | null;
/** Optional nonce information used for offline nonce'd transactions */
nonceInfo?: NonceInformation | null;
/** The transaction fee payer */
feePayer?: PublicKey | null;
/** One or more signatures */
signatures?: Array<SignaturePubkeyPair>;
/** A recent blockhash */
latestBlockhash?: {
blockhash: Blockhash;
/** the last block chain can advance to before tx is declared expired */
lastValidBlockHeight: number;
};
};

/**
Expand Down Expand Up @@ -163,6 +177,11 @@ export class Transaction {
*/
recentBlockhash?: Blockhash;

/**
* the last block chain can advance to before tx is declared expired
* */
lastValidBlockHeight?: number;

/**
* Optional Nonce information. If populated, transaction will use a durable
* Nonce hash instead of a recentBlockhash. Must be populated by the caller
Expand All @@ -172,8 +191,22 @@ export class Transaction {
/**
* Construct an empty Transaction
*/
constructor(opts?: TransactionCtorFields) {
opts && Object.assign(this, opts);
constructor(opts?: TransactionCtorFields | TransactionCtorFields_DEPRECATED) {
if (!opts) {
return;
} else if (Object.prototype.hasOwnProperty.call(opts, 'recentBlockhash')) {
console.warn(
'Creating a Transaction with `recentBlockhash` is deprecated. ',
);
const oldOpts = opts as TransactionCtorFields_DEPRECATED;
Object.assign(this, oldOpts);
this.recentBlockhash = oldOpts.recentBlockhash;
} else {
const newOpts = opts as TransactionCtorFields;
Object.assign(this, newOpts);
this.lastValidBlockHeight = newOpts.latestBlockhash?.lastValidBlockHeight;
this.recentBlockhash = newOpts.latestBlockhash?.blockhash;
}
}

/**
Expand Down Expand Up @@ -680,9 +713,13 @@ export class Transaction {
static populate(
message: Message,
signatures: Array<string> = [],
lastValidBlockHeight?: LastValidBlockHeight,
): Transaction {
const transaction = new Transaction();
transaction.recentBlockhash = message.recentBlockhash;
if (lastValidBlockHeight) {
transaction.lastValidBlockHeight = lastValidBlockHeight;
}
if (message.header.numRequiredSignatures > 0) {
transaction.feePayer = message.accountKeys[0];
}
Expand Down
39 changes: 29 additions & 10 deletions web3.js/src/util/send-and-confirm-transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {Transaction} from '../transaction';
import type {ConfirmOptions} from '../connection';
import type {Signer} from '../keypair';
import type {TransactionSignature} from '../transaction';
import {sleep} from './sleep';

/**
* Sign, send and confirm a transaction.
Expand Down Expand Up @@ -33,18 +34,36 @@ export async function sendAndConfirmTransaction(
sendOptions,
);

const status = (
await connection.confirmTransaction(
signature,
options && options.commitment,
)
).value;
const status = await connection.getSignatureStatus(signature);

if (status.err) {
throw new Error(
`Transaction ${signature} failed (${JSON.stringify(status)})`,
const checkBlockHeight = async () => {
const blockHeight = await connection.getBlockHeight(
options && options.commitment,
);
}

if (blockHeight > transaction.lastValidBlockHeight!) {
throw new Error('Transaction has expired.');
} else {
if (status) {
return;
}
await sleep(500);
await checkBlockHeight();
}
};

await checkBlockHeight();
// const status = (
// await connection.confirmTransaction(
// signature,
// options && options.commitment,
// )
// ).value;

// if (status.err) {
// throw new Error(
// `Transaction ${signature} failed (${JSON.stringify(status)})`,
// );
// }
return signature;
}

0 comments on commit 9b5775f

Please sign in to comment.