mirror of
https://github.com/mempool/mempool.git
synced 2025-02-22 22:25:34 +01:00
Exclude all conflicting transactions from audit score
This commit is contained in:
parent
81d1c0a4d5
commit
d7b874ac49
7 changed files with 36 additions and 17 deletions
|
@ -15,7 +15,7 @@ class Audit {
|
||||||
const matches: string[] = []; // present in both mined block and template
|
const matches: string[] = []; // present in both mined block and template
|
||||||
const added: string[] = []; // present in mined block, not in template
|
const added: string[] = []; // present in mined block, not in template
|
||||||
const fresh: string[] = []; // missing, but firstSeen or lastBoosted within PROPAGATION_MARGIN
|
const fresh: string[] = []; // missing, but firstSeen or lastBoosted within PROPAGATION_MARGIN
|
||||||
const fullrbf: string[] = []; // either missing or present, and part of a fullrbf replacement
|
const rbf: string[] = []; // either missing or present, and either part of a full-rbf replacement, or a conflict with the mined block
|
||||||
const isCensored = {}; // missing, without excuse
|
const isCensored = {}; // missing, without excuse
|
||||||
const isDisplaced = {};
|
const isDisplaced = {};
|
||||||
let displacedWeight = 0;
|
let displacedWeight = 0;
|
||||||
|
@ -36,8 +36,9 @@ class Audit {
|
||||||
// look for transactions that were expected in the template, but missing from the mined block
|
// look for transactions that were expected in the template, but missing from the mined block
|
||||||
for (const txid of projectedBlocks[0].transactionIds) {
|
for (const txid of projectedBlocks[0].transactionIds) {
|
||||||
if (!inBlock[txid]) {
|
if (!inBlock[txid]) {
|
||||||
if (rbfCache.isFullRbf(txid)) {
|
// allow missing transactions which either belong to a full rbf tree, or conflict with any transaction in the mined block
|
||||||
fullrbf.push(txid);
|
if (rbfCache.has(txid) && (rbfCache.isFullRbf(txid) || rbfCache.anyInSameTree(txid, (tx) => inBlock[tx.txid]))) {
|
||||||
|
rbf.push(txid);
|
||||||
} else if (mempool[txid]?.firstSeen != null && (now - (mempool[txid]?.firstSeen || 0)) <= PROPAGATION_MARGIN) {
|
} else if (mempool[txid]?.firstSeen != null && (now - (mempool[txid]?.firstSeen || 0)) <= PROPAGATION_MARGIN) {
|
||||||
// tx is recent, may have reached the miner too late for inclusion
|
// tx is recent, may have reached the miner too late for inclusion
|
||||||
fresh.push(txid);
|
fresh.push(txid);
|
||||||
|
@ -98,8 +99,8 @@ class Audit {
|
||||||
if (inTemplate[tx.txid]) {
|
if (inTemplate[tx.txid]) {
|
||||||
matches.push(tx.txid);
|
matches.push(tx.txid);
|
||||||
} else {
|
} else {
|
||||||
if (rbfCache.isFullRbf(tx.txid)) {
|
if (rbfCache.has(tx.txid)) {
|
||||||
fullrbf.push(tx.txid);
|
rbf.push(tx.txid);
|
||||||
} else if (!isDisplaced[tx.txid]) {
|
} else if (!isDisplaced[tx.txid]) {
|
||||||
added.push(tx.txid);
|
added.push(tx.txid);
|
||||||
}
|
}
|
||||||
|
@ -147,7 +148,7 @@ class Audit {
|
||||||
added,
|
added,
|
||||||
fresh,
|
fresh,
|
||||||
sigop: [],
|
sigop: [],
|
||||||
fullrbf,
|
fullrbf: rbf,
|
||||||
score,
|
score,
|
||||||
similarity,
|
similarity,
|
||||||
};
|
};
|
||||||
|
|
|
@ -100,6 +100,24 @@ class RbfCache {
|
||||||
this.dirtyTrees.add(treeId);
|
this.dirtyTrees.add(treeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public has(txId: string): boolean {
|
||||||
|
return this.txs.has(txId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public anyInSameTree(txId: string, predicate: (tx: RbfTransaction) => boolean): boolean {
|
||||||
|
const tree = this.getRbfTree(txId);
|
||||||
|
if (!tree) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const txs = this.getTransactionsInTree(tree);
|
||||||
|
for (const tx of txs) {
|
||||||
|
if (predicate(tx)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public getReplacedBy(txId: string): string | undefined {
|
public getReplacedBy(txId: string): string | undefined {
|
||||||
return this.replacedBy.get(txId);
|
return this.replacedBy.get(txId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ export default class TxView implements TransactionStripped {
|
||||||
value: number;
|
value: number;
|
||||||
feerate: number;
|
feerate: number;
|
||||||
rate?: number;
|
rate?: number;
|
||||||
status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'fullrbf';
|
status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'rbf';
|
||||||
context?: 'projected' | 'actual';
|
context?: 'projected' | 'actual';
|
||||||
scene?: BlockScene;
|
scene?: BlockScene;
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ export default class TxView implements TransactionStripped {
|
||||||
return auditColors.censored;
|
return auditColors.censored;
|
||||||
case 'missing':
|
case 'missing':
|
||||||
case 'sigop':
|
case 'sigop':
|
||||||
case 'fullrbf':
|
case 'rbf':
|
||||||
return marginalFeeColors[feeLevelIndex] || marginalFeeColors[mempoolFeeColors.length - 1];
|
return marginalFeeColors[feeLevelIndex] || marginalFeeColors[mempoolFeeColors.length - 1];
|
||||||
case 'fresh':
|
case 'fresh':
|
||||||
case 'freshcpfp':
|
case 'freshcpfp':
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
<td *ngSwitchCase="'freshcpfp'"><span class="badge badge-warning" i18n="transaction.audit.recently-cpfped">Recently CPFP'd</span></td>
|
<td *ngSwitchCase="'freshcpfp'"><span class="badge badge-warning" i18n="transaction.audit.recently-cpfped">Recently CPFP'd</span></td>
|
||||||
<td *ngSwitchCase="'added'"><span class="badge badge-warning" i18n="transaction.audit.added">Added</span></td>
|
<td *ngSwitchCase="'added'"><span class="badge badge-warning" i18n="transaction.audit.added">Added</span></td>
|
||||||
<td *ngSwitchCase="'selected'"><span class="badge badge-warning" i18n="transaction.audit.marginal">Marginal fee rate</span></td>
|
<td *ngSwitchCase="'selected'"><span class="badge badge-warning" i18n="transaction.audit.marginal">Marginal fee rate</span></td>
|
||||||
<td *ngSwitchCase="'fullrbf'"><span class="badge badge-warning" i18n="transaction.audit.fullrbf">Full RBF</span></td>
|
<td *ngSwitchCase="'rbf'"><span class="badge badge-warning" i18n="transaction.audit.conflicting">Conflicting</span></td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -339,7 +339,7 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||||
const isSelected = {};
|
const isSelected = {};
|
||||||
const isFresh = {};
|
const isFresh = {};
|
||||||
const isSigop = {};
|
const isSigop = {};
|
||||||
const isFullRbf = {};
|
const isRbf = {};
|
||||||
this.numMissing = 0;
|
this.numMissing = 0;
|
||||||
this.numUnexpected = 0;
|
this.numUnexpected = 0;
|
||||||
|
|
||||||
|
@ -363,7 +363,7 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||||
isSigop[txid] = true;
|
isSigop[txid] = true;
|
||||||
}
|
}
|
||||||
for (const txid of blockAudit.fullrbfTxs || []) {
|
for (const txid of blockAudit.fullrbfTxs || []) {
|
||||||
isFullRbf[txid] = true;
|
isRbf[txid] = true;
|
||||||
}
|
}
|
||||||
// set transaction statuses
|
// set transaction statuses
|
||||||
for (const tx of blockAudit.template) {
|
for (const tx of blockAudit.template) {
|
||||||
|
@ -381,8 +381,8 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
} else if (isSigop[tx.txid]) {
|
} else if (isSigop[tx.txid]) {
|
||||||
tx.status = 'sigop';
|
tx.status = 'sigop';
|
||||||
} else if (isFullRbf[tx.txid]) {
|
} else if (isRbf[tx.txid]) {
|
||||||
tx.status = 'fullrbf';
|
tx.status = 'rbf';
|
||||||
} else {
|
} else {
|
||||||
tx.status = 'missing';
|
tx.status = 'missing';
|
||||||
}
|
}
|
||||||
|
@ -398,8 +398,8 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||||
tx.status = 'added';
|
tx.status = 'added';
|
||||||
} else if (inTemplate[tx.txid]) {
|
} else if (inTemplate[tx.txid]) {
|
||||||
tx.status = 'found';
|
tx.status = 'found';
|
||||||
} else if (isFullRbf[tx.txid]) {
|
} else if (isRbf[tx.txid]) {
|
||||||
tx.status = 'fullrbf';
|
tx.status = 'rbf';
|
||||||
} else {
|
} else {
|
||||||
tx.status = 'selected';
|
tx.status = 'selected';
|
||||||
isSelected[tx.txid] = true;
|
isSelected[tx.txid] = true;
|
||||||
|
|
|
@ -174,7 +174,7 @@ export interface TransactionStripped {
|
||||||
vsize: number;
|
vsize: number;
|
||||||
value: number;
|
value: number;
|
||||||
rate?: number; // effective fee rate
|
rate?: number; // effective fee rate
|
||||||
status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'fullrbf';
|
status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'rbf';
|
||||||
context?: 'projected' | 'actual';
|
context?: 'projected' | 'actual';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ export interface TransactionStripped {
|
||||||
vsize: number;
|
vsize: number;
|
||||||
value: number;
|
value: number;
|
||||||
rate?: number; // effective fee rate
|
rate?: number; // effective fee rate
|
||||||
status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'fullrbf';
|
status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'rbf';
|
||||||
context?: 'projected' | 'actual';
|
context?: 'projected' | 'actual';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue