edge-currency-plugins 1.0.0-rc.1
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/LICENSE +21 -0
- package/README.md +3 -0
- package/lib/bch.js +15 -0
- package/lib/bsv.js +15 -0
- package/lib/btc.js +15 -0
- package/lib/common/constants.js +11 -0
- package/lib/common/fees/calcMinerFeePerByte.js +62 -0
- package/lib/common/fees/makeFees.js +182 -0
- package/lib/common/fees/processInfoServerFees.js +30 -0
- package/lib/common/fees/processMempoolSpaceFees.js +38 -0
- package/lib/common/plugin/makeCurrencyPlugin.js +66 -0
- package/lib/common/plugin/makeCurrencyTools.js +211 -0
- package/lib/common/plugin/makeEngineEmitter.js +102 -0
- package/lib/common/plugin/makeMetadata.js +99 -0
- package/lib/common/plugin/pluginState.js +253 -0
- package/lib/common/plugin/serverScores.js +328 -0
- package/lib/common/plugin/types.js +173 -0
- package/lib/common/plugin/utils.js +18 -0
- package/lib/common/utxobased/db/Models/ProcessorTransaction.js +122 -0
- package/lib/common/utxobased/db/Models/baselet.js +81 -0
- package/lib/common/utxobased/db/makeBaselets.js +123 -0
- package/lib/common/utxobased/db/makeMutex.js +17 -0
- package/lib/common/utxobased/db/makeProcessor.js +554 -0
- package/lib/common/utxobased/db/types.js +67 -0
- package/lib/common/utxobased/engine/await-lock.js +65 -0
- package/lib/common/utxobased/engine/constants.js +7 -0
- package/lib/common/utxobased/engine/makeServerStates.js +394 -0
- package/lib/common/utxobased/engine/makeUtxoEngine.js +690 -0
- package/lib/common/utxobased/engine/makeUtxoEngineState.js +1443 -0
- package/lib/common/utxobased/engine/makeUtxoWalletTools.js +216 -0
- package/lib/common/utxobased/engine/paymentRequest.js +102 -0
- package/lib/common/utxobased/engine/types.js +21 -0
- package/lib/common/utxobased/engine/util/defaultValidateConfirmations.js +19 -0
- package/lib/common/utxobased/engine/util/getOwnUtxosFromTx.js +54 -0
- package/lib/common/utxobased/engine/utils.js +239 -0
- package/lib/common/utxobased/info/all.js +67 -0
- package/lib/common/utxobased/info/badcoin.js +73 -0
- package/lib/common/utxobased/info/bitcoin.js +91 -0
- package/lib/common/utxobased/info/bitcoincash.js +93 -0
- package/lib/common/utxobased/info/bitcoincashtestnet.js +72 -0
- package/lib/common/utxobased/info/bitcoingold.js +85 -0
- package/lib/common/utxobased/info/bitcoingoldtestnet.js +71 -0
- package/lib/common/utxobased/info/bitcoinsv.js +76 -0
- package/lib/common/utxobased/info/bitcointestnet.js +81 -0
- package/lib/common/utxobased/info/dash.js +76 -0
- package/lib/common/utxobased/info/digibyte.js +76 -0
- package/lib/common/utxobased/info/dogecoin.js +76 -0
- package/lib/common/utxobased/info/eboost.js +70 -0
- package/lib/common/utxobased/info/feathercoin.js +76 -0
- package/lib/common/utxobased/info/groestlcoin.js +88 -0
- package/lib/common/utxobased/info/litecoin.js +82 -0
- package/lib/common/utxobased/info/qtum.js +67 -0
- package/lib/common/utxobased/info/ravencoin.js +70 -0
- package/lib/common/utxobased/info/scriptTemplates/bitcoincashScriptTemplates.js +56 -0
- package/lib/common/utxobased/info/scriptTemplates/types.js +14 -0
- package/lib/common/utxobased/info/smartcash.js +78 -0
- package/lib/common/utxobased/info/ufo.js +75 -0
- package/lib/common/utxobased/info/utxoPickers/dogeUtxoPicker.js +34 -0
- package/lib/common/utxobased/info/vertcoin.js +82 -0
- package/lib/common/utxobased/info/zcoin.js +72 -0
- package/lib/common/utxobased/keymanager/base.js +60 -0
- package/lib/common/utxobased/keymanager/bip69.js +31 -0
- package/lib/common/utxobased/keymanager/bitcoincashUtils/base32.js +88 -0
- package/lib/common/utxobased/keymanager/bitcoincashUtils/bn.js +210 -0
- package/lib/common/utxobased/keymanager/bitcoincashUtils/cashAddress.js +282 -0
- package/lib/common/utxobased/keymanager/cleaners.js +198 -0
- package/lib/common/utxobased/keymanager/coinmapper.js +12 -0
- package/lib/common/utxobased/keymanager/declarations/base58grscheck.d.js +1 -0
- package/lib/common/utxobased/keymanager/declarations/blake-hash.d.js +1 -0
- package/lib/common/utxobased/keymanager/declarations/bn.d.js +1 -0
- package/lib/common/utxobased/keymanager/declarations/bs58smartcheck.d.js +1 -0
- package/lib/common/utxobased/keymanager/declarations/wif-smart.d.js +1 -0
- package/lib/common/utxobased/keymanager/declarations/wifgrs.d.js +1 -0
- package/lib/common/utxobased/keymanager/keymanager.js +1214 -0
- package/lib/common/utxobased/keymanager/utxopicker/accumulative.js +52 -0
- package/lib/common/utxobased/keymanager/utxopicker/forceUseUtxo.js +59 -0
- package/lib/common/utxobased/keymanager/utxopicker/subtractFee.js +17 -0
- package/lib/common/utxobased/keymanager/utxopicker/types.js +42 -0
- package/lib/common/utxobased/keymanager/utxopicker/utils.js +159 -0
- package/lib/common/utxobased/keymanager/utxopicker.js +17 -0
- package/lib/common/utxobased/network/BlockBook.js +200 -0
- package/lib/common/utxobased/network/BlockBookAPI.js +335 -0
- package/lib/common/utxobased/network/Deferred.js +29 -0
- package/lib/common/utxobased/network/MakeSocketEmitter.js +35 -0
- package/lib/common/utxobased/network/Socket.js +362 -0
- package/lib/common/utxobased/network/nodejsWS.js +59 -0
- package/lib/common/utxobased/network/socketQueue.js +60 -0
- package/lib/common/utxobased/network/types.js +19 -0
- package/lib/common/utxobased/network/windowWS.js +54 -0
- package/lib/firo.js +15 -0
- package/lib/ftc.js +15 -0
- package/lib/index.js +19 -0
- package/lib/ltc.js +15 -0
- package/lib/src/bch.d.ts +3 -0
- package/lib/src/bsv.d.ts +3 -0
- package/lib/src/btc.d.ts +3 -0
- package/lib/src/common/constants.d.ts +9 -0
- package/lib/src/common/fees/calcMinerFeePerByte.d.ts +13 -0
- package/lib/src/common/fees/makeFees.d.ts +20 -0
- package/lib/src/common/fees/processInfoServerFees.d.ts +7 -0
- package/lib/src/common/fees/processMempoolSpaceFees.d.ts +13 -0
- package/lib/src/common/plugin/makeCurrencyPlugin.d.ts +3 -0
- package/lib/src/common/plugin/makeCurrencyTools.d.ts +8 -0
- package/lib/src/common/plugin/makeEngineEmitter.d.ts +23 -0
- package/lib/src/common/plugin/makeMetadata.d.ts +14 -0
- package/lib/src/common/plugin/pluginState.d.ts +34 -0
- package/lib/src/common/plugin/serverScores.d.ts +61 -0
- package/lib/src/common/plugin/types.d.ts +135 -0
- package/lib/src/common/plugin/utils.d.ts +6 -0
- package/lib/src/common/utxobased/db/Models/ProcessorTransaction.d.ts +16 -0
- package/lib/src/common/utxobased/db/Models/baselet.d.ts +28 -0
- package/lib/src/common/utxobased/db/makeBaselets.d.ts +33 -0
- package/lib/src/common/utxobased/db/makeMutex.d.ts +3 -0
- package/lib/src/common/utxobased/db/makeProcessor.d.ts +42 -0
- package/lib/src/common/utxobased/db/types.d.ts +47 -0
- package/lib/src/common/utxobased/engine/await-lock.d.ts +29 -0
- package/lib/src/common/utxobased/engine/constants.d.ts +4 -0
- package/lib/src/common/utxobased/engine/makeServerStates.d.ts +37 -0
- package/lib/src/common/utxobased/engine/makeUtxoEngine.d.ts +3 -0
- package/lib/src/common/utxobased/engine/makeUtxoEngineState.d.ts +108 -0
- package/lib/src/common/utxobased/engine/makeUtxoWalletTools.d.ts +52 -0
- package/lib/src/common/utxobased/engine/paymentRequest.d.ts +18 -0
- package/lib/src/common/utxobased/engine/types.d.ts +19 -0
- package/lib/src/common/utxobased/engine/util/defaultValidateConfirmations.d.ts +3 -0
- package/lib/src/common/utxobased/engine/util/getOwnUtxosFromTx.d.ts +4 -0
- package/lib/src/common/utxobased/engine/utils.d.ts +43 -0
- package/lib/src/common/utxobased/info/all.d.ts +22 -0
- package/lib/src/common/utxobased/info/badcoin.d.ts +3 -0
- package/lib/src/common/utxobased/info/bitcoin.d.ts +3 -0
- package/lib/src/common/utxobased/info/bitcoincash.d.ts +3 -0
- package/lib/src/common/utxobased/info/bitcoincashtestnet.d.ts +3 -0
- package/lib/src/common/utxobased/info/bitcoingold.d.ts +3 -0
- package/lib/src/common/utxobased/info/bitcoingoldtestnet.d.ts +3 -0
- package/lib/src/common/utxobased/info/bitcoinsv.d.ts +3 -0
- package/lib/src/common/utxobased/info/bitcointestnet.d.ts +6 -0
- package/lib/src/common/utxobased/info/dash.d.ts +3 -0
- package/lib/src/common/utxobased/info/digibyte.d.ts +3 -0
- package/lib/src/common/utxobased/info/dogecoin.d.ts +3 -0
- package/lib/src/common/utxobased/info/eboost.d.ts +3 -0
- package/lib/src/common/utxobased/info/feathercoin.d.ts +6 -0
- package/lib/src/common/utxobased/info/groestlcoin.d.ts +3 -0
- package/lib/src/common/utxobased/info/litecoin.d.ts +6 -0
- package/lib/src/common/utxobased/info/qtum.d.ts +3 -0
- package/lib/src/common/utxobased/info/ravencoin.d.ts +3 -0
- package/lib/src/common/utxobased/info/scriptTemplates/bitcoincashScriptTemplates.d.ts +2 -0
- package/lib/src/common/utxobased/info/scriptTemplates/types.d.ts +9 -0
- package/lib/src/common/utxobased/info/smartcash.d.ts +3 -0
- package/lib/src/common/utxobased/info/ufo.d.ts +3 -0
- package/lib/src/common/utxobased/info/utxoPickers/dogeUtxoPicker.d.ts +2 -0
- package/lib/src/common/utxobased/info/vertcoin.d.ts +3 -0
- package/lib/src/common/utxobased/info/zcoin.d.ts +6 -0
- package/lib/src/common/utxobased/keymanager/base.d.ts +9 -0
- package/lib/src/common/utxobased/keymanager/bip69.d.ts +19 -0
- package/lib/src/common/utxobased/keymanager/bitcoincashUtils/base32.d.ts +19 -0
- package/lib/src/common/utxobased/keymanager/bitcoincashUtils/bn.d.ts +2 -0
- package/lib/src/common/utxobased/keymanager/bitcoincashUtils/cashAddress.d.ts +12 -0
- package/lib/src/common/utxobased/keymanager/cleaners.d.ts +55 -0
- package/lib/src/common/utxobased/keymanager/coinmapper.d.ts +2 -0
- package/lib/src/common/utxobased/keymanager/keymanager.d.ts +198 -0
- package/lib/src/common/utxobased/keymanager/utxopicker/accumulative.d.ts +2 -0
- package/lib/src/common/utxobased/keymanager/utxopicker/forceUseUtxo.d.ts +2 -0
- package/lib/src/common/utxobased/keymanager/utxopicker/subtractFee.d.ts +2 -0
- package/lib/src/common/utxobased/keymanager/utxopicker/types.d.ts +36 -0
- package/lib/src/common/utxobased/keymanager/utxopicker/utils.d.ts +15 -0
- package/lib/src/common/utxobased/keymanager/utxopicker.d.ts +8 -0
- package/lib/src/common/utxobased/network/BlockBook.d.ts +33 -0
- package/lib/src/common/utxobased/network/BlockBookAPI.d.ts +163 -0
- package/lib/src/common/utxobased/network/Deferred.d.ts +8 -0
- package/lib/src/common/utxobased/network/MakeSocketEmitter.d.ts +13 -0
- package/lib/src/common/utxobased/network/Socket.d.ts +41 -0
- package/lib/src/common/utxobased/network/nodejsWS.d.ts +2 -0
- package/lib/src/common/utxobased/network/socketQueue.d.ts +8 -0
- package/lib/src/common/utxobased/network/types.d.ts +17 -0
- package/lib/src/common/utxobased/network/windowWS.d.ts +2 -0
- package/lib/src/firo.d.ts +3 -0
- package/lib/src/ftc.d.ts +3 -0
- package/lib/src/index.d.ts +4 -0
- package/lib/src/ltc.d.ts +3 -0
- package/lib/src/tbch.d.ts +3 -0
- package/lib/src/tbtc.d.ts +3 -0
- package/lib/src/tbtg.d.ts +3 -0
- package/lib/src/types.d.ts +6 -0
- package/lib/src/util/delay.d.ts +1 -0
- package/lib/src/util/filterUndefined.d.ts +1 -0
- package/lib/src/util/indexAtProtected.d.ts +5 -0
- package/lib/src/util/typeUtil.d.ts +8 -0
- package/lib/src/util/undefinedIfEmptyString.d.ts +1 -0
- package/lib/src/util/unixTime.d.ts +1 -0
- package/lib/tbch.js +15 -0
- package/lib/tbtc.js +15 -0
- package/lib/tbtg.js +15 -0
- package/lib/test/common/fees/calcMinerFeePerByte.spec.d.ts +1 -0
- package/lib/test/common/fees/fees.spec.d.ts +1 -0
- package/lib/test/common/plugin/currencyPlugin.fixtures/common.d.ts +29 -0
- package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/bitcoin.d.ts +2 -0
- package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/bitcoincash.d.ts +2 -0
- package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/bitcoinsv.d.ts +2 -0
- package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/digibyte.d.ts +2 -0
- package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/feathercoin.d.ts +2 -0
- package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/groestlcoin.d.ts +2 -0
- package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/litecoin.d.ts +2 -0
- package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/smartcash.d.ts +2 -0
- package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/zcoin.d.ts +2 -0
- package/lib/test/common/plugin/currencyPlugin.fixtures/index.d.ts +2 -0
- package/lib/test/common/plugin/currencyPlugin.spec.d.ts +1 -0
- package/lib/test/common/plugin/makeMetadata.spec.d.ts +1 -0
- package/lib/test/common/plugin/serverScores.spec.d.ts +1 -0
- package/lib/test/common/utxobased/addressFormat/addressFormatIndex/addressFormat.spec.d.ts +1 -0
- package/lib/test/common/utxobased/db/Processor.spec.d.ts +1 -0
- package/lib/test/common/utxobased/engine/PaymentRequest.spec.d.ts +1 -0
- package/lib/test/common/utxobased/engine/UtxoWalletTools.spec.d.ts +1 -0
- package/lib/test/common/utxobased/engine/engine.fixtures/bitcoinTestnet/tests.d.ts +70 -0
- package/lib/test/common/utxobased/engine/engine.fixtures/index.d.ts +65 -0
- package/lib/test/common/utxobased/engine/engine.spec.d.ts +1 -0
- package/lib/test/common/utxobased/keymanager/coins/altcointestfixtures.d.ts +54 -0
- package/lib/test/common/utxobased/keymanager/coins/bitcoincashtransactiontest.spec.d.ts +1 -0
- package/lib/test/common/utxobased/keymanager/coins/bitcointransactiontest.spec.d.ts +1 -0
- package/lib/test/common/utxobased/keymanager/coins/cashaddr.spec.d.ts +1 -0
- package/lib/test/common/utxobased/keymanager/coins/checkdatasig.spec.d.ts +1 -0
- package/lib/test/common/utxobased/keymanager/coins/groestlcointransactiontest.spec.d.ts +1 -0
- package/lib/test/common/utxobased/keymanager/coins/keymanagertest.spec.d.ts +1 -0
- package/lib/test/common/utxobased/network/BlockBook.spec.d.ts +1 -0
- package/lib/test/util/objectKeys.d.ts +8 -0
- package/lib/test/util/testLog.d.ts +3 -0
- package/lib/test/utils.d.ts +10 -0
- package/lib/types.js +7 -0
- package/lib/util/delay.js +4 -0
- package/lib/util/filterUndefined.js +4 -0
- package/lib/util/indexAtProtected.js +9 -0
- package/lib/util/typeUtil.js +9 -0
- package/lib/util/undefinedIfEmptyString.js +2 -0
- package/lib/util/unixTime.js +2 -0
- package/package.json +101 -0
|
@@ -0,0 +1,1443 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _biggystring = require('biggystring');
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
var _makeEngineEmitter = require('../../plugin/makeEngineEmitter');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
var _utils = require('../../plugin/utils');
|
|
19
|
+
|
|
20
|
+
var _ProcessorTransaction = require('../db/Models/ProcessorTransaction');
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
var _types5 = require('../db/types');
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
var _keymanager = require('../keymanager/keymanager');
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
var _BlockBookAPI = require('../network/BlockBookAPI');
|
|
44
|
+
var _Deferred = require('../network/Deferred'); var _Deferred2 = _interopRequireDefault(_Deferred);
|
|
45
|
+
|
|
46
|
+
var _awaitlock = require('./await-lock'); var _awaitlock2 = _interopRequireDefault(_awaitlock);
|
|
47
|
+
var _constants = require('./constants');
|
|
48
|
+
var _makeServerStates = require('./makeServerStates');
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
var _utils3 = require('./utils');
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
function makeUtxoEngineState(
|
|
88
|
+
config
|
|
89
|
+
) {
|
|
90
|
+
const {
|
|
91
|
+
pluginInfo,
|
|
92
|
+
walletInfo,
|
|
93
|
+
walletTools,
|
|
94
|
+
options: { emitter, log },
|
|
95
|
+
processor,
|
|
96
|
+
pluginState
|
|
97
|
+
} = config
|
|
98
|
+
|
|
99
|
+
const { walletFormats } = walletInfo.keys
|
|
100
|
+
|
|
101
|
+
const taskCache = {
|
|
102
|
+
addressWatching: false,
|
|
103
|
+
blockWatching: false,
|
|
104
|
+
addressSubscribeCache: {},
|
|
105
|
+
addressTransactionCache: {},
|
|
106
|
+
addressUtxoCache: {},
|
|
107
|
+
rawUtxoCache: {},
|
|
108
|
+
processorUtxoCache: {},
|
|
109
|
+
updateTransactionCache: {}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const clearTaskCache = () => {
|
|
113
|
+
taskCache.addressWatching = false
|
|
114
|
+
taskCache.blockWatching = false
|
|
115
|
+
taskCache.addressSubscribeCache = {}
|
|
116
|
+
taskCache.addressTransactionCache = {}
|
|
117
|
+
taskCache.addressUtxoCache = {}
|
|
118
|
+
taskCache.rawUtxoCache = {}
|
|
119
|
+
taskCache.processorUtxoCache = {}
|
|
120
|
+
taskCache.updateTransactionCache = {}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* There are two processes that need to complete per address:
|
|
125
|
+
* 1. Address transaction processing
|
|
126
|
+
* 2. Address UTXO processing
|
|
127
|
+
**/
|
|
128
|
+
const processesPerAddress = 2
|
|
129
|
+
let processedCount = 0
|
|
130
|
+
let processedPercent = 0
|
|
131
|
+
const updateProgressRatio = async () => {
|
|
132
|
+
// We expect the total number of progress updates to equal the number of
|
|
133
|
+
// addresses multiplied the number of processes per address.
|
|
134
|
+
const expectedProccessCount =
|
|
135
|
+
Object.keys(taskCache.addressSubscribeCache).length * processesPerAddress
|
|
136
|
+
|
|
137
|
+
// Increment the processed count
|
|
138
|
+
processedCount = processedCount + 1
|
|
139
|
+
|
|
140
|
+
// If we have no addresses, we should not have not yet began processing.
|
|
141
|
+
if (expectedProccessCount === 0) throw new Error('No addresses to process')
|
|
142
|
+
|
|
143
|
+
const percent = processedCount / expectedProccessCount
|
|
144
|
+
if (percent - processedPercent > _constants.CACHE_THROTTLE || percent === 1) {
|
|
145
|
+
log(
|
|
146
|
+
`processed changed, percent: ${percent}, processedCount: ${processedCount}, totalCount: ${expectedProccessCount}`
|
|
147
|
+
)
|
|
148
|
+
processedPercent = percent
|
|
149
|
+
emitter.emit(_makeEngineEmitter.EngineEvent.ADDRESSES_CHECKED, percent)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const lock = new (0, _awaitlock2.default)()
|
|
154
|
+
|
|
155
|
+
const serverStates = _makeServerStates.makeServerStates.call(void 0, {
|
|
156
|
+
engineEmitter: emitter,
|
|
157
|
+
log,
|
|
158
|
+
pluginInfo,
|
|
159
|
+
pluginState,
|
|
160
|
+
walletInfo
|
|
161
|
+
})
|
|
162
|
+
const commonArgs = {
|
|
163
|
+
pluginInfo,
|
|
164
|
+
walletInfo,
|
|
165
|
+
walletTools,
|
|
166
|
+
processor,
|
|
167
|
+
emitter,
|
|
168
|
+
taskCache,
|
|
169
|
+
updateProgressRatio,
|
|
170
|
+
io: config.io,
|
|
171
|
+
log,
|
|
172
|
+
serverStates,
|
|
173
|
+
walletFormats,
|
|
174
|
+
lock
|
|
175
|
+
}
|
|
176
|
+
const { currencyInfo } = pluginInfo
|
|
177
|
+
const { requiredConfirmations = 1 } = currencyInfo
|
|
178
|
+
|
|
179
|
+
const pickNextTaskCB = async (
|
|
180
|
+
uri
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
182
|
+
) => {
|
|
183
|
+
return await exports.pickNextTask.call(void 0, { ...commonArgs, uri })
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
serverStates.setPickNextTaskCB(pickNextTaskCB)
|
|
187
|
+
|
|
188
|
+
let running = false
|
|
189
|
+
const run = async () => {
|
|
190
|
+
if (running) return
|
|
191
|
+
running = true
|
|
192
|
+
|
|
193
|
+
await initializeAddressSubscriptions()
|
|
194
|
+
await setLookAhead(commonArgs)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
emitter.on(
|
|
198
|
+
_makeEngineEmitter.EngineEvent.BLOCK_HEIGHT_CHANGED,
|
|
199
|
+
async (_uri, walletBlockHeight) => {
|
|
200
|
+
// Check if unconfirmed transaction have been confirmed.
|
|
201
|
+
const unconfirmedTxs = await processor.fetchTransactions({
|
|
202
|
+
blockHeight: 0
|
|
203
|
+
})
|
|
204
|
+
for (const tx of unconfirmedTxs) {
|
|
205
|
+
if (tx == null) continue
|
|
206
|
+
taskCache.updateTransactionCache[tx.txid] = { processing: false }
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Trigger transactions change event to update its confirmation status
|
|
210
|
+
const pendingTxs = await processor.fetchTransactions({
|
|
211
|
+
blockHeight: walletBlockHeight - requiredConfirmations,
|
|
212
|
+
blockHeightMax: walletBlockHeight
|
|
213
|
+
})
|
|
214
|
+
for (const tx of pendingTxs) {
|
|
215
|
+
if (tx == null) continue
|
|
216
|
+
await exports.transactionChanged.call(void 0, {
|
|
217
|
+
emitter,
|
|
218
|
+
processor,
|
|
219
|
+
pluginInfo,
|
|
220
|
+
tx,
|
|
221
|
+
walletBlockHeight,
|
|
222
|
+
walletTools
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
emitter.on(
|
|
229
|
+
_makeEngineEmitter.EngineEvent.NEW_ADDRESS_TRANSACTION,
|
|
230
|
+
async (_uri, response) => {
|
|
231
|
+
const state = taskCache.addressSubscribeCache[response.address]
|
|
232
|
+
if (state != null) {
|
|
233
|
+
const { path } = state
|
|
234
|
+
taskCache.addressUtxoCache[response.address] = {
|
|
235
|
+
processing: false,
|
|
236
|
+
path
|
|
237
|
+
}
|
|
238
|
+
addToAddressTransactionCache(
|
|
239
|
+
commonArgs,
|
|
240
|
+
response.address,
|
|
241
|
+
path.format,
|
|
242
|
+
path.changeIndex,
|
|
243
|
+
0,
|
|
244
|
+
taskCache.addressTransactionCache
|
|
245
|
+
).catch(() => {
|
|
246
|
+
throw new Error('failed to add to transaction cache')
|
|
247
|
+
})
|
|
248
|
+
setLookAhead(commonArgs).catch(e => {
|
|
249
|
+
log(e)
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
// Initialize the addressSubscribeCache with the existing addresses already
|
|
256
|
+
// processed by the processor. This happens only once before any call to
|
|
257
|
+
// setLookAhead.
|
|
258
|
+
const initializeAddressSubscriptions = async () => {
|
|
259
|
+
for (const format of walletFormats) {
|
|
260
|
+
const branches = _utils3.getFormatSupportedBranches.call(void 0, format)
|
|
261
|
+
for (const branch of branches) {
|
|
262
|
+
const addressesToSubscribe = new Set()
|
|
263
|
+
const branchAddressCount = processor.numAddressesByFormatPath({
|
|
264
|
+
format,
|
|
265
|
+
changeIndex: branch
|
|
266
|
+
})
|
|
267
|
+
// If the processor has not processed any addresses then the loop
|
|
268
|
+
// condition will only iterate once when branchAddressCount is 0 for the
|
|
269
|
+
// first address in the derivation path.
|
|
270
|
+
for (
|
|
271
|
+
let addressIndex = 0;
|
|
272
|
+
addressIndex < branchAddressCount;
|
|
273
|
+
addressIndex++
|
|
274
|
+
) {
|
|
275
|
+
const processorAddress = await processor.fetchAddress({
|
|
276
|
+
format,
|
|
277
|
+
changeIndex: branch,
|
|
278
|
+
addressIndex
|
|
279
|
+
})
|
|
280
|
+
if (processorAddress == null) {
|
|
281
|
+
throw new Error(
|
|
282
|
+
'Missing processor during address subscription initialization'
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
const { address } = walletTools.scriptPubkeyToAddress({
|
|
286
|
+
scriptPubkey: processorAddress.scriptPubkey,
|
|
287
|
+
format
|
|
288
|
+
})
|
|
289
|
+
addressesToSubscribe.add(address)
|
|
290
|
+
}
|
|
291
|
+
addToAddressSubscribeCache(commonArgs.taskCache, addressesToSubscribe, {
|
|
292
|
+
format,
|
|
293
|
+
changeIndex: branch
|
|
294
|
+
})
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
processedPercent,
|
|
301
|
+
async start() {
|
|
302
|
+
processedCount = 0
|
|
303
|
+
processedPercent = 0
|
|
304
|
+
|
|
305
|
+
await run()
|
|
306
|
+
serverStates.refillServers()
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
async stop() {
|
|
310
|
+
serverStates.stop()
|
|
311
|
+
clearTaskCache()
|
|
312
|
+
running = false
|
|
313
|
+
},
|
|
314
|
+
|
|
315
|
+
async getFreshAddress(branch = 0) {
|
|
316
|
+
const walletPurpose = _utils3.currencyFormatToPurposeType.call(void 0,
|
|
317
|
+
walletInfo.keys.primaryFormat
|
|
318
|
+
)
|
|
319
|
+
if (walletPurpose === _keymanager.BIP43PurposeTypeEnum.Segwit) {
|
|
320
|
+
const { address: publicAddress } = await internalGetFreshAddress({
|
|
321
|
+
...commonArgs,
|
|
322
|
+
format: _utils3.getCurrencyFormatFromPurposeType.call(void 0,
|
|
323
|
+
_keymanager.BIP43PurposeTypeEnum.WrappedSegwit
|
|
324
|
+
),
|
|
325
|
+
changeIndex: branch
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
const { address: segwitAddress } = await internalGetFreshAddress({
|
|
329
|
+
...commonArgs,
|
|
330
|
+
format: _utils3.getCurrencyFormatFromPurposeType.call(void 0, _keymanager.BIP43PurposeTypeEnum.Segwit),
|
|
331
|
+
changeIndex: branch
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
publicAddress,
|
|
336
|
+
segwitAddress
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
// Airbitz wallets only use branch 0
|
|
340
|
+
if (walletPurpose === _keymanager.BIP43PurposeTypeEnum.Airbitz) {
|
|
341
|
+
branch = 0
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const {
|
|
345
|
+
address: publicAddress,
|
|
346
|
+
legacyAddress
|
|
347
|
+
} = await internalGetFreshAddress({
|
|
348
|
+
...commonArgs,
|
|
349
|
+
format: _utils3.getCurrencyFormatFromPurposeType.call(void 0, walletPurpose),
|
|
350
|
+
changeIndex: branch
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
return {
|
|
354
|
+
publicAddress,
|
|
355
|
+
legacyAddress:
|
|
356
|
+
legacyAddress !== publicAddress ? legacyAddress : undefined
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
async deriveScriptAddress(script) {
|
|
362
|
+
const { address } = await internalDeriveScriptAddress({
|
|
363
|
+
walletTools: commonArgs.walletTools,
|
|
364
|
+
engineInfo: commonArgs.pluginInfo.engineInfo,
|
|
365
|
+
processor: commonArgs.processor,
|
|
366
|
+
taskCache: commonArgs.taskCache,
|
|
367
|
+
format: walletInfo.keys.primaryFormat,
|
|
368
|
+
script
|
|
369
|
+
})
|
|
370
|
+
return {
|
|
371
|
+
publicAddress: address
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
|
|
375
|
+
async addGapLimitAddresses(addresses) {
|
|
376
|
+
const promises = addresses.map(async address => {
|
|
377
|
+
const scriptPubkey = walletTools.addressToScriptPubkey(address)
|
|
378
|
+
await processor.saveAddress(
|
|
379
|
+
_types5.makeIAddress.call(void 0, {
|
|
380
|
+
scriptPubkey,
|
|
381
|
+
used: true
|
|
382
|
+
})
|
|
383
|
+
)
|
|
384
|
+
})
|
|
385
|
+
await Promise.all(promises)
|
|
386
|
+
await run()
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
async broadcastTx(transaction) {
|
|
390
|
+
const txId = await serverStates.broadcastTx(transaction)
|
|
391
|
+
|
|
392
|
+
/*
|
|
393
|
+
After successfully broadcasting the tx, we must mark each UTXO, used as
|
|
394
|
+
an input for the tx, as spent so we don't try to reuse the UTXO.
|
|
395
|
+
*/
|
|
396
|
+
const txInputs = _nullishCoalesce(_optionalChain([transaction, 'access', _ => _.otherParams, 'optionalAccess', _2 => _2.psbt, 'access', _3 => _3.inputs]), () => ( []))
|
|
397
|
+
for (const input of txInputs) {
|
|
398
|
+
const scriptPubkey = Buffer.from(input.scriptPubkey).toString('hex')
|
|
399
|
+
const [utxo] = await processor.fetchUtxos({
|
|
400
|
+
scriptPubkey
|
|
401
|
+
})
|
|
402
|
+
if (utxo != null) {
|
|
403
|
+
utxo.spent = true
|
|
404
|
+
await processor.saveUtxo(utxo)
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return txId
|
|
409
|
+
},
|
|
410
|
+
refillServers() {
|
|
411
|
+
serverStates.refillServers()
|
|
412
|
+
},
|
|
413
|
+
getServerList() {
|
|
414
|
+
return serverStates.getServerList()
|
|
415
|
+
},
|
|
416
|
+
setServerList(serverList) {
|
|
417
|
+
serverStates.setServerList(serverList)
|
|
418
|
+
},
|
|
419
|
+
|
|
420
|
+
async loadWifs(wifs) {
|
|
421
|
+
for (const wif of wifs) {
|
|
422
|
+
for (const format of walletFormats) {
|
|
423
|
+
const changePath = {
|
|
424
|
+
format,
|
|
425
|
+
changeIndex: 0
|
|
426
|
+
}
|
|
427
|
+
const path = {
|
|
428
|
+
...changePath,
|
|
429
|
+
addressIndex: 0
|
|
430
|
+
}
|
|
431
|
+
const {
|
|
432
|
+
scriptPubkey,
|
|
433
|
+
redeemScript
|
|
434
|
+
} = walletTools.getScriptPubkeyFromWif(wif, format)
|
|
435
|
+
const { address } = walletTools.scriptPubkeyToAddress({
|
|
436
|
+
scriptPubkey,
|
|
437
|
+
format: path.format
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
// Make a new IAddress and save it
|
|
441
|
+
await processor.saveAddress(
|
|
442
|
+
_types5.makeIAddress.call(void 0, { scriptPubkey, redeemScript, path })
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
taskCache.addressSubscribeCache[address] = {
|
|
446
|
+
path: changePath,
|
|
447
|
+
processing: false
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
taskCache.addressWatching = false
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
} exports.makeUtxoEngineState = makeUtxoEngineState;
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
const setLookAhead = async (common) => {
|
|
519
|
+
const {
|
|
520
|
+
pluginInfo: { engineInfo },
|
|
521
|
+
lock,
|
|
522
|
+
processor,
|
|
523
|
+
walletFormats,
|
|
524
|
+
walletTools
|
|
525
|
+
} = common
|
|
526
|
+
|
|
527
|
+
// Wait for the lock to be released before continuing invocation.
|
|
528
|
+
// This is to ensure that setLockAhead is not called while the lock is held.
|
|
529
|
+
await lock.acquireAsync()
|
|
530
|
+
|
|
531
|
+
try {
|
|
532
|
+
for (const format of walletFormats) {
|
|
533
|
+
const branches = _utils3.getFormatSupportedBranches.call(void 0, format)
|
|
534
|
+
for (const branch of branches) {
|
|
535
|
+
await deriveKeys({ format, changeIndex: branch })
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
} finally {
|
|
539
|
+
lock.release()
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
async function deriveKeys(changePath) {
|
|
543
|
+
const addressesToSubscribe = new Set()
|
|
544
|
+
const totalAddressCount = processor.numAddressesByFormatPath(changePath)
|
|
545
|
+
let lastUsedIndex = await processor.lastUsedIndexByFormatPath(changePath)
|
|
546
|
+
|
|
547
|
+
// Loop until the total address count equals the lookahead count
|
|
548
|
+
let lookAheadIndex = lastUsedIndex + engineInfo.gapLimit
|
|
549
|
+
let nextAddressIndex = totalAddressCount
|
|
550
|
+
while (nextAddressIndex <= lookAheadIndex) {
|
|
551
|
+
const path = {
|
|
552
|
+
...changePath,
|
|
553
|
+
addressIndex: nextAddressIndex
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const { scriptPubkey, redeemScript } = walletTools.getScriptPubkey(path)
|
|
557
|
+
const { address } = walletTools.scriptPubkeyToAddress({
|
|
558
|
+
scriptPubkey,
|
|
559
|
+
format: path.format
|
|
560
|
+
})
|
|
561
|
+
|
|
562
|
+
// Make a new IAddress and save it
|
|
563
|
+
await processor.saveAddress(
|
|
564
|
+
_types5.makeIAddress.call(void 0, { scriptPubkey, redeemScript, path })
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
// Add the displayAddress to the set of addresses to subscribe to after loop
|
|
568
|
+
addressesToSubscribe.add(address)
|
|
569
|
+
|
|
570
|
+
// Update the state for the loop
|
|
571
|
+
lastUsedIndex = await processor.lastUsedIndexByFormatPath(changePath)
|
|
572
|
+
lookAheadIndex = lastUsedIndex + engineInfo.gapLimit
|
|
573
|
+
nextAddressIndex = processor.numAddressesByFormatPath(changePath)
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// Add all the addresses to the subscribe cache for registering subscriptions later
|
|
577
|
+
addToAddressSubscribeCache(
|
|
578
|
+
common.taskCache,
|
|
579
|
+
addressesToSubscribe,
|
|
580
|
+
changePath
|
|
581
|
+
)
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const addToAddressSubscribeCache = (
|
|
586
|
+
taskCache,
|
|
587
|
+
addresses,
|
|
588
|
+
path
|
|
589
|
+
) => {
|
|
590
|
+
addresses.forEach(address => {
|
|
591
|
+
taskCache.addressSubscribeCache[address] = {
|
|
592
|
+
path,
|
|
593
|
+
processing: false
|
|
594
|
+
}
|
|
595
|
+
taskCache.addressWatching = false
|
|
596
|
+
})
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const addToAddressTransactionCache = async (
|
|
600
|
+
args,
|
|
601
|
+
address,
|
|
602
|
+
format,
|
|
603
|
+
branch,
|
|
604
|
+
blockHeight,
|
|
605
|
+
addressTransactionCache
|
|
606
|
+
) => {
|
|
607
|
+
const { walletTools, processor } = args
|
|
608
|
+
// Fetch the blockHeight for the address from the database
|
|
609
|
+
const scriptPubkey = walletTools.addressToScriptPubkey(address)
|
|
610
|
+
|
|
611
|
+
if (blockHeight === 0) {
|
|
612
|
+
const { lastQueriedBlockHeight = 0 } =
|
|
613
|
+
await _asyncNullishCoalesce((await processor.fetchAddress(scriptPubkey)), async () => ( {}))
|
|
614
|
+
blockHeight = lastQueriedBlockHeight
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
addressTransactionCache[address] = {
|
|
618
|
+
processing: false,
|
|
619
|
+
path: {
|
|
620
|
+
format,
|
|
621
|
+
changeIndex: branch
|
|
622
|
+
},
|
|
623
|
+
page: 1, // Page starts on 1
|
|
624
|
+
blockHeight
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
const transactionChanged = async (
|
|
638
|
+
args
|
|
639
|
+
) => {
|
|
640
|
+
const {
|
|
641
|
+
emitter,
|
|
642
|
+
walletBlockHeight,
|
|
643
|
+
walletTools,
|
|
644
|
+
processor,
|
|
645
|
+
pluginInfo,
|
|
646
|
+
tx
|
|
647
|
+
} = args
|
|
648
|
+
const { currencyInfo } = pluginInfo
|
|
649
|
+
|
|
650
|
+
emitter.emit(_makeEngineEmitter.EngineEvent.TRANSACTIONS_CHANGED, [
|
|
651
|
+
await _ProcessorTransaction.toEdgeTransaction.call(void 0, {
|
|
652
|
+
tx,
|
|
653
|
+
currencyCode: currencyInfo.currencyCode,
|
|
654
|
+
pluginInfo,
|
|
655
|
+
processor,
|
|
656
|
+
walletBlockHeight: walletBlockHeight,
|
|
657
|
+
walletTools
|
|
658
|
+
})
|
|
659
|
+
])
|
|
660
|
+
}; exports.transactionChanged = transactionChanged
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
const pickNextTask = async (
|
|
667
|
+
args
|
|
668
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
669
|
+
) => {
|
|
670
|
+
const { taskCache, uri, serverStates } = args
|
|
671
|
+
|
|
672
|
+
const {
|
|
673
|
+
addressSubscribeCache,
|
|
674
|
+
addressUtxoCache,
|
|
675
|
+
rawUtxoCache,
|
|
676
|
+
processorUtxoCache,
|
|
677
|
+
addressTransactionCache,
|
|
678
|
+
updateTransactionCache
|
|
679
|
+
} = taskCache
|
|
680
|
+
|
|
681
|
+
const serverState = serverStates.getServerState(uri)
|
|
682
|
+
if (serverState == null) return
|
|
683
|
+
|
|
684
|
+
// subscribe all servers to new blocks
|
|
685
|
+
if (serverState.blockSubscriptionStatus === 'unsubscribed') {
|
|
686
|
+
serverStates.watchBlocks(uri)
|
|
687
|
+
return true
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Loop processed utxos, these are just database ops, triggers setLookAhead
|
|
691
|
+
if (Object.keys(processorUtxoCache).length > 0) {
|
|
692
|
+
for (const [scriptPubkey, state] of Object.entries(processorUtxoCache)) {
|
|
693
|
+
// Only process when all utxos for a specific address have been gathered
|
|
694
|
+
if (!state.processing && state.full) {
|
|
695
|
+
state.processing = true
|
|
696
|
+
await processProcessorUtxos({
|
|
697
|
+
...args,
|
|
698
|
+
scriptPubkey,
|
|
699
|
+
utxos: state.utxos,
|
|
700
|
+
path: state.path
|
|
701
|
+
})
|
|
702
|
+
_utils.removeItem.call(void 0, processorUtxoCache, scriptPubkey)
|
|
703
|
+
return true
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const blockHeight = serverStates.getBlockHeight(uri)
|
|
709
|
+
|
|
710
|
+
// Loop unparsed utxos, some require a network call to get the full tx data
|
|
711
|
+
for (const [utxoString, state] of Object.entries(rawUtxoCache)) {
|
|
712
|
+
const utxo = JSON.parse(utxoString)
|
|
713
|
+
if (utxo == null) continue
|
|
714
|
+
if (!state.processing) {
|
|
715
|
+
// check if we need to fetch additional network content for legacy purpose type
|
|
716
|
+
const purposeType = _utils3.currencyFormatToPurposeType.call(void 0, state.path.format)
|
|
717
|
+
if (
|
|
718
|
+
purposeType === _keymanager.BIP43PurposeTypeEnum.Airbitz ||
|
|
719
|
+
purposeType === _keymanager.BIP43PurposeTypeEnum.Legacy
|
|
720
|
+
) {
|
|
721
|
+
// if we do need to make a network call, check with the serverState
|
|
722
|
+
if (!serverStates.serverCanGetTx(uri, utxo.txid)) return
|
|
723
|
+
}
|
|
724
|
+
state.processing = true
|
|
725
|
+
_utils.removeItem.call(void 0, rawUtxoCache, utxoString)
|
|
726
|
+
const wsTask = await processRawUtxo({
|
|
727
|
+
...args,
|
|
728
|
+
...state,
|
|
729
|
+
utxo,
|
|
730
|
+
id: `${utxo.txid}_${utxo.vout}`
|
|
731
|
+
})
|
|
732
|
+
return _nullishCoalesce(wsTask, () => ( true))
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// Loop to process addresses to utxos
|
|
737
|
+
for (const [address, state] of Object.entries(addressUtxoCache)) {
|
|
738
|
+
// Check if we need to fetch address UTXOs
|
|
739
|
+
if (!state.processing && serverStates.serverCanGetAddress(uri, address)) {
|
|
740
|
+
state.processing = true
|
|
741
|
+
|
|
742
|
+
_utils.removeItem.call(void 0, addressUtxoCache, address)
|
|
743
|
+
|
|
744
|
+
// Fetch and process address UTXOs
|
|
745
|
+
const wsTask = await processAddressUtxos({
|
|
746
|
+
...args,
|
|
747
|
+
...state,
|
|
748
|
+
address
|
|
749
|
+
})
|
|
750
|
+
wsTask.deferred.promise
|
|
751
|
+
.then(() => {
|
|
752
|
+
serverState.addresses.add(address)
|
|
753
|
+
})
|
|
754
|
+
.catch(e => {
|
|
755
|
+
throw e
|
|
756
|
+
})
|
|
757
|
+
return wsTask
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Check if there are any addresses pending to be subscribed
|
|
762
|
+
if (
|
|
763
|
+
Object.keys(addressSubscribeCache).length > 0 &&
|
|
764
|
+
!taskCache.addressWatching
|
|
765
|
+
) {
|
|
766
|
+
// Loop each address that needs to be subscribed
|
|
767
|
+
for (const [address, state] of Object.entries(addressSubscribeCache)) {
|
|
768
|
+
// Add address in the cache to the set of addresses to watch
|
|
769
|
+
const { path, processing: subscribed } = state
|
|
770
|
+
// only process newly watched addresses
|
|
771
|
+
if (subscribed) continue
|
|
772
|
+
if (path != null) {
|
|
773
|
+
// Add the newly watched addresses to the UTXO cache
|
|
774
|
+
addressUtxoCache[address] = {
|
|
775
|
+
processing: false,
|
|
776
|
+
path
|
|
777
|
+
}
|
|
778
|
+
await addToAddressTransactionCache(
|
|
779
|
+
args,
|
|
780
|
+
address,
|
|
781
|
+
path.format,
|
|
782
|
+
path.changeIndex,
|
|
783
|
+
blockHeight,
|
|
784
|
+
addressTransactionCache
|
|
785
|
+
)
|
|
786
|
+
}
|
|
787
|
+
state.processing = true
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
taskCache.addressWatching = true
|
|
791
|
+
|
|
792
|
+
const queryTime = Date.now()
|
|
793
|
+
const deferred = new _Deferred2.default()
|
|
794
|
+
deferred.promise
|
|
795
|
+
.then(() => {
|
|
796
|
+
serverStates.serverScoreUp(uri, Date.now() - queryTime)
|
|
797
|
+
})
|
|
798
|
+
.catch(() => {
|
|
799
|
+
taskCache.addressWatching = false
|
|
800
|
+
})
|
|
801
|
+
deferred.promise.catch(() => {
|
|
802
|
+
taskCache.addressWatching = false
|
|
803
|
+
})
|
|
804
|
+
serverStates.watchAddresses(
|
|
805
|
+
uri,
|
|
806
|
+
Array.from(Object.keys(addressSubscribeCache)),
|
|
807
|
+
deferred
|
|
808
|
+
)
|
|
809
|
+
return true
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// filled when transactions potentially changed (e.g. through new block notification)
|
|
813
|
+
if (Object.keys(updateTransactionCache).length > 0) {
|
|
814
|
+
let hasProcessedAtLeastOnce = false
|
|
815
|
+
for (const [txId, state] of Object.entries(updateTransactionCache)) {
|
|
816
|
+
if (!state.processing && serverStates.serverCanGetTx(uri, txId)) {
|
|
817
|
+
hasProcessedAtLeastOnce = true
|
|
818
|
+
state.processing = true
|
|
819
|
+
_utils.removeItem.call(void 0, updateTransactionCache, txId)
|
|
820
|
+
const updateTransactionTask = updateTransactions({
|
|
821
|
+
...args,
|
|
822
|
+
walletBlockHeight: blockHeight,
|
|
823
|
+
txId
|
|
824
|
+
})
|
|
825
|
+
// once resolved, add the txid to the server cache
|
|
826
|
+
updateTransactionTask.deferred.promise
|
|
827
|
+
.then(() => {
|
|
828
|
+
serverState.txids.add(txId)
|
|
829
|
+
})
|
|
830
|
+
.catch(e => {
|
|
831
|
+
throw e
|
|
832
|
+
})
|
|
833
|
+
return updateTransactionTask
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
// This condition prevents infinite loops
|
|
837
|
+
if (hasProcessedAtLeastOnce) return true
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// loop to get and process transaction history of single addresses, triggers setLookAhead
|
|
841
|
+
for (const [address, state] of Object.entries(addressTransactionCache)) {
|
|
842
|
+
if (!state.processing && serverStates.serverCanGetAddress(uri, address)) {
|
|
843
|
+
state.processing = true
|
|
844
|
+
|
|
845
|
+
_utils.removeItem.call(void 0, addressTransactionCache, address)
|
|
846
|
+
|
|
847
|
+
// Fetch and process address UTXOs
|
|
848
|
+
const wsTask = await processAddressTransactions({
|
|
849
|
+
...args,
|
|
850
|
+
...state,
|
|
851
|
+
address
|
|
852
|
+
})
|
|
853
|
+
wsTask.deferred.promise
|
|
854
|
+
.then(() => {
|
|
855
|
+
serverState.addresses.add(address)
|
|
856
|
+
})
|
|
857
|
+
.catch(e => {
|
|
858
|
+
throw e
|
|
859
|
+
})
|
|
860
|
+
return wsTask
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}; exports.pickNextTask = pickNextTask
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
const updateTransactions = (
|
|
871
|
+
args
|
|
872
|
+
) => {
|
|
873
|
+
const {
|
|
874
|
+
walletBlockHeight,
|
|
875
|
+
emitter,
|
|
876
|
+
walletTools,
|
|
877
|
+
txId,
|
|
878
|
+
pluginInfo,
|
|
879
|
+
processor,
|
|
880
|
+
taskCache
|
|
881
|
+
} = args
|
|
882
|
+
const deferred = new _Deferred2.default()
|
|
883
|
+
deferred.promise
|
|
884
|
+
.then(async (txResponse) => {
|
|
885
|
+
// check if raw tx is still not confirmed, if so, don't change anything
|
|
886
|
+
if (txResponse.blockHeight < 1) return
|
|
887
|
+
// Create new tx from raw tx
|
|
888
|
+
const tx = processTransactionResponse({
|
|
889
|
+
...args,
|
|
890
|
+
txResponse
|
|
891
|
+
})
|
|
892
|
+
// Remove any existing input utxos from the processor
|
|
893
|
+
for (const input of tx.inputs) {
|
|
894
|
+
await processor.removeUtxos([`${input.txId}_${input.outputIndex}`])
|
|
895
|
+
}
|
|
896
|
+
// Update output utxos's blockHeight any existing input utxos from the processor
|
|
897
|
+
const utxoIds = tx.outputs.map(output => `${tx.txid}_${output.n}`)
|
|
898
|
+
const utxos = await processor.fetchUtxos({
|
|
899
|
+
utxoIds
|
|
900
|
+
})
|
|
901
|
+
for (const utxo of utxos) {
|
|
902
|
+
if (utxo == null) continue
|
|
903
|
+
utxo.blockHeight = tx.blockHeight
|
|
904
|
+
await processor.saveUtxo(utxo)
|
|
905
|
+
}
|
|
906
|
+
// Process and save new tx
|
|
907
|
+
const processedTx = await processor.saveTransaction({
|
|
908
|
+
tx
|
|
909
|
+
})
|
|
910
|
+
await exports.transactionChanged.call(void 0, {
|
|
911
|
+
emitter,
|
|
912
|
+
processor,
|
|
913
|
+
pluginInfo,
|
|
914
|
+
tx: processedTx,
|
|
915
|
+
walletBlockHeight,
|
|
916
|
+
walletTools
|
|
917
|
+
})
|
|
918
|
+
})
|
|
919
|
+
.catch(() => {
|
|
920
|
+
taskCache.updateTransactionCache[txId] = { processing: false }
|
|
921
|
+
})
|
|
922
|
+
return {
|
|
923
|
+
..._BlockBookAPI.transactionMessage.call(void 0, txId),
|
|
924
|
+
deferred
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
|
|
943
|
+
const internalDeriveScriptAddress = async ({
|
|
944
|
+
walletTools,
|
|
945
|
+
engineInfo,
|
|
946
|
+
processor,
|
|
947
|
+
format,
|
|
948
|
+
taskCache,
|
|
949
|
+
script
|
|
950
|
+
}) => {
|
|
951
|
+
if (engineInfo.scriptTemplates == null) {
|
|
952
|
+
throw new Error(
|
|
953
|
+
`cannot derive script address ${script} without defined script template`
|
|
954
|
+
)
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
const scriptTemplate = engineInfo.scriptTemplates[script]
|
|
958
|
+
|
|
959
|
+
const path = {
|
|
960
|
+
format,
|
|
961
|
+
changeIndex: _keymanager.derivationLevelScriptHash.call(void 0, scriptTemplate),
|
|
962
|
+
addressIndex: 0
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// save the address to the processor and add it to the cache
|
|
966
|
+
const { address, scriptPubkey, redeemScript } = walletTools.getScriptAddress({
|
|
967
|
+
path,
|
|
968
|
+
scriptTemplate
|
|
969
|
+
})
|
|
970
|
+
await processor.saveAddress(
|
|
971
|
+
_types5.makeIAddress.call(void 0, { scriptPubkey, redeemScript, path })
|
|
972
|
+
)
|
|
973
|
+
const addresses = new Set()
|
|
974
|
+
addresses.add(address)
|
|
975
|
+
addToAddressSubscribeCache(taskCache, addresses, {
|
|
976
|
+
format: path.format,
|
|
977
|
+
changeIndex: path.changeIndex
|
|
978
|
+
})
|
|
979
|
+
return { address, scriptPubkey, redeemScript }
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
const internalGetFreshAddress = async (
|
|
990
|
+
args
|
|
991
|
+
) => {
|
|
992
|
+
const { format, changeIndex: branch, walletTools, processor } = args
|
|
993
|
+
|
|
994
|
+
const numAddresses = processor.numAddressesByFormatPath({
|
|
995
|
+
format,
|
|
996
|
+
changeIndex: branch
|
|
997
|
+
})
|
|
998
|
+
|
|
999
|
+
const path = {
|
|
1000
|
+
format,
|
|
1001
|
+
changeIndex: branch,
|
|
1002
|
+
// while syncing, we may hit negative numbers when only subtracting. Use the address at /0 in that case.
|
|
1003
|
+
addressIndex: Math.max(
|
|
1004
|
+
numAddresses - args.pluginInfo.engineInfo.gapLimit,
|
|
1005
|
+
0
|
|
1006
|
+
)
|
|
1007
|
+
}
|
|
1008
|
+
const { scriptPubkey } =
|
|
1009
|
+
await _asyncNullishCoalesce((await processor.fetchAddress(path)), async () => (
|
|
1010
|
+
(await walletTools.getScriptPubkey(path))))
|
|
1011
|
+
if (scriptPubkey == null) {
|
|
1012
|
+
throw new Error('Unknown address path')
|
|
1013
|
+
}
|
|
1014
|
+
return walletTools.scriptPubkeyToAddress({
|
|
1015
|
+
scriptPubkey,
|
|
1016
|
+
format
|
|
1017
|
+
})
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
|
|
1021
|
+
|
|
1022
|
+
|
|
1023
|
+
|
|
1024
|
+
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
|
|
1029
|
+
const processAddressTransactions = async (
|
|
1030
|
+
args
|
|
1031
|
+
) => {
|
|
1032
|
+
const {
|
|
1033
|
+
address,
|
|
1034
|
+
page = 1,
|
|
1035
|
+
blockHeight: walletBlockHeight,
|
|
1036
|
+
emitter,
|
|
1037
|
+
pluginInfo,
|
|
1038
|
+
processor,
|
|
1039
|
+
walletTools,
|
|
1040
|
+
path,
|
|
1041
|
+
taskCache,
|
|
1042
|
+
serverStates,
|
|
1043
|
+
uri
|
|
1044
|
+
} = args
|
|
1045
|
+
const {
|
|
1046
|
+
engineInfo: { asBlockbookAddress }
|
|
1047
|
+
} = pluginInfo
|
|
1048
|
+
const addressTransactionCache = taskCache.addressTransactionCache
|
|
1049
|
+
|
|
1050
|
+
const scriptPubkey = walletTools.addressToScriptPubkey(address)
|
|
1051
|
+
const addressData = await processor.fetchAddress(scriptPubkey)
|
|
1052
|
+
if (addressData == null) {
|
|
1053
|
+
throw new Error(`could not find address with script pubkey ${scriptPubkey}`)
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
const queryTime = Date.now()
|
|
1057
|
+
const deferred = new _Deferred2.default()
|
|
1058
|
+
deferred.promise
|
|
1059
|
+
.then(async (value) => {
|
|
1060
|
+
serverStates.serverScoreUp(uri, Date.now() - queryTime)
|
|
1061
|
+
const { transactions = [], txs, unconfirmedTxs, totalPages } = value
|
|
1062
|
+
|
|
1063
|
+
// If address is used and previously not marked as used, mark as used.
|
|
1064
|
+
const used = txs > 0 || unconfirmedTxs > 0
|
|
1065
|
+
if (!addressData.used && used && page === 1) {
|
|
1066
|
+
addressData.used = true
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
// Process and save the address's transactions
|
|
1070
|
+
for (const txResponse of transactions) {
|
|
1071
|
+
const tx = processTransactionResponse({
|
|
1072
|
+
...args,
|
|
1073
|
+
txResponse
|
|
1074
|
+
})
|
|
1075
|
+
const processedTx = await processor.saveTransaction({
|
|
1076
|
+
tx,
|
|
1077
|
+
scriptPubkeys: [scriptPubkey]
|
|
1078
|
+
})
|
|
1079
|
+
await exports.transactionChanged.call(void 0, {
|
|
1080
|
+
emitter,
|
|
1081
|
+
processor,
|
|
1082
|
+
pluginInfo,
|
|
1083
|
+
tx: processedTx,
|
|
1084
|
+
walletBlockHeight,
|
|
1085
|
+
walletTools
|
|
1086
|
+
})
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
// Halt on finishing the processing of address transaction until
|
|
1090
|
+
// we have progressed through all of the blockbook pages
|
|
1091
|
+
if (page < totalPages) {
|
|
1092
|
+
// Add the address back to the cache, incrementing the page
|
|
1093
|
+
addressTransactionCache[address] = {
|
|
1094
|
+
path,
|
|
1095
|
+
processing: false,
|
|
1096
|
+
blockHeight: walletBlockHeight,
|
|
1097
|
+
page: page + 1
|
|
1098
|
+
}
|
|
1099
|
+
return
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
// Update the lastQueriedBlockHeight for the address
|
|
1103
|
+
addressData.lastQueriedBlockHeight = walletBlockHeight
|
|
1104
|
+
|
|
1105
|
+
// Save/update the fully-processed address
|
|
1106
|
+
await processor.saveAddress(addressData)
|
|
1107
|
+
|
|
1108
|
+
// Update the progress now that the transactions for an address have processed
|
|
1109
|
+
await args.updateProgressRatio()
|
|
1110
|
+
|
|
1111
|
+
// Call setLookAhead to update the lookahead
|
|
1112
|
+
await setLookAhead(args)
|
|
1113
|
+
})
|
|
1114
|
+
.catch(err => {
|
|
1115
|
+
// Log the error for debugging purposes without crashing the engine
|
|
1116
|
+
// This will cause frozen wallet syncs
|
|
1117
|
+
console.error(err.toString())
|
|
1118
|
+
console.log(err.stack)
|
|
1119
|
+
})
|
|
1120
|
+
|
|
1121
|
+
return {
|
|
1122
|
+
..._BlockBookAPI.addressMessage.call(void 0, address, asBlockbookAddress, {
|
|
1123
|
+
details: 'txs',
|
|
1124
|
+
from: addressData.lastQueriedBlockHeight,
|
|
1125
|
+
pageSize: _constants.BLOCKBOOK_TXS_PER_PAGE,
|
|
1126
|
+
page
|
|
1127
|
+
}),
|
|
1128
|
+
deferred
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
const processTransactionResponse = (
|
|
1137
|
+
args
|
|
1138
|
+
) => {
|
|
1139
|
+
const { txResponse, pluginInfo } = args
|
|
1140
|
+
const { coinInfo } = pluginInfo
|
|
1141
|
+
|
|
1142
|
+
return {
|
|
1143
|
+
txid: txResponse.txid,
|
|
1144
|
+
hex: txResponse.hex,
|
|
1145
|
+
// Blockbook can return a blockHeight of -1 when the tx is pending in the mempool
|
|
1146
|
+
blockHeight: txResponse.blockHeight > 0 ? txResponse.blockHeight : 0,
|
|
1147
|
+
date: txResponse.blockTime,
|
|
1148
|
+
fees: txResponse.fees,
|
|
1149
|
+
inputs: txResponse.vin.map(input => ({
|
|
1150
|
+
txId: input.txid,
|
|
1151
|
+
outputIndex: input.vout, // case for tx `fefac8c22ba1178df5d7c90b78cc1c203d1a9f5f5506f7b8f6f469fa821c2674` no `vout` for input
|
|
1152
|
+
n: input.n,
|
|
1153
|
+
scriptPubkey: _utils3.validScriptPubkeyFromAddress.call(void 0, {
|
|
1154
|
+
address: input.addresses[0],
|
|
1155
|
+
coin: coinInfo.name
|
|
1156
|
+
}),
|
|
1157
|
+
amount: input.value
|
|
1158
|
+
})),
|
|
1159
|
+
outputs: txResponse.vout.map(output => ({
|
|
1160
|
+
n: output.n,
|
|
1161
|
+
scriptPubkey:
|
|
1162
|
+
_nullishCoalesce(output.hex, () => (
|
|
1163
|
+
_utils3.validScriptPubkeyFromAddress.call(void 0, {
|
|
1164
|
+
address: output.addresses[0],
|
|
1165
|
+
coin: coinInfo.name
|
|
1166
|
+
}))),
|
|
1167
|
+
amount: output.value
|
|
1168
|
+
})),
|
|
1169
|
+
ourIns: [],
|
|
1170
|
+
ourOuts: [],
|
|
1171
|
+
ourAmount: '0'
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
|
|
1176
|
+
|
|
1177
|
+
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
|
|
1181
|
+
|
|
1182
|
+
const processAddressUtxos = async (
|
|
1183
|
+
args
|
|
1184
|
+
) => {
|
|
1185
|
+
const {
|
|
1186
|
+
address,
|
|
1187
|
+
walletTools,
|
|
1188
|
+
processor,
|
|
1189
|
+
taskCache,
|
|
1190
|
+
path,
|
|
1191
|
+
pluginInfo,
|
|
1192
|
+
serverStates,
|
|
1193
|
+
uri
|
|
1194
|
+
} = args
|
|
1195
|
+
const {
|
|
1196
|
+
engineInfo: { asBlockbookAddress }
|
|
1197
|
+
} = pluginInfo
|
|
1198
|
+
const { addressUtxoCache, rawUtxoCache, processorUtxoCache } = taskCache
|
|
1199
|
+
const queryTime = Date.now()
|
|
1200
|
+
const deferred = new _Deferred2.default()
|
|
1201
|
+
deferred.promise
|
|
1202
|
+
.then(async (utxos) => {
|
|
1203
|
+
serverStates.serverScoreUp(uri, Date.now() - queryTime)
|
|
1204
|
+
const scriptPubkey = walletTools.addressToScriptPubkey(address)
|
|
1205
|
+
const addressData = await processor.fetchAddress(scriptPubkey)
|
|
1206
|
+
if (addressData == null || addressData.path == null) {
|
|
1207
|
+
return
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
if (utxos.length === 0) {
|
|
1211
|
+
addToProcessorUtxoCache(processorUtxoCache, path, scriptPubkey, 0)
|
|
1212
|
+
return
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
for (const utxo of utxos) {
|
|
1216
|
+
rawUtxoCache[JSON.stringify(utxo)] = {
|
|
1217
|
+
processing: false,
|
|
1218
|
+
requiredCount: utxos.length,
|
|
1219
|
+
path,
|
|
1220
|
+
// TypeScript yells otherwise
|
|
1221
|
+
address: { ...addressData, path: addressData.path }
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
})
|
|
1225
|
+
.catch(() => {
|
|
1226
|
+
args.processing = false
|
|
1227
|
+
addressUtxoCache[address] = {
|
|
1228
|
+
processing: args.processing,
|
|
1229
|
+
path
|
|
1230
|
+
}
|
|
1231
|
+
})
|
|
1232
|
+
|
|
1233
|
+
return {
|
|
1234
|
+
..._BlockBookAPI.addressUtxosMessage.call(void 0, address, asBlockbookAddress),
|
|
1235
|
+
deferred
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
|
|
1240
|
+
|
|
1241
|
+
|
|
1242
|
+
|
|
1243
|
+
|
|
1244
|
+
|
|
1245
|
+
const processProcessorUtxos = async (
|
|
1246
|
+
args
|
|
1247
|
+
) => {
|
|
1248
|
+
const {
|
|
1249
|
+
utxos,
|
|
1250
|
+
processor,
|
|
1251
|
+
scriptPubkey,
|
|
1252
|
+
log,
|
|
1253
|
+
emitter,
|
|
1254
|
+
pluginInfo: { currencyInfo }
|
|
1255
|
+
} = args
|
|
1256
|
+
|
|
1257
|
+
const currentUtxos = await processor.fetchUtxos({ scriptPubkey })
|
|
1258
|
+
const currentUtxoIds = []
|
|
1259
|
+
let oldBalance = '0'
|
|
1260
|
+
for (const utxo of currentUtxos) {
|
|
1261
|
+
if (utxo == null)
|
|
1262
|
+
throw new Error(
|
|
1263
|
+
'Unexpected undefined utxo when processing unspent transactions'
|
|
1264
|
+
)
|
|
1265
|
+
oldBalance = _biggystring.add.call(void 0, utxo.value, oldBalance)
|
|
1266
|
+
currentUtxoIds.push(utxo.id)
|
|
1267
|
+
}
|
|
1268
|
+
await processor.removeUtxos(currentUtxoIds)
|
|
1269
|
+
|
|
1270
|
+
let newBalance = '0'
|
|
1271
|
+
for (const utxo of Array.from(utxos)) {
|
|
1272
|
+
newBalance = _biggystring.add.call(void 0, utxo.value, newBalance)
|
|
1273
|
+
await processor.saveUtxo(utxo)
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
const diff = _biggystring.sub.call(void 0, newBalance, oldBalance)
|
|
1277
|
+
if (diff !== '0') {
|
|
1278
|
+
log('balance changed:', { scriptPubkey, diff })
|
|
1279
|
+
emitter.emit(
|
|
1280
|
+
_makeEngineEmitter.EngineEvent.ADDRESS_BALANCE_CHANGED,
|
|
1281
|
+
currencyInfo.currencyCode,
|
|
1282
|
+
diff
|
|
1283
|
+
)
|
|
1284
|
+
|
|
1285
|
+
// Update balances for address that have this scriptPubkey
|
|
1286
|
+
const address = await processor.fetchAddress(scriptPubkey)
|
|
1287
|
+
|
|
1288
|
+
if (address == null) {
|
|
1289
|
+
throw new Error('address not found when processing UTXO transactions')
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
await processor.saveAddress({
|
|
1293
|
+
...address,
|
|
1294
|
+
balance: newBalance,
|
|
1295
|
+
used: true
|
|
1296
|
+
})
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// Update the progress now that the UTXOs for an address have been processed
|
|
1300
|
+
await args.updateProgressRatio()
|
|
1301
|
+
|
|
1302
|
+
await setLookAhead(args).catch(err => {
|
|
1303
|
+
log.error(err)
|
|
1304
|
+
throw err
|
|
1305
|
+
})
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
|
|
1309
|
+
|
|
1310
|
+
|
|
1311
|
+
|
|
1312
|
+
|
|
1313
|
+
|
|
1314
|
+
|
|
1315
|
+
|
|
1316
|
+
|
|
1317
|
+
const processRawUtxo = async (
|
|
1318
|
+
args
|
|
1319
|
+
) => {
|
|
1320
|
+
const {
|
|
1321
|
+
utxo,
|
|
1322
|
+
id,
|
|
1323
|
+
address,
|
|
1324
|
+
processor,
|
|
1325
|
+
path,
|
|
1326
|
+
taskCache,
|
|
1327
|
+
requiredCount,
|
|
1328
|
+
serverStates,
|
|
1329
|
+
uri,
|
|
1330
|
+
log
|
|
1331
|
+
} = args
|
|
1332
|
+
const { rawUtxoCache, processorUtxoCache } = taskCache
|
|
1333
|
+
let scriptType
|
|
1334
|
+
let script
|
|
1335
|
+
let redeemScript
|
|
1336
|
+
|
|
1337
|
+
// Function to call once we are finished
|
|
1338
|
+
const done = () =>
|
|
1339
|
+
addToProcessorUtxoCache(
|
|
1340
|
+
processorUtxoCache,
|
|
1341
|
+
path,
|
|
1342
|
+
address.scriptPubkey,
|
|
1343
|
+
requiredCount,
|
|
1344
|
+
{
|
|
1345
|
+
id,
|
|
1346
|
+
txid: utxo.txid,
|
|
1347
|
+
vout: utxo.vout,
|
|
1348
|
+
value: utxo.value,
|
|
1349
|
+
scriptPubkey: address.scriptPubkey,
|
|
1350
|
+
script,
|
|
1351
|
+
redeemScript,
|
|
1352
|
+
scriptType,
|
|
1353
|
+
blockHeight: _nullishCoalesce(utxo.height, () => ( -1)),
|
|
1354
|
+
spent: false
|
|
1355
|
+
}
|
|
1356
|
+
)
|
|
1357
|
+
|
|
1358
|
+
switch (_utils3.currencyFormatToPurposeType.call(void 0, path.format)) {
|
|
1359
|
+
case _keymanager.BIP43PurposeTypeEnum.Airbitz:
|
|
1360
|
+
case _keymanager.BIP43PurposeTypeEnum.Legacy:
|
|
1361
|
+
scriptType = _keymanager.ScriptTypeEnum.p2pkh
|
|
1362
|
+
if (address.redeemScript != null) {
|
|
1363
|
+
scriptType = _keymanager.ScriptTypeEnum.p2sh
|
|
1364
|
+
redeemScript = address.redeemScript
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
// Legacy UTXOs need the previous transaction hex as the script
|
|
1368
|
+
// If we do not currently have it, add it to the queue to fetch it
|
|
1369
|
+
{
|
|
1370
|
+
const [tx] = await processor.fetchTransactions({ txId: utxo.txid })
|
|
1371
|
+
if (tx == null) {
|
|
1372
|
+
const queryTime = Date.now()
|
|
1373
|
+
const deferred = new _Deferred2.default()
|
|
1374
|
+
deferred.promise
|
|
1375
|
+
.then((txResponse) => {
|
|
1376
|
+
serverStates.serverScoreUp(uri, Date.now() - queryTime)
|
|
1377
|
+
const processedTx = processTransactionResponse({
|
|
1378
|
+
...args,
|
|
1379
|
+
txResponse
|
|
1380
|
+
})
|
|
1381
|
+
script = processedTx.hex
|
|
1382
|
+
// Only after we have successfully fetched the tx, set our script and call done
|
|
1383
|
+
done()
|
|
1384
|
+
})
|
|
1385
|
+
.catch(e => {
|
|
1386
|
+
// If something went wrong, add the UTXO back to the queue
|
|
1387
|
+
log('error in processed utxos cache, re-adding utxo to cache:', e)
|
|
1388
|
+
rawUtxoCache[JSON.stringify(utxo)] = {
|
|
1389
|
+
processing: false,
|
|
1390
|
+
path,
|
|
1391
|
+
address,
|
|
1392
|
+
requiredCount
|
|
1393
|
+
}
|
|
1394
|
+
})
|
|
1395
|
+
return {
|
|
1396
|
+
..._BlockBookAPI.transactionMessage.call(void 0, utxo.txid),
|
|
1397
|
+
deferred
|
|
1398
|
+
}
|
|
1399
|
+
} else {
|
|
1400
|
+
script = tx.hex
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
break
|
|
1405
|
+
case _keymanager.BIP43PurposeTypeEnum.WrappedSegwit:
|
|
1406
|
+
scriptType = _keymanager.ScriptTypeEnum.p2wpkhp2sh
|
|
1407
|
+
script = address.scriptPubkey
|
|
1408
|
+
if (address.redeemScript == null) {
|
|
1409
|
+
throw new Error(
|
|
1410
|
+
'Address redeem script not defined, but required for p2sh wrapped segwit utxo processing'
|
|
1411
|
+
)
|
|
1412
|
+
}
|
|
1413
|
+
redeemScript = address.redeemScript
|
|
1414
|
+
|
|
1415
|
+
break
|
|
1416
|
+
case _keymanager.BIP43PurposeTypeEnum.Segwit:
|
|
1417
|
+
scriptType = _keymanager.ScriptTypeEnum.p2wpkh
|
|
1418
|
+
script = address.scriptPubkey
|
|
1419
|
+
|
|
1420
|
+
break
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
// Since we have everything, call done
|
|
1424
|
+
done()
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
const addToProcessorUtxoCache = (
|
|
1428
|
+
processorUtxosCache,
|
|
1429
|
+
path,
|
|
1430
|
+
scriptPubkey,
|
|
1431
|
+
requiredCount,
|
|
1432
|
+
utxo
|
|
1433
|
+
) => {
|
|
1434
|
+
const processorUtxos = _nullishCoalesce(processorUtxosCache[scriptPubkey], () => ( {
|
|
1435
|
+
utxos: new Set(),
|
|
1436
|
+
processing: false,
|
|
1437
|
+
path,
|
|
1438
|
+
full: false
|
|
1439
|
+
}))
|
|
1440
|
+
if (utxo != null) processorUtxos.utxos.add(utxo)
|
|
1441
|
+
processorUtxosCache[scriptPubkey] = processorUtxos
|
|
1442
|
+
processorUtxos.full = processorUtxos.utxos.size >= requiredCount
|
|
1443
|
+
}
|