@solana/web3.js 1.41.8 → 1.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2344,9 +2344,17 @@ function assert (condition, message) {
2344
2344
  }
2345
2345
  }
2346
2346
 
2347
+ let TransactionStatus;
2347
2348
  /**
2348
2349
  * Default (empty) signature
2349
2350
  */
2351
+
2352
+ (function (TransactionStatus) {
2353
+ TransactionStatus[TransactionStatus["BLOCKHEIGHT_EXCEEDED"] = 0] = "BLOCKHEIGHT_EXCEEDED";
2354
+ TransactionStatus[TransactionStatus["PROCESSED"] = 1] = "PROCESSED";
2355
+ TransactionStatus[TransactionStatus["TIMED_OUT"] = 2] = "TIMED_OUT";
2356
+ })(TransactionStatus || (TransactionStatus = {}));
2357
+
2350
2358
  const DEFAULT_SIGNATURE = Buffer.alloc(SIGNATURE_LENGTH_IN_BYTES).fill(0);
2351
2359
  /**
2352
2360
  * Account metadata used to define instructions
@@ -2437,10 +2445,23 @@ class Transaction {
2437
2445
  this.feePayer = void 0;
2438
2446
  this.instructions = [];
2439
2447
  this.recentBlockhash = void 0;
2448
+ this.lastValidBlockHeight = void 0;
2440
2449
  this.nonceInfo = void 0;
2441
2450
  this._message = void 0;
2442
2451
  this._json = void 0;
2443
- opts && Object.assign(this, opts);
2452
+
2453
+ if (!opts) {
2454
+ return;
2455
+ } else if (Object.prototype.hasOwnProperty.call(opts, 'lastValidBlockHeight')) {
2456
+ const newOpts = opts;
2457
+ Object.assign(this, newOpts);
2458
+ this.recentBlockhash = newOpts.blockhash;
2459
+ this.lastValidBlockHeight = newOpts.lastValidBlockHeight;
2460
+ } else {
2461
+ const oldOpts = opts;
2462
+ Object.assign(this, oldOpts);
2463
+ this.recentBlockhash = oldOpts.recentBlockhash;
2464
+ }
2444
2465
  }
2445
2466
  /**
2446
2467
  * @internal
@@ -3050,7 +3071,11 @@ async function sendAndConfirmTransaction(connection, transaction, signers, optio
3050
3071
  maxRetries: options.maxRetries
3051
3072
  };
3052
3073
  const signature = await connection.sendTransaction(transaction, signers, sendOptions);
3053
- const status = (await connection.confirmTransaction(signature, options && options.commitment)).value;
3074
+ const status = transaction.recentBlockhash != null && transaction.lastValidBlockHeight != null ? (await connection.confirmTransaction({
3075
+ signature: signature,
3076
+ blockhash: transaction.recentBlockhash,
3077
+ lastValidBlockHeight: transaction.lastValidBlockHeight
3078
+ }, options && options.commitment)).value : (await connection.confirmTransaction(signature, options && options.commitment)).value;
3054
3079
 
3055
3080
  if (status.err) {
3056
3081
  throw new Error(`Transaction ${signature} failed (${JSON.stringify(status)})`);
@@ -4962,16 +4987,28 @@ const NUM_SLOTS_PER_SECOND = NUM_TICKS_PER_SECOND / DEFAULT_TICKS_PER_SLOT;
4962
4987
 
4963
4988
  const MS_PER_SLOT = 1000 / NUM_SLOTS_PER_SECOND;
4964
4989
 
4965
- function promiseTimeout(promise, timeoutMs) {
4966
- let timeoutId;
4967
- const timeoutPromise = new Promise(resolve => {
4968
- timeoutId = setTimeout(() => resolve(null), timeoutMs);
4969
- });
4970
- return Promise.race([promise, timeoutPromise]).then(result => {
4971
- clearTimeout(timeoutId);
4972
- return result;
4973
- });
4990
+ class TransactionExpiredBlockheightExceededError extends Error {
4991
+ constructor(signature) {
4992
+ super(`Signature ${signature} has expired: block height exceeded.`);
4993
+ this.signature = void 0;
4994
+ this.signature = signature;
4995
+ }
4996
+
4997
+ }
4998
+ Object.defineProperty(TransactionExpiredBlockheightExceededError.prototype, 'name', {
4999
+ value: 'TransactionExpiredBlockheightExceededError'
5000
+ });
5001
+ class TransactionExpiredTimeoutError extends Error {
5002
+ constructor(signature, timeoutSeconds) {
5003
+ super(`Transaction was not confirmed in ${timeoutSeconds.toFixed(2)} seconds. It is ` + 'unknown if it succeeded or failed. Check signature ' + `${signature} using the Solana Explorer or CLI tools.`);
5004
+ this.signature = void 0;
5005
+ this.signature = signature;
5006
+ }
5007
+
4974
5008
  }
5009
+ Object.defineProperty(TransactionExpiredTimeoutError.prototype, 'name', {
5010
+ value: 'TransactionExpiredTimeoutError'
5011
+ });
4975
5012
 
4976
5013
  function makeWebsocketUrl(endpoint) {
4977
5014
  let url = new URL(endpoint);
@@ -5960,7 +5997,7 @@ class Connection {
5960
5997
  this._disableBlockhashCaching = false;
5961
5998
  this._pollingBlockhash = false;
5962
5999
  this._blockhashInfo = {
5963
- recentBlockhash: null,
6000
+ latestBlockhash: null,
5964
6001
  lastFetch: 0,
5965
6002
  transactionSignatures: [],
5966
6003
  simulatedSignatures: []
@@ -6441,67 +6478,124 @@ class Connection {
6441
6478
 
6442
6479
  return res.result;
6443
6480
  }
6444
- /**
6445
- * Confirm the transaction identified by the specified signature.
6446
- */
6447
6481
 
