@drift-labs/sdk 0.1.29 → 0.1.30-master.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.
- package/lib/accounts/bulkAccountLoader.d.ts +1 -0
- package/lib/accounts/bulkAccountLoader.js +32 -17
- package/lib/tx/retryTxSender.d.ts +5 -2
- package/lib/tx/retryTxSender.js +14 -1
- package/package.json +1 -1
- package/src/accounts/bulkAccountLoader.ts +40 -19
- package/src/tx/retryTxSender.ts +19 -1
- package/src/tx/retryTxSender.js +0 -137
- package/src/tx/retryTxSender.js.map +0 -1
|
@@ -29,11 +29,14 @@ class BulkAccountLoader {
|
|
|
29
29
|
addAccount(publicKey, callback) {
|
|
30
30
|
const existingSize = this.accountsToLoad.size;
|
|
31
31
|
const callbackId = (0, uuid_1.v4)();
|
|
32
|
+
this.log(`Adding account ${publicKey.toString()} callback id ${callbackId}`);
|
|
32
33
|
const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
|
|
33
34
|
if (existingAccountToLoad) {
|
|
35
|
+
this.log(`account already exists`);
|
|
34
36
|
existingAccountToLoad.callbacks.set(callbackId, callback);
|
|
35
37
|
}
|
|
36
38
|
else {
|
|
39
|
+
this.log(`account doesn't already exist. creating new callback map`);
|
|
37
40
|
const callbacks = new Map();
|
|
38
41
|
callbacks.set(callbackId, callback);
|
|
39
42
|
const newAccountToLoad = {
|
|
@@ -50,6 +53,7 @@ class BulkAccountLoader {
|
|
|
50
53
|
return callbackId;
|
|
51
54
|
}
|
|
52
55
|
removeAccount(publicKey, callbackId) {
|
|
56
|
+
this.log(`Removing account ${publicKey.toString()} callback id ${callbackId}`);
|
|
53
57
|
const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
|
|
54
58
|
if (existingAccountToLoad) {
|
|
55
59
|
existingAccountToLoad.callbacks.delete(callbackId);
|
|
@@ -78,13 +82,16 @@ class BulkAccountLoader {
|
|
|
78
82
|
load() {
|
|
79
83
|
return __awaiter(this, void 0, void 0, function* () {
|
|
80
84
|
if (this.loadPromise) {
|
|
85
|
+
this.log(`Load promise exists. Returning early`);
|
|
81
86
|
return this.loadPromise;
|
|
82
87
|
}
|
|
83
88
|
this.loadPromise = new Promise((resolver) => {
|
|
84
89
|
this.loadPromiseResolver = resolver;
|
|
85
90
|
});
|
|
91
|
+
this.log(`Loading`);
|
|
86
92
|
try {
|
|
87
93
|
const chunks = this.chunks(Array.from(this.accountsToLoad.values()), GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE);
|
|
94
|
+
this.log(`${chunks.length} chunks`);
|
|
88
95
|
yield Promise.all(chunks.map((chunk) => {
|
|
89
96
|
return this.loadChunk(chunk);
|
|
90
97
|
}));
|
|
@@ -95,15 +102,15 @@ class BulkAccountLoader {
|
|
|
95
102
|
for (const [_, callback] of this.errorCallbacks) {
|
|
96
103
|
callback(e);
|
|
97
104
|
}
|
|
105
|
+
this.log('finished error callbacks');
|
|
98
106
|
}
|
|
99
107
|
finally {
|
|
108
|
+
this.log(`resetting load promise`);
|
|
100
109
|
this.loadPromiseResolver();
|
|
101
110
|
this.loadPromise = undefined;
|
|
102
111
|
const now = Date.now();
|
|
103
112
|
if (now - this.lastUpdate > fiveMinutes) {
|
|
104
|
-
|
|
105
|
-
console.log("Haven't seen updated account in five minutes. Bulk account loader creating new Connection Object");
|
|
106
|
-
}
|
|
113
|
+
this.log("Haven't seen updated account in five minutes. Bulk account loader creating new Connection Object");
|
|
107
114
|
this.connection = new web3_js_1.Connection(
|
|
108
115
|
// @ts-ignore
|
|
109
116
|
this.connection._rpcEndpoint, this.connection.commitment);
|
|
@@ -114,6 +121,7 @@ class BulkAccountLoader {
|
|
|
114
121
|
loadChunk(accountsToLoad) {
|
|
115
122
|
return __awaiter(this, void 0, void 0, function* () {
|
|
116
123
|
if (accountsToLoad.length === 0) {
|
|
124
|
+
this.log(`no accounts in chunk`);
|
|
117
125
|
return;
|
|
118
126
|
}
|
|
119
127
|
const args = [
|
|
@@ -125,8 +133,8 @@ class BulkAccountLoader {
|
|
|
125
133
|
// @ts-ignore
|
|
126
134
|
const rpcResponse = yield this.connection._rpcRequest('getMultipleAccounts', args);
|
|
127
135
|
const oneMinuteSinceLastUpdate = Date.now() - this.lastUpdate > oneMinute;
|
|
128
|
-
if (
|
|
129
|
-
|
|
136
|
+
if (oneMinuteSinceLastUpdate) {
|
|
137
|
+
this.log('rpcResponse ' + JSON.stringify(rpcResponse));
|
|
130
138
|
}
|
|
131
139
|
const newSlot = rpcResponse.result.context.slot;
|
|
132
140
|
for (const i in accountsToLoad) {
|
|
@@ -139,10 +147,11 @@ class BulkAccountLoader {
|
|
|
139
147
|
const dataType = rpcResponse.result.value[i].data[1];
|
|
140
148
|
newBuffer = Buffer.from(raw, dataType);
|
|
141
149
|
}
|
|
142
|
-
if (
|
|
143
|
-
|
|
150
|
+
if (oneMinuteSinceLastUpdate) {
|
|
151
|
+
this.log('oldRPCResponse' + oldRPCResponse);
|
|
144
152
|
}
|
|
145
153
|
if (!oldRPCResponse) {
|
|
154
|
+
this.log('No old rpc response, updating account data');
|
|
146
155
|
this.accountData.set(key, {
|
|
147
156
|
slot: newSlot,
|
|
148
157
|
buffer: newBuffer,
|
|
@@ -152,10 +161,12 @@ class BulkAccountLoader {
|
|
|
152
161
|
continue;
|
|
153
162
|
}
|
|
154
163
|
if (newSlot <= oldRPCResponse.slot) {
|
|
164
|
+
this.log(`new slot ${newSlot} old slot ${oldRPCResponse.slot}`);
|
|
155
165
|
continue;
|
|
156
166
|
}
|
|
157
167
|
const oldBuffer = oldRPCResponse.buffer;
|
|
158
168
|
if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
|
|
169
|
+
this.log('new buffer, updating account data');
|
|
159
170
|
this.accountData.set(key, {
|
|
160
171
|
slot: newSlot,
|
|
161
172
|
buffer: newBuffer,
|
|
@@ -163,18 +174,21 @@ class BulkAccountLoader {
|
|
|
163
174
|
this.handleAccountCallbacks(accountToLoad, newBuffer);
|
|
164
175
|
this.lastUpdate = Date.now();
|
|
165
176
|
}
|
|
166
|
-
else
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
177
|
+
else {
|
|
178
|
+
this.log('unable to update account for newest slot');
|
|
179
|
+
this.log('oldBuffer ' + oldBuffer);
|
|
180
|
+
this.log('newBuffer ' + newBuffer);
|
|
181
|
+
this.log('buffers equal ' + newBuffer.equals(oldBuffer));
|
|
170
182
|
}
|
|
171
183
|
}
|
|
172
184
|
});
|
|
173
185
|
}
|
|
174
186
|
handleAccountCallbacks(accountToLoad, buffer) {
|
|
187
|
+
this.log('handling account callbacks');
|
|
175
188
|
for (const [_, callback] of accountToLoad.callbacks) {
|
|
176
189
|
callback(buffer);
|
|
177
190
|
}
|
|
191
|
+
this.log('finished account callbacks');
|
|
178
192
|
}
|
|
179
193
|
getAccountData(publicKey) {
|
|
180
194
|
const accountData = this.accountData.get(publicKey.toString());
|
|
@@ -184,18 +198,19 @@ class BulkAccountLoader {
|
|
|
184
198
|
if (this.intervalId) {
|
|
185
199
|
return;
|
|
186
200
|
}
|
|
187
|
-
|
|
188
|
-
console.log(`startPolling`);
|
|
189
|
-
}
|
|
201
|
+
this.log('startPolling');
|
|
190
202
|
this.intervalId = setInterval(this.load.bind(this), this.pollingFrequency);
|
|
191
203
|
}
|
|
192
204
|
stopPolling() {
|
|
193
205
|
if (this.intervalId) {
|
|
194
206
|
clearInterval(this.intervalId);
|
|
195
207
|
this.intervalId = undefined;
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
208
|
+
this.log('stopPolling');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
log(msg) {
|
|
212
|
+
if (this.loggingEnabled) {
|
|
213
|
+
console.log(msg);
|
|
199
214
|
}
|
|
200
215
|
}
|
|
201
216
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import { TxSender } from './types';
|
|
2
|
-
import { Commitment, ConfirmOptions, RpcResponseAndContext, Signer, SignatureResult, Transaction, TransactionSignature } from '@solana/web3.js';
|
|
3
|
+
import { Commitment, ConfirmOptions, RpcResponseAndContext, Signer, SignatureResult, Transaction, TransactionSignature, Connection } from '@solana/web3.js';
|
|
3
4
|
import { Provider } from '@project-serum/anchor';
|
|
4
5
|
declare type ResolveReference = {
|
|
5
6
|
resolve?: () => void;
|
|
@@ -8,12 +9,14 @@ export declare class RetryTxSender implements TxSender {
|
|
|
8
9
|
provider: Provider;
|
|
9
10
|
timeout: number;
|
|
10
11
|
retrySleep: number;
|
|
11
|
-
|
|
12
|
+
additionalConnections: Connection[];
|
|
13
|
+
constructor(provider: Provider, timeout?: number, retrySleep?: number, additionalConnections?: Connection[]);
|
|
12
14
|
send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<TransactionSignature>;
|
|
13
15
|
prepareTx(tx: Transaction, additionalSigners: Array<Signer>, opts: ConfirmOptions): Promise<Transaction>;
|
|
14
16
|
confirmTransaction(signature: TransactionSignature, commitment?: Commitment): Promise<RpcResponseAndContext<SignatureResult>>;
|
|
15
17
|
getTimestamp(): number;
|
|
16
18
|
sleep(reference: ResolveReference): Promise<void>;
|
|
17
19
|
promiseTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T | null>;
|
|
20
|
+
sendToAdditionalConnections(rawTx: Buffer, opts: ConfirmOptions): void;
|
|
18
21
|
}
|
|
19
22
|
export {};
|
package/lib/tx/retryTxSender.js
CHANGED
|
@@ -18,10 +18,11 @@ const bs58_1 = __importDefault(require("bs58"));
|
|
|
18
18
|
const DEFAULT_TIMEOUT = 35000;
|
|
19
19
|
const DEFAULT_RETRY = 8000;
|
|
20
20
|
class RetryTxSender {
|
|
21
|
-
constructor(provider, timeout, retrySleep) {
|
|
21
|
+
constructor(provider, timeout, retrySleep, additionalConnections = new Array()) {
|
|
22
22
|
this.provider = provider;
|
|
23
23
|
this.timeout = timeout !== null && timeout !== void 0 ? timeout : DEFAULT_TIMEOUT;
|
|
24
24
|
this.retrySleep = retrySleep !== null && retrySleep !== void 0 ? retrySleep : DEFAULT_RETRY;
|
|
25
|
+
this.additionalConnections = additionalConnections;
|
|
25
26
|
}
|
|
26
27
|
send(tx, additionalSigners, opts) {
|
|
27
28
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -35,6 +36,7 @@ class RetryTxSender {
|
|
|
35
36
|
const rawTransaction = tx.serialize();
|
|
36
37
|
const startTime = this.getTimestamp();
|
|
37
38
|
const txid = yield this.provider.connection.sendRawTransaction(rawTransaction, opts);
|
|
39
|
+
this.sendToAdditionalConnections(rawTransaction, opts);
|
|
38
40
|
let done = false;
|
|
39
41
|
const resolveReference = {
|
|
40
42
|
resolve: undefined,
|
|
@@ -55,6 +57,7 @@ class RetryTxSender {
|
|
|
55
57
|
console.error(e);
|
|
56
58
|
stopWaiting();
|
|
57
59
|
});
|
|
60
|
+
this.sendToAdditionalConnections(rawTransaction, opts);
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
63
|
}))();
|
|
@@ -149,5 +152,15 @@ class RetryTxSender {
|
|
|
149
152
|
return result;
|
|
150
153
|
});
|
|
151
154
|
}
|
|
155
|
+
sendToAdditionalConnections(rawTx, opts) {
|
|
156
|
+
this.additionalConnections.map((connection) => {
|
|
157
|
+
connection.sendRawTransaction(rawTx, opts).catch((e) => {
|
|
158
|
+
console.error(
|
|
159
|
+
// @ts-ignore
|
|
160
|
+
`error sending tx to additional connection ${connection._rpcEndpoint}`);
|
|
161
|
+
console.error(e);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
152
165
|
}
|
|
153
166
|
exports.RetryTxSender = RetryTxSender;
|
package/package.json
CHANGED
|
@@ -43,10 +43,15 @@ export class BulkAccountLoader {
|
|
|
43
43
|
const existingSize = this.accountsToLoad.size;
|
|
44
44
|
|
|
45
45
|
const callbackId = uuidv4();
|
|
46
|
+
this.log(
|
|
47
|
+
`Adding account ${publicKey.toString()} callback id ${callbackId}`
|
|
48
|
+
);
|
|
46
49
|
const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
|
|
47
50
|
if (existingAccountToLoad) {
|
|
51
|
+
this.log(`account already exists`);
|
|
48
52
|
existingAccountToLoad.callbacks.set(callbackId, callback);
|
|
49
53
|
} else {
|
|
54
|
+
this.log(`account doesn't already exist. creating new callback map`);
|
|
50
55
|
const callbacks = new Map<string, (buffer: Buffer) => void>();
|
|
51
56
|
callbacks.set(callbackId, callback);
|
|
52
57
|
const newAccountToLoad = {
|
|
@@ -67,6 +72,9 @@ export class BulkAccountLoader {
|
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
public removeAccount(publicKey: PublicKey, callbackId: string): void {
|
|
75
|
+
this.log(
|
|
76
|
+
`Removing account ${publicKey.toString()} callback id ${callbackId}`
|
|
77
|
+
);
|
|
70
78
|
const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
|
|
71
79
|
if (existingAccountToLoad) {
|
|
72
80
|
existingAccountToLoad.callbacks.delete(callbackId);
|
|
@@ -99,17 +107,21 @@ export class BulkAccountLoader {
|
|
|
99
107
|
|
|
100
108
|
public async load(): Promise<void> {
|
|
101
109
|
if (this.loadPromise) {
|
|
110
|
+
this.log(`Load promise exists. Returning early`);
|
|
102
111
|
return this.loadPromise;
|
|
103
112
|
}
|
|
104
113
|
this.loadPromise = new Promise((resolver) => {
|
|
105
114
|
this.loadPromiseResolver = resolver;
|
|
106
115
|
});
|
|
107
116
|
|
|
117
|
+
this.log(`Loading`);
|
|
118
|
+
|
|
108
119
|
try {
|
|
109
120
|
const chunks = this.chunks(
|
|
110
121
|
Array.from(this.accountsToLoad.values()),
|
|
111
122
|
GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE
|
|
112
123
|
);
|
|
124
|
+
this.log(`${chunks.length} chunks`);
|
|
113
125
|
|
|
114
126
|
await Promise.all(
|
|
115
127
|
chunks.map((chunk) => {
|
|
@@ -122,17 +134,17 @@ export class BulkAccountLoader {
|
|
|
122
134
|
for (const [_, callback] of this.errorCallbacks) {
|
|
123
135
|
callback(e);
|
|
124
136
|
}
|
|
137
|
+
this.log('finished error callbacks');
|
|
125
138
|
} finally {
|
|
139
|
+
this.log(`resetting load promise`);
|
|
126
140
|
this.loadPromiseResolver();
|
|
127
141
|
this.loadPromise = undefined;
|
|
128
142
|
|
|
129
143
|
const now = Date.now();
|
|
130
144
|
if (now - this.lastUpdate > fiveMinutes) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
);
|
|
135
|
-
}
|
|
145
|
+
this.log(
|
|
146
|
+
"Haven't seen updated account in five minutes. Bulk account loader creating new Connection Object"
|
|
147
|
+
);
|
|
136
148
|
this.connection = new Connection(
|
|
137
149
|
// @ts-ignore
|
|
138
150
|
this.connection._rpcEndpoint,
|
|
@@ -144,6 +156,7 @@ export class BulkAccountLoader {
|
|
|
144
156
|
|
|
145
157
|
async loadChunk(accountsToLoad: AccountToLoad[]): Promise<void> {
|
|
146
158
|
if (accountsToLoad.length === 0) {
|
|
159
|
+
this.log(`no accounts in chunk`);
|
|
147
160
|
return;
|
|
148
161
|
}
|
|
149
162
|
|
|
@@ -161,8 +174,8 @@ export class BulkAccountLoader {
|
|
|
161
174
|
);
|
|
162
175
|
|
|
163
176
|
const oneMinuteSinceLastUpdate = Date.now() - this.lastUpdate > oneMinute;
|
|
164
|
-
if (
|
|
165
|
-
|
|
177
|
+
if (oneMinuteSinceLastUpdate) {
|
|
178
|
+
this.log('rpcResponse ' + JSON.stringify(rpcResponse));
|
|
166
179
|
}
|
|
167
180
|
|
|
168
181
|
const newSlot = rpcResponse.result.context.slot;
|
|
@@ -179,11 +192,12 @@ export class BulkAccountLoader {
|
|
|
179
192
|
newBuffer = Buffer.from(raw, dataType);
|
|
180
193
|
}
|
|
181
194
|
|
|
182
|
-
if (
|
|
183
|
-
|
|
195
|
+
if (oneMinuteSinceLastUpdate) {
|
|
196
|
+
this.log('oldRPCResponse' + oldRPCResponse);
|
|
184
197
|
}
|
|
185
198
|
|
|
186
199
|
if (!oldRPCResponse) {
|
|
200
|
+
this.log('No old rpc response, updating account data');
|
|
187
201
|
this.accountData.set(key, {
|
|
188
202
|
slot: newSlot,
|
|
189
203
|
buffer: newBuffer,
|
|
@@ -194,29 +208,34 @@ export class BulkAccountLoader {
|
|
|
194
208
|
}
|
|
195
209
|
|
|
196
210
|
if (newSlot <= oldRPCResponse.slot) {
|
|
211
|
+
this.log(`new slot ${newSlot} old slot ${oldRPCResponse.slot}`);
|
|
197
212
|
continue;
|
|
198
213
|
}
|
|
199
214
|
|
|
200
215
|
const oldBuffer = oldRPCResponse.buffer;
|
|
201
216
|
if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
|
|
217
|
+
this.log('new buffer, updating account data');
|
|
202
218
|
this.accountData.set(key, {
|
|
203
219
|
slot: newSlot,
|
|
204
220
|
buffer: newBuffer,
|
|
205
221
|
});
|
|
206
222
|
this.handleAccountCallbacks(accountToLoad, newBuffer);
|
|
207
223
|
this.lastUpdate = Date.now();
|
|
208
|
-
} else
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
224
|
+
} else {
|
|
225
|
+
this.log('unable to update account for newest slot');
|
|
226
|
+
this.log('oldBuffer ' + oldBuffer);
|
|
227
|
+
this.log('newBuffer ' + newBuffer);
|
|
228
|
+
this.log('buffers equal ' + newBuffer.equals(oldBuffer));
|
|
212
229
|
}
|
|
213
230
|
}
|
|
214
231
|
}
|
|
215
232
|
|
|
216
233
|
handleAccountCallbacks(accountToLoad: AccountToLoad, buffer: Buffer): void {
|
|
234
|
+
this.log('handling account callbacks');
|
|
217
235
|
for (const [_, callback] of accountToLoad.callbacks) {
|
|
218
236
|
callback(buffer);
|
|
219
237
|
}
|
|
238
|
+
this.log('finished account callbacks');
|
|
220
239
|
}
|
|
221
240
|
|
|
222
241
|
public getAccountData(publicKey: PublicKey): Buffer | undefined {
|
|
@@ -229,9 +248,7 @@ export class BulkAccountLoader {
|
|
|
229
248
|
return;
|
|
230
249
|
}
|
|
231
250
|
|
|
232
|
-
|
|
233
|
-
console.log(`startPolling`);
|
|
234
|
-
}
|
|
251
|
+
this.log('startPolling');
|
|
235
252
|
|
|
236
253
|
this.intervalId = setInterval(this.load.bind(this), this.pollingFrequency);
|
|
237
254
|
}
|
|
@@ -241,9 +258,13 @@ export class BulkAccountLoader {
|
|
|
241
258
|
clearInterval(this.intervalId);
|
|
242
259
|
this.intervalId = undefined;
|
|
243
260
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
261
|
+
this.log('stopPolling');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
public log(msg: string): void {
|
|
266
|
+
if (this.loggingEnabled) {
|
|
267
|
+
console.log(msg);
|
|
247
268
|
}
|
|
248
269
|
}
|
|
249
270
|
}
|
package/src/tx/retryTxSender.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
SignatureResult,
|
|
9
9
|
Transaction,
|
|
10
10
|
TransactionSignature,
|
|
11
|
+
Connection,
|
|
11
12
|
} from '@solana/web3.js';
|
|
12
13
|
import { Provider } from '@project-serum/anchor';
|
|
13
14
|
import assert from 'assert';
|
|
@@ -24,15 +25,18 @@ export class RetryTxSender implements TxSender {
|
|
|
24
25
|
provider: Provider;
|
|
25
26
|
timeout: number;
|
|
26
27
|
retrySleep: number;
|
|
28
|
+
additionalConnections: Connection[];
|
|
27
29
|
|
|
28
30
|
public constructor(
|
|
29
31
|
provider: Provider,
|
|
30
32
|
timeout?: number,
|
|
31
|
-
retrySleep?: number
|
|
33
|
+
retrySleep?: number,
|
|
34
|
+
additionalConnections = new Array<Connection>()
|
|
32
35
|
) {
|
|
33
36
|
this.provider = provider;
|
|
34
37
|
this.timeout = timeout ?? DEFAULT_TIMEOUT;
|
|
35
38
|
this.retrySleep = retrySleep ?? DEFAULT_RETRY;
|
|
39
|
+
this.additionalConnections = additionalConnections;
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
async send(
|
|
@@ -54,6 +58,7 @@ export class RetryTxSender implements TxSender {
|
|
|
54
58
|
|
|
55
59
|
const txid: TransactionSignature =
|
|
56
60
|
await this.provider.connection.sendRawTransaction(rawTransaction, opts);
|
|
61
|
+
this.sendToAdditionalConnections(rawTransaction, opts);
|
|
57
62
|
|
|
58
63
|
let done = false;
|
|
59
64
|
const resolveReference: ResolveReference = {
|
|
@@ -76,6 +81,7 @@ export class RetryTxSender implements TxSender {
|
|
|
76
81
|
console.error(e);
|
|
77
82
|
stopWaiting();
|
|
78
83
|
});
|
|
84
|
+
this.sendToAdditionalConnections(rawTransaction, opts);
|
|
79
85
|
}
|
|
80
86
|
}
|
|
81
87
|
})();
|
|
@@ -193,4 +199,16 @@ export class RetryTxSender implements TxSender {
|
|
|
193
199
|
return result;
|
|
194
200
|
});
|
|
195
201
|
}
|
|
202
|
+
|
|
203
|
+
sendToAdditionalConnections(rawTx: Buffer, opts: ConfirmOptions): void {
|
|
204
|
+
this.additionalConnections.map((connection) => {
|
|
205
|
+
connection.sendRawTransaction(rawTx, opts).catch((e) => {
|
|
206
|
+
console.error(
|
|
207
|
+
// @ts-ignore
|
|
208
|
+
`error sending tx to additional connection ${connection._rpcEndpoint}`
|
|
209
|
+
);
|
|
210
|
+
console.error(e);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
}
|
|
196
214
|
}
|
package/src/tx/retryTxSender.js
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.RetryTxSender = void 0;
|
|
7
|
-
const assert_1 = __importDefault(require("assert"));
|
|
8
|
-
const bs58_1 = __importDefault(require("bs58"));
|
|
9
|
-
const DEFAULT_TIMEOUT = 35000;
|
|
10
|
-
const DEFAULT_RETRY = 8000;
|
|
11
|
-
class RetryTxSender {
|
|
12
|
-
constructor(provider, timeout, retrySleep) {
|
|
13
|
-
this.provider = provider;
|
|
14
|
-
this.timeout = timeout !== null && timeout !== void 0 ? timeout : DEFAULT_TIMEOUT;
|
|
15
|
-
this.retrySleep = retrySleep !== null && retrySleep !== void 0 ? retrySleep : DEFAULT_RETRY;
|
|
16
|
-
}
|
|
17
|
-
async send(tx, additionalSigners, opts) {
|
|
18
|
-
if (additionalSigners === undefined) {
|
|
19
|
-
additionalSigners = [];
|
|
20
|
-
}
|
|
21
|
-
if (opts === undefined) {
|
|
22
|
-
opts = this.provider.opts;
|
|
23
|
-
}
|
|
24
|
-
await this.prepareTx(tx, additionalSigners, opts);
|
|
25
|
-
const rawTransaction = tx.serialize();
|
|
26
|
-
const startTime = this.getTimestamp();
|
|
27
|
-
const txid = await this.provider.connection.sendRawTransaction(rawTransaction, opts);
|
|
28
|
-
let done = false;
|
|
29
|
-
const resolveReference = {
|
|
30
|
-
resolve: undefined,
|
|
31
|
-
};
|
|
32
|
-
const stopWaiting = () => {
|
|
33
|
-
done = true;
|
|
34
|
-
if (resolveReference.resolve) {
|
|
35
|
-
resolveReference.resolve();
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
(async () => {
|
|
39
|
-
while (!done && this.getTimestamp() - startTime < this.timeout) {
|
|
40
|
-
await this.sleep(resolveReference);
|
|
41
|
-
if (!done) {
|
|
42
|
-
this.provider.connection
|
|
43
|
-
.sendRawTransaction(rawTransaction, opts)
|
|
44
|
-
.catch((e) => {
|
|
45
|
-
console.error(e);
|
|
46
|
-
stopWaiting();
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
})();
|
|
51
|
-
try {
|
|
52
|
-
await this.confirmTransaction(txid, opts.commitment);
|
|
53
|
-
}
|
|
54
|
-
catch (e) {
|
|
55
|
-
console.error(e);
|
|
56
|
-
throw e;
|
|
57
|
-
}
|
|
58
|
-
finally {
|
|
59
|
-
stopWaiting();
|
|
60
|
-
}
|
|
61
|
-
return txid;
|
|
62
|
-
}
|
|
63
|
-
async prepareTx(tx, additionalSigners, opts) {
|
|
64
|
-
tx.feePayer = this.provider.wallet.publicKey;
|
|
65
|
-
tx.recentBlockhash = (await this.provider.connection.getRecentBlockhash(opts.preflightCommitment)).blockhash;
|
|
66
|
-
await this.provider.wallet.signTransaction(tx);
|
|
67
|
-
additionalSigners
|
|
68
|
-
.filter((s) => s !== undefined)
|
|
69
|
-
.forEach((kp) => {
|
|
70
|
-
tx.partialSign(kp);
|
|
71
|
-
});
|
|
72
|
-
return tx;
|
|
73
|
-
}
|
|
74
|
-
async confirmTransaction(signature, commitment) {
|
|
75
|
-
let decodedSignature;
|
|
76
|
-
try {
|
|
77
|
-
decodedSignature = bs58_1.default.decode(signature);
|
|
78
|
-
}
|
|
79
|
-
catch (err) {
|
|
80
|
-
throw new Error('signature must be base58 encoded: ' + signature);
|
|
81
|
-
}
|
|
82
|
-
(0, assert_1.default)(decodedSignature.length === 64, 'signature has invalid length');
|
|
83
|
-
const start = Date.now();
|
|
84
|
-
const subscriptionCommitment = commitment || this.provider.opts.commitment;
|
|
85
|
-
let subscriptionId;
|
|
86
|
-
let response = null;
|
|
87
|
-
const confirmPromise = new Promise((resolve, reject) => {
|
|
88
|
-
try {
|
|
89
|
-
subscriptionId = this.provider.connection.onSignature(signature, (result, context) => {
|
|
90
|
-
subscriptionId = undefined;
|
|
91
|
-
response = {
|
|
92
|
-
context,
|
|
93
|
-
value: result,
|
|
94
|
-
};
|
|
95
|
-
resolve(null);
|
|
96
|
-
}, subscriptionCommitment);
|
|
97
|
-
}
|
|
98
|
-
catch (err) {
|
|
99
|
-
reject(err);
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
try {
|
|
103
|
-
await this.promiseTimeout(confirmPromise, this.timeout);
|
|
104
|
-
}
|
|
105
|
-
finally {
|
|
106
|
-
if (subscriptionId) {
|
|
107
|
-
this.provider.connection.removeSignatureListener(subscriptionId);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (response === null) {
|
|
111
|
-
const duration = (Date.now() - start) / 1000;
|
|
112
|
-
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.`);
|
|
113
|
-
}
|
|
114
|
-
return response;
|
|
115
|
-
}
|
|
116
|
-
getTimestamp() {
|
|
117
|
-
return new Date().getTime();
|
|
118
|
-
}
|
|
119
|
-
async sleep(reference) {
|
|
120
|
-
return new Promise((resolve) => {
|
|
121
|
-
reference.resolve = resolve;
|
|
122
|
-
setTimeout(resolve, this.retrySleep);
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
promiseTimeout(promise, timeoutMs) {
|
|
126
|
-
let timeoutId;
|
|
127
|
-
const timeoutPromise = new Promise((resolve) => {
|
|
128
|
-
timeoutId = setTimeout(() => resolve(null), timeoutMs);
|
|
129
|
-
});
|
|
130
|
-
return Promise.race([promise, timeoutPromise]).then((result) => {
|
|
131
|
-
clearTimeout(timeoutId);
|
|
132
|
-
return result;
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
exports.RetryTxSender = RetryTxSender;
|
|
137
|
-
//# sourceMappingURL=retryTxSender.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"retryTxSender.js","sourceRoot":"","sources":["retryTxSender.ts"],"names":[],"mappings":"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"}
|