edge-currency-plugins 3.2.0 → 3.3.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/android/src/main/assets/edge-currency-plugins/edge-currency-plugins.js +41 -41
- package/lib/common/plugin/PluginState.js +73 -43
- package/lib/common/plugin/ServerScores.js +11 -0
- package/lib/common/plugin/types.js +1 -1
- package/lib/common/utxobased/db/{Processor.js → DataLayer.js} +15 -11
- package/lib/common/utxobased/db/Models/{ProcessorTransaction.js → TransactionData.js} +4 -6
- package/lib/common/utxobased/db/types.js +4 -4
- package/lib/common/utxobased/db/util/utxo.js +8 -8
- package/lib/common/utxobased/engine/ServerStates.js +324 -298
- package/lib/common/utxobased/engine/UtxoEngine.js +58 -55
- package/lib/common/utxobased/engine/{UtxoEngineState.js → UtxoEngineProcessor.js} +650 -714
- package/lib/common/utxobased/engine/types.js +4 -2
- package/lib/common/utxobased/engine/util/getOwnUtxosFromTx.js +4 -4
- package/lib/common/utxobased/info/bitcoin.js +2 -1
- package/lib/common/utxobased/info/bitcoincash.js +2 -1
- package/lib/common/utxobased/info/dash.js +2 -1
- package/lib/common/utxobased/info/digibyte.js +5 -1
- package/lib/common/utxobased/info/dogecoin.js +2 -1
- package/lib/common/utxobased/info/groestlcoin.js +4 -1
- package/lib/common/utxobased/info/litecoin.js +2 -1
- package/lib/common/utxobased/info/zcoin.js +4 -1
- package/lib/common/utxobased/network/Blockbook.js +33 -30
- package/lib/common/utxobased/network/BlockbookElectrum.js +79 -77
- package/lib/common/utxobased/network/Socket.js +84 -48
- package/lib/common/utxobased/network/windowWS.js +2 -2
- package/lib/src/common/plugin/PluginState.d.ts +4 -4
- package/lib/src/common/plugin/ServerScores.d.ts +1 -0
- package/lib/src/common/plugin/types.d.ts +4 -4
- package/lib/src/common/utxobased/db/{Processor.d.ts → DataLayer.d.ts} +17 -11
- package/lib/src/common/utxobased/db/Models/{ProcessorTransaction.d.ts → TransactionData.d.ts} +5 -5
- package/lib/src/common/utxobased/db/Models/baselet.d.ts +4 -4
- package/lib/src/common/utxobased/db/types.d.ts +9 -9
- package/lib/src/common/utxobased/db/util/utxo.d.ts +3 -3
- package/lib/src/common/utxobased/engine/ServerStates.d.ts +7 -7
- package/lib/src/common/utxobased/engine/{UtxoEngineState.d.ts → UtxoEngineProcessor.d.ts} +44 -42
- package/lib/src/common/utxobased/engine/types.d.ts +4 -4
- package/lib/src/common/utxobased/engine/util/getOwnUtxosFromTx.d.ts +3 -3
- package/lib/src/common/utxobased/engine/utils.d.ts +2 -2
- package/lib/src/common/utxobased/keymanager/keymanager.d.ts +3 -3
- package/lib/src/common/utxobased/network/Blockbook.d.ts +8 -7
- package/lib/src/common/utxobased/network/BlockbookElectrum.d.ts +4 -2
- package/lib/src/common/utxobased/network/Socket.d.ts +10 -8
- package/lib/src/common/utxobased/network/types.d.ts +1 -1
- package/lib/src/util/uriKeyParams.d.ts +4 -0
- package/lib/util/uriKeyParams.js +20 -0
- package/package.json +1 -1
- /package/lib/test/common/utxobased/db/{Processor.spec.d.ts → DataLayer.spec.d.ts} +0 -0
|
@@ -16,10 +16,9 @@ var _EngineEmitter = require('../../plugin/EngineEmitter');
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
|
|
20
19
|
var _utils = require('../../plugin/utils');
|
|
21
|
-
var _ProcessorTransaction = require('../db/Models/ProcessorTransaction');
|
|
22
20
|
|
|
21
|
+
var _TransactionData = require('../db/Models/TransactionData');
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
|
|
@@ -39,7 +38,6 @@ var _keymanager = require('../keymanager/keymanager');
|
|
|
39
38
|
|
|
40
39
|
|
|
41
40
|
|
|
42
|
-
var _Deferred = require('../network/Deferred'); var _Deferred2 = _interopRequireDefault(_Deferred);
|
|
43
41
|
|
|
44
42
|
var _awaitlock = require('./await-lock'); var _awaitlock2 = _interopRequireDefault(_awaitlock);
|
|
45
43
|
var _constants = require('./constants');
|
|
@@ -87,7 +85,7 @@ var _utils3 = require('./utils');
|
|
|
87
85
|
|
|
88
86
|
|
|
89
87
|
|
|
90
|
-
function
|
|
88
|
+
function makeUtxoEngineProcessor(
|
|
91
89
|
config
|
|
92
90
|
) {
|
|
93
91
|
const {
|
|
@@ -96,7 +94,7 @@ var _utils3 = require('./utils');
|
|
|
96
94
|
options,
|
|
97
95
|
pluginState,
|
|
98
96
|
pluginInfo,
|
|
99
|
-
|
|
97
|
+
dataLayer,
|
|
100
98
|
walletInfo,
|
|
101
99
|
walletTools
|
|
102
100
|
} = config
|
|
@@ -105,38 +103,36 @@ var _utils3 = require('./utils');
|
|
|
105
103
|
const { walletFormats } = walletInfo.keys
|
|
106
104
|
|
|
107
105
|
const taskCache = {
|
|
108
|
-
|
|
106
|
+
addressForTransactionsCache: {},
|
|
107
|
+
addressForUtxosCache: {},
|
|
109
108
|
addressSubscribeCache: {},
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
updateTransactionCache: {},
|
|
115
|
-
updateTransactionSpecificCache: {}
|
|
109
|
+
blockbookUtxoCache: {},
|
|
110
|
+
dataLayerUtxoCache: {},
|
|
111
|
+
transactionSpecificUpdateCache: {},
|
|
112
|
+
transactionUpdateCache: {}
|
|
116
113
|
}
|
|
117
114
|
|
|
118
115
|
const clearTaskCache = () => {
|
|
119
|
-
taskCache.
|
|
120
|
-
|
|
121
|
-
_utils.removeItem.call(void 0, taskCache.addressSubscribeCache, key)
|
|
116
|
+
for (const key of Object.keys(taskCache.addressForTransactionsCache)) {
|
|
117
|
+
_utils.removeItem.call(void 0, taskCache.addressForTransactionsCache, key)
|
|
122
118
|
}
|
|
123
|
-
for (const key of Object.keys(taskCache.
|
|
124
|
-
_utils.removeItem.call(void 0, taskCache.
|
|
119
|
+
for (const key of Object.keys(taskCache.addressForUtxosCache)) {
|
|
120
|
+
_utils.removeItem.call(void 0, taskCache.addressForUtxosCache, key)
|
|
125
121
|
}
|
|
126
|
-
for (const key of Object.keys(taskCache.
|
|
127
|
-
_utils.removeItem.call(void 0, taskCache.
|
|
122
|
+
for (const key of Object.keys(taskCache.addressSubscribeCache)) {
|
|
123
|
+
_utils.removeItem.call(void 0, taskCache.addressSubscribeCache, key)
|
|
128
124
|
}
|
|
129
|
-
for (const key of Object.keys(taskCache.
|
|
130
|
-
_utils.removeItem.call(void 0, taskCache.
|
|
125
|
+
for (const key of Object.keys(taskCache.blockbookUtxoCache)) {
|
|
126
|
+
_utils.removeItem.call(void 0, taskCache.blockbookUtxoCache, key)
|
|
131
127
|
}
|
|
132
|
-
for (const key of Object.keys(taskCache.
|
|
133
|
-
_utils.removeItem.call(void 0, taskCache.
|
|
128
|
+
for (const key of Object.keys(taskCache.dataLayerUtxoCache)) {
|
|
129
|
+
_utils.removeItem.call(void 0, taskCache.dataLayerUtxoCache, key)
|
|
134
130
|
}
|
|
135
|
-
for (const key of Object.keys(taskCache.
|
|
136
|
-
_utils.removeItem.call(void 0, taskCache.
|
|
131
|
+
for (const key of Object.keys(taskCache.transactionSpecificUpdateCache)) {
|
|
132
|
+
_utils.removeItem.call(void 0, taskCache.transactionSpecificUpdateCache, key)
|
|
137
133
|
}
|
|
138
|
-
for (const key of Object.keys(taskCache.
|
|
139
|
-
_utils.removeItem.call(void 0, taskCache.
|
|
134
|
+
for (const key of Object.keys(taskCache.transactionUpdateCache)) {
|
|
135
|
+
_utils.removeItem.call(void 0, taskCache.transactionUpdateCache, key)
|
|
140
136
|
}
|
|
141
137
|
}
|
|
142
138
|
|
|
@@ -184,24 +180,23 @@ var _utils3 = require('./utils');
|
|
|
184
180
|
pluginState,
|
|
185
181
|
walletInfo
|
|
186
182
|
})
|
|
187
|
-
const
|
|
183
|
+
const common = {
|
|
188
184
|
pluginInfo,
|
|
189
185
|
walletInfo,
|
|
190
186
|
walletTools,
|
|
191
|
-
|
|
187
|
+
dataLayer,
|
|
192
188
|
emitter,
|
|
193
189
|
taskCache,
|
|
194
190
|
updateProgressRatio,
|
|
195
191
|
io,
|
|
196
192
|
log,
|
|
197
193
|
serverStates,
|
|
198
|
-
pluginState,
|
|
199
194
|
walletFormats,
|
|
200
195
|
lock
|
|
201
196
|
}
|
|
202
197
|
|
|
203
|
-
serverStates.setPickNextTaskCB(
|
|
204
|
-
return
|
|
198
|
+
serverStates.setPickNextTaskCB(serverUri => {
|
|
199
|
+
return pickNextTask(common, serverUri)
|
|
205
200
|
})
|
|
206
201
|
|
|
207
202
|
let running = false
|
|
@@ -210,18 +205,18 @@ var _utils3 = require('./utils');
|
|
|
210
205
|
running = true
|
|
211
206
|
|
|
212
207
|
await initializeAddressSubscriptions()
|
|
213
|
-
await setLookAhead(
|
|
208
|
+
await setLookAhead(common)
|
|
214
209
|
}
|
|
215
210
|
|
|
216
211
|
emitter.on(
|
|
217
212
|
_EngineEmitter.EngineEvent.BLOCK_HEIGHT_CHANGED,
|
|
218
213
|
async (_uri, _blockHeight) => {
|
|
219
|
-
const txs = await
|
|
214
|
+
const txs = await dataLayer.fetchTransactions({
|
|
220
215
|
blockHeight: 0
|
|
221
216
|
})
|
|
222
217
|
for (const tx of txs) {
|
|
223
218
|
if (tx == null) continue
|
|
224
|
-
taskCache.
|
|
219
|
+
taskCache.transactionUpdateCache[tx.txid] = { processing: false }
|
|
225
220
|
}
|
|
226
221
|
}
|
|
227
222
|
)
|
|
@@ -232,20 +227,19 @@ var _utils3 = require('./utils');
|
|
|
232
227
|
const state = taskCache.addressSubscribeCache[response.address]
|
|
233
228
|
if (state != null) {
|
|
234
229
|
const { path } = state
|
|
235
|
-
taskCache.
|
|
230
|
+
taskCache.addressForUtxosCache[response.address] = {
|
|
236
231
|
processing: false,
|
|
237
232
|
path
|
|
238
233
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
).catch(() => {
|
|
234
|
+
addToAddressForTransactionsCache(common, {
|
|
235
|
+
address: response.address,
|
|
236
|
+
changePath: path,
|
|
237
|
+
blockHeight: 0,
|
|
238
|
+
addressForTransactionsCache: taskCache.addressForTransactionsCache
|
|
239
|
+
}).catch(() => {
|
|
246
240
|
throw new Error('failed to add to transaction cache')
|
|
247
241
|
})
|
|
248
|
-
setLookAhead(
|
|
242
|
+
setLookAhead(common).catch(e => {
|
|
249
243
|
log(e)
|
|
250
244
|
})
|
|
251
245
|
}
|
|
@@ -253,7 +247,7 @@ var _utils3 = require('./utils');
|
|
|
253
247
|
)
|
|
254
248
|
|
|
255
249
|
// Initialize the addressSubscribeCache with the existing addresses already
|
|
256
|
-
// processed by the
|
|
250
|
+
// processed by the DataLayer. This happens only once before any call to
|
|
257
251
|
// setLookAhead.
|
|
258
252
|
const initializeAddressSubscriptions = async () => {
|
|
259
253
|
const addressBalanceChanges
|
|
@@ -269,10 +263,10 @@ var _utils3 = require('./utils');
|
|
|
269
263
|
format,
|
|
270
264
|
changeIndex: branch
|
|
271
265
|
}
|
|
272
|
-
const branchAddressCount =
|
|
266
|
+
const branchAddressCount = dataLayer.numAddressesByFormatPath(
|
|
273
267
|
changePath
|
|
274
268
|
)
|
|
275
|
-
// If the
|
|
269
|
+
// If the DataLayer has not processed any addresses then the loop
|
|
276
270
|
// condition will only iterate once when branchAddressCount is 0 for the
|
|
277
271
|
// first address in the derivation path.
|
|
278
272
|
for (
|
|
@@ -280,29 +274,29 @@ var _utils3 = require('./utils');
|
|
|
280
274
|
addressIndex < branchAddressCount;
|
|
281
275
|
addressIndex++
|
|
282
276
|
) {
|
|
283
|
-
const
|
|
277
|
+
const addressData = await dataLayer.fetchAddress({
|
|
284
278
|
format,
|
|
285
279
|
changeIndex: branch,
|
|
286
280
|
addressIndex
|
|
287
281
|
})
|
|
288
|
-
if (
|
|
282
|
+
if (addressData == null) {
|
|
289
283
|
throw new Error(
|
|
290
|
-
`Missing
|
|
284
|
+
`Missing data-layer address with '${format}/${branch}/${addressIndex}' path during initialization`
|
|
291
285
|
)
|
|
292
286
|
}
|
|
293
287
|
const { address } = walletTools.scriptPubkeyToAddress({
|
|
294
288
|
changePath,
|
|
295
|
-
scriptPubkey:
|
|
289
|
+
scriptPubkey: addressData.scriptPubkey
|
|
296
290
|
})
|
|
297
291
|
addressesToSubscribe.add(address)
|
|
298
|
-
if (
|
|
292
|
+
if (addressData.balance != null) {
|
|
299
293
|
addressBalanceChanges.push({
|
|
300
|
-
scriptPubkey:
|
|
301
|
-
balance:
|
|
294
|
+
scriptPubkey: addressData.scriptPubkey,
|
|
295
|
+
balance: addressData.balance
|
|
302
296
|
})
|
|
303
297
|
}
|
|
304
298
|
}
|
|
305
|
-
addToAddressSubscribeCache(
|
|
299
|
+
addToAddressSubscribeCache(common.taskCache, addressesToSubscribe, {
|
|
306
300
|
format,
|
|
307
301
|
changeIndex: branch
|
|
308
302
|
})
|
|
@@ -348,11 +342,12 @@ var _utils3 = require('./utils');
|
|
|
348
342
|
address: publicAddress,
|
|
349
343
|
nativeBalance = '0',
|
|
350
344
|
legacyAddress
|
|
351
|
-
} = await internalGetFreshAddress({
|
|
352
|
-
...commonArgs,
|
|
353
|
-
format: privateKeyFormat,
|
|
345
|
+
} = await internalGetFreshAddress(common, {
|
|
354
346
|
forceIndex,
|
|
355
|
-
|
|
347
|
+
changePath: {
|
|
348
|
+
format: privateKeyFormat,
|
|
349
|
+
changeIndex: branch
|
|
350
|
+
}
|
|
356
351
|
})
|
|
357
352
|
|
|
358
353
|
const freshAddress = {
|
|
@@ -378,11 +373,12 @@ var _utils3 = require('./utils');
|
|
|
378
373
|
const {
|
|
379
374
|
address,
|
|
380
375
|
nativeBalance = '0'
|
|
381
|
-
} = await internalGetFreshAddress({
|
|
382
|
-
...commonArgs,
|
|
383
|
-
format,
|
|
376
|
+
} = await internalGetFreshAddress(common, {
|
|
384
377
|
forceIndex,
|
|
385
|
-
|
|
378
|
+
changePath: {
|
|
379
|
+
format,
|
|
380
|
+
changeIndex: branch
|
|
381
|
+
}
|
|
386
382
|
})
|
|
387
383
|
|
|
388
384
|
freshAddress.segwitAddress = address
|
|
@@ -395,10 +391,10 @@ var _utils3 = require('./utils');
|
|
|
395
391
|
|
|
396
392
|
async deriveScriptAddress(script) {
|
|
397
393
|
const { address } = await internalDeriveScriptAddress({
|
|
398
|
-
walletTools:
|
|
399
|
-
engineInfo:
|
|
400
|
-
|
|
401
|
-
taskCache:
|
|
394
|
+
walletTools: common.walletTools,
|
|
395
|
+
engineInfo: common.pluginInfo.engineInfo,
|
|
396
|
+
dataLayer: common.dataLayer,
|
|
397
|
+
taskCache: common.taskCache,
|
|
402
398
|
format: walletInfo.keys.privateKeyFormat,
|
|
403
399
|
script
|
|
404
400
|
})
|
|
@@ -410,8 +406,8 @@ var _utils3 = require('./utils');
|
|
|
410
406
|
async addGapLimitAddresses(addresses) {
|
|
411
407
|
const promises = addresses.map(async address => {
|
|
412
408
|
const scriptPubkey = walletTools.addressToScriptPubkey(address)
|
|
413
|
-
await
|
|
414
|
-
_types5.
|
|
409
|
+
await dataLayer.saveAddress(
|
|
410
|
+
_types5.makeAddressData.call(void 0, {
|
|
415
411
|
scriptPubkey,
|
|
416
412
|
used: true
|
|
417
413
|
})
|
|
@@ -457,8 +453,8 @@ var _utils3 = require('./utils');
|
|
|
457
453
|
})
|
|
458
454
|
|
|
459
455
|
// Make a new IAddress and save it
|
|
460
|
-
await
|
|
461
|
-
_types5.
|
|
456
|
+
await dataLayer.saveAddress(
|
|
457
|
+
_types5.makeAddressData.call(void 0, { scriptPubkey, redeemScript, path })
|
|
462
458
|
)
|
|
463
459
|
|
|
464
460
|
taskCache.addressSubscribeCache[address] = {
|
|
@@ -469,7 +465,6 @@ var _utils3 = require('./utils');
|
|
|
469
465
|
}
|
|
470
466
|
},
|
|
471
467
|
async processUtxos(utxos) {
|
|
472
|
-
// Map of scriptPubkey to IUTXOs
|
|
473
468
|
const utxoMap = new Map()
|
|
474
469
|
const utxoIds = new Set()
|
|
475
470
|
|
|
@@ -487,7 +482,7 @@ var _utils3 = require('./utils');
|
|
|
487
482
|
// Process UTXO sets for each scriptPubkey in map
|
|
488
483
|
for (const [scriptPubkey, utxos] of utxoMap.entries()) {
|
|
489
484
|
// Get saved utxo set
|
|
490
|
-
const savedUtxos = await
|
|
485
|
+
const savedUtxos = await dataLayer.fetchUtxos({ scriptPubkey })
|
|
491
486
|
// Filter UTXOs to de-duplicate (and undefined utxo as a type assert)
|
|
492
487
|
const filteredUtxos = savedUtxos.filter(
|
|
493
488
|
utxo => utxo != null && !utxoIds.has(_optionalChain([utxo, 'optionalAccess', _ => _.id]))
|
|
@@ -496,15 +491,62 @@ var _utils3 = require('./utils');
|
|
|
496
491
|
// Add updated utxos to utxo set
|
|
497
492
|
const combinedUtxos = [...filteredUtxos, ...utxos]
|
|
498
493
|
|
|
499
|
-
await
|
|
500
|
-
...commonArgs,
|
|
494
|
+
await processDataLayerUtxos(common, {
|
|
501
495
|
scriptPubkey,
|
|
502
496
|
utxos: combinedUtxos
|
|
503
497
|
})
|
|
504
498
|
}
|
|
505
499
|
}
|
|
506
500
|
}
|
|
507
|
-
} exports.
|
|
501
|
+
} exports.makeUtxoEngineProcessor = makeUtxoEngineProcessor;
|
|
502
|
+
|
|
503
|
+
const internalDeriveScriptAddress = async (args
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
) => {
|
|
515
|
+
const { walletTools, engineInfo, dataLayer, format, taskCache, script } = args
|
|
516
|
+
if (engineInfo.scriptTemplates == null) {
|
|
517
|
+
throw new Error(
|
|
518
|
+
`cannot derive script address ${script} without defined script template`
|
|
519
|
+
)
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const scriptTemplate = engineInfo.scriptTemplates[script]
|
|
523
|
+
|
|
524
|
+
const path = {
|
|
525
|
+
format,
|
|
526
|
+
changeIndex: _keymanager.derivationLevelScriptHash.call(void 0, scriptTemplate),
|
|
527
|
+
addressIndex: 0
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// save the address to the dataLayer and add it to the cache
|
|
531
|
+
const { address, scriptPubkey, redeemScript } = walletTools.getScriptAddress({
|
|
532
|
+
path,
|
|
533
|
+
scriptTemplate
|
|
534
|
+
})
|
|
535
|
+
await dataLayer.saveAddress(
|
|
536
|
+
_types5.makeAddressData.call(void 0, { scriptPubkey, redeemScript, path })
|
|
537
|
+
)
|
|
538
|
+
const addresses = new Set()
|
|
539
|
+
addresses.add(address)
|
|
540
|
+
addToAddressSubscribeCache(taskCache, addresses, {
|
|
541
|
+
format: path.format,
|
|
542
|
+
changeIndex: path.changeIndex
|
|
543
|
+
})
|
|
544
|
+
return { address, scriptPubkey, redeemScript }
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const internalGetFreshAddress = async (
|
|
548
|
+
common,
|
|
549
|
+
args
|
|
508
550
|
|
|
509
551
|
|
|
510
552
|
|
|
@@ -512,9 +554,42 @@ var _utils3 = require('./utils');
|
|
|
512
554
|
|
|
513
555
|
|
|
514
556
|
|
|
557
|
+
) => {
|
|
558
|
+
const { changePath, forceIndex } = args
|
|
515
559
|
|
|
560
|
+
const numAddresses = common.dataLayer.numAddressesByFormatPath(changePath)
|
|
516
561
|
|
|
562
|
+
const path = {
|
|
563
|
+
format: changePath.format,
|
|
564
|
+
changeIndex: changePath.changeIndex,
|
|
565
|
+
// while syncing, we may hit negative numbers when only subtracting. Use the address at /0 in that case.
|
|
566
|
+
addressIndex: Math.max(
|
|
567
|
+
numAddresses - common.pluginInfo.engineInfo.gapLimit,
|
|
568
|
+
0
|
|
569
|
+
)
|
|
570
|
+
}
|
|
571
|
+
if (forceIndex != null) {
|
|
572
|
+
path.addressIndex = forceIndex
|
|
573
|
+
}
|
|
517
574
|
|
|
575
|
+
const iAddress = await common.dataLayer.fetchAddress(path)
|
|
576
|
+
const nativeBalance = _nullishCoalesce(_optionalChain([iAddress, 'optionalAccess', _2 => _2.balance]), () => ( '0'))
|
|
577
|
+
const { scriptPubkey } =
|
|
578
|
+
await _asyncNullishCoalesce(iAddress, async () => ( (await common.walletTools.getScriptPubkey(path))))
|
|
579
|
+
|
|
580
|
+
if (scriptPubkey == null) {
|
|
581
|
+
throw new Error('Unknown address path')
|
|
582
|
+
}
|
|
583
|
+
const address = common.walletTools.scriptPubkeyToAddress({
|
|
584
|
+
changePath: path,
|
|
585
|
+
scriptPubkey
|
|
586
|
+
})
|
|
587
|
+
|
|
588
|
+
return {
|
|
589
|
+
...address,
|
|
590
|
+
nativeBalance
|
|
591
|
+
}
|
|
592
|
+
}
|
|
518
593
|
|
|
519
594
|
|
|
520
595
|
|
|
@@ -573,37 +648,41 @@ var _utils3 = require('./utils');
|
|
|
573
648
|
|
|
574
649
|
|
|
575
650
|
|
|
576
|
-
const setLookAhead = async (common) => {
|
|
577
|
-
const {
|
|
578
|
-
pluginInfo: { engineInfo },
|
|
579
|
-
lock,
|
|
580
|
-
processor,
|
|
581
|
-
walletFormats,
|
|
582
|
-
walletTools
|
|
583
|
-
} = common
|
|
584
651
|
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
const setLookAhead = async (common) => {
|
|
585
657
|
// Wait for the lock to be released before continuing invocation.
|
|
586
658
|
// This is to ensure that setLockAhead is not called while the lock is held.
|
|
587
|
-
await lock.acquireAsync()
|
|
659
|
+
await common.lock.acquireAsync()
|
|
588
660
|
|
|
589
661
|
try {
|
|
590
|
-
for (const format of walletFormats) {
|
|
591
|
-
const branches = _utils3.getFormatSupportedBranches.call(void 0,
|
|
662
|
+
for (const format of common.walletFormats) {
|
|
663
|
+
const branches = _utils3.getFormatSupportedBranches.call(void 0,
|
|
664
|
+
common.pluginInfo.engineInfo,
|
|
665
|
+
format
|
|
666
|
+
)
|
|
592
667
|
for (const branch of branches) {
|
|
593
668
|
await deriveKeys({ format, changeIndex: branch })
|
|
594
669
|
}
|
|
595
670
|
}
|
|
596
671
|
} finally {
|
|
597
|
-
lock.release()
|
|
672
|
+
common.lock.release()
|
|
598
673
|
}
|
|
599
674
|
|
|
600
675
|
async function deriveKeys(changePath) {
|
|
601
676
|
const addressesToSubscribe = new Set()
|
|
602
|
-
const totalAddressCount =
|
|
603
|
-
|
|
677
|
+
const totalAddressCount = common.dataLayer.numAddressesByFormatPath(
|
|
678
|
+
changePath
|
|
679
|
+
)
|
|
680
|
+
let lastUsedIndex = await common.dataLayer.lastUsedIndexByFormatPath(
|
|
681
|
+
changePath
|
|
682
|
+
)
|
|
604
683
|
|
|
605
684
|
// Loop until the total address count equals the lookahead count
|
|
606
|
-
let lookAheadIndex = lastUsedIndex + engineInfo.gapLimit
|
|
685
|
+
let lookAheadIndex = lastUsedIndex + common.pluginInfo.engineInfo.gapLimit
|
|
607
686
|
let nextAddressIndex = totalAddressCount
|
|
608
687
|
while (nextAddressIndex <= lookAheadIndex) {
|
|
609
688
|
const path = {
|
|
@@ -611,24 +690,28 @@ const setLookAhead = async (common) => {
|
|
|
611
690
|
addressIndex: nextAddressIndex
|
|
612
691
|
}
|
|
613
692
|
|
|
614
|
-
const { scriptPubkey, redeemScript } = walletTools.getScriptPubkey(
|
|
615
|
-
|
|
693
|
+
const { scriptPubkey, redeemScript } = common.walletTools.getScriptPubkey(
|
|
694
|
+
path
|
|
695
|
+
)
|
|
696
|
+
const { address } = common.walletTools.scriptPubkeyToAddress({
|
|
616
697
|
changePath: path,
|
|
617
698
|
scriptPubkey
|
|
618
699
|
})
|
|
619
700
|
|
|
620
701
|
// Make a new IAddress and save it
|
|
621
|
-
await
|
|
622
|
-
_types5.
|
|
702
|
+
await common.dataLayer.saveAddress(
|
|
703
|
+
_types5.makeAddressData.call(void 0, { scriptPubkey, redeemScript, path })
|
|
623
704
|
)
|
|
624
705
|
|
|
625
706
|
// Add the displayAddress to the set of addresses to subscribe to after loop
|
|
626
707
|
addressesToSubscribe.add(address)
|
|
627
708
|
|
|
628
709
|
// Update the state for the loop
|
|
629
|
-
lastUsedIndex = await
|
|
630
|
-
|
|
631
|
-
|
|
710
|
+
lastUsedIndex = await common.dataLayer.lastUsedIndexByFormatPath(
|
|
711
|
+
changePath
|
|
712
|
+
)
|
|
713
|
+
lookAheadIndex = lastUsedIndex + common.pluginInfo.engineInfo.gapLimit
|
|
714
|
+
nextAddressIndex = common.dataLayer.numAddressesByFormatPath(changePath)
|
|
632
715
|
}
|
|
633
716
|
|
|
634
717
|
// Add all the addresses to the subscribe cache for registering subscriptions later
|
|
@@ -653,24 +736,27 @@ const addToAddressSubscribeCache = (
|
|
|
653
736
|
})
|
|
654
737
|
}
|
|
655
738
|
|
|
656
|
-
const
|
|
739
|
+
const addToAddressForTransactionsCache = async (
|
|
657
740
|
common,
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
741
|
+
args
|
|
742
|
+
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
|
|
662
747
|
) => {
|
|
663
|
-
const {
|
|
748
|
+
const { address, changePath, addressForTransactionsCache } = args
|
|
749
|
+
let { blockHeight } = args
|
|
664
750
|
// Fetch the blockHeight for the address from the database
|
|
665
|
-
const scriptPubkey = walletTools.addressToScriptPubkey(address)
|
|
751
|
+
const scriptPubkey = common.walletTools.addressToScriptPubkey(address)
|
|
666
752
|
|
|
667
753
|
if (blockHeight === 0) {
|
|
668
754
|
const { lastQueriedBlockHeight = 0 } =
|
|
669
|
-
await _asyncNullishCoalesce((await
|
|
755
|
+
await _asyncNullishCoalesce((await common.dataLayer.fetchAddress(scriptPubkey)), async () => ( {}))
|
|
670
756
|
blockHeight = lastQueriedBlockHeight
|
|
671
757
|
}
|
|
672
758
|
|
|
673
|
-
|
|
759
|
+
addressForTransactionsCache[address] = {
|
|
674
760
|
processing: false,
|
|
675
761
|
path: changePath,
|
|
676
762
|
page: 1, // Page starts on 1
|
|
@@ -678,88 +764,96 @@ const addToAddressTransactionCache = async (
|
|
|
678
764
|
}
|
|
679
765
|
}
|
|
680
766
|
|
|
767
|
+
const transactionChanged = async (args
|
|
681
768
|
|
|
682
769
|
|
|
683
770
|
|
|
684
771
|
|
|
685
772
|
|
|
686
773
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
const transactionChanged = async (
|
|
691
|
-
args
|
|
692
774
|
) => {
|
|
693
|
-
const {
|
|
775
|
+
const { dataLayer, emitter, pluginInfo, tx, walletTools, walletId } = args
|
|
694
776
|
emitter.emit(_EngineEmitter.EngineEvent.TRANSACTIONS_CHANGED, [
|
|
695
|
-
await
|
|
777
|
+
await _TransactionData.toEdgeTransaction.call(void 0, {
|
|
696
778
|
walletId,
|
|
697
779
|
tx,
|
|
698
780
|
walletTools,
|
|
699
|
-
|
|
781
|
+
dataLayer,
|
|
700
782
|
pluginInfo
|
|
701
783
|
})
|
|
702
784
|
])
|
|
703
785
|
}; exports.transactionChanged = transactionChanged
|
|
704
786
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
787
|
+
/**
|
|
788
|
+
* Some currencies require an additional blockbook payload 'getTransactionSpecific' in order
|
|
789
|
+
* to provide all relevant transaction data. Since this is currency-specific, we can limit
|
|
790
|
+
* the usage to currencies that require it.
|
|
791
|
+
**/
|
|
792
|
+
const needsTxSpecific = (common) => {
|
|
793
|
+
return common.pluginInfo.engineInfo.txSpecificHandling != null
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* The pickNextTask generator is responsible for selecting the next WsTask
|
|
798
|
+
* to be done by the network layer. It will yield WsTasks or booleans for early
|
|
799
|
+
* exit, and it will return a boolean when it's done.
|
|
800
|
+
*/
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
|
|
710
804
|
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
async function* pickNextTask(
|
|
809
|
+
common,
|
|
810
|
+
serverUri
|
|
811
|
+
) {
|
|
711
812
|
const {
|
|
813
|
+
addressForTransactionsCache,
|
|
814
|
+
addressForUtxosCache,
|
|
712
815
|
addressSubscribeCache,
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
updateTransactionSpecificCache
|
|
719
|
-
} = taskCache
|
|
816
|
+
blockbookUtxoCache,
|
|
817
|
+
dataLayerUtxoCache,
|
|
818
|
+
transactionSpecificUpdateCache,
|
|
819
|
+
transactionUpdateCache
|
|
820
|
+
} = common.taskCache
|
|
720
821
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
* to provide all relevant transaction data. Since this is currency-specific, we can limit
|
|
724
|
-
* the useage to currencies that require it.
|
|
725
|
-
**/
|
|
726
|
-
const needsTxSpecific = pluginInfo.engineInfo.txSpecificHandling != null
|
|
727
|
-
|
|
728
|
-
const serverState = serverStates.getServerState(serverUri)
|
|
729
|
-
if (serverState == null) return
|
|
822
|
+
const serverState = common.serverStates.getServerState(serverUri)
|
|
823
|
+
if (serverState == null) return false
|
|
730
824
|
|
|
731
825
|
// subscribe all servers to new blocks
|
|
732
826
|
if (serverState.blockSubscriptionStatus === 'unsubscribed') {
|
|
733
|
-
serverStates.watchBlocks(serverUri)
|
|
827
|
+
common.serverStates.watchBlocks(serverUri)
|
|
734
828
|
return true
|
|
735
829
|
}
|
|
736
830
|
|
|
737
831
|
// Loop processed utxos, these are just database ops, triggers setLookAhead
|
|
738
|
-
if (Object.keys(
|
|
739
|
-
for (const [scriptPubkey,
|
|
832
|
+
if (Object.keys(dataLayerUtxoCache).length > 0) {
|
|
833
|
+
for (const [scriptPubkey, cacheItem] of Object.entries(
|
|
834
|
+
dataLayerUtxoCache
|
|
835
|
+
)) {
|
|
740
836
|
// Only process when all utxos for a specific address have been gathered
|
|
741
|
-
if (!
|
|
742
|
-
|
|
743
|
-
await
|
|
744
|
-
...args,
|
|
837
|
+
if (!cacheItem.processing && cacheItem.full) {
|
|
838
|
+
cacheItem.processing = true
|
|
839
|
+
await processDataLayerUtxos(common, {
|
|
745
840
|
scriptPubkey,
|
|
746
|
-
utxos:
|
|
841
|
+
utxos: cacheItem.utxos
|
|
747
842
|
})
|
|
748
|
-
_utils.removeItem.call(void 0,
|
|
843
|
+
_utils.removeItem.call(void 0, dataLayerUtxoCache, scriptPubkey)
|
|
749
844
|
return true
|
|
750
845
|
}
|
|
751
846
|
}
|
|
752
847
|
}
|
|
753
848
|
|
|
754
849
|
// Loop unparsed utxos, some require a network call to get the full tx data
|
|
755
|
-
for (const [utxoId,
|
|
756
|
-
const utxo =
|
|
757
|
-
if (
|
|
758
|
-
if (!state.processing) {
|
|
850
|
+
for (const [utxoId, cacheItem] of Object.entries(blockbookUtxoCache)) {
|
|
851
|
+
const utxo = cacheItem.blockbookUtxo
|
|
852
|
+
if (!cacheItem.processing) {
|
|
759
853
|
// check if we need to fetch additional network content for legacy purpose type
|
|
760
854
|
const purposeType = _utils3.pathToPurposeType.call(void 0,
|
|
761
|
-
|
|
762
|
-
pluginInfo.engineInfo.scriptTemplates
|
|
855
|
+
cacheItem.path,
|
|
856
|
+
common.pluginInfo.engineInfo.scriptTemplates
|
|
763
857
|
)
|
|
764
858
|
if (
|
|
765
859
|
purposeType === _keymanager.BIP43PurposeTypeEnum.Airbitz ||
|
|
@@ -767,50 +861,36 @@ const addToAddressTransactionCache = async (
|
|
|
767
861
|
purposeType === _keymanager.BIP43PurposeTypeEnum.ReplayProtection
|
|
768
862
|
) {
|
|
769
863
|
// if we do need to make a network call, check with the serverState
|
|
770
|
-
if (!serverStates.serverCanGetTx(serverUri, utxo.txid))
|
|
864
|
+
if (!common.serverStates.serverCanGetTx(serverUri, utxo.txid))
|
|
865
|
+
return false
|
|
771
866
|
}
|
|
772
|
-
|
|
773
|
-
_utils.removeItem.call(void 0,
|
|
774
|
-
|
|
775
|
-
...args,
|
|
776
|
-
...state,
|
|
777
|
-
address: state.address,
|
|
867
|
+
cacheItem.processing = true
|
|
868
|
+
_utils.removeItem.call(void 0, blockbookUtxoCache, utxoId)
|
|
869
|
+
yield* processBlockbookUtxo(common, {
|
|
778
870
|
serverUri,
|
|
779
|
-
|
|
780
|
-
id: `${utxo.txid}_${utxo.vout}`
|
|
871
|
+
cacheItem
|
|
781
872
|
})
|
|
782
|
-
return _nullishCoalesce(wsTask, () => ( true))
|
|
783
873
|
}
|
|
784
874
|
}
|
|
785
875
|
|
|
786
876
|
// Loop to process addresses to utxos
|
|
787
|
-
for (const [address,
|
|
877
|
+
for (const [address, cacheItem] of Object.entries(addressForUtxosCache)) {
|
|
788
878
|
// Check if we need to fetch address UTXOs
|
|
789
879
|
if (
|
|
790
|
-
!
|
|
791
|
-
serverStates.serverCanGetAddress(serverUri, address)
|
|
880
|
+
!cacheItem.processing &&
|
|
881
|
+
common.serverStates.serverCanGetAddress(serverUri, address)
|
|
792
882
|
) {
|
|
793
|
-
|
|
883
|
+
cacheItem.processing = true
|
|
794
884
|
|
|
795
|
-
_utils.removeItem.call(void 0,
|
|
885
|
+
_utils.removeItem.call(void 0, addressForUtxosCache, address)
|
|
796
886
|
|
|
797
|
-
// Fetch and process address UTXOs
|
|
798
|
-
|
|
799
|
-
...args,
|
|
800
|
-
...state,
|
|
887
|
+
// Fetch and process address for UTXOs
|
|
888
|
+
yield* processAddressForUtxos(common, {
|
|
801
889
|
address,
|
|
890
|
+
cacheItem,
|
|
891
|
+
serverState,
|
|
802
892
|
serverUri
|
|
803
893
|
})
|
|
804
|
-
wsTask.deferred.promise
|
|
805
|
-
.then(() => {
|
|
806
|
-
serverState.addresses.add(address)
|
|
807
|
-
})
|
|
808
|
-
.catch(err => {
|
|
809
|
-
addressUtxoCache[address] = state
|
|
810
|
-
console.error(err)
|
|
811
|
-
args.log('error in addressUtxoCache:', err)
|
|
812
|
-
})
|
|
813
|
-
return wsTask
|
|
814
894
|
}
|
|
815
895
|
}
|
|
816
896
|
|
|
@@ -818,11 +898,11 @@ const addToAddressTransactionCache = async (
|
|
|
818
898
|
if (Object.keys(addressSubscribeCache).length > 0) {
|
|
819
899
|
// These are addresses to which the server has not subscribed
|
|
820
900
|
const newAddresses = []
|
|
821
|
-
const blockHeight = serverStates.getBlockHeight(serverUri)
|
|
901
|
+
const blockHeight = common.serverStates.getBlockHeight(serverUri)
|
|
822
902
|
|
|
823
903
|
// Loop each address in the cache
|
|
824
|
-
for (const [address,
|
|
825
|
-
const isAddressNewlySubscribed = !serverStates.serverIsAwareOfAddress(
|
|
904
|
+
for (const [address, cacheItem] of Object.entries(addressSubscribeCache)) {
|
|
905
|
+
const isAddressNewlySubscribed = !common.serverStates.serverIsAwareOfAddress(
|
|
826
906
|
serverUri,
|
|
827
907
|
address
|
|
828
908
|
)
|
|
@@ -832,61 +912,52 @@ const addToAddressTransactionCache = async (
|
|
|
832
912
|
newAddresses.push(address)
|
|
833
913
|
}
|
|
834
914
|
|
|
835
|
-
// Add to the
|
|
915
|
+
// Add to the addressForTransactionsCache if they're not yet added:
|
|
836
916
|
// Only process newly watched addresses
|
|
837
|
-
if (
|
|
917
|
+
if (cacheItem.processing) continue
|
|
838
918
|
|
|
839
919
|
// Add the newly watched addresses to the UTXO cache
|
|
840
920
|
if (isAddressNewlySubscribed) {
|
|
841
|
-
|
|
921
|
+
addressForUtxosCache[address] = {
|
|
842
922
|
processing: false,
|
|
843
|
-
path:
|
|
923
|
+
path: cacheItem.path
|
|
844
924
|
}
|
|
845
925
|
}
|
|
846
926
|
|
|
847
|
-
await
|
|
848
|
-
args,
|
|
927
|
+
await addToAddressForTransactionsCache(common, {
|
|
849
928
|
address,
|
|
850
|
-
|
|
929
|
+
changePath: cacheItem.path,
|
|
851
930
|
blockHeight,
|
|
852
|
-
|
|
853
|
-
)
|
|
854
|
-
|
|
931
|
+
addressForTransactionsCache
|
|
932
|
+
})
|
|
933
|
+
cacheItem.processing = true
|
|
855
934
|
}
|
|
856
935
|
|
|
857
936
|
// Subscribe to any new addresses
|
|
858
937
|
if (newAddresses.length > 0) {
|
|
859
|
-
serverStates.watchAddresses(serverUri, newAddresses)
|
|
938
|
+
common.serverStates.watchAddresses(serverUri, newAddresses)
|
|
860
939
|
return true
|
|
861
940
|
}
|
|
862
941
|
}
|
|
863
942
|
|
|
864
943
|
// filled when transactions potentially changed (e.g. through new block notification)
|
|
865
|
-
if (Object.keys(
|
|
944
|
+
if (Object.keys(transactionSpecificUpdateCache).length > 0) {
|
|
866
945
|
let hasProcessedAtLeastOnce = false
|
|
867
|
-
for (const [txId,
|
|
868
|
-
|
|
946
|
+
for (const [txId, cacheItem] of Object.entries(
|
|
947
|
+
transactionSpecificUpdateCache
|
|
869
948
|
)) {
|
|
870
|
-
if (
|
|
949
|
+
if (
|
|
950
|
+
!cacheItem.processing &&
|
|
951
|
+
common.serverStates.serverCanGetTx(serverUri, txId)
|
|
952
|
+
) {
|
|
871
953
|
hasProcessedAtLeastOnce = true
|
|
872
|
-
|
|
873
|
-
_utils.removeItem.call(void 0,
|
|
874
|
-
|
|
875
|
-
|
|
954
|
+
cacheItem.processing = true
|
|
955
|
+
_utils.removeItem.call(void 0, transactionSpecificUpdateCache, txId)
|
|
956
|
+
yield* processTransactionsSpecificUpdate(common, {
|
|
957
|
+
serverState,
|
|
876
958
|
serverUri,
|
|
877
959
|
txId
|
|
878
960
|
})
|
|
879
|
-
// once resolved, add the txid to the server cache
|
|
880
|
-
updateTransactionSpecificTask.deferred.promise
|
|
881
|
-
.then(() => {
|
|
882
|
-
serverState.txids.add(txId)
|
|
883
|
-
})
|
|
884
|
-
.catch(err => {
|
|
885
|
-
updateTransactionSpecificCache[txId] = state
|
|
886
|
-
console.error(err)
|
|
887
|
-
args.log('error in updateTransactionSpecificCache:', err)
|
|
888
|
-
})
|
|
889
|
-
return updateTransactionSpecificTask
|
|
890
961
|
}
|
|
891
962
|
}
|
|
892
963
|
// This condition prevents infinite loops
|
|
@@ -894,30 +965,21 @@ const addToAddressTransactionCache = async (
|
|
|
894
965
|
}
|
|
895
966
|
|
|
896
967
|
// filled when transactions potentially changed (e.g. through new block notification)
|
|
897
|
-
if (Object.keys(
|
|
968
|
+
if (Object.keys(transactionUpdateCache).length > 0) {
|
|
898
969
|
let hasProcessedAtLeastOnce = false
|
|
899
|
-
for (const [txId,
|
|
900
|
-
if (
|
|
970
|
+
for (const [txId, cacheItem] of Object.entries(transactionUpdateCache)) {
|
|
971
|
+
if (
|
|
972
|
+
!cacheItem.processing &&
|
|
973
|
+
common.serverStates.serverCanGetTx(serverUri, txId)
|
|
974
|
+
) {
|
|
901
975
|
hasProcessedAtLeastOnce = true
|
|
902
|
-
|
|
903
|
-
_utils.removeItem.call(void 0,
|
|
904
|
-
|
|
905
|
-
|
|
976
|
+
cacheItem.processing = true
|
|
977
|
+
_utils.removeItem.call(void 0, transactionUpdateCache, txId)
|
|
978
|
+
yield* processTransactionUpdate(common, {
|
|
979
|
+
serverState,
|
|
906
980
|
serverUri,
|
|
907
|
-
needsTxSpecific,
|
|
908
981
|
txId
|
|
909
982
|
})
|
|
910
|
-
// once resolved, add the txid to the server cache
|
|
911
|
-
updateTransactionTask.deferred.promise
|
|
912
|
-
.then(() => {
|
|
913
|
-
serverState.txids.add(txId)
|
|
914
|
-
})
|
|
915
|
-
.catch(err => {
|
|
916
|
-
updateTransactionCache[txId] = state
|
|
917
|
-
console.error(err)
|
|
918
|
-
args.log('error in updateTransactionCache:', err)
|
|
919
|
-
})
|
|
920
|
-
return updateTransactionTask
|
|
921
983
|
}
|
|
922
984
|
}
|
|
923
985
|
// This condition prevents infinite loops
|
|
@@ -925,399 +987,276 @@ const addToAddressTransactionCache = async (
|
|
|
925
987
|
}
|
|
926
988
|
|
|
927
989
|
// loop to get and process transaction history of single addresses, triggers setLookAhead
|
|
928
|
-
for (const [address,
|
|
990
|
+
for (const [address, cacheItem] of Object.entries(
|
|
991
|
+
addressForTransactionsCache
|
|
992
|
+
)) {
|
|
929
993
|
if (
|
|
930
|
-
!
|
|
931
|
-
serverStates.serverCanGetAddress(serverUri, address)
|
|
994
|
+
!cacheItem.processing &&
|
|
995
|
+
common.serverStates.serverCanGetAddress(serverUri, address)
|
|
932
996
|
) {
|
|
933
|
-
|
|
997
|
+
cacheItem.processing = true
|
|
934
998
|
|
|
935
|
-
_utils.removeItem.call(void 0,
|
|
999
|
+
_utils.removeItem.call(void 0, addressForTransactionsCache, address)
|
|
936
1000
|
|
|
937
1001
|
// Fetch and process address UTXOs
|
|
938
|
-
|
|
939
|
-
...args,
|
|
940
|
-
addressTransactionState: state,
|
|
1002
|
+
yield* processAddressForTransactions(common, {
|
|
941
1003
|
address,
|
|
942
|
-
|
|
1004
|
+
cacheItem,
|
|
1005
|
+
serverState,
|
|
943
1006
|
serverUri
|
|
944
1007
|
})
|
|
945
|
-
wsTask.deferred.promise
|
|
946
|
-
.then(() => {
|
|
947
|
-
serverState.addresses.add(address)
|
|
948
|
-
})
|
|
949
|
-
.catch(err => {
|
|
950
|
-
addressTransactionCache[address] = state
|
|
951
|
-
console.error(err)
|
|
952
|
-
args.log('error in updateTransactionCache:', err)
|
|
953
|
-
})
|
|
954
|
-
return wsTask
|
|
955
1008
|
}
|
|
956
1009
|
}
|
|
957
|
-
}; exports.pickNextTask = pickNextTask
|
|
958
|
-
|
|
959
|
-
|
|
960
1010
|
|
|
1011
|
+
// Nothing to do
|
|
1012
|
+
return false
|
|
1013
|
+
} exports.pickNextTask = pickNextTask;
|
|
961
1014
|
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1015
|
+
/**
|
|
1016
|
+
* Process a transaction specific update from the TransactionSpecificUpdateCache
|
|
1017
|
+
* by querying the network for the transaction data using the specific handling
|
|
1018
|
+
* query and processing the data into the DataLayer.
|
|
1019
|
+
*/
|
|
1020
|
+
async function* processTransactionsSpecificUpdate(
|
|
1021
|
+
common,
|
|
965
1022
|
args
|
|
966
|
-
) => {
|
|
967
|
-
const {
|
|
968
|
-
walletInfo,
|
|
969
|
-
emitter,
|
|
970
|
-
walletTools,
|
|
971
|
-
pluginInfo,
|
|
972
|
-
processor,
|
|
973
|
-
serverUri,
|
|
974
|
-
txId,
|
|
975
|
-
taskCache
|
|
976
|
-
} = args
|
|
977
|
-
const deferred = new _Deferred2.default()
|
|
978
|
-
deferred.promise
|
|
979
|
-
.then(async (txResponse) => {
|
|
980
|
-
// Grab tx to update it
|
|
981
|
-
const txs = await processor.fetchTransactions({ txId })
|
|
982
|
-
let tx = txs[0]
|
|
983
|
-
if (tx == null) return
|
|
984
|
-
|
|
985
|
-
if (pluginInfo.engineInfo.txSpecificHandling != null) {
|
|
986
|
-
// Do coin-specific things to it
|
|
987
|
-
tx = pluginInfo.engineInfo.txSpecificHandling(tx, txResponse)
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
// Process and save new tx
|
|
991
|
-
const processedTx = await processor.saveTransaction({
|
|
992
|
-
tx
|
|
993
|
-
})
|
|
994
|
-
|
|
995
|
-
await exports.transactionChanged.call(void 0, {
|
|
996
|
-
walletId: walletInfo.id,
|
|
997
|
-
emitter,
|
|
998
|
-
walletTools,
|
|
999
|
-
processor,
|
|
1000
|
-
pluginInfo,
|
|
1001
|
-
tx: processedTx
|
|
1002
|
-
})
|
|
1003
|
-
})
|
|
1004
|
-
.catch(err => {
|
|
1005
|
-
console.error(err)
|
|
1006
|
-
args.log('error in updateTransactionsSpecific:', err)
|
|
1007
|
-
taskCache.updateTransactionSpecificCache[txId] = { processing: false }
|
|
1008
|
-
})
|
|
1009
|
-
|
|
1010
|
-
return args.serverStates.transactionSpecialQueryTask(
|
|
1011
|
-
serverUri,
|
|
1012
|
-
txId,
|
|
1013
|
-
deferred
|
|
1014
|
-
)
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
1023
|
|
|
1018
1024
|
|
|
1019
1025
|
|
|
1020
1026
|
|
|
1027
|
+
) {
|
|
1028
|
+
const { serverState, serverUri, txId } = args
|
|
1029
|
+
try {
|
|
1030
|
+
const txResponse = yield* common.serverStates.transactionSpecialQueryTask(
|
|
1031
|
+
serverUri,
|
|
1032
|
+
txId
|
|
1033
|
+
)
|
|
1034
|
+
// Grab tx to update it
|
|
1035
|
+
const txs = await common.dataLayer.fetchTransactions({ txId })
|
|
1036
|
+
let tx = txs[0]
|
|
1037
|
+
if (tx == null) return true
|
|
1038
|
+
|
|
1039
|
+
if (common.pluginInfo.engineInfo.txSpecificHandling != null) {
|
|
1040
|
+
// Do coin-specific things to it
|
|
1041
|
+
tx = common.pluginInfo.engineInfo.txSpecificHandling(tx, txResponse)
|
|
1042
|
+
}
|
|
1021
1043
|
|
|
1022
|
-
|
|
1023
|
-
const
|
|
1024
|
-
|
|
1025
|
-
) => {
|
|
1026
|
-
const {
|
|
1027
|
-
walletInfo,
|
|
1028
|
-
emitter,
|
|
1029
|
-
walletTools,
|
|
1030
|
-
txId,
|
|
1031
|
-
needsTxSpecific,
|
|
1032
|
-
pluginInfo,
|
|
1033
|
-
processor,
|
|
1034
|
-
serverUri,
|
|
1035
|
-
taskCache
|
|
1036
|
-
} = args
|
|
1037
|
-
const deferred = new _Deferred2.default()
|
|
1038
|
-
deferred.promise
|
|
1039
|
-
.then(async (txResponse) => {
|
|
1040
|
-
// check if raw tx is still not confirmed, if so, don't change anything
|
|
1041
|
-
if (txResponse.blockHeight < 1) return
|
|
1042
|
-
// Create new tx from raw tx
|
|
1043
|
-
const tx = processTransactionResponse({ ...args, txResponse })
|
|
1044
|
-
// Remove any existing input utxos from the processor
|
|
1045
|
-
for (const input of tx.inputs) {
|
|
1046
|
-
await processor.removeUtxos([`${input.txId}_${input.outputIndex}`])
|
|
1047
|
-
}
|
|
1048
|
-
// Update output utxos's blockHeight any existing input utxos from the processor
|
|
1049
|
-
const utxoIds = tx.outputs.map(output => `${tx.txid}_${output.n}`)
|
|
1050
|
-
const utxos = await processor.fetchUtxos({
|
|
1051
|
-
utxoIds
|
|
1052
|
-
})
|
|
1053
|
-
for (const utxo of utxos) {
|
|
1054
|
-
if (utxo == null) continue
|
|
1055
|
-
utxo.blockHeight = tx.blockHeight
|
|
1056
|
-
await processor.saveUtxo(utxo)
|
|
1057
|
-
}
|
|
1058
|
-
// Process and save new tx
|
|
1059
|
-
const processedTx = await processor.saveTransaction({
|
|
1060
|
-
tx
|
|
1061
|
-
})
|
|
1062
|
-
|
|
1063
|
-
await exports.transactionChanged.call(void 0, {
|
|
1064
|
-
walletId: walletInfo.id,
|
|
1065
|
-
emitter,
|
|
1066
|
-
walletTools,
|
|
1067
|
-
processor,
|
|
1068
|
-
pluginInfo,
|
|
1069
|
-
tx: processedTx
|
|
1070
|
-
})
|
|
1071
|
-
|
|
1072
|
-
if (needsTxSpecific) {
|
|
1073
|
-
// Add task to grab transactionSpecific payload
|
|
1074
|
-
taskCache.updateTransactionSpecificCache[txId] = {
|
|
1075
|
-
processing: false
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
})
|
|
1079
|
-
.catch(err => {
|
|
1080
|
-
console.error(err)
|
|
1081
|
-
args.log('error in updateTransactions:', err)
|
|
1082
|
-
taskCache.updateTransactionCache[txId] = { processing: false }
|
|
1044
|
+
// Process and save new tx
|
|
1045
|
+
const processedTx = await common.dataLayer.saveTransaction({
|
|
1046
|
+
tx
|
|
1083
1047
|
})
|
|
1084
1048
|
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
const internalDeriveScriptAddress = async ({
|
|
1104
|
-
walletTools,
|
|
1105
|
-
engineInfo,
|
|
1106
|
-
processor,
|
|
1107
|
-
format,
|
|
1108
|
-
taskCache,
|
|
1109
|
-
script
|
|
1110
|
-
}) => {
|
|
1111
|
-
if (engineInfo.scriptTemplates == null) {
|
|
1112
|
-
throw new Error(
|
|
1113
|
-
`cannot derive script address ${script} without defined script template`
|
|
1114
|
-
)
|
|
1115
|
-
}
|
|
1049
|
+
await exports.transactionChanged.call(void 0, {
|
|
1050
|
+
walletId: common.walletInfo.id,
|
|
1051
|
+
emitter: common.emitter,
|
|
1052
|
+
walletTools: common.walletTools,
|
|
1053
|
+
dataLayer: common.dataLayer,
|
|
1054
|
+
pluginInfo: common.pluginInfo,
|
|
1055
|
+
tx: processedTx
|
|
1056
|
+
})
|
|
1116
1057
|
|
|
1117
|
-
|
|
1058
|
+
// Add the txid to the server cache
|
|
1059
|
+
serverState.txids.add(txId)
|
|
1118
1060
|
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1061
|
+
return true
|
|
1062
|
+
} catch (err) {
|
|
1063
|
+
console.error(err)
|
|
1064
|
+
common.log('error while processing transaction specific update:', err)
|
|
1065
|
+
common.taskCache.transactionSpecificUpdateCache[txId] = {
|
|
1066
|
+
processing: false
|
|
1067
|
+
}
|
|
1068
|
+
return false
|
|
1123
1069
|
}
|
|
1124
|
-
|
|
1125
|
-
// save the address to the processor and add it to the cache
|
|
1126
|
-
const { address, scriptPubkey, redeemScript } = walletTools.getScriptAddress({
|
|
1127
|
-
path,
|
|
1128
|
-
scriptTemplate
|
|
1129
|
-
})
|
|
1130
|
-
await processor.saveAddress(
|
|
1131
|
-
_types5.makeIAddress.call(void 0, { scriptPubkey, redeemScript, path })
|
|
1132
|
-
)
|
|
1133
|
-
const addresses = new Set()
|
|
1134
|
-
addresses.add(address)
|
|
1135
|
-
addToAddressSubscribeCache(taskCache, addresses, {
|
|
1136
|
-
format: path.format,
|
|
1137
|
-
changeIndex: path.changeIndex
|
|
1138
|
-
})
|
|
1139
|
-
return { address, scriptPubkey, redeemScript }
|
|
1140
1070
|
}
|
|
1141
1071
|
|
|
1072
|
+
/**
|
|
1073
|
+
* Processes a transaction update from the TransactionUpdateCache by querying
|
|
1074
|
+
* the network for the transaction data and processing it into the DataLayer.
|
|
1075
|
+
*/
|
|
1076
|
+
async function* processTransactionUpdate(
|
|
1077
|
+
common,
|
|
1078
|
+
args
|
|
1142
1079
|
|
|
1143
1080
|
|
|
1144
1081
|
|
|
1145
1082
|
|
|
1083
|
+
) {
|
|
1084
|
+
const { serverState, serverUri, txId } = args
|
|
1146
1085
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
const internalGetFreshAddress = async (
|
|
1153
|
-
args
|
|
1154
|
-
) => {
|
|
1155
|
-
const {
|
|
1156
|
-
format,
|
|
1157
|
-
changeIndex: branch,
|
|
1158
|
-
walletTools,
|
|
1159
|
-
processor,
|
|
1160
|
-
forceIndex
|
|
1161
|
-
} = args
|
|
1162
|
-
|
|
1163
|
-
const numAddresses = processor.numAddressesByFormatPath({
|
|
1164
|
-
format,
|
|
1165
|
-
changeIndex: branch
|
|
1166
|
-
})
|
|
1167
|
-
|
|
1168
|
-
const path = {
|
|
1169
|
-
format,
|
|
1170
|
-
changeIndex: branch,
|
|
1171
|
-
// while syncing, we may hit negative numbers when only subtracting. Use the address at /0 in that case.
|
|
1172
|
-
addressIndex: Math.max(
|
|
1173
|
-
numAddresses - args.pluginInfo.engineInfo.gapLimit,
|
|
1174
|
-
0
|
|
1086
|
+
try {
|
|
1087
|
+
const txResponse = yield* common.serverStates.transactionQueryTask(
|
|
1088
|
+
serverUri,
|
|
1089
|
+
txId
|
|
1175
1090
|
)
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1091
|
+
// check if blockbook tx is still not confirmed, if so, don't change anything
|
|
1092
|
+
if (txResponse.blockHeight < 1) return false
|
|
1093
|
+
// Create new tx from raw tx
|
|
1094
|
+
const tx = processTransactionResponse(common, { txResponse })
|
|
1095
|
+
// Remove any existing input utxos from the dataLayer
|
|
1096
|
+
for (const input of tx.inputs) {
|
|
1097
|
+
await common.dataLayer.removeUtxos([`${input.txId}_${input.outputIndex}`])
|
|
1098
|
+
}
|
|
1099
|
+
// Update output utxos's blockHeight any existing input utxos from the dataLayer
|
|
1100
|
+
const utxoIds = tx.outputs.map(output => `${tx.txid}_${output.n}`)
|
|
1101
|
+
const utxos = await common.dataLayer.fetchUtxos({
|
|
1102
|
+
utxoIds
|
|
1103
|
+
})
|
|
1104
|
+
for (const utxo of utxos) {
|
|
1105
|
+
if (utxo == null) continue
|
|
1106
|
+
utxo.blockHeight = tx.blockHeight
|
|
1107
|
+
await common.dataLayer.saveUtxo(utxo)
|
|
1108
|
+
}
|
|
1109
|
+
// Process and save new tx
|
|
1110
|
+
const processedTx = await common.dataLayer.saveTransaction({
|
|
1111
|
+
tx
|
|
1112
|
+
})
|
|
1180
1113
|
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1114
|
+
await exports.transactionChanged.call(void 0, {
|
|
1115
|
+
walletId: common.walletInfo.id,
|
|
1116
|
+
emitter: common.emitter,
|
|
1117
|
+
walletTools: common.walletTools,
|
|
1118
|
+
dataLayer: common.dataLayer,
|
|
1119
|
+
pluginInfo: common.pluginInfo,
|
|
1120
|
+
tx: processedTx
|
|
1121
|
+
})
|
|
1184
1122
|
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
})
|
|
1123
|
+
if (needsTxSpecific(common)) {
|
|
1124
|
+
// Add task to grab transactionSpecific payload
|
|
1125
|
+
common.taskCache.transactionSpecificUpdateCache[txId] = {
|
|
1126
|
+
processing: false
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1192
1129
|
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1130
|
+
// Add the txid to the server cache
|
|
1131
|
+
serverState.txids.add(txId)
|
|
1132
|
+
|
|
1133
|
+
return true
|
|
1134
|
+
} catch (err) {
|
|
1135
|
+
console.error(err)
|
|
1136
|
+
common.log('error while processing transaction update:', err)
|
|
1137
|
+
common.taskCache.transactionUpdateCache[txId] = { processing: false }
|
|
1138
|
+
return false
|
|
1196
1139
|
}
|
|
1197
1140
|
}
|
|
1198
1141
|
|
|
1142
|
+
/**
|
|
1143
|
+
* Processes an address for transactions by querying the network for the
|
|
1144
|
+
* transaction data.
|
|
1145
|
+
*/
|
|
1146
|
+
async function* processAddressForTransactions(
|
|
1147
|
+
common,
|
|
1148
|
+
args
|
|
1199
1149
|
|
|
1200
1150
|
|
|
1201
1151
|
|
|
1202
1152
|
|
|
1203
1153
|
|
|
1154
|
+
) {
|
|
1155
|
+
const { address, cacheItem, serverState, serverUri } = args
|
|
1156
|
+
const { page = 1, blockHeight } = cacheItem
|
|
1157
|
+
const addressForTransactionsCache =
|
|
1158
|
+
common.taskCache.addressForTransactionsCache
|
|
1204
1159
|
|
|
1205
|
-
|
|
1206
|
-
const
|
|
1207
|
-
args
|
|
1208
|
-
) => {
|
|
1209
|
-
const {
|
|
1210
|
-
walletInfo,
|
|
1211
|
-
address,
|
|
1212
|
-
addressTransactionState,
|
|
1213
|
-
emitter,
|
|
1214
|
-
needsTxSpecific,
|
|
1215
|
-
pluginInfo,
|
|
1216
|
-
processor,
|
|
1217
|
-
walletTools,
|
|
1218
|
-
taskCache,
|
|
1219
|
-
pluginState,
|
|
1220
|
-
serverUri
|
|
1221
|
-
} = args
|
|
1222
|
-
const { page = 1, blockHeight } = addressTransactionState
|
|
1223
|
-
const addressTransactionCache = taskCache.addressTransactionCache
|
|
1224
|
-
|
|
1225
|
-
const scriptPubkey = walletTools.addressToScriptPubkey(address)
|
|
1226
|
-
const addressData = await processor.fetchAddress(scriptPubkey)
|
|
1160
|
+
const scriptPubkey = common.walletTools.addressToScriptPubkey(address)
|
|
1161
|
+
const addressData = await common.dataLayer.fetchAddress(scriptPubkey)
|
|
1227
1162
|
if (addressData == null) {
|
|
1228
1163
|
throw new Error(`could not find address with script pubkey ${scriptPubkey}`)
|
|
1229
1164
|
}
|
|
1230
1165
|
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
// If address is used and previously not marked as used, mark as used.
|
|
1239
|
-
const used = txs > 0 || unconfirmedTxs > 0
|
|
1240
|
-
if (!addressData.used && used && page === 1) {
|
|
1241
|
-
addressData.used = true
|
|
1166
|
+
try {
|
|
1167
|
+
const addressResponse = yield* common.serverStates.addressQueryTask(
|
|
1168
|
+
serverUri,
|
|
1169
|
+
address,
|
|
1170
|
+
{
|
|
1171
|
+
lastQueriedBlockHeight: addressData.lastQueriedBlockHeight,
|
|
1172
|
+
page
|
|
1242
1173
|
}
|
|
1174
|
+
)
|
|
1175
|
+
const {
|
|
1176
|
+
transactions = [],
|
|
1177
|
+
txs,
|
|
1178
|
+
unconfirmedTxs,
|
|
1179
|
+
totalPages
|
|
1180
|
+
} = addressResponse
|
|
1181
|
+
|
|
1182
|
+
// If address is used and previously not marked as used, mark as used.
|
|
1183
|
+
const used = txs > 0 || unconfirmedTxs > 0
|
|
1184
|
+
if (!addressData.used && used && page === 1) {
|
|
1185
|
+
addressData.used = true
|
|
1186
|
+
}
|
|
1243
1187
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1188
|
+
// Process and save the address's transactions
|
|
1189
|
+
for (const txResponse of transactions) {
|
|
1190
|
+
const tx = processTransactionResponse(common, { txResponse })
|
|
1191
|
+
const processedTx = await common.dataLayer.saveTransaction({
|
|
1192
|
+
tx,
|
|
1193
|
+
scriptPubkeys: [scriptPubkey]
|
|
1194
|
+
})
|
|
1195
|
+
await exports.transactionChanged.call(void 0, {
|
|
1196
|
+
walletId: common.walletInfo.id,
|
|
1197
|
+
emitter: common.emitter,
|
|
1198
|
+
walletTools: common.walletTools,
|
|
1199
|
+
dataLayer: common.dataLayer,
|
|
1200
|
+
pluginInfo: common.pluginInfo,
|
|
1201
|
+
tx: processedTx
|
|
1202
|
+
})
|
|
1259
1203
|
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
}
|
|
1204
|
+
if (needsTxSpecific(common)) {
|
|
1205
|
+
// Add task to grab transactionSpecific payload
|
|
1206
|
+
common.taskCache.transactionSpecificUpdateCache[tx.txid] = {
|
|
1207
|
+
processing: false
|
|
1265
1208
|
}
|
|
1266
1209
|
}
|
|
1210
|
+
}
|
|
1267
1211
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
}
|
|
1277
|
-
return
|
|
1212
|
+
// Halt on finishing the processing of address transaction until
|
|
1213
|
+
// we have progressed through all of the blockbook pages
|
|
1214
|
+
if (page < totalPages) {
|
|
1215
|
+
// Add the address back to the cache, incrementing the page
|
|
1216
|
+
addressForTransactionsCache[address] = {
|
|
1217
|
+
...cacheItem,
|
|
1218
|
+
processing: false,
|
|
1219
|
+
page: page + 1
|
|
1278
1220
|
}
|
|
1221
|
+
return true
|
|
1222
|
+
}
|
|
1279
1223
|
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
// Save/update the fully-processed address
|
|
1284
|
-
await processor.saveAddress(addressData)
|
|
1285
|
-
|
|
1286
|
-
// Update the progress now that the transactions for an address have processed
|
|
1287
|
-
await args.updateProgressRatio()
|
|
1224
|
+
// Update the lastQueriedBlockHeight for the address
|
|
1225
|
+
addressData.lastQueriedBlockHeight = blockHeight
|
|
1288
1226
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
})
|
|
1292
|
-
.catch(err => {
|
|
1293
|
-
// Log the error for debugging purposes without crashing the engine
|
|
1294
|
-
// This will cause frozen wallet syncs
|
|
1295
|
-
console.error(err)
|
|
1296
|
-
addressTransactionCache[address] = addressTransactionState
|
|
1297
|
-
})
|
|
1298
|
-
|
|
1299
|
-
return args.serverStates.addressQueryTask(
|
|
1300
|
-
serverUri,
|
|
1301
|
-
address,
|
|
1302
|
-
{
|
|
1303
|
-
lastQueriedBlockHeight: addressData.lastQueriedBlockHeight,
|
|
1304
|
-
page
|
|
1305
|
-
},
|
|
1306
|
-
deferred
|
|
1307
|
-
)
|
|
1308
|
-
}
|
|
1227
|
+
// Save/update the fully-processed address
|
|
1228
|
+
await common.dataLayer.saveAddress(addressData)
|
|
1309
1229
|
|
|
1230
|
+
// Update the progress now that the transactions for an address have processed
|
|
1231
|
+
await common.updateProgressRatio()
|
|
1310
1232
|
|
|
1233
|
+
// Call setLookAhead to update the lookahead
|
|
1234
|
+
await setLookAhead(common)
|
|
1311
1235
|
|
|
1236
|
+
// Add the address to the server cache
|
|
1237
|
+
serverState.addresses.add(address)
|
|
1312
1238
|
|
|
1239
|
+
return true
|
|
1240
|
+
} catch (err) {
|
|
1241
|
+
// Log the error for debugging purposes without crashing the engine
|
|
1242
|
+
// This will cause frozen wallet syncs
|
|
1243
|
+
console.error(err)
|
|
1244
|
+
common.log('error while processing address for transactions:', err)
|
|
1245
|
+
addressForTransactionsCache[address] = { ...cacheItem, processing: false }
|
|
1246
|
+
return false
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1313
1249
|
|
|
1250
|
+
/**
|
|
1251
|
+
* Processes a blockbook transaction response object (a blockbook transaction).
|
|
1252
|
+
* It will simply convert the blockbook transaction into a TransactionData
|
|
1253
|
+
* object to be saved in the DataLayer
|
|
1254
|
+
*/
|
|
1314
1255
|
const processTransactionResponse = (
|
|
1256
|
+
common,
|
|
1315
1257
|
args
|
|
1316
1258
|
) => {
|
|
1317
|
-
const {
|
|
1318
|
-
txResponse,
|
|
1319
|
-
pluginInfo: { coinInfo }
|
|
1320
|
-
} = args
|
|
1259
|
+
const { txResponse } = args
|
|
1321
1260
|
const inputs = txResponse.vin.map(vin => {
|
|
1322
1261
|
const scriptPubkey =
|
|
1323
1262
|
// Note: Blockbook has empirically not sent a hex value as the
|
|
@@ -1328,7 +1267,7 @@ const processTransactionResponse = (
|
|
|
1328
1267
|
'unknown'
|
|
1329
1268
|
)({
|
|
1330
1269
|
address: vin.addresses[0],
|
|
1331
|
-
coin: coinInfo.name
|
|
1270
|
+
coin: common.pluginInfo.coinInfo.name
|
|
1332
1271
|
})
|
|
1333
1272
|
return {
|
|
1334
1273
|
txId: vin.txid,
|
|
@@ -1347,7 +1286,7 @@ const processTransactionResponse = (
|
|
|
1347
1286
|
'unknown'
|
|
1348
1287
|
)({
|
|
1349
1288
|
address: vout.addresses[0],
|
|
1350
|
-
coin: coinInfo.name
|
|
1289
|
+
coin: common.pluginInfo.coinInfo.name
|
|
1351
1290
|
})))
|
|
1352
1291
|
return {
|
|
1353
1292
|
n: vout.n,
|
|
@@ -1370,87 +1309,88 @@ const processTransactionResponse = (
|
|
|
1370
1309
|
}
|
|
1371
1310
|
}
|
|
1372
1311
|
|
|
1312
|
+
/**
|
|
1313
|
+
* Process a given address for UTXO data by querying the network for UTXO data
|
|
1314
|
+
* and processing it into the `blockbookUtxoCache` to later be processed by
|
|
1315
|
+
* `processBlockbookUtxo`.
|
|
1316
|
+
*/
|
|
1317
|
+
async function* processAddressForUtxos(
|
|
1318
|
+
common,
|
|
1319
|
+
args
|
|
1373
1320
|
|
|
1374
1321
|
|
|
1375
1322
|
|
|
1376
1323
|
|
|
1377
1324
|
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
const processAddressUtxos = async (
|
|
1381
|
-
args
|
|
1382
|
-
) => {
|
|
1325
|
+
) {
|
|
1326
|
+
const { address, cacheItem, serverState, serverUri } = args
|
|
1383
1327
|
const {
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
const scriptPubkey = walletTools.addressToScriptPubkey(address)
|
|
1399
|
-
const addressData = await processor.fetchAddress(scriptPubkey)
|
|
1400
|
-
if (addressData == null || addressData.path == null) {
|
|
1401
|
-
return
|
|
1402
|
-
}
|
|
1328
|
+
addressForUtxosCache,
|
|
1329
|
+
blockbookUtxoCache,
|
|
1330
|
+
dataLayerUtxoCache
|
|
1331
|
+
} = common.taskCache
|
|
1332
|
+
try {
|
|
1333
|
+
const utxos = yield* common.serverStates.utxoListQueryTask(
|
|
1334
|
+
serverUri,
|
|
1335
|
+
address
|
|
1336
|
+
)
|
|
1337
|
+
const scriptPubkey = common.walletTools.addressToScriptPubkey(address)
|
|
1338
|
+
const addressData = await common.dataLayer.fetchAddress(scriptPubkey)
|
|
1339
|
+
if (addressData == null || addressData.path == null) {
|
|
1340
|
+
return true
|
|
1341
|
+
}
|
|
1403
1342
|
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1343
|
+
if (utxos.length === 0) {
|
|
1344
|
+
addToDataLayerUtxoCache(
|
|
1345
|
+
dataLayerUtxoCache,
|
|
1346
|
+
cacheItem.path,
|
|
1347
|
+
scriptPubkey,
|
|
1348
|
+
0
|
|
1349
|
+
)
|
|
1350
|
+
return true
|
|
1351
|
+
}
|
|
1408
1352
|
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
}
|
|
1353
|
+
for (const utxo of utxos) {
|
|
1354
|
+
const utxoId = `${utxo.txid}_${utxo.vout}`
|
|
1355
|
+
blockbookUtxoCache[utxoId] = {
|
|
1356
|
+
blockbookUtxo: utxo,
|
|
1357
|
+
processing: false,
|
|
1358
|
+
requiredCount: utxos.length,
|
|
1359
|
+
path: cacheItem.path,
|
|
1360
|
+
// TypeScript yells otherwise
|
|
1361
|
+
address: { ...addressData, path: addressData.path }
|
|
1419
1362
|
}
|
|
1420
|
-
}
|
|
1421
|
-
.catch(() => {
|
|
1422
|
-
args.processing = false
|
|
1423
|
-
addressUtxoCache[address] = {
|
|
1424
|
-
processing: args.processing,
|
|
1425
|
-
path
|
|
1426
|
-
}
|
|
1427
|
-
})
|
|
1428
|
-
|
|
1429
|
-
return args.serverStates.utxoListQueryTask(serverUri, address, deferred)
|
|
1430
|
-
}
|
|
1363
|
+
}
|
|
1431
1364
|
|
|
1365
|
+
serverState.addresses.add(address)
|
|
1432
1366
|
|
|
1367
|
+
return true
|
|
1368
|
+
} catch (err) {
|
|
1369
|
+
console.error(err)
|
|
1370
|
+
common.log('error while processing address for UTXOs:', err)
|
|
1371
|
+
addressForUtxosCache[address] = { ...cacheItem, processing: false }
|
|
1372
|
+
return false
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1433
1375
|
|
|
1376
|
+
/**
|
|
1377
|
+
* Processes UtxoData from the DataLayerUtxoCache by saving/removing UTXOs
|
|
1378
|
+
* to/from the DataLayer and updating the address balance.
|
|
1379
|
+
*/
|
|
1380
|
+
const processDataLayerUtxos = async (
|
|
1381
|
+
common,
|
|
1382
|
+
args
|
|
1434
1383
|
|
|
1435
1384
|
|
|
1436
1385
|
|
|
1437
|
-
const processProcessorUtxos = async (
|
|
1438
|
-
args
|
|
1439
1386
|
) => {
|
|
1440
|
-
const {
|
|
1441
|
-
utxos,
|
|
1442
|
-
processor,
|
|
1443
|
-
scriptPubkey,
|
|
1444
|
-
log,
|
|
1445
|
-
emitter,
|
|
1446
|
-
pluginInfo: { currencyInfo }
|
|
1447
|
-
} = args
|
|
1387
|
+
const { utxos, scriptPubkey } = args
|
|
1448
1388
|
|
|
1449
1389
|
const updatedUtxos = Object.fromEntries(
|
|
1450
1390
|
[...utxos].map(utxo => [utxo.id, utxo])
|
|
1451
1391
|
)
|
|
1452
1392
|
const utxoIdsToRemove = []
|
|
1453
|
-
const currentUtxos = await
|
|
1393
|
+
const currentUtxos = await common.dataLayer.fetchUtxos({ scriptPubkey })
|
|
1454
1394
|
|
|
1455
1395
|
//
|
|
1456
1396
|
// Modify existing UTXO set
|
|
@@ -1475,7 +1415,7 @@ const processProcessorUtxos = async (
|
|
|
1475
1415
|
}
|
|
1476
1416
|
|
|
1477
1417
|
// Remove any spent UTXOs that have confirmations
|
|
1478
|
-
await
|
|
1418
|
+
await common.dataLayer.removeUtxos(utxoIdsToRemove)
|
|
1479
1419
|
|
|
1480
1420
|
//
|
|
1481
1421
|
// Save updated UTXO set
|
|
@@ -1488,7 +1428,7 @@ const processProcessorUtxos = async (
|
|
|
1488
1428
|
newBalance = _biggystring.add.call(void 0, utxo.value, newBalance)
|
|
1489
1429
|
}
|
|
1490
1430
|
// Save new UTXOs
|
|
1491
|
-
await
|
|
1431
|
+
await common.dataLayer.saveUtxo(utxo)
|
|
1492
1432
|
}
|
|
1493
1433
|
|
|
1494
1434
|
//
|
|
@@ -1497,10 +1437,14 @@ const processProcessorUtxos = async (
|
|
|
1497
1437
|
|
|
1498
1438
|
// Address balance and emit address balance change event
|
|
1499
1439
|
if (newBalance !== oldBalance) {
|
|
1500
|
-
log('address balance changed:', {
|
|
1501
|
-
|
|
1440
|
+
common.log('address balance changed:', {
|
|
1441
|
+
scriptPubkey,
|
|
1442
|
+
oldBalance,
|
|
1443
|
+
newBalance
|
|
1444
|
+
})
|
|
1445
|
+
common.emitter.emit(
|
|
1502
1446
|
_EngineEmitter.EngineEvent.ADDRESS_BALANCE_CHANGED,
|
|
1503
|
-
currencyInfo.currencyCode,
|
|
1447
|
+
common.pluginInfo.currencyInfo.currencyCode,
|
|
1504
1448
|
[
|
|
1505
1449
|
{
|
|
1506
1450
|
scriptPubkey,
|
|
@@ -1510,13 +1454,13 @@ const processProcessorUtxos = async (
|
|
|
1510
1454
|
)
|
|
1511
1455
|
|
|
1512
1456
|
// Update balances for address that have this scriptPubkey
|
|
1513
|
-
const address = await
|
|
1457
|
+
const address = await common.dataLayer.fetchAddress(scriptPubkey)
|
|
1514
1458
|
|
|
1515
1459
|
if (address == null) {
|
|
1516
1460
|
throw new Error('address not found when processing UTXO transactions')
|
|
1517
1461
|
}
|
|
1518
1462
|
|
|
1519
|
-
await
|
|
1463
|
+
await common.dataLayer.saveAddress({
|
|
1520
1464
|
...address,
|
|
1521
1465
|
balance: newBalance,
|
|
1522
1466
|
used: true
|
|
@@ -1524,43 +1468,32 @@ const processProcessorUtxos = async (
|
|
|
1524
1468
|
}
|
|
1525
1469
|
|
|
1526
1470
|
// Update the progress now that the UTXOs for an address have been processed
|
|
1527
|
-
await
|
|
1471
|
+
await common.updateProgressRatio()
|
|
1528
1472
|
|
|
1529
|
-
await setLookAhead(
|
|
1530
|
-
log.error(err)
|
|
1473
|
+
await setLookAhead(common).catch(err => {
|
|
1474
|
+
common.log.error(err)
|
|
1531
1475
|
throw err
|
|
1532
1476
|
})
|
|
1533
1477
|
}
|
|
1534
1478
|
|
|
1479
|
+
/**
|
|
1480
|
+
* Process a blockbook UTXO from the cache by querying the network for
|
|
1481
|
+
* the UTXO's transaction data to get its script for legacy addresses.
|
|
1482
|
+
* After the network fetching, the UTXO is processed into a UtxoData object
|
|
1483
|
+
* to be later processed into the DataLayer.
|
|
1484
|
+
*/
|
|
1485
|
+
async function* processBlockbookUtxo(
|
|
1486
|
+
common,
|
|
1487
|
+
args
|
|
1535
1488
|
|
|
1536
1489
|
|
|
1537
1490
|
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
const processRawUtxo = async (
|
|
1545
|
-
args
|
|
1546
|
-
) => {
|
|
1547
|
-
const {
|
|
1548
|
-
utxo,
|
|
1549
|
-
id,
|
|
1550
|
-
address,
|
|
1551
|
-
pluginInfo,
|
|
1552
|
-
processor,
|
|
1553
|
-
path,
|
|
1554
|
-
taskCache,
|
|
1555
|
-
requiredCount,
|
|
1556
|
-
pluginState,
|
|
1557
|
-
serverUri,
|
|
1558
|
-
log
|
|
1559
|
-
} = args
|
|
1560
|
-
const { rawUtxoCache, processorUtxoCache } = taskCache
|
|
1491
|
+
) {
|
|
1492
|
+
const { serverUri, cacheItem } = args
|
|
1493
|
+
const { blockbookUtxoCache, dataLayerUtxoCache } = common.taskCache
|
|
1561
1494
|
const purposeType = _utils3.pathToPurposeType.call(void 0,
|
|
1562
|
-
path,
|
|
1563
|
-
pluginInfo.engineInfo.scriptTemplates
|
|
1495
|
+
cacheItem.path,
|
|
1496
|
+
common.pluginInfo.engineInfo.scriptTemplates
|
|
1564
1497
|
)
|
|
1565
1498
|
const scriptType = _utils3.getScriptTypeFromPurposeType.call(void 0, purposeType)
|
|
1566
1499
|
let script
|
|
@@ -1568,24 +1501,24 @@ const processRawUtxo = async (
|
|
|
1568
1501
|
|
|
1569
1502
|
// Function to call once we are finished
|
|
1570
1503
|
const done = () => {
|
|
1571
|
-
const
|
|
1572
|
-
id
|
|
1573
|
-
txid:
|
|
1574
|
-
vout:
|
|
1575
|
-
value:
|
|
1576
|
-
scriptPubkey: address.scriptPubkey,
|
|
1504
|
+
const utxoData = {
|
|
1505
|
+
id: `${cacheItem.blockbookUtxo.txid}_${cacheItem.blockbookUtxo.vout}`,
|
|
1506
|
+
txid: cacheItem.blockbookUtxo.txid,
|
|
1507
|
+
vout: cacheItem.blockbookUtxo.vout,
|
|
1508
|
+
value: cacheItem.blockbookUtxo.value,
|
|
1509
|
+
scriptPubkey: cacheItem.address.scriptPubkey,
|
|
1577
1510
|
script,
|
|
1578
1511
|
redeemScript,
|
|
1579
1512
|
scriptType,
|
|
1580
|
-
blockHeight: _nullishCoalesce(
|
|
1513
|
+
blockHeight: _nullishCoalesce(cacheItem.blockbookUtxo.height, () => ( -1)),
|
|
1581
1514
|
spent: false
|
|
1582
1515
|
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
path,
|
|
1586
|
-
address.scriptPubkey,
|
|
1587
|
-
requiredCount,
|
|
1588
|
-
|
|
1516
|
+
addToDataLayerUtxoCache(
|
|
1517
|
+
dataLayerUtxoCache,
|
|
1518
|
+
cacheItem.path,
|
|
1519
|
+
cacheItem.address.scriptPubkey,
|
|
1520
|
+
cacheItem.requiredCount,
|
|
1521
|
+
utxoData
|
|
1589
1522
|
)
|
|
1590
1523
|
}
|
|
1591
1524
|
|
|
@@ -1593,46 +1526,42 @@ const processRawUtxo = async (
|
|
|
1593
1526
|
case _keymanager.BIP43PurposeTypeEnum.Airbitz:
|
|
1594
1527
|
case _keymanager.BIP43PurposeTypeEnum.Legacy:
|
|
1595
1528
|
case _keymanager.BIP43PurposeTypeEnum.ReplayProtection:
|
|
1596
|
-
redeemScript = address.redeemScript
|
|
1529
|
+
redeemScript = cacheItem.address.redeemScript
|
|
1597
1530
|
|
|
1598
1531
|
// Legacy UTXOs need the previous transaction hex as the script
|
|
1599
1532
|
// If we do not currently have it, add it to the queue to fetch it
|
|
1600
1533
|
{
|
|
1601
|
-
const [tx] = await
|
|
1602
|
-
txId:
|
|
1534
|
+
const [tx] = await common.dataLayer.fetchTransactions({
|
|
1535
|
+
txId: cacheItem.blockbookUtxo.txid
|
|
1603
1536
|
})
|
|
1604
1537
|
if (tx == null) {
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
const processedTx = processTransactionResponse({
|
|
1611
|
-
...args,
|
|
1612
|
-
txResponse
|
|
1613
|
-
})
|
|
1614
|
-
script = processedTx.hex
|
|
1615
|
-
// Only after we have successfully fetched the tx, set our script and call done
|
|
1616
|
-
done()
|
|
1617
|
-
})
|
|
1618
|
-
.catch(err => {
|
|
1619
|
-
// If something went wrong, add the UTXO back to the queue
|
|
1620
|
-
log('error in processRawUtxo:', err)
|
|
1621
|
-
const utxoId = `${utxo.txid}_${utxo.vout}`
|
|
1622
|
-
rawUtxoCache[utxoId] = {
|
|
1623
|
-
blockbookUtxo: utxo,
|
|
1624
|
-
processing: false,
|
|
1625
|
-
path,
|
|
1626
|
-
address,
|
|
1627
|
-
requiredCount
|
|
1628
|
-
}
|
|
1629
|
-
})
|
|
1538
|
+
try {
|
|
1539
|
+
const txResponse = yield* common.serverStates.transactionQueryTask(
|
|
1540
|
+
serverUri,
|
|
1541
|
+
cacheItem.blockbookUtxo.txid
|
|
1542
|
+
)
|
|
1630
1543
|
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1544
|
+
const processedTx = processTransactionResponse(common, {
|
|
1545
|
+
txResponse
|
|
1546
|
+
})
|
|
1547
|
+
script = processedTx.hex
|
|
1548
|
+
// Only after we have successfully fetched the tx, set our script and call done
|
|
1549
|
+
done()
|
|
1550
|
+
|
|
1551
|
+
return true
|
|
1552
|
+
} catch (err) {
|
|
1553
|
+
// If something went wrong, add the UTXO back to the queue
|
|
1554
|
+
common.log('error while processing Blockbook UTXO:', err)
|
|
1555
|
+
const utxoId = `${cacheItem.blockbookUtxo.txid}_${cacheItem.blockbookUtxo.vout}`
|
|
1556
|
+
blockbookUtxoCache[utxoId] = {
|
|
1557
|
+
blockbookUtxo: cacheItem.blockbookUtxo,
|
|
1558
|
+
processing: false,
|
|
1559
|
+
path: cacheItem.path,
|
|
1560
|
+
address: cacheItem.address,
|
|
1561
|
+
requiredCount: cacheItem.requiredCount
|
|
1562
|
+
}
|
|
1563
|
+
return false
|
|
1564
|
+
}
|
|
1636
1565
|
} else {
|
|
1637
1566
|
script = tx.hex
|
|
1638
1567
|
}
|
|
@@ -1640,39 +1569,46 @@ const processRawUtxo = async (
|
|
|
1640
1569
|
|
|
1641
1570
|
break
|
|
1642
1571
|
case _keymanager.BIP43PurposeTypeEnum.WrappedSegwit:
|
|
1643
|
-
script = address.scriptPubkey
|
|
1644
|
-
if (address.redeemScript == null) {
|
|
1572
|
+
script = cacheItem.address.scriptPubkey
|
|
1573
|
+
if (cacheItem.address.redeemScript == null) {
|
|
1645
1574
|
throw new Error(
|
|
1646
1575
|
'Address redeem script not defined, but required for p2sh wrapped segwit utxo processing'
|
|
1647
1576
|
)
|
|
1648
1577
|
}
|
|
1649
|
-
redeemScript = address.redeemScript
|
|
1578
|
+
redeemScript = cacheItem.address.redeemScript
|
|
1650
1579
|
|
|
1651
1580
|
break
|
|
1652
1581
|
case _keymanager.BIP43PurposeTypeEnum.Segwit:
|
|
1653
|
-
script = address.scriptPubkey
|
|
1582
|
+
script = cacheItem.address.scriptPubkey
|
|
1654
1583
|
|
|
1655
1584
|
break
|
|
1656
1585
|
}
|
|
1657
1586
|
|
|
1658
1587
|
// Since we have everything, call done
|
|
1659
1588
|
done()
|
|
1589
|
+
|
|
1590
|
+
return true
|
|
1660
1591
|
}
|
|
1661
1592
|
|
|
1662
|
-
|
|
1663
|
-
|
|
1593
|
+
/**
|
|
1594
|
+
* This adds a UtxoData object to the DataLayerUtxoCache. It will mark the cache
|
|
1595
|
+
* with processing and full flags which tell the pickNextTask routine when to
|
|
1596
|
+
* process the UtxoData into the data-later.
|
|
1597
|
+
*/
|
|
1598
|
+
const addToDataLayerUtxoCache = (
|
|
1599
|
+
dataLayerUtxoCache,
|
|
1664
1600
|
path,
|
|
1665
1601
|
scriptPubkey,
|
|
1666
1602
|
requiredCount,
|
|
1667
1603
|
utxo
|
|
1668
1604
|
) => {
|
|
1669
|
-
const
|
|
1605
|
+
const dataLayerUtxos = _nullishCoalesce(dataLayerUtxoCache[scriptPubkey], () => ( {
|
|
1670
1606
|
utxos: [],
|
|
1671
1607
|
processing: false,
|
|
1672
1608
|
path,
|
|
1673
1609
|
full: false
|
|
1674
1610
|
}))
|
|
1675
|
-
if (utxo != null)
|
|
1676
|
-
|
|
1677
|
-
|
|
1611
|
+
if (utxo != null) dataLayerUtxos.utxos.push(utxo)
|
|
1612
|
+
dataLayerUtxoCache[scriptPubkey] = dataLayerUtxos
|
|
1613
|
+
dataLayerUtxos.full = dataLayerUtxos.utxos.length >= requiredCount
|
|
1678
1614
|
}
|