perferendisdistinctio
Version:
Scoop Core Wallet: dual-signature timelock Bitcoin wallet - multi-asset, cross-platform and open-source
203 lines (177 loc) • 11.8 kB
JavaScript
// Distributed under AGPLv3 license: see /LICENSE for terms. Copyright 2019-2023 Dominic Morris.
const configExternal = require('../config/wallet-external')
const workerAddrMemPool = require('./worker-blockbook-mempool')
const utilsWallet = require('../utils')
module.exports = {
// setup/teardown address monitoring
addressMonitors_Sub_Unsub: (wallet, sub) => {
if (wallet && wallet.assets) {
if (sub) { // subscribe
for (const asset of wallet.assets) {
if (asset.symbol === 'EOS') {
; // todo
}
else if (utilsWallet.isERC20(asset)) {
; // nop - we get through eth addr-monitor
}
else {
if (asset.use_BBv3 || asset.symbol === 'ETH' || asset.symbol === 'ETH_TEST') {
subAddr_Blockbook(wallet, asset)
}
else {
subAddr_Insight(asset)
}
}
}
}
else { // unsubscribe
for (const asset of wallet.assets) {
if (asset.symbol === 'EOS') {
; // todo
}
else if (utilsWallet.isERC20(asset)) {
; // nop
}
else {
if (asset.use_BBv3 || asset.symbol === 'ETH' || asset.symbol === 'ETH_TEST') {
unsubAddr_Blockbook(asset.symbol)
}
else {
unsubAddr_Insight(asset.symbol)
}
}
}
}
}
},
}
function subAddr_Blockbook(wallet, asset) {
const ownAddresses = asset.addresses.map(p => { return p.addr })
//var socket = worker.get_BlockbookSocketIo(asset)
var socket = self.get_BlockbookSocketIo(asset)
if (socket === undefined) { utilsWallet.warn(`appWorker >> ${self.workerId} subAddr_Blockbook ${asset.symbol}: no socket setup!`); return }
try {
// subscribe addr monitor
socket.emit('subscribe', "bitcoind/addresstxid", ownAddresses, (result) => {})
////utilsWallet.debug(`appWorker >> ${self.workerId} subAddr_Blockbook ${asset.symbol}, ownAddresses=`, ownAddresses.join(','), { logServerConsole: true })
// callback
socket.on("bitcoind/addresstxid", function (data) {
if (data && data.txid) {
const txid = data.txid
//const addr = data.address
if (!self.blockbook_OwnAddrTxIds[asset.symbol]) self.blockbook_OwnAddrTxIds[asset.symbol] = []
if (self.blockbook_OwnAddrTxIds[asset.symbol].some(p => { return p === txid })) {
utilsWallet.log(`appWorker >> ${self.workerId} *** subAddr_Blockbook - new TX - ${asset.symbol} *** - ignoring: already processed this txid - data=`, data)
}
else {
self.blockbook_OwnAddrTxIds[asset.symbol].push(txid)
if (asset.symbol === 'ETH' || asset.symbol === 'ETH_TEST') {
//utilsWallet.log('DBG1 - got addr-monitor callback, txid=', txid)
//utilsWallet.log(`appWorker >> ${self.workerId} bitcoind/addresstxid ETH data - requesting ASSET_REFRESH_ADDR_MONITOR`)
//postMessage({ msg: 'REQUEST_STATE', status: 'REQ', data: { stateItem: 'ASSET', stateKey: asset.symbol, context: 'ASSET_REFRESH_ADDR_MONITOR' } })
// as below for SW; BB mempool is simply not reliably in sync with its bitcoind/addresstxid callbacks
// so, we query web3 directly for the txid and process with mempool_process_BB_EthTx();
// double and tripple checked: the BB mempool is definitely lagging, i.e. we get bitcoind/addresstxid notifications
// but BB *doesn't* report the tx in its mempool (sometimes it does, sometimes it doesn't until the next block) -- this lines up
// with its status page intermitently reporting mempool is not in sync for ETH
utilsWallet.logMajor('green','white', `appWorker >> ${self.workerId} bitcoind/addresstxid data - ${asset.symbol} - web3 getTx... txid=`, txid, { logServerConsole: true })
const web3 = self.web3_Sockets[asset.symbol] // socket instance
if (!web3) {
utilsWallet.error(`appWorker >> ${self.workerId} subAddr_Blockbook - ${asset.symbol} - web3 socket provider is not available!`); return
}
else {
web3.eth.getTransaction(txid)
.then((tx) => {
const erc20s = Object.keys(configExternal.erc20Contracts).map(p => { return { erc20_addr: configExternal.erc20Contracts[p], symbol: p } })
const erc20 = erc20s.find(p => { return p.erc20_addr.toLowerCase() === tx.to.toLowerCase() })
const weAreSender = ownAddresses.some(ownAddr => ownAddr.toLowerCase() === tx.from.toLowerCase())
workerAddrMemPool.mempool_process_BB_EthTx(web3, wallet, asset, txid, tx, weAreSender, erc20)
})
}
utilsWallet.log(`appWorker >> ${self.workerId} bitcoind/addresstxid ETH data - requesting ASSET_REFRESH_ADDR_MONITOR`)
postMessage({ msg: 'REQUEST_STATE', status: 'REQ', data: { stateItem: 'ASSET', stateKey: asset.symbol, context: 'ASSET_REFRESH_ADDR_MONITOR' } })
}
else {
utilsWallet.logMajor('green','white', `appWorker >> ${self.workerId} bitcoind/addresstxid data - ${asset.symbol} - BB getDetailedTransaction... txid=`, txid, { logServerConsole: true })
// trigger refresh: we will walk the mempool utxo list and record the mempool tx in local_txs[]
// DMS - reverting to this path, (deprecate mempool_process_BB_UtxoTx)
utilsWallet.log(`appWorker >> ${self.workerId} bitcoind/addresstxid UTXO data - requesting ASSET_REFRESH_ADDR_MONITOR`)
postMessage({ msg: 'REQUEST_STATE', status: 'REQ', data: { stateItem: 'ASSET', stateKey: asset.symbol, context: 'ASSET_REFRESH_ADDR_MONITOR' } })
// query blockbook for full tx details (see https://btc1.trezor.io/static/test.html for full blockbook socket interface)
// socket.send({ method: 'getDetailedTransaction', params: [txid] }, (bb_txData) => {
// //utilsWallet.log('bb_txData', bb_txData) // DMS: bb_txData contains UTXO data... we sould put into local_tx's
// if (bb_txData && bb_txData.result) {
// // this works much more reliably, i.e. writing the local_tx directly instead of
// // requesting a full asset refresh and requiring its mempool read to pick up the tx
// // const tx = bb_txData.result
// // const ownAddresses = asset.addresses.map(p => { return p.addr })
// // const weAreSender = tx.inputs.some(p => { return ownAddresses.some(p2 => p2 === p.address) })
// // const mempool_spent_txids = []
// // workerAddrMemPool.mempool_process_BB_UtxoTx(wallet, asset, txid, tx, weAreSender, ownAddresses, mempool_spent_txids)
// }
// })
}
}
}
})
}
catch (err) {
utilsWallet.error(`### appWorker >> ${self.workerId} subAddr_Blockbook ${asset.symbol}, err=`, err)
utilsWallet.trace()
}
}
// insight addr sub's -- we are sharing the insight sockets used for block and pending tx polling
function subAddr_Insight(asset) {
//utilsWallet.debug(`appWorker >> ${self.workerId} subAddr_Insight ${asset.symbol}...`)
const ownAddresses = asset.addresses.map(p => { return p.addr })
var socket = self.insightSocketIos[asset.symbol]
if (socket === undefined) { utilsWallet.warn(`appWorker >> ${self.workerId} subAddr_Insight ${asset.symbol}: no socket setup!`); return }
try {
// subscribe address mintor
socket.emit('subscribe', 'bitcoind/addresstxid', ownAddresses)
utilsWallet.log(`appWorker >> ${self.workerId} subAddr_Insight ${asset.symbol}, ownAddresses=`, ownAddresses.join(','), { logServerConsole: true })
// callback
socket.on('bitcoind/addresstxid', function (data) {
if (data && data.txid) {
const txid = data.txid
//const addr = data.address
if (!self.insight_OwnAddrTxIds[asset.symbol]) self.insight_OwnAddrTxIds[asset.symbol] = []
if (self.insight_OwnAddrTxIds[asset.symbol].some(p => { return p === txid })) {
utilsWallet.warn(`appWorker >> ${self.workerId} *** subscribe_InsightSocket - new TX - ${asset.symbol} *** - ignoring: already processed this txid - data=`, data)
}
else {
utilsWallet.logMajor('green','white', `appWorker >> ${self.workerId} bitcoind/addresstxid data - ${asset.symbol} - insightApi.txid=`, data.txid, { logServerConsole: true })
self.insight_OwnAddrTxIds[asset.symbol].push(txid)
utilsWallet.log(`appWorker >> ${self.workerId} *** subscribe_InsightSocket - new TX - ${asset.symbol} *** data=`, data)
postMessage({ msg: 'REQUEST_STATE', status: 'REQ', data: { stateItem: 'ASSET', stateKey: asset.symbol, context: 'ASSET_REFRESH_ADDR_MONITOR' } })
}
}
})
}
catch (err) {
utilsWallet.error(`### appWorker >> ${self.workerId} subAddr_Insight ${asset.symbol}, err=`, err)
utilsWallet.trace()
}
}
function unsubAddr_Blockbook(assetSymbol) {
////utilsWallet.debug(`appWorker >> ${self.workerId} unsubAddr_Blockbook ${assetSymbol}...`)
var socket = self.blockbookSocketIos[assetSymbol]
if (socket === undefined) { utilsWallet.warn(`appWorker >> ${self.workerId} unsubAddr_Blockbook ${assetSymbol}: no socket setup!`); return }
else {
try {
socket.removeAllListeners("bitcoind/addresstxid")
}
catch (err) { utilsWallet.error(`### appWorker >> ${self.workerId} unsubAddr_Blockbook ${assetSymbol}, err=`, err) }
}
}
function unsubAddr_Insight(assetSymbol) {
//utilsWallet.debug(`appWorker >> ${self.workerId} unsubAddr_Insight ${assetSymbol}...`)
var socket = self.insightSocketIos[assetSymbol]
if (socket === undefined) { utilsWallet.warn(`appWorker >> ${self.workerId} unsubAddr_Insight ${assetSymbol}: no socket setup!`); return }
else {
try {
socket.emit('unsubscribe', 'bitcoind/addresstxid')
}
catch (err) { utilsWallet.error(`### appWorker >> ${self.workerId} unsubAddr_Insight ${assetSymbol}, err=`, err) }
}
}