Omit possible high-sigop txs from block health score
This commit is contained in:
@@ -6,14 +6,15 @@ const PROPAGATION_MARGIN = 180; // in seconds, time since a transaction is first
|
||||
|
||||
class Audit {
|
||||
auditBlock(transactions: TransactionExtended[], projectedBlocks: MempoolBlockWithTransactions[], mempool: { [txId: string]: TransactionExtended })
|
||||
: { censored: string[], added: string[], fresh: string[], score: number, similarity: number } {
|
||||
: { censored: string[], added: string[], fresh: string[], sigop: string[], score: number, similarity: number } {
|
||||
if (!projectedBlocks?.[0]?.transactionIds || !mempool) {
|
||||
return { censored: [], added: [], fresh: [], score: 0, similarity: 1 };
|
||||
return { censored: [], added: [], fresh: [], sigop: [], score: 0, similarity: 1 };
|
||||
}
|
||||
|
||||
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 sigop: string[] = []; // missing, but possibly has an adjusted vsize due to high sigop count
|
||||
const isCensored = {}; // missing, without excuse
|
||||
const isDisplaced = {};
|
||||
let displacedWeight = 0;
|
||||
@@ -37,6 +38,8 @@ class Audit {
|
||||
// tx is recent, may have reached the miner too late for inclusion
|
||||
if (mempool[txid]?.firstSeen != null && (now - (mempool[txid]?.firstSeen || 0)) <= PROPAGATION_MARGIN) {
|
||||
fresh.push(txid);
|
||||
} else if (this.isPossibleHighSigop(mempool[txid])) {
|
||||
sigop.push(txid);
|
||||
} else {
|
||||
isCensored[txid] = true;
|
||||
}
|
||||
@@ -137,10 +140,19 @@ class Audit {
|
||||
censored: Object.keys(isCensored),
|
||||
added,
|
||||
fresh,
|
||||
sigop,
|
||||
score,
|
||||
similarity,
|
||||
};
|
||||
}
|
||||
|
||||
// Detect transactions with a possibly adjusted vsize due to high sigop count
|
||||
// very rough heuristic based on number of OP_CHECKMULTISIG outputs
|
||||
// will miss cases with other sources of sigops
|
||||
isPossibleHighSigop(tx: TransactionExtended): boolean {
|
||||
const numBareMultisig = tx.vout.reduce((count, vout) => count + (vout.scriptpubkey_asm.includes('OP_CHECKMULTISIG') ? 1 : 0), 0);
|
||||
return (numBareMultisig * 400) > tx.vsize;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Audit();
|
||||
@@ -7,7 +7,7 @@ import cpfpRepository from '../repositories/CpfpRepository';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
|
||||
class DatabaseMigration {
|
||||
private static currentVersion = 59;
|
||||
private static currentVersion = 60;
|
||||
private queryTimeout = 3600_000;
|
||||
private statisticsAddedIndexed = false;
|
||||
private uniqueLogs: string[] = [];
|
||||
@@ -516,6 +516,11 @@ class DatabaseMigration {
|
||||
// https://github.com/mempool/mempool/issues/3360
|
||||
await this.$executeQuery(`TRUNCATE prices`);
|
||||
}
|
||||
|
||||
if (databaseSchemaVersion < 60 && isBitcoin === true) {
|
||||
await this.$executeQuery('ALTER TABLE `blocks_audits` ADD sigop_txs JSON DEFAULT "[]"');
|
||||
await this.updateToSchemaVersion(60);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -557,7 +557,7 @@ class WebsocketHandler {
|
||||
}
|
||||
|
||||
if (Common.indexingEnabled() && memPool.isInSync()) {
|
||||
const { censored, added, fresh, score, similarity } = Audit.auditBlock(transactions, projectedBlocks, auditMempool);
|
||||
const { censored, added, fresh, sigop, score, similarity } = Audit.auditBlock(transactions, projectedBlocks, auditMempool);
|
||||
const matchRate = Math.round(score * 100 * 100) / 100;
|
||||
|
||||
const stripped = projectedBlocks[0]?.transactions ? projectedBlocks[0].transactions.map((tx) => {
|
||||
@@ -584,6 +584,7 @@ class WebsocketHandler {
|
||||
addedTxs: added,
|
||||
missingTxs: censored,
|
||||
freshTxs: fresh,
|
||||
sigopTxs: sigop,
|
||||
matchRate: matchRate,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user