Merge pull request #3971 from mempool/mononaut/audit-recently-cpfpd
Add "recently cpfpd" exception to audits
This commit is contained in:
		
						commit
						be599ca624
					
				| @ -1,12 +1,12 @@ | ||||
| import config from '../config'; | ||||
| import logger from '../logger'; | ||||
| import { TransactionExtended, MempoolBlockWithTransactions } from '../mempool.interfaces'; | ||||
| import { MempoolTransactionExtended, MempoolBlockWithTransactions } from '../mempool.interfaces'; | ||||
| import rbfCache from './rbf-cache'; | ||||
| 
 | ||||
| const PROPAGATION_MARGIN = 180; // in seconds, time since a transaction is first seen after which it is assumed to have propagated to all miners
 | ||||
| 
 | ||||
| class Audit { | ||||
|   auditBlock(transactions: TransactionExtended[], projectedBlocks: MempoolBlockWithTransactions[], mempool: { [txId: string]: TransactionExtended }) | ||||
|   auditBlock(transactions: MempoolTransactionExtended[], projectedBlocks: MempoolBlockWithTransactions[], mempool: { [txId: string]: MempoolTransactionExtended }) | ||||
|    : { censored: string[], added: string[], fresh: string[], sigop: string[], fullrbf: string[], score: number, similarity: number } { | ||||
|     if (!projectedBlocks?.[0]?.transactionIds || !mempool) { | ||||
|       return { censored: [], added: [], fresh: [], sigop: [], fullrbf: [], score: 0, similarity: 1 }; | ||||
| @ -14,7 +14,7 @@ class Audit { | ||||
| 
 | ||||
|     const matches: string[] = []; // present in both mined block and template
 | ||||
|     const added: string[] = []; // present in mined block, not in template
 | ||||
|     const fresh: string[] = []; // missing, but firstSeen 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 isCensored = {}; // missing, without excuse
 | ||||
|     const isDisplaced = {}; | ||||
| @ -36,10 +36,13 @@ class Audit { | ||||
|     // look for transactions that were expected in the template, but missing from the mined block
 | ||||
|     for (const txid of projectedBlocks[0].transactionIds) { | ||||
|       if (!inBlock[txid]) { | ||||
|         // tx is recent, may have reached the miner too late for inclusion
 | ||||
|         if (rbfCache.isFullRbf(txid)) { | ||||
|           fullrbf.push(txid); | ||||
|         } 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
 | ||||
|           fresh.push(txid); | ||||
|         } else if (mempool[txid]?.lastBoosted != null && (now - (mempool[txid]?.lastBoosted || 0)) <= PROPAGATION_MARGIN) { | ||||
|           // tx was recently cpfp'd, miner may not have the latest effective rate
 | ||||
|           fresh.push(txid); | ||||
|         } else { | ||||
|           isCensored[txid] = true; | ||||
|  | ||||
| @ -457,6 +457,7 @@ class MempoolBlocks { | ||||
|               }; | ||||
|               if (matched) { | ||||
|                 descendants.push(relative); | ||||
|                 mempoolTx.lastBoosted = Math.max(mempoolTx.lastBoosted || 0, mempool[txid].firstSeen || 0); | ||||
|               } else { | ||||
|                 ancestors.push(relative); | ||||
|               } | ||||
|  | ||||
| @ -100,6 +100,7 @@ export interface MempoolTransactionExtended extends TransactionExtended { | ||||
|   adjustedVsize: number; | ||||
|   adjustedFeePerVsize: number; | ||||
|   inputs?: number[]; | ||||
|   lastBoosted?: number; | ||||
| } | ||||
| 
 | ||||
| export interface AuditTransaction { | ||||
|  | ||||
| @ -38,7 +38,7 @@ export default class TxView implements TransactionStripped { | ||||
|   value: number; | ||||
|   feerate: number; | ||||
|   rate?: number; | ||||
|   status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'added' | 'censored' | 'selected' | 'fullrbf'; | ||||
|   status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'fullrbf'; | ||||
|   context?: 'projected' | 'actual'; | ||||
|   scene?: BlockScene; | ||||
| 
 | ||||
| @ -210,6 +210,7 @@ export default class TxView implements TransactionStripped { | ||||
|       case 'fullrbf': | ||||
|         return marginalFeeColors[feeLevelIndex] || marginalFeeColors[mempoolFeeColors.length - 1]; | ||||
|       case 'fresh': | ||||
|       case 'freshcpfp': | ||||
|         return auditColors.missing; | ||||
|       case 'added': | ||||
|         return auditColors.added; | ||||
|  | ||||
| @ -50,6 +50,7 @@ | ||||
|           <td *ngSwitchCase="'missing'"><span class="badge badge-warning" i18n="transaction.audit.marginal">Marginal fee rate</span></td> | ||||
|           <td *ngSwitchCase="'sigop'"><span class="badge badge-warning" i18n="transaction.audit.sigop">High sigop count</span></td> | ||||
|           <td *ngSwitchCase="'fresh'"><span class="badge badge-warning" i18n="transaction.audit.recently-broadcasted">Recently broadcasted</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="'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> | ||||
|  | ||||
| @ -370,7 +370,11 @@ export class BlockComponent implements OnInit, OnDestroy { | ||||
|               tx.status = 'found'; | ||||
|             } else { | ||||
|               if (isFresh[tx.txid]) { | ||||
|                 tx.status = 'fresh'; | ||||
|                 if (tx.rate - (tx.fee / tx.vsize) >= 0.1) { | ||||
|                   tx.status = 'freshcpfp'; | ||||
|                 } else { | ||||
|                   tx.status = 'fresh'; | ||||
|                 } | ||||
|               } else if (isSigop[tx.txid]) { | ||||
|                 tx.status = 'sigop'; | ||||
|               } else if (isFullRbf[tx.txid]) { | ||||
|  | ||||
| @ -173,7 +173,8 @@ export interface TransactionStripped { | ||||
|   fee: number; | ||||
|   vsize: number; | ||||
|   value: number; | ||||
|   status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'added' | 'censored' | 'selected' | 'fullrbf'; | ||||
|   rate?: number; // effective fee rate
 | ||||
|   status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'fullrbf'; | ||||
|   context?: 'projected' | 'actual'; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -89,7 +89,7 @@ export interface TransactionStripped { | ||||
|   vsize: number; | ||||
|   value: number; | ||||
|   rate?: number; // effective fee rate
 | ||||
|   status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'added' | 'censored' | 'selected' | 'fullrbf'; | ||||
|   status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'fullrbf'; | ||||
|   context?: 'projected' | 'actual'; | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user