@solana/web3.js 1.40.1 → 1.41.2
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.
- package/lib/index.browser.cjs.js +648 -388
- package/lib/index.browser.cjs.js.map +1 -1
- package/lib/index.browser.esm.js +646 -388
- package/lib/index.browser.esm.js.map +1 -1
- package/lib/index.cjs.js +648 -388
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +96 -30
- package/lib/index.esm.js +646 -388
- package/lib/index.esm.js.map +1 -1
- package/lib/index.iife.js +680 -629
- package/lib/index.iife.js.map +1 -1
- package/lib/index.iife.min.js +2 -24
- package/lib/index.iife.min.js.map +1 -1
- package/package.json +11 -8
- package/src/compute-budget.ts +189 -0
- package/src/connection.ts +657 -486
- package/src/index.ts +1 -0
- package/src/loader.ts +2 -1
- package/src/message.ts +1 -1
- package/src/transaction-constants.ts +10 -0
- package/src/transaction.ts +7 -16
package/lib/index.cjs.js
CHANGED
|
@@ -2120,6 +2120,16 @@ class Account {
|
|
|
2120
2120
|
|
|
2121
2121
|
const BPF_LOADER_DEPRECATED_PROGRAM_ID = new PublicKey('BPFLoader1111111111111111111111111111111111');
|
|
2122
2122
|
|
|
2123
|
+
/**
|
|
2124
|
+
* Maximum over-the-wire size of a Transaction
|
|
2125
|
+
*
|
|
2126
|
+
* 1280 is IPv6 minimum MTU
|
|
2127
|
+
* 40 bytes is the size of the IPv6 header
|
|
2128
|
+
* 8 bytes is the size of the fragment header
|
|
2129
|
+
*/
|
|
2130
|
+
const PACKET_DATA_SIZE = 1280 - 40 - 8;
|
|
2131
|
+
const SIGNATURE_LENGTH_IN_BYTES = 64;
|
|
2132
|
+
|
|
2123
2133
|
/**
|
|
2124
2134
|
* Layout for a public key
|
|
2125
2135
|
*/
|
|
@@ -2379,20 +2389,8 @@ function assert (condition, message) {
|
|
|
2379
2389
|
|
|
2380
2390
|
/**
|
|
2381
2391
|
* Default (empty) signature
|
|
2382
|
-
*
|
|
2383
|
-
* Signatures are 64 bytes in length
|
|
2384
|
-
*/
|
|
2385
|
-
const DEFAULT_SIGNATURE = buffer.Buffer.alloc(64).fill(0);
|
|
2386
|
-
/**
|
|
2387
|
-
* Maximum over-the-wire size of a Transaction
|
|
2388
|
-
*
|
|
2389
|
-
* 1280 is IPv6 minimum MTU
|
|
2390
|
-
* 40 bytes is the size of the IPv6 header
|
|
2391
|
-
* 8 bytes is the size of the fragment header
|
|
2392
2392
|
*/
|
|
2393
|
-
|
|
2394
|
-
const PACKET_DATA_SIZE = 1280 - 40 - 8;
|
|
2395
|
-
const SIGNATURE_LENGTH = 64;
|
|
2393
|
+
const DEFAULT_SIGNATURE = buffer.Buffer.alloc(SIGNATURE_LENGTH_IN_BYTES).fill(0);
|
|
2396
2394
|
/**
|
|
2397
2395
|
* Account metadata used to define instructions
|
|
2398
2396
|
*/
|
|
@@ -3022,8 +3020,8 @@ class Transaction {
|
|
|
3022
3020
|
let signatures = [];
|
|
3023
3021
|
|
|
3024
3022
|
for (let i = 0; i < signatureCount; i++) {
|
|
3025
|
-
const signature = byteArray.slice(0,
|
|
3026
|
-
byteArray = byteArray.slice(
|
|
3023
|
+
const signature = byteArray.slice(0, SIGNATURE_LENGTH_IN_BYTES);
|
|
3024
|
+
byteArray = byteArray.slice(SIGNATURE_LENGTH_IN_BYTES);
|
|
3027
3025
|
signatures.push(bs58__default["default"].encode(buffer.Buffer.from(signature)));
|
|
3028
3026
|
}
|
|
3029
3027
|
|
|
@@ -3912,11 +3910,11 @@ class SystemProgram {
|
|
|
3912
3910
|
}
|
|
3913
3911
|
SystemProgram.programId = new PublicKey('11111111111111111111111111111111');
|
|
3914
3912
|
|
|
3915
|
-
// Keep program chunks under PACKET_DATA_SIZE, leaving enough room for the
|
|
3916
3913
|
// rest of the Transaction fields
|
|
3917
3914
|
//
|
|
3918
3915
|
// TODO: replace 300 with a proper constant for the size of the other
|
|
3919
3916
|
// Transaction fields
|
|
3917
|
+
|
|
3920
3918
|
const CHUNK_SIZE = PACKET_DATA_SIZE - 300;
|
|
3921
3919
|
/**
|
|
3922
3920
|
* Program loader interface
|
|
@@ -4116,6 +4114,212 @@ class BpfLoader {
|
|
|
4116
4114
|
|
|
4117
4115
|
}
|
|
4118
4116
|
|
|
4117
|
+
/**
|
|
4118
|
+
* Compute Budget Instruction class
|
|
4119
|
+
*/
|
|
4120
|
+
|
|
4121
|
+
class ComputeBudgetInstruction {
|
|
4122
|
+
/**
|
|
4123
|
+
* @internal
|
|
4124
|
+
*/
|
|
4125
|
+
constructor() {}
|
|
4126
|
+
/**
|
|
4127
|
+
* Decode a compute budget instruction and retrieve the instruction type.
|
|
4128
|
+
*/
|
|
4129
|
+
|
|
4130
|
+
|
|
4131
|
+
static decodeInstructionType(instruction) {
|
|
4132
|
+
this.checkProgramId(instruction.programId);
|
|
4133
|
+
const instructionTypeLayout = BufferLayout__namespace.u8('instruction');
|
|
4134
|
+
const typeIndex = instructionTypeLayout.decode(instruction.data);
|
|
4135
|
+
let type;
|
|
4136
|
+
|
|
4137
|
+
for (const [ixType, layout] of Object.entries(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS)) {
|
|
4138
|
+
if (layout.index == typeIndex) {
|
|
4139
|
+
type = ixType;
|
|
4140
|
+
break;
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
if (!type) {
|
|
4145
|
+
throw new Error('Instruction type incorrect; not a ComputeBudgetInstruction');
|
|
4146
|
+
}
|
|
4147
|
+
|
|
4148
|
+
return type;
|
|
4149
|
+
}
|
|
4150
|
+
/**
|
|
4151
|
+
* Decode request units compute budget instruction and retrieve the instruction params.
|
|
4152
|
+
*/
|
|
4153
|
+
|
|
4154
|
+
|
|
4155
|
+
static decodeRequestUnits(instruction) {
|
|
4156
|
+
this.checkProgramId(instruction.programId);
|
|
4157
|
+
const {
|
|
4158
|
+
units,
|
|
4159
|
+
additionalFee
|
|
4160
|
+
} = decodeData(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestUnits, instruction.data);
|
|
4161
|
+
return {
|
|
4162
|
+
units,
|
|
4163
|
+
additionalFee
|
|
4164
|
+
};
|
|
4165
|
+
}
|
|
4166
|
+
/**
|
|
4167
|
+
* Decode request heap frame compute budget instruction and retrieve the instruction params.
|
|
4168
|
+
*/
|
|
4169
|
+
|
|
4170
|
+
|
|
4171
|
+
static decodeRequestHeapFrame(instruction) {
|
|
4172
|
+
this.checkProgramId(instruction.programId);
|
|
4173
|
+
const {
|
|
4174
|
+
bytes
|
|
4175
|
+
} = decodeData(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestHeapFrame, instruction.data);
|
|
4176
|
+
return {
|
|
4177
|
+
bytes
|
|
4178
|
+
};
|
|
4179
|
+
}
|
|
4180
|
+
/**
|
|
4181
|
+
* @internal
|
|
4182
|
+
*/
|
|
4183
|
+
|
|
4184
|
+
|
|
4185
|
+
static checkProgramId(programId) {
|
|
4186
|
+
if (!programId.equals(ComputeBudgetProgram.programId)) {
|
|
4187
|
+
throw new Error('invalid instruction; programId is not ComputeBudgetProgram');
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4190
|
+
|
|
4191
|
+
}
|
|
4192
|
+
/**
|
|
4193
|
+
* An enumeration of valid ComputeBudgetInstructionType's
|
|
4194
|
+
*/
|
|
4195
|
+
|
|
4196
|
+
/**
|
|
4197
|
+
* An enumeration of valid ComputeBudget InstructionType's
|
|
4198
|
+
* @internal
|
|
4199
|
+
*/
|
|
4200
|
+
const COMPUTE_BUDGET_INSTRUCTION_LAYOUTS = Object.freeze({
|
|
4201
|
+
RequestUnits: {
|
|
4202
|
+
index: 0,
|
|
4203
|
+
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u8('instruction'), BufferLayout__namespace.u32('units'), BufferLayout__namespace.u32('additionalFee')])
|
|
4204
|
+
},
|
|
4205
|
+
RequestHeapFrame: {
|
|
4206
|
+
index: 1,
|
|
4207
|
+
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u8('instruction'), BufferLayout__namespace.u32('bytes')])
|
|
4208
|
+
}
|
|
4209
|
+
});
|
|
4210
|
+
/**
|
|
4211
|
+
* Factory class for transaction instructions to interact with the Compute Budget program
|
|
4212
|
+
*/
|
|
4213
|
+
|
|
4214
|
+
class ComputeBudgetProgram {
|
|
4215
|
+
/**
|
|
4216
|
+
* @internal
|
|
4217
|
+
*/
|
|
4218
|
+
constructor() {}
|
|
4219
|
+
/**
|
|
4220
|
+
* Public key that identifies the Compute Budget program
|
|
4221
|
+
*/
|
|
4222
|
+
|
|
4223
|
+
|
|
4224
|
+
static requestUnits(params) {
|
|
4225
|
+
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestUnits;
|
|
4226
|
+
const data = encodeData(type, params);
|
|
4227
|
+
return new TransactionInstruction({
|
|
4228
|
+
keys: [],
|
|
4229
|
+
programId: this.programId,
|
|
4230
|
+
data
|
|
4231
|
+
});
|
|
4232
|
+
}
|
|
4233
|
+
|
|
4234
|
+
static requestHeapFrame(params) {
|
|
4235
|
+
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestHeapFrame;
|
|
4236
|
+
const data = encodeData(type, params);
|
|
4237
|
+
return new TransactionInstruction({
|
|
4238
|
+
keys: [],
|
|
4239
|
+
programId: this.programId,
|
|
4240
|
+
data
|
|
4241
|
+
});
|
|
4242
|
+
}
|
|
4243
|
+
|
|
4244
|
+
}
|
|
4245
|
+
ComputeBudgetProgram.programId = new PublicKey('ComputeBudget111111111111111111111111111111');
|
|
4246
|
+
|
|
4247
|
+
var objToString = Object.prototype.toString;
|
|
4248
|
+
var objKeys = Object.keys || function(obj) {
|
|
4249
|
+
var keys = [];
|
|
4250
|
+
for (var name in obj) {
|
|
4251
|
+
keys.push(name);
|
|
4252
|
+
}
|
|
4253
|
+
return keys;
|
|
4254
|
+
};
|
|
4255
|
+
|
|
4256
|
+
function stringify(val, isArrayProp) {
|
|
4257
|
+
var i, max, str, keys, key, propVal, toStr;
|
|
4258
|
+
if (val === true) {
|
|
4259
|
+
return "true";
|
|
4260
|
+
}
|
|
4261
|
+
if (val === false) {
|
|
4262
|
+
return "false";
|
|
4263
|
+
}
|
|
4264
|
+
switch (typeof val) {
|
|
4265
|
+
case "object":
|
|
4266
|
+
if (val === null) {
|
|
4267
|
+
return null;
|
|
4268
|
+
} else if (val.toJSON && typeof val.toJSON === "function") {
|
|
4269
|
+
return stringify(val.toJSON(), isArrayProp);
|
|
4270
|
+
} else {
|
|
4271
|
+
toStr = objToString.call(val);
|
|
4272
|
+
if (toStr === "[object Array]") {
|
|
4273
|
+
str = '[';
|
|
4274
|
+
max = val.length - 1;
|
|
4275
|
+
for(i = 0; i < max; i++) {
|
|
4276
|
+
str += stringify(val[i], true) + ',';
|
|
4277
|
+
}
|
|
4278
|
+
if (max > -1) {
|
|
4279
|
+
str += stringify(val[i], true);
|
|
4280
|
+
}
|
|
4281
|
+
return str + ']';
|
|
4282
|
+
} else if (toStr === "[object Object]") {
|
|
4283
|
+
// only object is left
|
|
4284
|
+
keys = objKeys(val).sort();
|
|
4285
|
+
max = keys.length;
|
|
4286
|
+
str = "";
|
|
4287
|
+
i = 0;
|
|
4288
|
+
while (i < max) {
|
|
4289
|
+
key = keys[i];
|
|
4290
|
+
propVal = stringify(val[key], false);
|
|
4291
|
+
if (propVal !== undefined) {
|
|
4292
|
+
if (str) {
|
|
4293
|
+
str += ',';
|
|
4294
|
+
}
|
|
4295
|
+
str += JSON.stringify(key) + ':' + propVal;
|
|
4296
|
+
}
|
|
4297
|
+
i++;
|
|
4298
|
+
}
|
|
4299
|
+
return '{' + str + '}';
|
|
4300
|
+
} else {
|
|
4301
|
+
return JSON.stringify(val);
|
|
4302
|
+
}
|
|
4303
|
+
}
|
|
4304
|
+
case "function":
|
|
4305
|
+
case "undefined":
|
|
4306
|
+
return isArrayProp ? null : undefined;
|
|
4307
|
+
case "string":
|
|
4308
|
+
return JSON.stringify(val);
|
|
4309
|
+
default:
|
|
4310
|
+
return isFinite(val) ? val : null;
|
|
4311
|
+
}
|
|
4312
|
+
}
|
|
4313
|
+
|
|
4314
|
+
var fastStableStringify = function(val) {
|
|
4315
|
+
var returnVal = stringify(val, false);
|
|
4316
|
+
if (returnVal !== undefined) {
|
|
4317
|
+
return ''+ returnVal;
|
|
4318
|
+
}
|
|
4319
|
+
};
|
|
4320
|
+
|
|
4321
|
+
var fastStableStringify$1 = fastStableStringify;
|
|
4322
|
+
|
|
4119
4323
|
const DESTROY_TIMEOUT_MS = 5000;
|
|
4120
4324
|
class AgentManager {
|
|
4121
4325
|
static _newAgent(useHttps) {
|
|
@@ -4331,6 +4535,12 @@ const BufferFromRawAccountData = superstruct.coerce(superstruct.instance(buffer.
|
|
|
4331
4535
|
*/
|
|
4332
4536
|
|
|
4333
4537
|
const BLOCKHASH_CACHE_TIMEOUT_MS = 30 * 1000;
|
|
4538
|
+
/**
|
|
4539
|
+
* HACK.
|
|
4540
|
+
* Copied from rpc-websockets/dist/lib/client.
|
|
4541
|
+
* Otherwise, `yarn build` fails with:
|
|
4542
|
+
* https://gist.github.com/steveluscher/c057eca81d479ef705cdb53162f9971d
|
|
4543
|
+
*/
|
|
4334
4544
|
|
|
4335
4545
|
/**
|
|
4336
4546
|
* @internal
|
|
@@ -5205,14 +5415,9 @@ const LogsNotificationResult = superstruct.type({
|
|
|
5205
5415
|
* Filter for log subscriptions.
|
|
5206
5416
|
*/
|
|
5207
5417
|
|
|
5208
|
-
function createSubscriptionWarningMessage(id, label) {
|
|
5209
|
-
return 'Ignored unsubscribe request because an active subscription ' + `with id \`${id}\` for '${label}' events could not be found.`;
|
|
5210
|
-
}
|
|
5211
5418
|
/**
|
|
5212
5419
|
* A connection to a fullnode JSON RPC endpoint
|
|
5213
5420
|
*/
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
5421
|
class Connection {
|
|
5217
5422
|
/** @internal */
|
|
5218
5423
|
|
|
@@ -5236,21 +5441,13 @@ class Connection {
|
|
|
5236
5441
|
|
|
5237
5442
|
/** @internal */
|
|
5238
5443
|
|
|
5239
|
-
/** @internal
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
/** @internal */
|
|
5248
|
-
|
|
5249
|
-
/** @internal */
|
|
5250
|
-
|
|
5251
|
-
/** @internal */
|
|
5252
|
-
|
|
5253
|
-
/** @internal */
|
|
5444
|
+
/** @internal
|
|
5445
|
+
* A number that we increment every time an active connection closes.
|
|
5446
|
+
* Used to determine whether the same socket connection that was open
|
|
5447
|
+
* when an async operation started is the same one that's active when
|
|
5448
|
+
* its continuation fires.
|
|
5449
|
+
*
|
|
5450
|
+
*/
|
|
5254
5451
|
|
|
5255
5452
|
/** @internal */
|
|
5256
5453
|
|
|
@@ -5266,7 +5463,19 @@ class Connection {
|
|
|
5266
5463
|
|
|
5267
5464
|
/** @internal */
|
|
5268
5465
|
|
|
5269
|
-
/**
|
|
5466
|
+
/**
|
|
5467
|
+
* Special case.
|
|
5468
|
+
* After a signature is processed, RPCs automatically dispose of the
|
|
5469
|
+
* subscription on the server side. We need to track which of these
|
|
5470
|
+
* subscriptions have been disposed in such a way, so that we know
|
|
5471
|
+
* whether the client is dealing with a not-yet-processed signature
|
|
5472
|
+
* (in which case we must tear down the server subscription) or an
|
|
5473
|
+
* already-processed signature (in which case the client can simply
|
|
5474
|
+
* clear out the subscription locally without telling the server).
|
|
5475
|
+
*
|
|
5476
|
+
* NOTE: There is a proposal to eliminate this special case, here:
|
|
5477
|
+
* https://github.com/solana-labs/solana/issues/18892
|
|
5478
|
+
*/
|
|
5270
5479
|
|
|
5271
5480
|
/** @internal */
|
|
5272
5481
|
|
|
@@ -5288,6 +5497,7 @@ class Connection {
|
|
|
5288
5497
|
this._rpcWebSocketConnected = false;
|
|
5289
5498
|
this._rpcWebSocketHeartbeat = null;
|
|
5290
5499
|
this._rpcWebSocketIdleTimeout = null;
|
|
5500
|
+
this._rpcWebSocketGeneration = 0;
|
|
5291
5501
|
this._disableBlockhashCaching = false;
|
|
5292
5502
|
this._pollingBlockhash = false;
|
|
5293
5503
|
this._blockhashInfo = {
|
|
@@ -5296,20 +5506,11 @@ class Connection {
|
|
|
5296
5506
|
transactionSignatures: [],
|
|
5297
5507
|
simulatedSignatures: []
|
|
5298
5508
|
};
|
|
5299
|
-
this.
|
|
5300
|
-
this.
|
|
5301
|
-
this.
|
|
5302
|
-
this.
|
|
5303
|
-
this.
|
|
5304
|
-
this._rootSubscriptions = {};
|
|
5305
|
-
this._signatureSubscriptionCounter = 0;
|
|
5306
|
-
this._signatureSubscriptions = {};
|
|
5307
|
-
this._slotSubscriptionCounter = 0;
|
|
5308
|
-
this._slotSubscriptions = {};
|
|
5309
|
-
this._logsSubscriptionCounter = 0;
|
|
5310
|
-
this._logsSubscriptions = {};
|
|
5311
|
-
this._slotUpdateSubscriptionCounter = 0;
|
|
5312
|
-
this._slotUpdateSubscriptions = {};
|
|
5509
|
+
this._nextClientSubscriptionId = 0;
|
|
5510
|
+
this._subscriptionDisposeFunctionsByClientSubscriptionId = {};
|
|
5511
|
+
this._subscriptionCallbacksByServerSubscriptionId = {};
|
|
5512
|
+
this._subscriptionsByHash = {};
|
|
5513
|
+
this._subscriptionsAutoDisposedByRpc = new Set();
|
|
5313
5514
|
let url = new URL(endpoint);
|
|
5314
5515
|
const useHttps = url.protocol === 'https:';
|
|
5315
5516
|
let wsEndpoint;
|
|
@@ -7077,6 +7278,8 @@ class Connection {
|
|
|
7077
7278
|
|
|
7078
7279
|
|
|
7079
7280
|
_wsOnClose(code) {
|
|
7281
|
+
this._rpcWebSocketGeneration++;
|
|
7282
|
+
|
|
7080
7283
|
if (this._rpcWebSocketHeartbeat) {
|
|
7081
7284
|
clearInterval(this._rpcWebSocketHeartbeat);
|
|
7082
7285
|
this._rpcWebSocketHeartbeat = null;
|
|
@@ -7090,85 +7293,20 @@ class Connection {
|
|
|
7090
7293
|
} // implicit close, prepare subscriptions for auto-reconnect
|
|
7091
7294
|
|
|
7092
7295
|
|
|
7093
|
-
this.
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
async _subscribe(sub, rpcMethod, rpcArgs) {
|
|
7101
|
-
if (sub.subscriptionId == null) {
|
|
7102
|
-
sub.subscriptionId = 'subscribing';
|
|
7103
|
-
|
|
7104
|
-
try {
|
|
7105
|
-
const id = await this._rpcWebSocket.call(rpcMethod, rpcArgs);
|
|
7106
|
-
|
|
7107
|
-
if (typeof id === 'number' && sub.subscriptionId === 'subscribing') {
|
|
7108
|
-
// eslint-disable-next-line require-atomic-updates
|
|
7109
|
-
sub.subscriptionId = id;
|
|
7110
|
-
}
|
|
7111
|
-
} catch (err) {
|
|
7112
|
-
if (sub.subscriptionId === 'subscribing') {
|
|
7113
|
-
// eslint-disable-next-line require-atomic-updates
|
|
7114
|
-
sub.subscriptionId = null;
|
|
7115
|
-
}
|
|
7116
|
-
|
|
7117
|
-
if (err instanceof Error) {
|
|
7118
|
-
console.error(`${rpcMethod} error for argument`, rpcArgs, err.message);
|
|
7119
|
-
}
|
|
7120
|
-
}
|
|
7121
|
-
}
|
|
7122
|
-
}
|
|
7123
|
-
/**
|
|
7124
|
-
* @internal
|
|
7125
|
-
*/
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
async _unsubscribe(sub, rpcMethod) {
|
|
7129
|
-
const subscriptionId = sub.subscriptionId;
|
|
7130
|
-
|
|
7131
|
-
if (subscriptionId != null && typeof subscriptionId != 'string') {
|
|
7132
|
-
const unsubscribeId = subscriptionId;
|
|
7133
|
-
|
|
7134
|
-
try {
|
|
7135
|
-
await this._rpcWebSocket.call(rpcMethod, [unsubscribeId]);
|
|
7136
|
-
} catch (err) {
|
|
7137
|
-
if (err instanceof Error) {
|
|
7138
|
-
console.error(`${rpcMethod} error:`, err.message);
|
|
7139
|
-
}
|
|
7140
|
-
}
|
|
7141
|
-
}
|
|
7142
|
-
}
|
|
7143
|
-
/**
|
|
7144
|
-
* @internal
|
|
7145
|
-
*/
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
_resetSubscriptions() {
|
|
7149
|
-
Object.values(this._accountChangeSubscriptions).forEach(s => s.subscriptionId = null);
|
|
7150
|
-
Object.values(this._logsSubscriptions).forEach(s => s.subscriptionId = null);
|
|
7151
|
-
Object.values(this._programAccountChangeSubscriptions).forEach(s => s.subscriptionId = null);
|
|
7152
|
-
Object.values(this._rootSubscriptions).forEach(s => s.subscriptionId = null);
|
|
7153
|
-
Object.values(this._signatureSubscriptions).forEach(s => s.subscriptionId = null);
|
|
7154
|
-
Object.values(this._slotSubscriptions).forEach(s => s.subscriptionId = null);
|
|
7155
|
-
Object.values(this._slotUpdateSubscriptions).forEach(s => s.subscriptionId = null);
|
|
7296
|
+
this._subscriptionCallbacksByServerSubscriptionId = {};
|
|
7297
|
+
Object.entries(this._subscriptionsByHash).forEach(([hash, subscription]) => {
|
|
7298
|
+
this._subscriptionsByHash[hash] = { ...subscription,
|
|
7299
|
+
state: 'pending'
|
|
7300
|
+
};
|
|
7301
|
+
});
|
|
7156
7302
|
}
|
|
7157
7303
|
/**
|
|
7158
7304
|
* @internal
|
|
7159
7305
|
*/
|
|
7160
7306
|
|
|
7161
7307
|
|
|
7162
|
-
_updateSubscriptions() {
|
|
7163
|
-
|
|
7164
|
-
const programKeys = Object.keys(this._programAccountChangeSubscriptions).map(Number);
|
|
7165
|
-
const slotKeys = Object.keys(this._slotSubscriptions).map(Number);
|
|
7166
|
-
const slotUpdateKeys = Object.keys(this._slotUpdateSubscriptions).map(Number);
|
|
7167
|
-
const signatureKeys = Object.keys(this._signatureSubscriptions).map(Number);
|
|
7168
|
-
const rootKeys = Object.keys(this._rootSubscriptions).map(Number);
|
|
7169
|
-
const logsKeys = Object.keys(this._logsSubscriptions).map(Number);
|
|
7170
|
-
|
|
7171
|
-
if (accountKeys.length === 0 && programKeys.length === 0 && slotKeys.length === 0 && slotUpdateKeys.length === 0 && signatureKeys.length === 0 && rootKeys.length === 0 && logsKeys.length === 0) {
|
|
7308
|
+
async _updateSubscriptions() {
|
|
7309
|
+
if (Object.keys(this._subscriptionsByHash).length === 0) {
|
|
7172
7310
|
if (this._rpcWebSocketConnected) {
|
|
7173
7311
|
this._rpcWebSocketConnected = false;
|
|
7174
7312
|
this._rpcWebSocketIdleTimeout = setTimeout(() => {
|
|
@@ -7200,60 +7338,167 @@ class Connection {
|
|
|
7200
7338
|
return;
|
|
7201
7339
|
}
|
|
7202
7340
|
|
|
7203
|
-
|
|
7204
|
-
const sub = this._accountChangeSubscriptions[id];
|
|
7341
|
+
const activeWebSocketGeneration = this._rpcWebSocketGeneration;
|
|
7205
7342
|
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
for (let id of programKeys) {
|
|
7210
|
-
const sub = this._programAccountChangeSubscriptions[id];
|
|
7343
|
+
const isCurrentConnectionStillActive = () => {
|
|
7344
|
+
return activeWebSocketGeneration === this._rpcWebSocketGeneration;
|
|
7345
|
+
};
|
|
7211
7346
|
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7347
|
+
await Promise.all( // Don't be tempted to change this to `Object.entries`. We call
|
|
7348
|
+
// `_updateSubscriptions` recursively when processing the state,
|
|
7349
|
+
// so it's important that we look up the *current* version of
|
|
7350
|
+
// each subscription, every time we process a hash.
|
|
7351
|
+
Object.keys(this._subscriptionsByHash).map(async hash => {
|
|
7352
|
+
const subscription = this._subscriptionsByHash[hash];
|
|
7216
7353
|
|
|
7217
|
-
|
|
7218
|
-
|
|
7354
|
+
if (subscription === undefined) {
|
|
7355
|
+
// This entry has since been deleted. Skip.
|
|
7356
|
+
return;
|
|
7357
|
+
}
|
|
7219
7358
|
|
|
7220
|
-
|
|
7221
|
-
|
|
7359
|
+
switch (subscription.state) {
|
|
7360
|
+
case 'pending':
|
|
7361
|
+
case 'unsubscribed':
|
|
7362
|
+
if (subscription.callbacks.size === 0) {
|
|
7363
|
+
/**
|
|
7364
|
+
* You can end up here when:
|
|
7365
|
+
*
|
|
7366
|
+
* - a subscription has recently unsubscribed
|
|
7367
|
+
* without having new callbacks added to it
|
|
7368
|
+
* while the unsubscribe was in flight, or
|
|
7369
|
+
* - when a pending subscription has its
|
|
7370
|
+
* listeners removed before a request was
|
|
7371
|
+
* sent to the server.
|
|
7372
|
+
*
|
|
7373
|
+
* Being that nobody is interested in this
|
|
7374
|
+
* subscription any longer, delete it.
|
|
7375
|
+
*/
|
|
7376
|
+
delete this._subscriptionsByHash[hash];
|
|
7377
|
+
|
|
7378
|
+
if (subscription.state === 'unsubscribed') {
|
|
7379
|
+
delete this._subscriptionCallbacksByServerSubscriptionId[subscription.serverSubscriptionId];
|
|
7380
|
+
}
|
|
7222
7381
|
|
|
7223
|
-
|
|
7224
|
-
|
|
7382
|
+
await this._updateSubscriptions();
|
|
7383
|
+
return;
|
|
7384
|
+
}
|
|
7225
7385
|
|
|
7226
|
-
|
|
7227
|
-
|
|
7386
|
+
await (async () => {
|
|
7387
|
+
const {
|
|
7388
|
+
args,
|
|
7389
|
+
method
|
|
7390
|
+
} = subscription;
|
|
7228
7391
|
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7392
|
+
try {
|
|
7393
|
+
this._subscriptionsByHash[hash] = { ...subscription,
|
|
7394
|
+
state: 'subscribing'
|
|
7395
|
+
};
|
|
7396
|
+
const serverSubscriptionId = await this._rpcWebSocket.call(method, args);
|
|
7397
|
+
this._subscriptionsByHash[hash] = { ...subscription,
|
|
7398
|
+
serverSubscriptionId,
|
|
7399
|
+
state: 'subscribed'
|
|
7400
|
+
};
|
|
7401
|
+
this._subscriptionCallbacksByServerSubscriptionId[serverSubscriptionId] = subscription.callbacks;
|
|
7402
|
+
await this._updateSubscriptions();
|
|
7403
|
+
} catch (e) {
|
|
7404
|
+
if (e instanceof Error) {
|
|
7405
|
+
console.error(`${method} error for argument`, args, e.message);
|
|
7406
|
+
}
|
|
7407
|
+
|
|
7408
|
+
if (!isCurrentConnectionStillActive()) {
|
|
7409
|
+
return;
|
|
7410
|
+
} // TODO: Maybe add an 'errored' state or a retry limit?
|
|
7233
7411
|
|
|
7234
|
-
this._subscribe(sub, 'signatureSubscribe', args);
|
|
7235
|
-
}
|
|
7236
7412
|
|
|
7237
|
-
|
|
7238
|
-
|
|
7413
|
+
this._subscriptionsByHash[hash] = { ...subscription,
|
|
7414
|
+
state: 'pending'
|
|
7415
|
+
};
|
|
7416
|
+
await this._updateSubscriptions();
|
|
7417
|
+
}
|
|
7418
|
+
})();
|
|
7419
|
+
break;
|
|
7239
7420
|
|
|
7240
|
-
|
|
7241
|
-
|
|
7421
|
+
case 'subscribed':
|
|
7422
|
+
if (subscription.callbacks.size === 0) {
|
|
7423
|
+
// By the time we successfully set up a subscription
|
|
7424
|
+
// with the server, the client stopped caring about it.
|
|
7425
|
+
// Tear it down now.
|
|
7426
|
+
await (async () => {
|
|
7427
|
+
const {
|
|
7428
|
+
serverSubscriptionId,
|
|
7429
|
+
unsubscribeMethod
|
|
7430
|
+
} = subscription;
|
|
7431
|
+
|
|
7432
|
+
if (this._subscriptionsAutoDisposedByRpc.has(serverSubscriptionId)) {
|
|
7433
|
+
/**
|
|
7434
|
+
* Special case.
|
|
7435
|
+
* If we're dealing with a subscription that has been auto-
|
|
7436
|
+
* disposed by the RPC, then we can skip the RPC call to
|
|
7437
|
+
* tear down the subscription here.
|
|
7438
|
+
*
|
|
7439
|
+
* NOTE: There is a proposal to eliminate this special case, here:
|
|
7440
|
+
* https://github.com/solana-labs/solana/issues/18892
|
|
7441
|
+
*/
|
|
7442
|
+
this._subscriptionsAutoDisposedByRpc.delete(serverSubscriptionId);
|
|
7443
|
+
} else {
|
|
7444
|
+
this._subscriptionsByHash[hash] = { ...subscription,
|
|
7445
|
+
state: 'unsubscribing'
|
|
7446
|
+
};
|
|
7447
|
+
|
|
7448
|
+
try {
|
|
7449
|
+
await this._rpcWebSocket.call(unsubscribeMethod, [serverSubscriptionId]);
|
|
7450
|
+
} catch (e) {
|
|
7451
|
+
if (e instanceof Error) {
|
|
7452
|
+
console.error(`${unsubscribeMethod} error:`, e.message);
|
|
7453
|
+
}
|
|
7454
|
+
|
|
7455
|
+
if (!isCurrentConnectionStillActive()) {
|
|
7456
|
+
return;
|
|
7457
|
+
} // TODO: Maybe add an 'errored' state or a retry limit?
|
|
7458
|
+
|
|
7459
|
+
|
|
7460
|
+
this._subscriptionsByHash[hash] = { ...subscription,
|
|
7461
|
+
state: 'subscribed'
|
|
7462
|
+
};
|
|
7463
|
+
await this._updateSubscriptions();
|
|
7464
|
+
return;
|
|
7465
|
+
}
|
|
7466
|
+
}
|
|
7242
7467
|
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7468
|
+
this._subscriptionsByHash[hash] = { ...subscription,
|
|
7469
|
+
state: 'unsubscribed'
|
|
7470
|
+
};
|
|
7471
|
+
await this._updateSubscriptions();
|
|
7472
|
+
})();
|
|
7473
|
+
}
|
|
7246
7474
|
|
|
7247
|
-
|
|
7248
|
-
filter = {
|
|
7249
|
-
mentions: [sub.filter.toString()]
|
|
7250
|
-
};
|
|
7251
|
-
} else {
|
|
7252
|
-
filter = sub.filter;
|
|
7475
|
+
break;
|
|
7253
7476
|
}
|
|
7477
|
+
}));
|
|
7478
|
+
}
|
|
7479
|
+
/**
|
|
7480
|
+
* @internal
|
|
7481
|
+
*/
|
|
7482
|
+
|
|
7483
|
+
|
|
7484
|
+
_handleServerNotification(serverSubscriptionId, callbackArgs) {
|
|
7485
|
+
const callbacks = this._subscriptionCallbacksByServerSubscriptionId[serverSubscriptionId];
|
|
7254
7486
|
|
|
7255
|
-
|
|
7487
|
+
if (callbacks === undefined) {
|
|
7488
|
+
return;
|
|
7256
7489
|
}
|
|
7490
|
+
|
|
7491
|
+
callbacks.forEach(cb => {
|
|
7492
|
+
try {
|
|
7493
|
+
cb( // I failed to find a way to convince TypeScript that `cb` is of type
|
|
7494
|
+
// `TCallback` which is certainly compatible with `Parameters<TCallback>`.
|
|
7495
|
+
// See https://github.com/microsoft/TypeScript/issues/47615
|
|
7496
|
+
// @ts-ignore
|
|
7497
|
+
...callbackArgs);
|
|
7498
|
+
} catch (e) {
|
|
7499
|
+
console.error(e);
|
|
7500
|
+
}
|
|
7501
|
+
});
|
|
7257
7502
|
}
|
|
7258
7503
|
/**
|
|
7259
7504
|
* @internal
|
|
@@ -7261,14 +7506,71 @@ class Connection {
|
|
|
7261
7506
|
|
|
7262
7507
|
|
|
7263
7508
|
_wsOnAccountNotification(notification) {
|
|
7264
|
-
const
|
|
7509
|
+
const {
|
|
7510
|
+
result,
|
|
7511
|
+
subscription
|
|
7512
|
+
} = superstruct.create(notification, AccountNotificationResult);
|
|
7265
7513
|
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7514
|
+
this._handleServerNotification(subscription, [result.value, result.context]);
|
|
7515
|
+
}
|
|
7516
|
+
/**
|
|
7517
|
+
* @internal
|
|
7518
|
+
*/
|
|
7519
|
+
|
|
7520
|
+
|
|
7521
|
+
_makeSubscription(subscriptionConfig,
|
|
7522
|
+
/**
|
|
7523
|
+
* When preparing `args` for a call to `_makeSubscription`, be sure
|
|
7524
|
+
* to carefully apply a default `commitment` property, if necessary.
|
|
7525
|
+
*
|
|
7526
|
+
* - If the user supplied a `commitment` use that.
|
|
7527
|
+
* - Otherwise, if the `Connection::commitment` is set, use that.
|
|
7528
|
+
* - Otherwise, set it to the RPC server default: `finalized`.
|
|
7529
|
+
*
|
|
7530
|
+
* This is extremely important to ensure that these two fundamentally
|
|
7531
|
+
* identical subscriptions produce the same identifying hash:
|
|
7532
|
+
*
|
|
7533
|
+
* - A subscription made without specifying a commitment.
|
|
7534
|
+
* - A subscription made where the commitment specified is the same
|
|
7535
|
+
* as the default applied to the subscription above.
|
|
7536
|
+
*
|
|
7537
|
+
* Example; these two subscriptions must produce the same hash:
|
|
7538
|
+
*
|
|
7539
|
+
* - An `accountSubscribe` subscription for `'PUBKEY'`
|
|
7540
|
+
* - An `accountSubscribe` subscription for `'PUBKEY'` with commitment
|
|
7541
|
+
* `'finalized'`.
|
|
7542
|
+
*
|
|
7543
|
+
* See the 'making a subscription with defaulted params omitted' test
|
|
7544
|
+
* in `connection-subscriptions.ts` for more.
|
|
7545
|
+
*/
|
|
7546
|
+
args) {
|
|
7547
|
+
const clientSubscriptionId = this._nextClientSubscriptionId++;
|
|
7548
|
+
const hash = fastStableStringify$1([subscriptionConfig.method, args], true
|
|
7549
|
+
/* isArrayProp */
|
|
7550
|
+
);
|
|
7551
|
+
const existingSubscription = this._subscriptionsByHash[hash];
|
|
7552
|
+
|
|
7553
|
+
if (existingSubscription === undefined) {
|
|
7554
|
+
this._subscriptionsByHash[hash] = { ...subscriptionConfig,
|
|
7555
|
+
args,
|
|
7556
|
+
callbacks: new Set([subscriptionConfig.callback]),
|
|
7557
|
+
state: 'pending'
|
|
7558
|
+
};
|
|
7559
|
+
} else {
|
|
7560
|
+
existingSubscription.callbacks.add(subscriptionConfig.callback);
|
|
7271
7561
|
}
|
|
7562
|
+
|
|
7563
|
+
this._subscriptionDisposeFunctionsByClientSubscriptionId[clientSubscriptionId] = async () => {
|
|
7564
|
+
delete this._subscriptionDisposeFunctionsByClientSubscriptionId[clientSubscriptionId];
|
|
7565
|
+
const subscription = this._subscriptionsByHash[hash];
|
|
7566
|
+
assert(subscription !== undefined, `Could not find a \`Subscription\` when tearing down client subscription #${clientSubscriptionId}`);
|
|
7567
|
+
subscription.callbacks.delete(subscriptionConfig.callback);
|
|
7568
|
+
await this._updateSubscriptions();
|
|
7569
|
+
};
|
|
7570
|
+
|
|
7571
|
+
this._updateSubscriptions();
|
|
7572
|
+
|
|
7573
|
+
return clientSubscriptionId;
|
|
7272
7574
|
}
|
|
7273
7575
|
/**
|
|
7274
7576
|
* Register a callback to be invoked whenever the specified account changes
|
|
@@ -7281,35 +7583,24 @@ class Connection {
|
|
|
7281
7583
|
|
|
7282
7584
|
|
|
7283
7585
|
onAccountChange(publicKey, callback, commitment) {
|
|
7284
|
-
const
|
|
7285
|
-
|
|
7286
|
-
publicKey: publicKey.toBase58(),
|
|
7287
|
-
callback,
|
|
7288
|
-
commitment,
|
|
7289
|
-
subscriptionId: null
|
|
7290
|
-
};
|
|
7291
|
-
|
|
7292
|
-
this._updateSubscriptions();
|
|
7586
|
+
const args = this._buildArgs([publicKey.toBase58()], commitment || this._commitment || 'finalized', // Apply connection/server default.
|
|
7587
|
+
'base64');
|
|
7293
7588
|
|
|
7294
|
-
return
|
|
7589
|
+
return this._makeSubscription({
|
|
7590
|
+
callback,
|
|
7591
|
+
method: 'accountSubscribe',
|
|
7592
|
+
unsubscribeMethod: 'accountUnsubscribe'
|
|
7593
|
+
}, args);
|
|
7295
7594
|
}
|
|
7296
7595
|
/**
|
|
7297
7596
|
* Deregister an account notification callback
|
|
7298
7597
|
*
|
|
7299
|
-
* @param id subscription id to deregister
|
|
7598
|
+
* @param id client subscription id to deregister
|
|
7300
7599
|
*/
|
|
7301
7600
|
|
|
7302
7601
|
|
|
7303
|
-
async removeAccountChangeListener(
|
|
7304
|
-
|
|
7305
|
-
const subInfo = this._accountChangeSubscriptions[id];
|
|
7306
|
-
delete this._accountChangeSubscriptions[id];
|
|
7307
|
-
await this._unsubscribe(subInfo, 'accountUnsubscribe');
|
|
7308
|
-
|
|
7309
|
-
this._updateSubscriptions();
|
|
7310
|
-
} else {
|
|
7311
|
-
console.warn(createSubscriptionWarningMessage(id, 'account change'));
|
|
7312
|
-
}
|
|
7602
|
+
async removeAccountChangeListener(clientSubscriptionId) {
|
|
7603
|
+
await this._unsubscribeClientSubscription(clientSubscriptionId, 'account change');
|
|
7313
7604
|
}
|
|
7314
7605
|
/**
|
|
7315
7606
|
* @internal
|
|
@@ -7317,21 +7608,15 @@ class Connection {
|
|
|
7317
7608
|
|
|
7318
7609
|
|
|
7319
7610
|
_wsOnProgramAccountNotification(notification) {
|
|
7320
|
-
const
|
|
7611
|
+
const {
|
|
7612
|
+
result,
|
|
7613
|
+
subscription
|
|
7614
|
+
} = superstruct.create(notification, ProgramAccountNotificationResult);
|
|
7321
7615
|
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
context
|
|
7327
|
-
} = res.result;
|
|
7328
|
-
sub.callback({
|
|
7329
|
-
accountId: value.pubkey,
|
|
7330
|
-
accountInfo: value.account
|
|
7331
|
-
}, context);
|
|
7332
|
-
return;
|
|
7333
|
-
}
|
|
7334
|
-
}
|
|
7616
|
+
this._handleServerNotification(subscription, [{
|
|
7617
|
+
accountId: result.value.pubkey,
|
|
7618
|
+
accountInfo: result.value.account
|
|
7619
|
+
}, result.context]);
|
|
7335
7620
|
}
|
|
7336
7621
|
/**
|
|
7337
7622
|
* Register a callback to be invoked whenever accounts owned by the
|
|
@@ -7346,36 +7631,30 @@ class Connection {
|
|
|
7346
7631
|
|
|
7347
7632
|
|
|
7348
7633
|
onProgramAccountChange(programId, callback, commitment, filters) {
|
|
7349
|
-
const
|
|
7350
|
-
|
|
7351
|
-
|
|
7634
|
+
const args = this._buildArgs([programId.toBase58()], commitment || this._commitment || 'finalized', // Apply connection/server default.
|
|
7635
|
+
'base64'
|
|
7636
|
+
/* encoding */
|
|
7637
|
+
, filters ? {
|
|
7638
|
+
filters: filters
|
|
7639
|
+
} : undefined
|
|
7640
|
+
/* extra */
|
|
7641
|
+
);
|
|
7642
|
+
|
|
7643
|
+
return this._makeSubscription({
|
|
7352
7644
|
callback,
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
};
|
|
7357
|
-
|
|
7358
|
-
this._updateSubscriptions();
|
|
7359
|
-
|
|
7360
|
-
return id;
|
|
7645
|
+
method: 'programSubscribe',
|
|
7646
|
+
unsubscribeMethod: 'programUnsubscribe'
|
|
7647
|
+
}, args);
|
|
7361
7648
|
}
|
|
7362
7649
|
/**
|
|
7363
7650
|
* Deregister an account notification callback
|
|
7364
7651
|
*
|
|
7365
|
-
* @param id subscription id to deregister
|
|
7652
|
+
* @param id client subscription id to deregister
|
|
7366
7653
|
*/
|
|
7367
7654
|
|
|
7368
7655
|
|
|
7369
|
-
async removeProgramAccountChangeListener(
|
|
7370
|
-
|
|
7371
|
-
const subInfo = this._programAccountChangeSubscriptions[id];
|
|
7372
|
-
delete this._programAccountChangeSubscriptions[id];
|
|
7373
|
-
await this._unsubscribe(subInfo, 'programUnsubscribe');
|
|
7374
|
-
|
|
7375
|
-
this._updateSubscriptions();
|
|
7376
|
-
} else {
|
|
7377
|
-
console.warn(createSubscriptionWarningMessage(id, 'program account change'));
|
|
7378
|
-
}
|
|
7656
|
+
async removeProgramAccountChangeListener(clientSubscriptionId) {
|
|
7657
|
+
await this._unsubscribeClientSubscription(clientSubscriptionId, 'program account change');
|
|
7379
7658
|
}
|
|
7380
7659
|
/**
|
|
7381
7660
|
* Registers a callback to be invoked whenever logs are emitted.
|
|
@@ -7383,35 +7662,26 @@ class Connection {
|
|
|
7383
7662
|
|
|
7384
7663
|
|
|
7385
7664
|
onLogs(filter, callback, commitment) {
|
|
7386
|
-
const
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
commitment,
|
|
7391
|
-
subscriptionId: null
|
|
7392
|
-
};
|
|
7665
|
+
const args = this._buildArgs([typeof filter === 'object' ? {
|
|
7666
|
+
mentions: [filter.toString()]
|
|
7667
|
+
} : filter], commitment || this._commitment || 'finalized' // Apply connection/server default.
|
|
7668
|
+
);
|
|
7393
7669
|
|
|
7394
|
-
this.
|
|
7395
|
-
|
|
7396
|
-
|
|
7670
|
+
return this._makeSubscription({
|
|
7671
|
+
callback,
|
|
7672
|
+
method: 'logsSubscribe',
|
|
7673
|
+
unsubscribeMethod: 'logsUnsubscribe'
|
|
7674
|
+
}, args);
|
|
7397
7675
|
}
|
|
7398
7676
|
/**
|
|
7399
7677
|
* Deregister a logs callback.
|
|
7400
7678
|
*
|
|
7401
|
-
* @param id subscription id to deregister.
|
|
7679
|
+
* @param id client subscription id to deregister.
|
|
7402
7680
|
*/
|
|
7403
7681
|
|
|
7404
7682
|
|
|
7405
|
-
async removeOnLogsListener(
|
|
7406
|
-
|
|
7407
|
-
const subInfo = this._logsSubscriptions[id];
|
|
7408
|
-
delete this._logsSubscriptions[id];
|
|
7409
|
-
await this._unsubscribe(subInfo, 'logsUnsubscribe');
|
|
7410
|
-
|
|
7411
|
-
this._updateSubscriptions();
|
|
7412
|
-
} else {
|
|
7413
|
-
console.warn(createSubscriptionWarningMessage(id, 'logs'));
|
|
7414
|
-
}
|
|
7683
|
+
async removeOnLogsListener(clientSubscriptionId) {
|
|
7684
|
+
await this._unsubscribeClientSubscription(clientSubscriptionId, 'logs');
|
|
7415
7685
|
}
|
|
7416
7686
|
/**
|
|
7417
7687
|
* @internal
|
|
@@ -7419,17 +7689,12 @@ class Connection {
|
|
|
7419
7689
|
|
|
7420
7690
|
|
|
7421
7691
|
_wsOnLogsNotification(notification) {
|
|
7422
|
-
const
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
const sub = this._logsSubscriptions[id];
|
|
7692
|
+
const {
|
|
7693
|
+
result,
|
|
7694
|
+
subscription
|
|
7695
|
+
} = superstruct.create(notification, LogsNotificationResult);
|
|
7427
7696
|
|
|
7428
|
-
|
|
7429
|
-
sub.callback(res.result.value, res.result.context);
|
|
7430
|
-
return;
|
|
7431
|
-
}
|
|
7432
|
-
}
|
|
7697
|
+
this._handleServerNotification(subscription, [result.value, result.context]);
|
|
7433
7698
|
}
|
|
7434
7699
|
/**
|
|
7435
7700
|
* @internal
|
|
@@ -7437,14 +7702,12 @@ class Connection {
|
|
|
7437
7702
|
|
|
7438
7703
|
|
|
7439
7704
|
_wsOnSlotNotification(notification) {
|
|
7440
|
-
const
|
|
7705
|
+
const {
|
|
7706
|
+
result,
|
|
7707
|
+
subscription
|
|
7708
|
+
} = superstruct.create(notification, SlotNotificationResult);
|
|
7441
7709
|
|
|
7442
|
-
|
|
7443
|
-
if (sub.subscriptionId === res.subscription) {
|
|
7444
|
-
sub.callback(res.result);
|
|
7445
|
-
return;
|
|
7446
|
-
}
|
|
7447
|
-
}
|
|
7710
|
+
this._handleServerNotification(subscription, [result]);
|
|
7448
7711
|
}
|
|
7449
7712
|
/**
|
|
7450
7713
|
* Register a callback to be invoked upon slot changes
|
|
@@ -7455,33 +7718,23 @@ class Connection {
|
|
|
7455
7718
|
|
|
7456
7719
|
|
|
7457
7720
|
onSlotChange(callback) {
|
|
7458
|
-
|
|
7459
|
-
this._slotSubscriptions[id] = {
|
|
7721
|
+
return this._makeSubscription({
|
|
7460
7722
|
callback,
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
return id;
|
|
7723
|
+
method: 'slotSubscribe',
|
|
7724
|
+
unsubscribeMethod: 'slotUnsubscribe'
|
|
7725
|
+
}, []
|
|
7726
|
+
/* args */
|
|
7727
|
+
);
|
|
7467
7728
|
}
|
|
7468
7729
|
/**
|
|
7469
7730
|
* Deregister a slot notification callback
|
|
7470
7731
|
*
|
|
7471
|
-
* @param id subscription id to deregister
|
|
7732
|
+
* @param id client subscription id to deregister
|
|
7472
7733
|
*/
|
|
7473
7734
|
|
|
7474
7735
|
|
|
7475
|
-
async removeSlotChangeListener(
|
|
7476
|
-
|
|
7477
|
-
const subInfo = this._slotSubscriptions[id];
|
|
7478
|
-
delete this._slotSubscriptions[id];
|
|
7479
|
-
await this._unsubscribe(subInfo, 'slotUnsubscribe');
|
|
7480
|
-
|
|
7481
|
-
this._updateSubscriptions();
|
|
7482
|
-
} else {
|
|
7483
|
-
console.warn(createSubscriptionWarningMessage(id, 'slot change'));
|
|
7484
|
-
}
|
|
7736
|
+
async removeSlotChangeListener(clientSubscriptionId) {
|
|
7737
|
+
await this._unsubscribeClientSubscription(clientSubscriptionId, 'slot change');
|
|
7485
7738
|
}
|
|
7486
7739
|
/**
|
|
7487
7740
|
* @internal
|
|
@@ -7489,14 +7742,12 @@ class Connection {
|
|
|
7489
7742
|
|
|
7490
7743
|
|
|
7491
7744
|
_wsOnSlotUpdatesNotification(notification) {
|
|
7492
|
-
const
|
|
7745
|
+
const {
|
|
7746
|
+
result,
|
|
7747
|
+
subscription
|
|
7748
|
+
} = superstruct.create(notification, SlotUpdateNotificationResult);
|
|
7493
7749
|
|
|
7494
|
-
|
|
7495
|
-
if (sub.subscriptionId === res.subscription) {
|
|
7496
|
-
sub.callback(res.result);
|
|
7497
|
-
return;
|
|
7498
|
-
}
|
|
7499
|
-
}
|
|
7750
|
+
this._handleServerNotification(subscription, [result]);
|
|
7500
7751
|
}
|
|
7501
7752
|
/**
|
|
7502
7753
|
* Register a callback to be invoked upon slot updates. {@link SlotUpdate}'s
|
|
@@ -7508,32 +7759,36 @@ class Connection {
|
|
|
7508
7759
|
|
|
7509
7760
|
|
|
7510
7761
|
onSlotUpdate(callback) {
|
|
7511
|
-
|
|
7512
|
-
this._slotUpdateSubscriptions[id] = {
|
|
7762
|
+
return this._makeSubscription({
|
|
7513
7763
|
callback,
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
return id;
|
|
7764
|
+
method: 'slotsUpdatesSubscribe',
|
|
7765
|
+
unsubscribeMethod: 'slotsUpdatesUnsubscribe'
|
|
7766
|
+
}, []
|
|
7767
|
+
/* args */
|
|
7768
|
+
);
|
|
7520
7769
|
}
|
|
7521
7770
|
/**
|
|
7522
7771
|
* Deregister a slot update notification callback
|
|
7523
7772
|
*
|
|
7524
|
-
* @param id subscription id to deregister
|
|
7773
|
+
* @param id client subscription id to deregister
|
|
7525
7774
|
*/
|
|
7526
7775
|
|
|
7527
7776
|
|
|
7528
|
-
async removeSlotUpdateListener(
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7777
|
+
async removeSlotUpdateListener(clientSubscriptionId) {
|
|
7778
|
+
await this._unsubscribeClientSubscription(clientSubscriptionId, 'slot update');
|
|
7779
|
+
}
|
|
7780
|
+
/**
|
|
7781
|
+
* @internal
|
|
7782
|
+
*/
|
|
7533
7783
|
|
|
7534
|
-
|
|
7784
|
+
|
|
7785
|
+
async _unsubscribeClientSubscription(clientSubscriptionId, subscriptionName) {
|
|
7786
|
+
const dispose = this._subscriptionDisposeFunctionsByClientSubscriptionId[clientSubscriptionId];
|
|
7787
|
+
|
|
7788
|
+
if (dispose) {
|
|
7789
|
+
await dispose();
|
|
7535
7790
|
} else {
|
|
7536
|
-
console.warn(
|
|
7791
|
+
console.warn('Ignored unsubscribe request because an active subscription with id ' + `\`${clientSubscriptionId}\` for '${subscriptionName}' events ` + 'could not be found.');
|
|
7537
7792
|
}
|
|
7538
7793
|
}
|
|
7539
7794
|
|
|
@@ -7580,30 +7835,34 @@ class Connection {
|
|
|
7580
7835
|
|
|
7581
7836
|
|
|
7582
7837
|
_wsOnSignatureNotification(notification) {
|
|
7583
|
-
const
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7838
|
+
const {
|
|
7839
|
+
result,
|
|
7840
|
+
subscription
|
|
7841
|
+
} = superstruct.create(notification, SignatureNotificationResult);
|
|
7842
|
+
|
|
7843
|
+
if (result.value !== 'receivedSignature') {
|
|
7844
|
+
/**
|
|
7845
|
+
* Special case.
|
|
7846
|
+
* After a signature is processed, RPCs automatically dispose of the
|
|
7847
|
+
* subscription on the server side. We need to track which of these
|
|
7848
|
+
* subscriptions have been disposed in such a way, so that we know
|
|
7849
|
+
* whether the client is dealing with a not-yet-processed signature
|
|
7850
|
+
* (in which case we must tear down the server subscription) or an
|
|
7851
|
+
* already-processed signature (in which case the client can simply
|
|
7852
|
+
* clear out the subscription locally without telling the server).
|
|
7853
|
+
*
|
|
7854
|
+
* NOTE: There is a proposal to eliminate this special case, here:
|
|
7855
|
+
* https://github.com/solana-labs/solana/issues/18892
|
|
7856
|
+
*/
|
|
7857
|
+
this._subscriptionsAutoDisposedByRpc.add(subscription);
|
|
7858
|
+
}
|
|
7859
|
+
|
|
7860
|
+
this._handleServerNotification(subscription, result.value === 'receivedSignature' ? [{
|
|
7861
|
+
type: 'received'
|
|
7862
|
+
}, result.context] : [{
|
|
7863
|
+
type: 'status',
|
|
7864
|
+
result: result.value
|
|
7865
|
+
}, result.context]);
|
|
7607
7866
|
}
|
|
7608
7867
|
/**
|
|
7609
7868
|
* Register a callback to be invoked upon signature updates
|
|
@@ -7616,23 +7875,26 @@ class Connection {
|
|
|
7616
7875
|
|
|
7617
7876
|
|
|
7618
7877
|
onSignature(signature, callback, commitment) {
|
|
7619
|
-
const
|
|
7620
|
-
|
|
7621
|
-
|
|
7878
|
+
const args = this._buildArgs([signature], commitment || this._commitment || 'finalized' // Apply connection/server default.
|
|
7879
|
+
);
|
|
7880
|
+
|
|
7881
|
+
const clientSubscriptionId = this._makeSubscription({
|
|
7622
7882
|
callback: (notification, context) => {
|
|
7623
7883
|
if (notification.type === 'status') {
|
|
7624
|
-
callback(notification.result, context);
|
|
7884
|
+
callback(notification.result, context); // Signatures subscriptions are auto-removed by the RPC service
|
|
7885
|
+
// so no need to explicitly send an unsubscribe message.
|
|
7886
|
+
|
|
7887
|
+
try {
|
|
7888
|
+
this.removeSignatureListener(clientSubscriptionId); // eslint-disable-next-line no-empty
|
|
7889
|
+
} catch {// Already removed.
|
|
7890
|
+
}
|
|
7625
7891
|
}
|
|
7626
7892
|
},
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
subscriptionId: null
|
|
7631
|
-
};
|
|
7893
|
+
method: 'signatureSubscribe',
|
|
7894
|
+
unsubscribeMethod: 'signatureUnsubscribe'
|
|
7895
|
+
}, args);
|
|
7632
7896
|
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
return id;
|
|
7897
|
+
return clientSubscriptionId;
|
|
7636
7898
|
}
|
|
7637
7899
|
/**
|
|
7638
7900
|
* Register a callback to be invoked when a transaction is
|
|
@@ -7647,35 +7909,43 @@ class Connection {
|
|
|
7647
7909
|
|
|
7648
7910
|
|
|
7649
7911
|
onSignatureWithOptions(signature, callback, options) {
|
|
7650
|
-
const
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
options
|
|
7655
|
-
|
|
7912
|
+
const {
|
|
7913
|
+
commitment,
|
|
7914
|
+
...extra
|
|
7915
|
+
} = { ...options,
|
|
7916
|
+
commitment: options && options.commitment || this._commitment || 'finalized' // Apply connection/server default.
|
|
7917
|
+
|
|
7656
7918
|
};
|
|
7657
7919
|
|
|
7658
|
-
this.
|
|
7920
|
+
const args = this._buildArgs([signature], commitment, undefined
|
|
7921
|
+
/* encoding */
|
|
7922
|
+
, extra);
|
|
7659
7923
|
|
|
7660
|
-
|
|
7924
|
+
const clientSubscriptionId = this._makeSubscription({
|
|
7925
|
+
callback: (notification, context) => {
|
|
7926
|
+
callback(notification, context); // Signatures subscriptions are auto-removed by the RPC service
|
|
7927
|
+
// so no need to explicitly send an unsubscribe message.
|
|
7928
|
+
|
|
7929
|
+
try {
|
|
7930
|
+
this.removeSignatureListener(clientSubscriptionId); // eslint-disable-next-line no-empty
|
|
7931
|
+
} catch {// Already removed.
|
|
7932
|
+
}
|
|
7933
|
+
},
|
|
7934
|
+
method: 'signatureSubscribe',
|
|
7935
|
+
unsubscribeMethod: 'signatureUnsubscribe'
|
|
7936
|
+
}, args);
|
|
7937
|
+
|
|
7938
|
+
return clientSubscriptionId;
|
|
7661
7939
|
}
|
|
7662
7940
|
/**
|
|
7663
7941
|
* Deregister a signature notification callback
|
|
7664
7942
|
*
|
|
7665
|
-
* @param id subscription id to deregister
|
|
7943
|
+
* @param id client subscription id to deregister
|
|
7666
7944
|
*/
|
|
7667
7945
|
|
|
7668
7946
|
|
|
7669
|
-
async removeSignatureListener(
|
|
7670
|
-
|
|
7671
|
-
const subInfo = this._signatureSubscriptions[id];
|
|
7672
|
-
delete this._signatureSubscriptions[id];
|
|
7673
|
-
await this._unsubscribe(subInfo, 'signatureUnsubscribe');
|
|
7674
|
-
|
|
7675
|
-
this._updateSubscriptions();
|
|
7676
|
-
} else {
|
|
7677
|
-
console.warn(createSubscriptionWarningMessage(id, 'signature result'));
|
|
7678
|
-
}
|
|
7947
|
+
async removeSignatureListener(clientSubscriptionId) {
|
|
7948
|
+
await this._unsubscribeClientSubscription(clientSubscriptionId, 'signature result');
|
|
7679
7949
|
}
|
|
7680
7950
|
/**
|
|
7681
7951
|
* @internal
|
|
@@ -7683,14 +7953,12 @@ class Connection {
|
|
|
7683
7953
|
|
|
7684
7954
|
|
|
7685
7955
|
_wsOnRootNotification(notification) {
|
|
7686
|
-
const
|
|
7956
|
+
const {
|
|
7957
|
+
result,
|
|
7958
|
+
subscription
|
|
7959
|
+
} = superstruct.create(notification, RootNotificationResult);
|
|
7687
7960
|
|
|
7688
|
-
|
|
7689
|
-
if (sub.subscriptionId === res.subscription) {
|
|
7690
|
-
sub.callback(res.result);
|
|
7691
|
-
return;
|
|
7692
|
-
}
|
|
7693
|
-
}
|
|
7961
|
+
this._handleServerNotification(subscription, [result]);
|
|
7694
7962
|
}
|
|
7695
7963
|
/**
|
|
7696
7964
|
* Register a callback to be invoked upon root changes
|
|
@@ -7701,33 +7969,23 @@ class Connection {
|
|
|
7701
7969
|
|
|
7702
7970
|
|
|
7703
7971
|
onRootChange(callback) {
|
|
7704
|
-
|
|
7705
|
-
this._rootSubscriptions[id] = {
|
|
7972
|
+
return this._makeSubscription({
|
|
7706
7973
|
callback,
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
return id;
|
|
7974
|
+
method: 'rootSubscribe',
|
|
7975
|
+
unsubscribeMethod: 'rootUnsubscribe'
|
|
7976
|
+
}, []
|
|
7977
|
+
/* args */
|
|
7978
|
+
);
|
|
7713
7979
|
}
|
|
7714
7980
|
/**
|
|
7715
7981
|
* Deregister a root notification callback
|
|
7716
7982
|
*
|
|
7717
|
-
* @param id subscription id to deregister
|
|
7983
|
+
* @param id client subscription id to deregister
|
|
7718
7984
|
*/
|
|
7719
7985
|
|
|
7720
7986
|
|
|
7721
|
-
async removeRootChangeListener(
|
|
7722
|
-
|
|
7723
|
-
const subInfo = this._rootSubscriptions[id];
|
|
7724
|
-
delete this._rootSubscriptions[id];
|
|
7725
|
-
await this._unsubscribe(subInfo, 'rootUnsubscribe');
|
|
7726
|
-
|
|
7727
|
-
this._updateSubscriptions();
|
|
7728
|
-
} else {
|
|
7729
|
-
console.warn(createSubscriptionWarningMessage(id, 'root change'));
|
|
7730
|
-
}
|
|
7987
|
+
async removeRootChangeListener(clientSubscriptionId) {
|
|
7988
|
+
await this._unsubscribeClientSubscription(clientSubscriptionId, 'root change');
|
|
7731
7989
|
}
|
|
7732
7990
|
|
|
7733
7991
|
}
|
|
@@ -9413,6 +9671,9 @@ exports.BLOCKHASH_CACHE_TIMEOUT_MS = BLOCKHASH_CACHE_TIMEOUT_MS;
|
|
|
9413
9671
|
exports.BPF_LOADER_DEPRECATED_PROGRAM_ID = BPF_LOADER_DEPRECATED_PROGRAM_ID;
|
|
9414
9672
|
exports.BPF_LOADER_PROGRAM_ID = BPF_LOADER_PROGRAM_ID;
|
|
9415
9673
|
exports.BpfLoader = BpfLoader;
|
|
9674
|
+
exports.COMPUTE_BUDGET_INSTRUCTION_LAYOUTS = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS;
|
|
9675
|
+
exports.ComputeBudgetInstruction = ComputeBudgetInstruction;
|
|
9676
|
+
exports.ComputeBudgetProgram = ComputeBudgetProgram;
|
|
9416
9677
|
exports.Connection = Connection;
|
|
9417
9678
|
exports.Ed25519Program = Ed25519Program;
|
|
9418
9679
|
exports.Enum = Enum;
|
|
@@ -9426,7 +9687,6 @@ exports.MAX_SEED_LENGTH = MAX_SEED_LENGTH;
|
|
|
9426
9687
|
exports.Message = Message;
|
|
9427
9688
|
exports.NONCE_ACCOUNT_LENGTH = NONCE_ACCOUNT_LENGTH;
|
|
9428
9689
|
exports.NonceAccount = NonceAccount;
|
|
9429
|
-
exports.PACKET_DATA_SIZE = PACKET_DATA_SIZE;
|
|
9430
9690
|
exports.PublicKey = PublicKey;
|
|
9431
9691
|
exports.SOLANA_SCHEMA = SOLANA_SCHEMA;
|
|
9432
9692
|
exports.STAKE_CONFIG_ID = STAKE_CONFIG_ID;
|