diff --git a/backend/src/api/common.ts b/backend/src/api/common.ts index 751bab5a3..4cd2b0873 100644 --- a/backend/src/api/common.ts +++ b/backend/src/api/common.ts @@ -222,7 +222,25 @@ export class Common { } static getTransactionFlags(tx: TransactionExtended): number { - let flags = 0n; + let flags = tx.flags ? BigInt(tx.flags) : 0n; + + // Update variable flags (CPFP, RBF) + if (tx.ancestors?.length) { + flags |= TransactionFlags.cpfp_child; + } + if (tx.descendants?.length) { + flags |= TransactionFlags.cpfp_parent; + } + if (rbfCache.getRbfTree(tx.txid)) { + flags |= TransactionFlags.replacement; + } + + // Already processed static flags, no need to do it again + if (tx.flags) { + return Number(flags); + } + + // Process static flags if (tx.version === 1) { flags |= TransactionFlags.v1; } else if (tx.version === 2) { @@ -306,15 +324,7 @@ export class Common { if (hasFakePubkey) { flags |= TransactionFlags.fake_pubkey; } - if (tx.ancestors?.length) { - flags |= TransactionFlags.cpfp_child; - } - if (tx.descendants?.length) { - flags |= TransactionFlags.cpfp_parent; - } - if (rbfCache.getRbfTree(tx.txid)) { - flags |= TransactionFlags.replacement; - } + // fast but bad heuristic to detect possible coinjoins // (at least 5 inputs and 5 outputs, less than half of which are unique amounts, with no address reuse) const addressReuse = Object.values(reusedAddresses).reduce((acc, count) => Math.max(acc, count), 0) > 1; @@ -335,6 +345,7 @@ export class Common { static classifyTransaction(tx: TransactionExtended): TransactionClassified { const flags = this.getTransactionFlags(tx); + tx.flags = flags; return { ...this.stripTransaction(tx), flags, diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts index 4a630f1e4..d5dfcbf14 100644 --- a/backend/src/mempool.interfaces.ts +++ b/backend/src/mempool.interfaces.ts @@ -95,6 +95,7 @@ export interface TransactionExtended extends IEsploraApi.Transaction { }; acceleration?: boolean; uid?: number; + flags?: number; } export interface MempoolTransactionExtended extends TransactionExtended {