Merge pull request #4515 from mempool/mononaut/faster-goggles

Faster goggles
This commit is contained in:
softsimon 2023-12-17 18:44:39 +07:00 committed by GitHub
commit 30da419fb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 34 additions and 14 deletions

View File

@ -222,7 +222,25 @@ export class Common {
} }
static getTransactionFlags(tx: TransactionExtended): number { 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 (tx.replacement) {
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) { if (tx.version === 1) {
flags |= TransactionFlags.v1; flags |= TransactionFlags.v1;
} else if (tx.version === 2) { } else if (tx.version === 2) {
@ -306,15 +324,7 @@ export class Common {
if (hasFakePubkey) { if (hasFakePubkey) {
flags |= TransactionFlags.fake_pubkey; 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 // 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) // (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; 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 { static classifyTransaction(tx: TransactionExtended): TransactionClassified {
const flags = this.getTransactionFlags(tx); const flags = this.getTransactionFlags(tx);
tx.flags = flags;
return { return {
...this.stripTransaction(tx), ...this.stripTransaction(tx),
flags, flags,

View File

@ -256,6 +256,7 @@ class DiskCache {
txs: rbfData.rbf.txs.map(([txid, entry]) => ({ value: entry })), txs: rbfData.rbf.txs.map(([txid, entry]) => ({ value: entry })),
trees: rbfData.rbf.trees, trees: rbfData.rbf.trees,
expiring: rbfData.rbf.expiring.map(([txid, value]) => ({ key: txid, value })), expiring: rbfData.rbf.expiring.map(([txid, value]) => ({ key: txid, value })),
mempool: memPool.getMempool(),
}); });
} }
} catch (e) { } catch (e) {

View File

@ -97,6 +97,8 @@ class RbfCache {
return; return;
} }
newTxExtended.replacement = true;
const newTx = Common.stripTransaction(newTxExtended) as RbfTransaction; const newTx = Common.stripTransaction(newTxExtended) as RbfTransaction;
const newTime = newTxExtended.firstSeen || (Date.now() / 1000); const newTime = newTxExtended.firstSeen || (Date.now() / 1000);
newTx.rbf = newTxExtended.vin.some((v) => v.sequence < 0xfffffffe); newTx.rbf = newTxExtended.vin.some((v) => v.sequence < 0xfffffffe);
@ -368,14 +370,14 @@ class RbfCache {
}; };
} }
public async load({ txs, trees, expiring }): Promise<void> { public async load({ txs, trees, expiring, mempool }): Promise<void> {
try { try {
txs.forEach(txEntry => { txs.forEach(txEntry => {
this.txs.set(txEntry.value.txid, txEntry.value); this.txs.set(txEntry.value.txid, txEntry.value);
}); });
this.staleCount = 0; this.staleCount = 0;
for (const deflatedTree of trees) { for (const deflatedTree of trees) {
await this.importTree(deflatedTree.root, deflatedTree.root, deflatedTree, this.txs); await this.importTree(mempool, deflatedTree.root, deflatedTree.root, deflatedTree, this.txs);
} }
expiring.forEach(expiringEntry => { expiring.forEach(expiringEntry => {
if (this.txs.has(expiringEntry.key)) { if (this.txs.has(expiringEntry.key)) {
@ -413,7 +415,7 @@ class RbfCache {
return deflated; return deflated;
} }
async importTree(root, txid, deflated, txs: Map<string, MempoolTransactionExtended>, mined: boolean = false): Promise<RbfTree | void> { async importTree(mempool, root, txid, deflated, txs: Map<string, MempoolTransactionExtended>, mined: boolean = false): Promise<RbfTree | void> {
const treeInfo = deflated[txid]; const treeInfo = deflated[txid];
const replaces: RbfTree[] = []; const replaces: RbfTree[] = [];
@ -426,9 +428,12 @@ class RbfCache {
// recursively reconstruct child trees // recursively reconstruct child trees
for (const childId of treeInfo.replaces) { for (const childId of treeInfo.replaces) {
const replaced = await this.importTree(root, childId, deflated, txs, mined); const replaced = await this.importTree(mempool, root, childId, deflated, txs, mined);
if (replaced) { if (replaced) {
this.replacedBy.set(replaced.tx.txid, txid); this.replacedBy.set(replaced.tx.txid, txid);
if (mempool[replaced.tx.txid]) {
mempool[replaced.tx.txid].replacement = true;
}
replaces.push(replaced); replaces.push(replaced);
if (replaced.mined) { if (replaced.mined) {
mined = true; mined = true;

View File

@ -222,6 +222,7 @@ class RedisCache {
txs: rbfTxs, txs: rbfTxs,
trees: rbfTrees.map(loadedTree => { loadedTree.value.key = loadedTree.key; return loadedTree.value; }), trees: rbfTrees.map(loadedTree => { loadedTree.value.key = loadedTree.key; return loadedTree.value; }),
expiring: rbfExpirations, expiring: rbfExpirations,
mempool: memPool.getMempool(),
}); });
} }

View File

@ -94,7 +94,9 @@ export interface TransactionExtended extends IEsploraApi.Transaction {
vsize: number, vsize: number,
}; };
acceleration?: boolean; acceleration?: boolean;
replacement?: boolean;
uid?: number; uid?: number;
flags?: number;
} }
export interface MempoolTransactionExtended extends TransactionExtended { export interface MempoolTransactionExtended extends TransactionExtended {