Merge pull request #4258 from mempool/mononaut/esplora-sigops
Sigops everywhere
This commit is contained in:
commit
12b49abfdd
@ -251,7 +251,7 @@ class BitcoinRoutes {
|
|||||||
|
|
||||||
private async getTransaction(req: Request, res: Response) {
|
private async getTransaction(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
const transaction = await transactionUtils.$getTransactionExtended(req.params.txId, true);
|
const transaction = await transactionUtils.$getTransactionExtended(req.params.txId, true, false, false, true);
|
||||||
res.json(transaction);
|
res.json(transaction);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
let statusCode = 500;
|
let statusCode = 500;
|
||||||
|
@ -6,6 +6,7 @@ export namespace IEsploraApi {
|
|||||||
size: number;
|
size: number;
|
||||||
weight: number;
|
weight: number;
|
||||||
fee: number;
|
fee: number;
|
||||||
|
sigops?: number;
|
||||||
vin: Vin[];
|
vin: Vin[];
|
||||||
vout: Vout[];
|
vout: Vout[];
|
||||||
status: Status;
|
status: Status;
|
||||||
|
@ -94,7 +94,7 @@ class Mempool {
|
|||||||
logger.debug(`Migrating ${Object.keys(this.mempoolCache).length} transactions from disk cache to Redis cache`);
|
logger.debug(`Migrating ${Object.keys(this.mempoolCache).length} transactions from disk cache to Redis cache`);
|
||||||
}
|
}
|
||||||
for (const txid of Object.keys(this.mempoolCache)) {
|
for (const txid of Object.keys(this.mempoolCache)) {
|
||||||
if (!this.mempoolCache[txid].sigops || this.mempoolCache[txid].effectiveFeePerVsize == null) {
|
if (!this.mempoolCache[txid].adjustedVsize || this.mempoolCache[txid].sigops == null || this.mempoolCache[txid].effectiveFeePerVsize == null) {
|
||||||
this.mempoolCache[txid] = transactionUtils.extendMempoolTransaction(this.mempoolCache[txid]);
|
this.mempoolCache[txid] = transactionUtils.extendMempoolTransaction(this.mempoolCache[txid]);
|
||||||
}
|
}
|
||||||
if (this.mempoolCache[txid].order == null) {
|
if (this.mempoolCache[txid].order == null) {
|
||||||
|
@ -116,7 +116,7 @@ class TransactionUtils {
|
|||||||
public extendMempoolTransaction(transaction: IEsploraApi.Transaction): MempoolTransactionExtended {
|
public extendMempoolTransaction(transaction: IEsploraApi.Transaction): MempoolTransactionExtended {
|
||||||
const vsize = Math.ceil(transaction.weight / 4);
|
const vsize = Math.ceil(transaction.weight / 4);
|
||||||
const fractionalVsize = (transaction.weight / 4);
|
const fractionalVsize = (transaction.weight / 4);
|
||||||
const sigops = !Common.isLiquid() ? this.countSigops(transaction) : 0;
|
let sigops = Common.isLiquid() ? 0 : (transaction.sigops != null ? transaction.sigops : this.countSigops(transaction));
|
||||||
// https://github.com/bitcoin/bitcoin/blob/e9262ea32a6e1d364fb7974844fadc36f931f8c6/src/policy/policy.cpp#L295-L298
|
// https://github.com/bitcoin/bitcoin/blob/e9262ea32a6e1d364fb7974844fadc36f931f8c6/src/policy/policy.cpp#L295-L298
|
||||||
const adjustedVsize = Math.max(fractionalVsize, sigops * 5); // adjusted vsize = Max(weight, sigops * bytes_per_sigop) / witness_scale_factor
|
const adjustedVsize = Math.max(fractionalVsize, sigops * 5); // adjusted vsize = Max(weight, sigops * bytes_per_sigop) / witness_scale_factor
|
||||||
const feePerVbytes = (transaction.fee || 0) / fractionalVsize;
|
const feePerVbytes = (transaction.fee || 0) / fractionalVsize;
|
||||||
@ -155,7 +155,7 @@ class TransactionUtils {
|
|||||||
sigops += 20 * (script.match(/OP_CHECKMULTISIG/g)?.length || 0);
|
sigops += 20 * (script.match(/OP_CHECKMULTISIG/g)?.length || 0);
|
||||||
} else {
|
} else {
|
||||||
// in redeem scripts and witnesses, worth N if preceded by OP_N, 20 otherwise
|
// in redeem scripts and witnesses, worth N if preceded by OP_N, 20 otherwise
|
||||||
const matches = script.matchAll(/(?:OP_(\d+))? OP_CHECKMULTISIG/g);
|
const matches = script.matchAll(/(?:OP_(?:PUSHNUM_)?(\d+))? OP_CHECKMULTISIG/g);
|
||||||
for (const match of matches) {
|
for (const match of matches) {
|
||||||
const n = parseInt(match[1]);
|
const n = parseInt(match[1]);
|
||||||
if (Number.isInteger(n)) {
|
if (Number.isInteger(n)) {
|
||||||
@ -189,6 +189,12 @@ class TransactionUtils {
|
|||||||
sigops += this.countScriptSigops(bitcoinjs.script.toASM(Buffer.from(input.witness[input.witness.length - 1], 'hex')), false, true);
|
sigops += this.countScriptSigops(bitcoinjs.script.toASM(Buffer.from(input.witness[input.witness.length - 1], 'hex')), false, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case input.prevout.scriptpubkey_type === 'p2sh':
|
||||||
|
if (input.inner_redeemscript_asm) {
|
||||||
|
sigops += this.countScriptSigops(input.inner_redeemscript_asm);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,9 +292,9 @@
|
|||||||
<td i18n="transaction.vsize|Transaction Virtual Size">Virtual size</td>
|
<td i18n="transaction.vsize|Transaction Virtual Size">Virtual size</td>
|
||||||
<td [innerHTML]="'‎' + (tx.weight / 4 | vbytes: 2)"></td>
|
<td [innerHTML]="'‎' + (tx.weight / 4 | vbytes: 2)"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="cpfpInfo && cpfpInfo.adjustedVsize && cpfpInfo.adjustedVsize > (tx.weight / 4)">
|
<tr *ngIf="adjustedVsize != null">
|
||||||
<td i18n="transaction.adjusted-vsize|Transaction Adjusted VSize">Adjusted vsize</td>
|
<td i18n="transaction.adjusted-vsize|Transaction Adjusted VSize">Adjusted vsize</td>
|
||||||
<td [innerHTML]="'‎' + (cpfpInfo.adjustedVsize | vbytes: 2)"></td>
|
<td [innerHTML]="'‎' + (adjustedVsize | vbytes: 2)"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="block.weight">Weight</td>
|
<td i18n="block.weight">Weight</td>
|
||||||
@ -314,9 +314,9 @@
|
|||||||
<td i18n="transaction.locktime">Locktime</td>
|
<td i18n="transaction.locktime">Locktime</td>
|
||||||
<td [innerHTML]="'‎' + (tx.locktime | number)"></td>
|
<td [innerHTML]="'‎' + (tx.locktime | number)"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="cpfpInfo && cpfpInfo.adjustedVsize && cpfpInfo.adjustedVsize > (tx.weight / 4)">
|
<tr *ngIf="sigops != null">
|
||||||
<td i18n="transaction.sigops|Transaction Sigops">Sigops</td>
|
<td i18n="transaction.sigops|Transaction Sigops">Sigops</td>
|
||||||
<td [innerHTML]="'‎' + (cpfpInfo.sigops | number)"></td>
|
<td [innerHTML]="'‎' + (sigops | number)"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="transaction.hex">Transaction hex</td>
|
<td i18n="transaction.hex">Transaction hex</td>
|
||||||
|
@ -62,6 +62,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
rbfReplaces: string[];
|
rbfReplaces: string[];
|
||||||
rbfInfo: RbfTree;
|
rbfInfo: RbfTree;
|
||||||
cpfpInfo: CpfpInfo | null;
|
cpfpInfo: CpfpInfo | null;
|
||||||
|
sigops: number | null;
|
||||||
|
adjustedVsize: number | null;
|
||||||
showCpfpDetails = false;
|
showCpfpDetails = false;
|
||||||
fetchCpfp$ = new Subject<string>();
|
fetchCpfp$ = new Subject<string>();
|
||||||
fetchRbfHistory$ = new Subject<string>();
|
fetchRbfHistory$ = new Subject<string>();
|
||||||
@ -343,6 +345,10 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
if (tx.fee === undefined) {
|
if (tx.fee === undefined) {
|
||||||
this.tx.fee = 0;
|
this.tx.fee = 0;
|
||||||
}
|
}
|
||||||
|
if (this.tx.sigops != null) {
|
||||||
|
this.sigops = this.tx.sigops;
|
||||||
|
this.adjustedVsize = Math.max(this.tx.weight / 4, this.sigops * 5);
|
||||||
|
}
|
||||||
this.tx.feePerVsize = tx.fee / (tx.weight / 4);
|
this.tx.feePerVsize = tx.fee / (tx.weight / 4);
|
||||||
this.isLoadingTx = false;
|
this.isLoadingTx = false;
|
||||||
this.error = undefined;
|
this.error = undefined;
|
||||||
@ -543,6 +549,10 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.cpfpInfo = cpfpInfo;
|
this.cpfpInfo = cpfpInfo;
|
||||||
|
if (this.cpfpInfo.adjustedVsize && this.cpfpInfo.sigops != null) {
|
||||||
|
this.sigops = this.cpfpInfo.sigops;
|
||||||
|
this.adjustedVsize = this.cpfpInfo.adjustedVsize;
|
||||||
|
}
|
||||||
this.hasEffectiveFeeRate = hasRelatives || (this.tx.effectiveFeePerVsize && (Math.abs(this.tx.effectiveFeePerVsize - this.tx.feePerVsize) > 0.01));
|
this.hasEffectiveFeeRate = hasRelatives || (this.tx.effectiveFeePerVsize && (Math.abs(this.tx.effectiveFeePerVsize - this.tx.feePerVsize) > 0.01));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,6 +579,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.replaced = false;
|
this.replaced = false;
|
||||||
this.transactionTime = -1;
|
this.transactionTime = -1;
|
||||||
this.cpfpInfo = null;
|
this.cpfpInfo = null;
|
||||||
|
this.adjustedVsize = null;
|
||||||
|
this.sigops = null;
|
||||||
this.hasEffectiveFeeRate = false;
|
this.hasEffectiveFeeRate = false;
|
||||||
this.rbfInfo = null;
|
this.rbfInfo = null;
|
||||||
this.rbfReplaces = [];
|
this.rbfReplaces = [];
|
||||||
|
@ -26,6 +26,7 @@ export interface Transaction {
|
|||||||
_outspends?: Outspend[];
|
_outspends?: Outspend[];
|
||||||
_channels?: TransactionChannels;
|
_channels?: TransactionChannels;
|
||||||
price?: Price;
|
price?: Price;
|
||||||
|
sigops?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransactionChannels {
|
export interface TransactionChannels {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user