Merge pull request #4095 from mempool/mononaut/refactor-address-tracking
Refactor websocket address tracking
This commit is contained in:
commit
41eecfa7df
@ -198,18 +198,14 @@ class WebsocketHandler {
|
|||||||
matchedAddress = matchedAddress.toLowerCase();
|
matchedAddress = matchedAddress.toLowerCase();
|
||||||
}
|
}
|
||||||
if (/^04[a-fA-F0-9]{128}$/.test(parsedMessage['track-address'])) {
|
if (/^04[a-fA-F0-9]{128}$/.test(parsedMessage['track-address'])) {
|
||||||
client['track-address'] = null;
|
client['track-address'] = '41' + matchedAddress + 'ac';
|
||||||
client['track-scriptpubkey'] = '41' + matchedAddress + 'ac';
|
} else if (/^(02|03)[a-fA-F0-9]{64}$/.test(parsedMessage['track-address'])) {
|
||||||
} else if (/^|(02|03)[a-fA-F0-9]{64}$/.test(parsedMessage['track-address'])) {
|
client['track-address'] = '21' + matchedAddress + 'ac';
|
||||||
client['track-address'] = null;
|
|
||||||
client['track-scriptpubkey'] = '21' + matchedAddress + 'ac';
|
|
||||||
} else {
|
} else {
|
||||||
client['track-address'] = matchedAddress;
|
client['track-address'] = matchedAddress;
|
||||||
client['track-scriptpubkey'] = null;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
client['track-address'] = null;
|
client['track-address'] = null;
|
||||||
client['track-scriptpubkey'] = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,6 +484,9 @@ class WebsocketHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pre-compute address transactions
|
||||||
|
const addressCache = this.makeAddressCache(newTransactions);
|
||||||
|
|
||||||
this.wss.clients.forEach(async (client) => {
|
this.wss.clients.forEach(async (client) => {
|
||||||
if (client.readyState !== WebSocket.OPEN) {
|
if (client.readyState !== WebSocket.OPEN) {
|
||||||
return;
|
return;
|
||||||
@ -527,78 +526,13 @@ class WebsocketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (client['track-address']) {
|
if (client['track-address']) {
|
||||||
const foundTransactions: TransactionExtended[] = [];
|
const foundTransactions = Array.from(addressCache[client['track-address']]?.values() || []);
|
||||||
|
// txs may be missing prevouts in non-esplora backends
|
||||||
|
// so fetch the full transactions now
|
||||||
|
const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(foundTransactions) : foundTransactions;
|
||||||
|
|
||||||
for (const tx of newTransactions) {
|
if (fullTransactions.length) {
|
||||||
const someVin = tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_address === client['track-address']);
|
response['address-transactions'] = JSON.stringify(fullTransactions);
|
||||||
if (someVin) {
|
|
||||||
if (config.MEMPOOL.BACKEND !== 'esplora') {
|
|
||||||
try {
|
|
||||||
const fullTx = await transactionUtils.$getMempoolTransactionExtended(tx.txid, true);
|
|
||||||
foundTransactions.push(fullTx);
|
|
||||||
} catch (e) {
|
|
||||||
logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foundTransactions.push(tx);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const someVout = tx.vout.some((vout) => vout.scriptpubkey_address === client['track-address']);
|
|
||||||
if (someVout) {
|
|
||||||
if (config.MEMPOOL.BACKEND !== 'esplora') {
|
|
||||||
try {
|
|
||||||
const fullTx = await transactionUtils.$getMempoolTransactionExtended(tx.txid, true);
|
|
||||||
foundTransactions.push(fullTx);
|
|
||||||
} catch (e) {
|
|
||||||
logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foundTransactions.push(tx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foundTransactions.length) {
|
|
||||||
response['address-transactions'] = JSON.stringify(foundTransactions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client['track-scriptpubkey']) {
|
|
||||||
const foundTransactions: TransactionExtended[] = [];
|
|
||||||
|
|
||||||
for (const tx of newTransactions) {
|
|
||||||
const someVin = tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_type === 'p2pk' && vin.prevout.scriptpubkey === client['track-scriptpubkey']);
|
|
||||||
if (someVin) {
|
|
||||||
if (config.MEMPOOL.BACKEND !== 'esplora') {
|
|
||||||
try {
|
|
||||||
const fullTx = await transactionUtils.$getMempoolTransactionExtended(tx.txid, true);
|
|
||||||
foundTransactions.push(fullTx);
|
|
||||||
} catch (e) {
|
|
||||||
logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foundTransactions.push(tx);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const someVout = tx.vout.some((vout) => vout.scriptpubkey_type === 'p2pk' && vout.scriptpubkey === client['track-scriptpubkey']);
|
|
||||||
if (someVout) {
|
|
||||||
if (config.MEMPOOL.BACKEND !== 'esplora') {
|
|
||||||
try {
|
|
||||||
const fullTx = await transactionUtils.$getMempoolTransactionExtended(tx.txid, true);
|
|
||||||
foundTransactions.push(fullTx);
|
|
||||||
} catch (e) {
|
|
||||||
logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foundTransactions.push(tx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foundTransactions.length) {
|
|
||||||
response['address-transactions'] = JSON.stringify(foundTransactions);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,7 +540,6 @@ class WebsocketHandler {
|
|||||||
const foundTransactions: TransactionExtended[] = [];
|
const foundTransactions: TransactionExtended[] = [];
|
||||||
|
|
||||||
newTransactions.forEach((tx) => {
|
newTransactions.forEach((tx) => {
|
||||||
|
|
||||||
if (client['track-asset'] === Common.nativeAssetId) {
|
if (client['track-asset'] === Common.nativeAssetId) {
|
||||||
if (tx.vin.some((vin) => !!vin.is_pegin)) {
|
if (tx.vin.some((vin) => !!vin.is_pegin)) {
|
||||||
foundTransactions.push(tx);
|
foundTransactions.push(tx);
|
||||||
@ -805,6 +738,9 @@ class WebsocketHandler {
|
|||||||
const fees = feeApi.getRecommendedFee();
|
const fees = feeApi.getRecommendedFee();
|
||||||
const mempoolInfo = memPool.getMempoolInfo();
|
const mempoolInfo = memPool.getMempoolInfo();
|
||||||
|
|
||||||
|
// pre-compute address transactions
|
||||||
|
const addressCache = this.makeAddressCache(transactions);
|
||||||
|
|
||||||
// update init data
|
// update init data
|
||||||
this.updateSocketDataFields({
|
this.updateSocketDataFields({
|
||||||
'mempoolInfo': mempoolInfo,
|
'mempoolInfo': mempoolInfo,
|
||||||
@ -867,44 +803,7 @@ class WebsocketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (client['track-address']) {
|
if (client['track-address']) {
|
||||||
const foundTransactions: TransactionExtended[] = [];
|
const foundTransactions: TransactionExtended[] = Array.from(addressCache[client['track-address']]?.values() || []);
|
||||||
|
|
||||||
transactions.forEach((tx) => {
|
|
||||||
if (tx.vin && tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_address === client['track-address'])) {
|
|
||||||
foundTransactions.push(tx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (tx.vout && tx.vout.some((vout) => vout.scriptpubkey_address === client['track-address'])) {
|
|
||||||
foundTransactions.push(tx);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (foundTransactions.length) {
|
|
||||||
foundTransactions.forEach((tx) => {
|
|
||||||
tx.status = {
|
|
||||||
confirmed: true,
|
|
||||||
block_height: block.height,
|
|
||||||
block_hash: block.id,
|
|
||||||
block_time: block.timestamp,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
response['block-transactions'] = JSON.stringify(foundTransactions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client['track-scriptpubkey']) {
|
|
||||||
const foundTransactions: TransactionExtended[] = [];
|
|
||||||
|
|
||||||
transactions.forEach((tx) => {
|
|
||||||
if (tx.vin && tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_type === 'p2pk' && vin.prevout.scriptpubkey === client['track-scriptpubkey'])) {
|
|
||||||
foundTransactions.push(tx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (tx.vout && tx.vout.some((vout) => vout.scriptpubkey_type === 'p2pk' && vout.scriptpubkey === client['track-scriptpubkey'])) {
|
|
||||||
foundTransactions.push(tx);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (foundTransactions.length) {
|
if (foundTransactions.length) {
|
||||||
foundTransactions.forEach((tx) => {
|
foundTransactions.forEach((tx) => {
|
||||||
@ -982,6 +881,52 @@ class WebsocketHandler {
|
|||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private makeAddressCache(transactions: MempoolTransactionExtended[]): { [address: string]: Set<MempoolTransactionExtended> } {
|
||||||
|
const addressCache: { [address: string]: Set<MempoolTransactionExtended> } = {};
|
||||||
|
for (const tx of transactions) {
|
||||||
|
for (const vin of tx.vin) {
|
||||||
|
if (vin?.prevout?.scriptpubkey_address) {
|
||||||
|
if (!addressCache[vin.prevout.scriptpubkey_address]) {
|
||||||
|
addressCache[vin.prevout.scriptpubkey_address] = new Set();
|
||||||
|
}
|
||||||
|
addressCache[vin.prevout.scriptpubkey_address].add(tx);
|
||||||
|
}
|
||||||
|
if (vin?.prevout?.scriptpubkey) {
|
||||||
|
if (!addressCache[vin.prevout.scriptpubkey]) {
|
||||||
|
addressCache[vin.prevout.scriptpubkey] = new Set();
|
||||||
|
}
|
||||||
|
addressCache[vin.prevout.scriptpubkey].add(tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const vout of tx.vout) {
|
||||||
|
if (vout?.scriptpubkey_address) {
|
||||||
|
if (!addressCache[vout?.scriptpubkey_address]) {
|
||||||
|
addressCache[vout?.scriptpubkey_address] = new Set();
|
||||||
|
}
|
||||||
|
addressCache[vout?.scriptpubkey_address].add(tx);
|
||||||
|
}
|
||||||
|
if (vout?.scriptpubkey) {
|
||||||
|
if (!addressCache[vout.scriptpubkey]) {
|
||||||
|
addressCache[vout.scriptpubkey] = new Set();
|
||||||
|
}
|
||||||
|
addressCache[vout.scriptpubkey].add(tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addressCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getFullTransactions(transactions: MempoolTransactionExtended[]): Promise<MempoolTransactionExtended[]> {
|
||||||
|
for (let i = 0; i < transactions.length; i++) {
|
||||||
|
try {
|
||||||
|
transactions[i] = await transactionUtils.$getMempoolTransactionExtended(transactions[i].txid, true);
|
||||||
|
} catch (e) {
|
||||||
|
logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return transactions;
|
||||||
|
}
|
||||||
|
|
||||||
private printLogs(): void {
|
private printLogs(): void {
|
||||||
if (this.wss) {
|
if (this.wss) {
|
||||||
const count = this.wss?.clients?.size || 0;
|
const count = this.wss?.clients?.size || 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user