6482
+ // eslint-disable-next-line no-dupe-class-members
6483
+ async confirmTransaction(strategy, commitment) {
6484
+ let rawSignature;
6485
+
6486
+ if (typeof strategy == 'string') {
6487
+ rawSignature = strategy;
6488
+ } else {
6489
+ const config = strategy;
6490
+ rawSignature = config.signature;
6491
+ }
6448
6492
 
6449
- async confirmTransaction(signature, commitment) {
6450
6493
  let decodedSignature;
6451
6494
 
6452
6495
  try {
6453
- decodedSignature = bs58.decode(signature);
6496
+ decodedSignature = bs58.decode(rawSignature);
6454
6497
  } catch (err) {
6455
- throw new Error('signature must be base58 encoded: ' + signature);
6498
+ throw new Error('signature must be base58 encoded: ' + rawSignature);
6456
6499
  }
6457
6500
 
6458
6501
  assert(decodedSignature.length === 64, 'signature has invalid length');
6459
- const start = Date.now();
6460
6502
  const subscriptionCommitment = commitment || this.commitment;
6503
+ let timeoutId;
6461
6504
  let subscriptionId;
6462
- let response = null;
6463
- const confirmPromise = new Promise((resolve, reject) => {
6505
+ let done = false;
6506
+ const confirmationPromise = new Promise((resolve, reject) => {
6464
6507
  try {
6465
- subscriptionId = this.onSignature(signature, (result, context) => {
6508
+ subscriptionId = this.onSignature(rawSignature, (result, context) => {
6466
6509
  subscriptionId = undefined;
6467
- response = {
6510
+ const response = {
6468
6511
  context,
6469
6512
  value: result
6470
6513
  };
6471
- resolve(null);
6514
+ done = true;
6515
+ resolve({
6516
+ __type: TransactionStatus.PROCESSED,
6517
+ response
6518
+ });
6472
6519
  }, subscriptionCommitment);
6473
6520
  } catch (err) {
6474
6521
  reject(err);
6475
6522
  }
6476
6523
  });
6477
- let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
6478
-
6479
- switch (subscriptionCommitment) {
6480
- case 'processed':
6481
- case 'recent':
6482
- case 'single':
6483
- case 'confirmed':
6484
- case 'singleGossip':
6485
- {
6486
- timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
6487
- break;
6524
+
6525
+ const checkBlockHeight = async () => {
6526
+ try {
6527
+ const blockHeight = await this.getBlockHeight(commitment);
6528
+ return blockHeight;
6529
+ } catch (_e) {
6530
+ return -1;
6531
+ }
6532
+ };
6533
+
6534
+ const expiryPromise = new Promise(resolve => {
6535
+ if (typeof strategy === 'string') {
6536
+ let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
6537
+
6538
+ switch (subscriptionCommitment) {
6539
+ case 'processed':
6540
+ case 'recent':
6541
+ case 'single':
6542
+ case 'confirmed':
6543
+ case 'singleGossip':
6544
+ {
6545
+ timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
6546
+ break;
6547
+ }
6488
6548
  }
6489
- }
6549
+
6550
+ timeoutId = setTimeout(() => resolve({
6551
+ __type: TransactionStatus.TIMED_OUT,
6552
+ timeoutMs
6553
+ }), timeoutMs);
6554
+ } else {
6555
+ let config = strategy;
6556
+
6557
+ (async () => {
6558
+ let currentBlockHeight = await checkBlockHeight();
6559
+ if (done) return;
6560
+
6561
+ while (currentBlockHeight <= config.lastValidBlockHeight) {
6562
+ await sleep(1000);
6563
+ if (done) return;
6564
+ currentBlockHeight = await checkBlockHeight();
6565
+ if (done) return;
6566
+ }
6567
+
6568
+ resolve({
6569
+ __type: TransactionStatus.BLOCKHEIGHT_EXCEEDED
6570
+ });
6571
+ })();
6572
+ }
6573
+ });
6574
+ let result;
6490
6575
 
6491
6576
  try {
6492
- await promiseTimeout(confirmPromise, timeoutMs);
6577
+ const outcome = await Promise.race([confirmationPromise, expiryPromise]);
6578
+
6579
+ switch (outcome.__type) {
6580
+ case TransactionStatus.BLOCKHEIGHT_EXCEEDED:
6581
+ throw new TransactionExpiredBlockheightExceededError(rawSignature);
6582
+
6583
+ case TransactionStatus.PROCESSED:
6584
+ result = outcome.response;
6585
+ break;
6586
+
6587
+ case TransactionStatus.TIMED_OUT:
6588
+ throw new TransactionExpiredTimeoutError(rawSignature, outcome.timeoutMs / 1000);
6589
+ }
6493
6590
  } finally {
6591
+ clearTimeout(timeoutId);
6592
+
6494
6593
  if (subscriptionId) {
6495
6594
  this.removeSignatureListener(subscriptionId);
6496
6595
  }
6497
6596
  }
6498
6597
 
6499
- if (response === null) {
6500
- const duration = (Date.now() - start) / 1000;
6501
- throw new Error(`Transaction was not confirmed in ${duration.toFixed(2)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`);
6502
- }
6503
-
6504
- return response;
6598
+ return result;
6505
6599
  }
6506
6600
  /**
6507
6601
  * Return the list of nodes that are currently participating in the cluster
@@ -6866,7 +6960,7 @@ class Connection {
6866
6960
  }
6867
6961
  /**
6868
6962
  * Fetch the latest blockhash from the cluster
6869
- * @return {Promise<{blockhash: Blockhash, lastValidBlockHeight: number}>}
6963
+ * @return {Promise<BlockhashWithExpiryBlockHeight>}
6870
6964
  */
6871
6965
 
6872
6966
 
@@ -6880,7 +6974,7 @@ class Connection {
6880
6974
  }
6881
6975
  /**
6882
6976
  * Fetch the latest blockhash from the cluster
6883
- * @return {Promise<{blockhash: Blockhash, lastValidBlockHeight: number}>}
6977
+ * @return {Promise<BlockhashWithExpiryBlockHeight>}
6884
6978
  */
6885
6979
 
6886
6980
 
@@ -7463,7 +7557,7 @@ class Connection {
7463
7557
  */
7464
7558
 
7465
7559
 
7466
- async _recentBlockhash(disableCache) {
7560
+ async _blockhashWithExpiryBlockHeight(disableCache) {
7467
7561
  if (!disableCache) {
7468
7562
  // Wait for polling to finish
7469
7563
  while (this._pollingBlockhash) {
@@ -7474,8 +7568,8 @@ class Connection {
7474
7568
 
7475
7569
  const expired = timeSinceFetch >= BLOCKHASH_CACHE_TIMEOUT_MS;
7476
7570
 
7477
- if (this._blockhashInfo.recentBlockhash !== null && !expired) {
7478
- return this._blockhashInfo.recentBlockhash;
7571
+ if (this._blockhashInfo.latestBlockhash !== null && !expired) {
7572
+ return this._blockhashInfo.latestBlockhash;
7479
7573
  }
7480
7574
  }
7481
7575
 
@@ -7491,20 +7585,20 @@ class Connection {
7491
7585
 
7492
7586
  try {
7493
7587
  const startTime = Date.now();
7588
+ const cachedLatestBlockhash = this._blockhashInfo.latestBlockhash;
7589
+ const cachedBlockhash = cachedLatestBlockhash ? cachedLatestBlockhash.blockhash : null;
7494
7590
 
7495
7591
  for (let i = 0; i < 50; i++) {
7496
- const {
7497
- blockhash
7498
- } = await this.getRecentBlockhash('finalized');
7592
+ const latestBlockhash = await this.getLatestBlockhash('finalized');
7499
7593
 
7500
- if (this._blockhashInfo.recentBlockhash != blockhash) {
7594
+ if (cachedBlockhash !== latestBlockhash.blockhash) {
7501
7595
  this._blockhashInfo = {
7502
- recentBlockhash: blockhash,
7596
+ latestBlockhash,
7503
7597
  lastFetch: Date.now(),
7504
7598
  transactionSignatures: [],
7505
7599
  simulatedSignatures: []
7506
7600
  };
7507
- return blockhash;
7601
+ return latestBlockhash;
7508
7602
  } // Sleep for approximately half a slot
7509
7603
 
7510
7604
 
@@ -7526,13 +7620,11 @@ class Connection {
7526
7620
 
7527
7621
  if (transactionOrMessage instanceof Transaction) {
7528
7622
  let originalTx = transactionOrMessage;
7529
- transaction = new Transaction({
7530
- recentBlockhash: originalTx.recentBlockhash,
7531
- nonceInfo: originalTx.nonceInfo,
7532
- feePayer: originalTx.feePayer,
7533
- signatures: [...originalTx.signatures]
7534
- });
7623
+ transaction = new Transaction();
7624
+ transaction.feePayer = originalTx.feePayer;
7535
7625
  transaction.instructions = transactionOrMessage.instructions;
7626
+ transaction.nonceInfo = originalTx.nonceInfo;
7627
+ transaction.signatures = originalTx.signatures;
7536
7628
  } else {
7537
7629
  transaction = Transaction.populate(transactionOrMessage); // HACK: this function relies on mutating the populated transaction
7538
7630
 
@@ -7545,7 +7637,9 @@ class Connection {
7545
7637
  let disableCache = this._disableBlockhashCaching;
7546
7638
 
7547
7639
  for (;;) {
7548
- transaction.recentBlockhash = await this._recentBlockhash(disableCache);
7640
+ const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
7641
+ transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
7642
+ transaction.recentBlockhash = latestBlockhash.blockhash;
7549
7643
  if (!signers) break;
7550
7644
  transaction.sign(...signers);
7551
7645
 
@@ -7629,7 +7723,9 @@ class Connection {
7629
7723
  let disableCache = this._disableBlockhashCaching;
7630
7724
 
7631
7725
  for (;;) {
7632
- transaction.recentBlockhash = await this._recentBlockhash(disableCache);
7726
+ const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
7727
+ transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
7728
+ transaction.recentBlockhash = latestBlockhash.blockhash;
7633
7729
  transaction.sign(...signers);
7634
7730
 
7635
7731
  if (!transaction.signature) {
@@ -7729,6 +7825,7 @@ class Connection {
7729
7825
 
7730
7826
 
7731
7827
  _wsOnError(err) {
7828
+ this._rpcWebSocketConnected = false;
7732
7829
  console.error('ws error:', err.message);
7733
7830
  }
7734
7831
  /**
@@ -7737,6 +7834,7 @@ class Connection {
7737
7834
 
7738
7835
 
7739
7836
  _wsOnClose(code) {
7837
+ this._rpcWebSocketConnected = false;
7740
7838
  this._rpcWebSocketGeneration++;
7741
7839
 
7742
7840
  if (this._rpcWebSocketHeartbeat) {
@@ -10068,16 +10166,36 @@ VoteProgram.space = 3731;
10068
10166
  *
10069
10167
  * @param {Connection} connection
10070
10168
  * @param {Buffer} rawTransaction
10169
+ * @param {BlockheightBasedTransactionConfimationStrategy} confirmationStrategy
10071
10170
  * @param {ConfirmOptions} [options]
10072
10171
  * @returns {Promise<TransactionSignature>}
10073
10172
  */
10074
- async function sendAndConfirmRawTransaction(connection, rawTransaction, options) {
10173
+
10174
+ /**
10175
+ * @deprecated Calling `sendAndConfirmRawTransaction()` without a `confirmationStrategy`
10176
+ * is no longer supported and will be removed in a future version.
10177
+ */
10178
+ // eslint-disable-next-line no-redeclare
10179
+ // eslint-disable-next-line no-redeclare
10180
+ async function sendAndConfirmRawTransaction(connection, rawTransaction, confirmationStrategyOrConfirmOptions, maybeConfirmOptions) {
10181
+ let confirmationStrategy;
10182
+ let options;
10183
+
10184
+ if (confirmationStrategyOrConfirmOptions && Object.prototype.hasOwnProperty.call(confirmationStrategyOrConfirmOptions, 'lastValidBlockHeight')) {
10185
+ confirmationStrategy = confirmationStrategyOrConfirmOptions;
10186
+ options = maybeConfirmOptions;
10187
+ } else {
10188
+ options = confirmationStrategyOrConfirmOptions;
10189
+ }
10190
+
10075
10191
  const sendOptions = options && {
10076
10192
  skipPreflight: options.skipPreflight,
10077
10193
  preflightCommitment: options.preflightCommitment || options.commitment
10078
10194
  };
10079
10195
  const signature = await connection.sendRawTransaction(rawTransaction, sendOptions);
10080
- const status = (await connection.confirmTransaction(signature, options && options.commitment)).value;
10196
+ const commitment = options && options.commitment;
10197
+ const confirmationPromise = confirmationStrategy ? connection.confirmTransaction(confirmationStrategy, commitment) : connection.confirmTransaction(signature, commitment);
10198
+ const status = (await confirmationPromise).value;
10081
10199
 
10082
10200
  if (status.err) {
10083
10201
  throw new Error(`Raw transaction ${signature} failed (${JSON.stringify(status)})`);
@@ -10124,5 +10242,5 @@ function clusterApiUrl(cluster, tls) {
10124
10242
 
10125
10243
  const LAMPORTS_PER_SOL = 1000000000;
10126
10244
 
10127
- export { Account, Authorized, BLOCKHASH_CACHE_TIMEOUT_MS, BPF_LOADER_DEPRECATED_PROGRAM_ID, BPF_LOADER_PROGRAM_ID, BpfLoader, COMPUTE_BUDGET_INSTRUCTION_LAYOUTS, ComputeBudgetInstruction, ComputeBudgetProgram, Connection, Ed25519Program, Enum, EpochSchedule, FeeCalculatorLayout, Keypair, LAMPORTS_PER_SOL, Loader, Lockup, MAX_SEED_LENGTH, Message, NONCE_ACCOUNT_LENGTH, NonceAccount, PACKET_DATA_SIZE, PublicKey, SIGNATURE_LENGTH_IN_BYTES, SOLANA_SCHEMA, STAKE_CONFIG_ID, STAKE_INSTRUCTION_LAYOUTS, SYSTEM_INSTRUCTION_LAYOUTS, SYSVAR_CLOCK_PUBKEY, SYSVAR_EPOCH_SCHEDULE_PUBKEY, SYSVAR_INSTRUCTIONS_PUBKEY, SYSVAR_RECENT_BLOCKHASHES_PUBKEY, SYSVAR_RENT_PUBKEY, SYSVAR_REWARDS_PUBKEY, SYSVAR_SLOT_HASHES_PUBKEY, SYSVAR_SLOT_HISTORY_PUBKEY, SYSVAR_STAKE_HISTORY_PUBKEY, Secp256k1Program, SendTransactionError, StakeAuthorizationLayout, StakeInstruction, StakeProgram, Struct, SystemInstruction, SystemProgram, Transaction, TransactionInstruction, VALIDATOR_INFO_KEY, VOTE_PROGRAM_ID, ValidatorInfo, VoteAccount, VoteAuthorizationLayout, VoteInit, VoteInstruction, VoteProgram, clusterApiUrl, sendAndConfirmRawTransaction, sendAndConfirmTransaction };
10245
+ export { Account, Authorized, BLOCKHASH_CACHE_TIMEOUT_MS, BPF_LOADER_DEPRECATED_PROGRAM_ID, BPF_LOADER_PROGRAM_ID, BpfLoader, COMPUTE_BUDGET_INSTRUCTION_LAYOUTS, ComputeBudgetInstruction, ComputeBudgetProgram, Connection, Ed25519Program, Enum, EpochSchedule, FeeCalculatorLayout, Keypair, LAMPORTS_PER_SOL, Loader, Lockup, MAX_SEED_LENGTH, Message, NONCE_ACCOUNT_LENGTH, NonceAccount, PACKET_DATA_SIZE, PublicKey, SIGNATURE_LENGTH_IN_BYTES, SOLANA_SCHEMA, STAKE_CONFIG_ID, STAKE_INSTRUCTION_LAYOUTS, SYSTEM_INSTRUCTION_LAYOUTS, SYSVAR_CLOCK_PUBKEY, SYSVAR_EPOCH_SCHEDULE_PUBKEY, SYSVAR_INSTRUCTIONS_PUBKEY, SYSVAR_RECENT_BLOCKHASHES_PUBKEY, SYSVAR_RENT_PUBKEY, SYSVAR_REWARDS_PUBKEY, SYSVAR_SLOT_HASHES_PUBKEY, SYSVAR_SLOT_HISTORY_PUBKEY, SYSVAR_STAKE_HISTORY_PUBKEY, Secp256k1Program, SendTransactionError, StakeAuthorizationLayout, StakeInstruction, StakeProgram, Struct, SystemInstruction, SystemProgram, Transaction, TransactionInstruction, TransactionStatus, VALIDATOR_INFO_KEY, VOTE_PROGRAM_ID, ValidatorInfo, VoteAccount, VoteAuthorizationLayout, VoteInit, VoteInstruction, VoteProgram, clusterApiUrl, sendAndConfirmRawTransaction, sendAndConfirmTransaction };
10128
10246
  //# sourceMappingURL=index.browser.esm.js.map