@rosen-bridge/tx-pot 1.0.3 → 2.0.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/CHANGELOG.md +27 -0
- package/README.md +8 -8
- package/dist/db/entities/transactionEntity.d.ts +15 -0
- package/dist/db/entities/{TransactionEntity.d.ts.map → transactionEntity.d.ts.map} +1 -1
- package/dist/db/entities/transactionEntity.js +81 -0
- package/dist/db/migrations/index.d.ts +3 -3
- package/dist/db/migrations/index.js +3 -3
- package/dist/db/migrations/postgres/1706350644686-migration.d.ts +4 -4
- package/dist/db/migrations/postgres/1706350644686-migration.d.ts.map +1 -1
- package/dist/db/migrations/postgres/1706350644686-migration.js +8 -8
- package/dist/db/migrations/sqlite/1706007154531-migration.d.ts +4 -4
- package/dist/db/migrations/sqlite/1706007154531-migration.d.ts.map +1 -1
- package/dist/db/migrations/sqlite/1706007154531-migration.js +8 -8
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/network/abstractPotChainManager.d.ts +36 -0
- package/dist/network/{AbstractPotChainManager.d.ts.map → abstractPotChainManager.d.ts.map} +1 -1
- package/dist/network/{AbstractPotChainManager.js → abstractPotChainManager.js} +3 -2
- package/dist/transaction/txPot.d.ts +212 -0
- package/dist/transaction/txPot.d.ts.map +1 -0
- package/dist/transaction/{TxPot.js → txPot.js} +2 -2
- package/dist/transaction/types.d.ts +21 -24
- package/dist/transaction/types.d.ts.map +1 -1
- package/dist/transaction/types.js +13 -13
- package/dist/transaction/utils.d.ts +2 -4
- package/dist/transaction/utils.d.ts.map +1 -1
- package/dist/transaction/utils.js +48 -43
- package/package.json +25 -21
- package/.eslintignore +0 -1
- package/dist/db/entities/TransactionEntity.d.ts +0 -15
- package/dist/db/entities/TransactionEntity.js +0 -125
- package/dist/network/AbstractPotChainManager.d.ts +0 -39
- package/dist/transaction/TxPot.d.ts +0 -284
- package/dist/transaction/TxPot.d.ts.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/lib/db/entities/TransactionEntity.ts +0 -44
- package/lib/db/migrations/index.ts +0 -7
- package/lib/db/migrations/postgres/1706350644686-migration.ts +0 -31
- package/lib/db/migrations/sqlite/1706007154531-migration.ts +0 -31
- package/lib/index.ts +0 -5
- package/lib/network/AbstractPotChainManager.ts +0 -44
- package/lib/transaction/TxPot.ts +0 -728
- package/lib/transaction/types.ts +0 -46
- package/lib/transaction/utils.ts +0 -59
- package/tests/.gitkeep +0 -0
- package/tests/db/dataSource.mock.ts +0 -18
- package/tests/network/TestPotChainManager.ts +0 -23
- package/tests/transaction/TestTxPot.ts +0 -32
- package/tests/transaction/TxPot.spec.ts +0 -1881
- package/tests/transaction/testData.ts +0 -84
- package/tsconfig.build.json +0 -8
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -9
- package/vitest.config.ts +0 -13
package/lib/transaction/TxPot.ts
DELETED
|
@@ -1,728 +0,0 @@
|
|
|
1
|
-
import { DataSource, Repository } from 'typeorm';
|
|
2
|
-
import { TransactionEntity } from '../db/entities/TransactionEntity';
|
|
3
|
-
import { AbstractLogger, DummyLogger } from '@rosen-bridge/abstract-logger';
|
|
4
|
-
import {
|
|
5
|
-
CallbackFunction,
|
|
6
|
-
SigningStatus,
|
|
7
|
-
TransactionStatus,
|
|
8
|
-
TxOptions,
|
|
9
|
-
UnregisteredChain,
|
|
10
|
-
ValidatorFunction,
|
|
11
|
-
} from './types';
|
|
12
|
-
import { txOptionToClause } from './utils';
|
|
13
|
-
import { AbstractPotChainManager } from '../network/AbstractPotChainManager';
|
|
14
|
-
|
|
15
|
-
export class TxPot {
|
|
16
|
-
protected static instance: TxPot;
|
|
17
|
-
protected readonly txRepository: Repository<TransactionEntity>;
|
|
18
|
-
protected chains = new Map<string, AbstractPotChainManager>();
|
|
19
|
-
protected validators = new Map<
|
|
20
|
-
string,
|
|
21
|
-
Map<string, Map<string, ValidatorFunction>>
|
|
22
|
-
>();
|
|
23
|
-
protected txTypeCallbacks = new Map<
|
|
24
|
-
string,
|
|
25
|
-
Map<TransactionStatus, Map<string, CallbackFunction>>
|
|
26
|
-
>();
|
|
27
|
-
protected submissionAllowance = new Map<
|
|
28
|
-
string,
|
|
29
|
-
Map<string, ValidatorFunction>
|
|
30
|
-
>();
|
|
31
|
-
protected logger: AbstractLogger;
|
|
32
|
-
|
|
33
|
-
protected constructor(dataSource: DataSource, logger?: AbstractLogger) {
|
|
34
|
-
this.txRepository = dataSource.getRepository(TransactionEntity);
|
|
35
|
-
this.logger = logger ?? new DummyLogger();
|
|
36
|
-
this.logger.debug('TxPot instantiated');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* initiates TxPot
|
|
41
|
-
* @param dataSource typeorm data source
|
|
42
|
-
* @param logger
|
|
43
|
-
* @returns
|
|
44
|
-
*/
|
|
45
|
-
public static setup = (
|
|
46
|
-
dataSource: DataSource,
|
|
47
|
-
logger?: AbstractLogger
|
|
48
|
-
): TxPot => {
|
|
49
|
-
TxPot.instance = new TxPot(dataSource, logger);
|
|
50
|
-
return TxPot.instance;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* returns TxPot instance (throws error if none exists)
|
|
55
|
-
* @returns TxPot instance
|
|
56
|
-
*/
|
|
57
|
-
public static getInstance = (): TxPot => {
|
|
58
|
-
if (!TxPot.instance) throw Error(`TxPot instance doesn't exist`);
|
|
59
|
-
return TxPot.instance;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* registers a chain to TxPot
|
|
64
|
-
* @param chain
|
|
65
|
-
* @param chainManager
|
|
66
|
-
*/
|
|
67
|
-
registerChain = (
|
|
68
|
-
chain: string,
|
|
69
|
-
chainManager: AbstractPotChainManager
|
|
70
|
-
): void => {
|
|
71
|
-
this.chains.set(chain, chainManager);
|
|
72
|
-
this.logger.debug(
|
|
73
|
-
`A TxPot chain manager is registered for chain [${chain}]`
|
|
74
|
-
);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* registers a validator function
|
|
79
|
-
* @param chain
|
|
80
|
-
* @param txType
|
|
81
|
-
* @param id
|
|
82
|
-
* @param validator
|
|
83
|
-
*/
|
|
84
|
-
registerValidator = (
|
|
85
|
-
chain: string,
|
|
86
|
-
txType: string,
|
|
87
|
-
id: string,
|
|
88
|
-
validator: ValidatorFunction
|
|
89
|
-
): void => {
|
|
90
|
-
let chainValidators = this.validators.get(chain);
|
|
91
|
-
if (!chainValidators) {
|
|
92
|
-
chainValidators = new Map<string, Map<string, ValidatorFunction>>();
|
|
93
|
-
this.validators.set(chain, chainValidators);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
let typeValidators = chainValidators.get(txType);
|
|
97
|
-
if (!typeValidators) {
|
|
98
|
-
typeValidators = new Map<string, ValidatorFunction>();
|
|
99
|
-
chainValidators.set(txType, typeValidators);
|
|
100
|
-
}
|
|
101
|
-
const currentValidator = typeValidators.get(id);
|
|
102
|
-
typeValidators.set(id, validator);
|
|
103
|
-
if (currentValidator) {
|
|
104
|
-
this.logger.debug(
|
|
105
|
-
`The tx validator function for chain [${chain}], type [${txType}] and id [${id}] is replaced`
|
|
106
|
-
);
|
|
107
|
-
} else {
|
|
108
|
-
this.logger.info(
|
|
109
|
-
`New tx validator function is registered for chain [${chain}] and type [${txType}] by id [${id}]`
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* removes a validator function
|
|
116
|
-
* @param chain
|
|
117
|
-
* @param txType
|
|
118
|
-
* @param id
|
|
119
|
-
*/
|
|
120
|
-
unregisterValidator = (chain: string, txType: string, id: string): void => {
|
|
121
|
-
const validators = this.validators.get(chain)?.get(txType);
|
|
122
|
-
if (!validators) {
|
|
123
|
-
this.logger.debug(
|
|
124
|
-
`No tx validator function is set for chain [${chain}], type [${txType}] and id [${id}]`
|
|
125
|
-
);
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
validators.delete(id);
|
|
130
|
-
this.logger.info(
|
|
131
|
-
`Removed tx validator function for chain [${chain}], type [${txType}] and id [${id}]`
|
|
132
|
-
);
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* registers a submit validator function
|
|
137
|
-
* @param chain
|
|
138
|
-
* @param id
|
|
139
|
-
* @param validator
|
|
140
|
-
*/
|
|
141
|
-
registerSubmitValidator = (
|
|
142
|
-
chain: string,
|
|
143
|
-
id: string,
|
|
144
|
-
validator: ValidatorFunction
|
|
145
|
-
): void => {
|
|
146
|
-
let chainAllowance = this.submissionAllowance.get(chain);
|
|
147
|
-
if (!chainAllowance) {
|
|
148
|
-
chainAllowance = new Map<string, ValidatorFunction>();
|
|
149
|
-
this.submissionAllowance.set(chain, chainAllowance);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const currentValidator = chainAllowance.get(id);
|
|
153
|
-
chainAllowance.set(id, validator);
|
|
154
|
-
if (currentValidator) {
|
|
155
|
-
this.logger.debug(
|
|
156
|
-
`The tx submit validator function for chain [${chain}] and id [${id}] is replaced`
|
|
157
|
-
);
|
|
158
|
-
} else {
|
|
159
|
-
this.logger.info(
|
|
160
|
-
`New tx submit validator function is registered for chain [${chain}] by id [${id}]`
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* removes a submit validator function
|
|
167
|
-
* @param chain
|
|
168
|
-
* @param id
|
|
169
|
-
*/
|
|
170
|
-
unregisterSubmitValidator = (chain: string, id: string): void => {
|
|
171
|
-
const chainAllowance = this.submissionAllowance.get(chain);
|
|
172
|
-
if (!chainAllowance) {
|
|
173
|
-
this.logger.debug(
|
|
174
|
-
`No tx submit validator function is set for chain [${chain}] and id [${id}]`
|
|
175
|
-
);
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
chainAllowance.delete(id);
|
|
180
|
-
this.logger.info(
|
|
181
|
-
`Removed tx submit validator function for chain [${chain}] and id [${id}]`
|
|
182
|
-
);
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* registers a callback function
|
|
187
|
-
* the callback will be called when status of any transactions
|
|
188
|
-
* of given type changes to given status
|
|
189
|
-
* @param txType
|
|
190
|
-
* @param status
|
|
191
|
-
* @param id
|
|
192
|
-
* @param callback
|
|
193
|
-
*/
|
|
194
|
-
registerCallback = (
|
|
195
|
-
txType: string,
|
|
196
|
-
status: TransactionStatus,
|
|
197
|
-
id: string,
|
|
198
|
-
callback: CallbackFunction
|
|
199
|
-
): void => {
|
|
200
|
-
let typeCallbacks = this.txTypeCallbacks.get(txType);
|
|
201
|
-
if (!typeCallbacks) {
|
|
202
|
-
typeCallbacks = new Map<
|
|
203
|
-
TransactionStatus,
|
|
204
|
-
Map<string, CallbackFunction>
|
|
205
|
-
>();
|
|
206
|
-
this.txTypeCallbacks.set(txType, typeCallbacks);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
let statusCallbacks = typeCallbacks.get(status);
|
|
210
|
-
if (!statusCallbacks) {
|
|
211
|
-
statusCallbacks = new Map<string, CallbackFunction>();
|
|
212
|
-
typeCallbacks.set(status, statusCallbacks);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const currentCallback = statusCallbacks.get(id);
|
|
216
|
-
statusCallbacks.set(id, callback);
|
|
217
|
-
if (currentCallback) {
|
|
218
|
-
this.logger.debug(
|
|
219
|
-
`The tx status callback function for type [${txType}] and status [${status}] and id [${id}] is replaced`
|
|
220
|
-
);
|
|
221
|
-
} else {
|
|
222
|
-
this.logger.info(
|
|
223
|
-
`New tx status callback function is registered for type [${txType}] and status [${status}] by id [${id}]`
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* removes a callback function
|
|
230
|
-
* @param txType
|
|
231
|
-
* @param status
|
|
232
|
-
* @param id
|
|
233
|
-
*/
|
|
234
|
-
unregisterCallback = (
|
|
235
|
-
txType: string,
|
|
236
|
-
status: TransactionStatus,
|
|
237
|
-
id: string
|
|
238
|
-
): void => {
|
|
239
|
-
const callbacks = this.txTypeCallbacks.get(txType)?.get(status);
|
|
240
|
-
if (!callbacks) {
|
|
241
|
-
this.logger.debug(
|
|
242
|
-
`No tx status callback function is set for type [${txType}] and status [${status}] and id [${id}]`
|
|
243
|
-
);
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
callbacks.delete(id);
|
|
248
|
-
this.logger.info(
|
|
249
|
-
`Removed tx status callback function for type [${txType}] and status [${status}] and id [${id}]`
|
|
250
|
-
);
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* returns chain manager for given chain
|
|
255
|
-
* throws error if no manager is registered for it
|
|
256
|
-
* @param chain
|
|
257
|
-
*/
|
|
258
|
-
protected getChainManager = (chain: string): AbstractPotChainManager => {
|
|
259
|
-
const manager = this.chains.get(chain);
|
|
260
|
-
if (!manager)
|
|
261
|
-
throw new UnregisteredChain(
|
|
262
|
-
`No manager is registered for chain [${chain}]`
|
|
263
|
-
);
|
|
264
|
-
return manager;
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* sets the tx as invalid if enough blocks is passed from last check
|
|
269
|
-
* @param tx
|
|
270
|
-
*/
|
|
271
|
-
protected setTransactionAsInvalid = async (
|
|
272
|
-
tx: TransactionEntity
|
|
273
|
-
): Promise<void> => {
|
|
274
|
-
const manager = this.getChainManager(tx.chain);
|
|
275
|
-
|
|
276
|
-
const currentHeight = await manager.getHeight();
|
|
277
|
-
const requiredConfirmation = manager.getTxRequiredConfirmation(tx.txType);
|
|
278
|
-
|
|
279
|
-
if (currentHeight - tx.lastCheck >= requiredConfirmation) {
|
|
280
|
-
await this.setTxStatus(tx, TransactionStatus.INVALID);
|
|
281
|
-
this.logger.info(`Tx [${tx.txId}] is invalid`);
|
|
282
|
-
} else {
|
|
283
|
-
this.logger.info(
|
|
284
|
-
`Tx [${
|
|
285
|
-
tx.txId
|
|
286
|
-
}] seems invalid. Waiting for enough confirmation of this proposition [${
|
|
287
|
-
currentHeight - tx.lastCheck
|
|
288
|
-
}/${requiredConfirmation}]`
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* validates a transaction
|
|
295
|
-
* returns true if no validator functions is set or tx is valid
|
|
296
|
-
* otherwise handle the tx as invalid and returns false
|
|
297
|
-
* @param tx
|
|
298
|
-
*/
|
|
299
|
-
protected validateTx = async (tx: TransactionEntity): Promise<boolean> => {
|
|
300
|
-
const validators = this.validators.get(tx.chain)?.get(tx.txType);
|
|
301
|
-
if (validators === undefined) {
|
|
302
|
-
// tx is valid since no validator is found
|
|
303
|
-
this.logger.debug(
|
|
304
|
-
`No validator function is found for chain [${tx.chain}] and type [${tx.txType}]`
|
|
305
|
-
);
|
|
306
|
-
return true;
|
|
307
|
-
}
|
|
308
|
-
for (const idValidatorPair of validators) {
|
|
309
|
-
if ((await idValidatorPair[1](tx)) === false) {
|
|
310
|
-
this.logger.debug(
|
|
311
|
-
`tx [${tx.txId}] is recognized as invalid by validator [${idValidatorPair[0]}]`
|
|
312
|
-
);
|
|
313
|
-
await this.setTransactionAsInvalid(tx);
|
|
314
|
-
return false;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
return true;
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* checks a transaction for submission
|
|
322
|
-
* returns true if no validator functions is set or all validators allow tx to submit
|
|
323
|
-
* otherwise returns false
|
|
324
|
-
* @param tx
|
|
325
|
-
*/
|
|
326
|
-
protected isSubmitAllowed = async (
|
|
327
|
-
tx: TransactionEntity
|
|
328
|
-
): Promise<boolean> => {
|
|
329
|
-
const validators = this.submissionAllowance.get(tx.chain);
|
|
330
|
-
if (validators === undefined) {
|
|
331
|
-
// tx is allowed for submission since no validator is found
|
|
332
|
-
this.logger.debug(
|
|
333
|
-
`No submit validator function is found for chain [${tx.chain}]`
|
|
334
|
-
);
|
|
335
|
-
return true;
|
|
336
|
-
}
|
|
337
|
-
for (const idValidatorPair of validators) {
|
|
338
|
-
if ((await idValidatorPair[1](tx)) === false) {
|
|
339
|
-
this.logger.debug(
|
|
340
|
-
`tx [${tx.txId}] is not allowed for submission by submit validator [${idValidatorPair[0]}]`
|
|
341
|
-
);
|
|
342
|
-
return false;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
return true;
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* updates the status of a tx
|
|
350
|
-
* @param txKey tx id and chain
|
|
351
|
-
* @param status new status
|
|
352
|
-
*/
|
|
353
|
-
protected setTxStatus = async (
|
|
354
|
-
tx: TransactionEntity,
|
|
355
|
-
status: TransactionStatus
|
|
356
|
-
): Promise<void> => {
|
|
357
|
-
await this.txRepository.update(
|
|
358
|
-
{
|
|
359
|
-
txId: tx.txId,
|
|
360
|
-
chain: tx.chain,
|
|
361
|
-
},
|
|
362
|
-
{
|
|
363
|
-
status: status,
|
|
364
|
-
lastStatusUpdate: this.currentTime(),
|
|
365
|
-
}
|
|
366
|
-
);
|
|
367
|
-
const callbacks = this.txTypeCallbacks.get(tx.txType)?.get(status);
|
|
368
|
-
if (callbacks) {
|
|
369
|
-
for (const idCallbackPair of callbacks) {
|
|
370
|
-
idCallbackPair[1](tx, status).catch((e) => {
|
|
371
|
-
this.logger.debug(
|
|
372
|
-
`An error occurred while handling tx [${tx.txId}] status change in callback [${idCallbackPair[0]}]: ${e}`
|
|
373
|
-
);
|
|
374
|
-
if (e instanceof Error && e.stack) this.logger.debug(e.stack);
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
} else
|
|
378
|
-
this.logger.debug(
|
|
379
|
-
`No callback function is set for type [${tx.txType}] and status [${status}]`
|
|
380
|
-
);
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* @returns current timestamp in seconds and string format
|
|
385
|
-
*/
|
|
386
|
-
protected currentTime = () => String(Math.round(Date.now() / 1000));
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* submits the signed transaction to the blockchain
|
|
390
|
-
* @param tx
|
|
391
|
-
*/
|
|
392
|
-
protected processSignedTx = async (tx: TransactionEntity): Promise<void> => {
|
|
393
|
-
if (!(await this.isSubmitAllowed(tx))) return;
|
|
394
|
-
const manager = this.getChainManager(tx.chain);
|
|
395
|
-
try {
|
|
396
|
-
await manager.submitTransaction(tx.serializedTx);
|
|
397
|
-
} catch (e) {
|
|
398
|
-
this.logger.warn(
|
|
399
|
-
`Failed to submit tx [${tx.txId}] to chain [${tx.chain}]: ${e}`
|
|
400
|
-
);
|
|
401
|
-
if (e instanceof Error && e.stack) this.logger.warn(e.stack);
|
|
402
|
-
}
|
|
403
|
-
await this.setTxStatus(tx, TransactionStatus.SENT);
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* processes the sent transaction
|
|
408
|
-
* @param tx
|
|
409
|
-
*/
|
|
410
|
-
protected processesSentTx = async (tx: TransactionEntity): Promise<void> => {
|
|
411
|
-
const manager = this.getChainManager(tx.chain);
|
|
412
|
-
|
|
413
|
-
const txConfirmation = await manager.getTxConfirmation(tx.txId);
|
|
414
|
-
const requiredConfirmation = manager.getTxRequiredConfirmation(tx.txType);
|
|
415
|
-
|
|
416
|
-
if (txConfirmation >= requiredConfirmation) {
|
|
417
|
-
// tx is confirmed enough
|
|
418
|
-
await this.setTxStatus(tx, TransactionStatus.COMPLETED);
|
|
419
|
-
} else if (txConfirmation === -1) {
|
|
420
|
-
// tx is not mined, checking mempool...
|
|
421
|
-
if (await manager.isTxInMempool(tx.txId)) {
|
|
422
|
-
// tx is in mempool, updating last check...
|
|
423
|
-
const height = await manager.getHeight();
|
|
424
|
-
await this.updateTxLastCheck(tx.txId, tx.chain, height);
|
|
425
|
-
this.logger.info(`Tx [${tx.txId}] is in mempool`);
|
|
426
|
-
} else {
|
|
427
|
-
// tx is not in mempool, checking if tx is still valid
|
|
428
|
-
const isValidTx = await manager.isTxValid(
|
|
429
|
-
tx.serializedTx,
|
|
430
|
-
SigningStatus.Signed
|
|
431
|
-
);
|
|
432
|
-
const isValidToType = await this.validateTx(tx);
|
|
433
|
-
|
|
434
|
-
if (isValidTx && isValidToType) {
|
|
435
|
-
// tx is valid. resending...
|
|
436
|
-
this.logger.info(
|
|
437
|
-
`Tx [${tx.txId}] is still valid. Attempting resend...`
|
|
438
|
-
);
|
|
439
|
-
if (await this.isSubmitAllowed(tx)) {
|
|
440
|
-
try {
|
|
441
|
-
await manager.submitTransaction(tx.serializedTx);
|
|
442
|
-
} catch (e) {
|
|
443
|
-
this.logger.warn(
|
|
444
|
-
`Failed to submit tx [${tx.txId}] to chain [${tx.chain}]: ${e}`
|
|
445
|
-
);
|
|
446
|
-
if (e instanceof Error && e.stack) this.logger.warn(e.stack);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
} else {
|
|
450
|
-
// tx seems invalid. reset status if enough blocks past.
|
|
451
|
-
await this.setTransactionAsInvalid(tx);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
} else {
|
|
455
|
-
// tx is mined, but is not confirmed enough, updating last check...
|
|
456
|
-
const height = await manager.getHeight();
|
|
457
|
-
await this.updateTxLastCheck(tx.txId, tx.chain, height);
|
|
458
|
-
this.logger.info(
|
|
459
|
-
`Tx [${tx.txId}] is in confirmation process [${txConfirmation}/${requiredConfirmation}]`
|
|
460
|
-
);
|
|
461
|
-
}
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* runs all jobs of TxPot
|
|
466
|
-
* - process signed txs
|
|
467
|
-
* - process sent txs
|
|
468
|
-
*/
|
|
469
|
-
update = async (): Promise<void> => {
|
|
470
|
-
// fetch signed and sent txs
|
|
471
|
-
const signedTxs = await this.getTxsByStatus(TransactionStatus.SIGNED);
|
|
472
|
-
const sentTxs = await this.getTxsByStatus(TransactionStatus.SENT);
|
|
473
|
-
|
|
474
|
-
// process signed txs
|
|
475
|
-
for (const tx of signedTxs) {
|
|
476
|
-
try {
|
|
477
|
-
await this.processSignedTx(tx);
|
|
478
|
-
} catch (e) {
|
|
479
|
-
this.logger.warn(
|
|
480
|
-
`An error occurred while processing tx [${tx.txId}] with status [${TransactionStatus.SIGNED}]: ${e}`
|
|
481
|
-
);
|
|
482
|
-
if (e instanceof Error && e.stack) this.logger.warn(e.stack);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
this.logger.debug(
|
|
486
|
-
`Processed [${signedTxs.length}] txs with status [${TransactionStatus.SIGNED}]`
|
|
487
|
-
);
|
|
488
|
-
|
|
489
|
-
// process sent txs
|
|
490
|
-
for (const tx of sentTxs) {
|
|
491
|
-
try {
|
|
492
|
-
await this.processesSentTx(tx);
|
|
493
|
-
} catch (e) {
|
|
494
|
-
this.logger.warn(
|
|
495
|
-
`An error occurred while processing tx [${tx.txId}] with status [${TransactionStatus.SENT}]: ${e}`
|
|
496
|
-
);
|
|
497
|
-
if (e instanceof Error && e.stack) this.logger.warn(e.stack);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
this.logger.debug(
|
|
501
|
-
`Processed [${sentTxs.length}] txs with status [${TransactionStatus.SENT}]`
|
|
502
|
-
);
|
|
503
|
-
};
|
|
504
|
-
|
|
505
|
-
/**
|
|
506
|
-
* gets transactions by status
|
|
507
|
-
* @param status
|
|
508
|
-
* @param validate
|
|
509
|
-
* @returns
|
|
510
|
-
*/
|
|
511
|
-
getTxsByStatus = async (
|
|
512
|
-
status: TransactionStatus,
|
|
513
|
-
validate = false
|
|
514
|
-
): Promise<Array<TransactionEntity>> => {
|
|
515
|
-
const txs = await this.txRepository.find({
|
|
516
|
-
where: {
|
|
517
|
-
status: status,
|
|
518
|
-
},
|
|
519
|
-
});
|
|
520
|
-
if (!validate) return txs;
|
|
521
|
-
|
|
522
|
-
// validate the transactions
|
|
523
|
-
const validTxs: Array<TransactionEntity> = [];
|
|
524
|
-
for (const tx of txs) {
|
|
525
|
-
if (await this.validateTx(tx)) validTxs.push(tx);
|
|
526
|
-
}
|
|
527
|
-
return validTxs;
|
|
528
|
-
};
|
|
529
|
-
|
|
530
|
-
/**
|
|
531
|
-
* inserts a new transaction into db
|
|
532
|
-
* Note: make sure to set `lastCheck` field if initialStatus is `signed` or `sent`
|
|
533
|
-
* @param txId
|
|
534
|
-
* @param chain
|
|
535
|
-
* @param txType
|
|
536
|
-
* @param requiredSign
|
|
537
|
-
* @param serializedTx
|
|
538
|
-
* @param initialStatus
|
|
539
|
-
* @param lastCheck last blockchain height that tx was valid
|
|
540
|
-
* @param extra
|
|
541
|
-
* @param extra2
|
|
542
|
-
*/
|
|
543
|
-
addTx = async (
|
|
544
|
-
txId: string,
|
|
545
|
-
chain: string,
|
|
546
|
-
txType: string,
|
|
547
|
-
requiredSign: number,
|
|
548
|
-
serializedTx: string,
|
|
549
|
-
initialStatus = TransactionStatus.APPROVED,
|
|
550
|
-
lastCheck = 0,
|
|
551
|
-
extra?: string | null,
|
|
552
|
-
extra2?: string | null
|
|
553
|
-
): Promise<void> => {
|
|
554
|
-
await this.txRepository.insert({
|
|
555
|
-
txId: txId,
|
|
556
|
-
chain: chain,
|
|
557
|
-
txType: txType,
|
|
558
|
-
status: initialStatus,
|
|
559
|
-
requiredSign: requiredSign,
|
|
560
|
-
lastCheck: lastCheck,
|
|
561
|
-
lastStatusUpdate: this.currentTime(),
|
|
562
|
-
failedInSign: false,
|
|
563
|
-
signFailedCount: 0,
|
|
564
|
-
serializedTx: serializedTx,
|
|
565
|
-
extra: extra,
|
|
566
|
-
extra2: extra2,
|
|
567
|
-
});
|
|
568
|
-
};
|
|
569
|
-
|
|
570
|
-
/**
|
|
571
|
-
* updates the status of a tx
|
|
572
|
-
* @param txId
|
|
573
|
-
* @param chain
|
|
574
|
-
* @param status new status
|
|
575
|
-
*/
|
|
576
|
-
setTxStatusById = async (
|
|
577
|
-
txId: string,
|
|
578
|
-
chain: string,
|
|
579
|
-
status: TransactionStatus
|
|
580
|
-
): Promise<void> => {
|
|
581
|
-
const tx = await this.txRepository.findOneOrFail({
|
|
582
|
-
where: { txId, chain },
|
|
583
|
-
});
|
|
584
|
-
await this.setTxStatus(tx, status);
|
|
585
|
-
};
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* updates tx info when failed in sign process
|
|
589
|
-
* @param txId
|
|
590
|
-
* @param chain
|
|
591
|
-
*/
|
|
592
|
-
setTxAsSignFailed = async (txId: string, chain: string): Promise<void> => {
|
|
593
|
-
await this.txRepository.update(
|
|
594
|
-
{
|
|
595
|
-
txId: txId,
|
|
596
|
-
chain: chain,
|
|
597
|
-
status: TransactionStatus.IN_SIGN,
|
|
598
|
-
},
|
|
599
|
-
{
|
|
600
|
-
status: TransactionStatus.SIGN_FAILED,
|
|
601
|
-
lastStatusUpdate: this.currentTime(),
|
|
602
|
-
signFailedCount: () => '"signFailedCount" + 1',
|
|
603
|
-
failedInSign: true,
|
|
604
|
-
}
|
|
605
|
-
);
|
|
606
|
-
};
|
|
607
|
-
|
|
608
|
-
/**
|
|
609
|
-
* updates the tx and set status as signed
|
|
610
|
-
* @param txId
|
|
611
|
-
* @param chain
|
|
612
|
-
* @param serializedTx
|
|
613
|
-
* @param currentHeight current height of the blockchain
|
|
614
|
-
* @param extra
|
|
615
|
-
* @param extra2
|
|
616
|
-
*/
|
|
617
|
-
setTxAsSigned = async (
|
|
618
|
-
txId: string,
|
|
619
|
-
chain: string,
|
|
620
|
-
serializedTx: string,
|
|
621
|
-
currentHeight: number,
|
|
622
|
-
extra?: string,
|
|
623
|
-
extra2?: string
|
|
624
|
-
): Promise<void> => {
|
|
625
|
-
const updatedFields: Partial<TransactionEntity> = {
|
|
626
|
-
serializedTx: serializedTx,
|
|
627
|
-
status: TransactionStatus.SIGNED,
|
|
628
|
-
lastStatusUpdate: this.currentTime(),
|
|
629
|
-
lastCheck: currentHeight,
|
|
630
|
-
};
|
|
631
|
-
if (extra) updatedFields.extra = extra;
|
|
632
|
-
if (extra2) updatedFields.extra2 = extra2;
|
|
633
|
-
|
|
634
|
-
await this.txRepository.update({ txId, chain }, updatedFields);
|
|
635
|
-
};
|
|
636
|
-
|
|
637
|
-
/**
|
|
638
|
-
* updates last check value of a tx
|
|
639
|
-
* @param txId
|
|
640
|
-
* @param chain
|
|
641
|
-
* @param currentHeight current height of the blockchain
|
|
642
|
-
*/
|
|
643
|
-
updateTxLastCheck = async (
|
|
644
|
-
txId: string,
|
|
645
|
-
chain: string,
|
|
646
|
-
currentHeight: number
|
|
647
|
-
): Promise<void> => {
|
|
648
|
-
await this.txRepository.update(
|
|
649
|
-
{ txId, chain },
|
|
650
|
-
{ lastCheck: currentHeight }
|
|
651
|
-
);
|
|
652
|
-
};
|
|
653
|
-
|
|
654
|
-
/**
|
|
655
|
-
* updates failedInSign field of a transaction to false
|
|
656
|
-
* @param txId
|
|
657
|
-
* @param chain
|
|
658
|
-
*/
|
|
659
|
-
resetFailedInSign = async (txId: string, chain: string): Promise<void> => {
|
|
660
|
-
await this.txRepository.update(
|
|
661
|
-
{ txId, chain },
|
|
662
|
-
{
|
|
663
|
-
failedInSign: false,
|
|
664
|
-
}
|
|
665
|
-
);
|
|
666
|
-
};
|
|
667
|
-
|
|
668
|
-
/**
|
|
669
|
-
* updates requiredSign field of a transaction
|
|
670
|
-
* @param txId
|
|
671
|
-
* @param chain
|
|
672
|
-
* @param requiredSign
|
|
673
|
-
*/
|
|
674
|
-
updateRequiredSign = async (
|
|
675
|
-
txId: string,
|
|
676
|
-
chain: string,
|
|
677
|
-
requiredSign: number
|
|
678
|
-
): Promise<void> => {
|
|
679
|
-
await this.txRepository.update(
|
|
680
|
-
{ txId, chain },
|
|
681
|
-
{
|
|
682
|
-
requiredSign: requiredSign,
|
|
683
|
-
}
|
|
684
|
-
);
|
|
685
|
-
};
|
|
686
|
-
|
|
687
|
-
/**
|
|
688
|
-
* gets the transaction by its id and chain
|
|
689
|
-
* @param txId
|
|
690
|
-
* @param chain
|
|
691
|
-
*/
|
|
692
|
-
getTxByKey = async (
|
|
693
|
-
txId: string,
|
|
694
|
-
chain: string
|
|
695
|
-
): Promise<TransactionEntity | null> => {
|
|
696
|
-
return await this.txRepository.findOne({
|
|
697
|
-
where: { txId, chain },
|
|
698
|
-
});
|
|
699
|
-
};
|
|
700
|
-
|
|
701
|
-
/**
|
|
702
|
-
* @returns the transactions with valid status
|
|
703
|
-
*/
|
|
704
|
-
getTxsQuery = (
|
|
705
|
-
options: Array<TxOptions> = []
|
|
706
|
-
): Promise<TransactionEntity[]> => {
|
|
707
|
-
return this.txRepository.find({
|
|
708
|
-
where: options.map(txOptionToClause),
|
|
709
|
-
});
|
|
710
|
-
};
|
|
711
|
-
|
|
712
|
-
/**
|
|
713
|
-
* updates extra fields of a transaction
|
|
714
|
-
* @param txId
|
|
715
|
-
* @param chain
|
|
716
|
-
* @param extra
|
|
717
|
-
* @param extra2
|
|
718
|
-
*/
|
|
719
|
-
updateExtra = async (
|
|
720
|
-
txId: string,
|
|
721
|
-
chain: string,
|
|
722
|
-
extra?: string | null,
|
|
723
|
-
extra2?: string | null
|
|
724
|
-
): Promise<void> => {
|
|
725
|
-
if (extra === undefined && extra2 === undefined) return;
|
|
726
|
-
await this.txRepository.update({ txId, chain }, { extra, extra2 });
|
|
727
|
-
};
|
|
728
|
-
}
|