Merge pull request #3380 from mempool/mononaut/mempool-effective-rates
Use effective fee rates in mempool block visualizations & tooltips
This commit is contained in:
commit
90154aec83
@ -83,6 +83,7 @@ export class Common {
|
|||||||
fee: tx.fee,
|
fee: tx.fee,
|
||||||
vsize: tx.weight / 4,
|
vsize: tx.weight / 4,
|
||||||
value: tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0),
|
value: tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0),
|
||||||
|
rate: tx.effectiveFeePerVsize,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +138,7 @@ class MempoolBlocks {
|
|||||||
for (let i = 0; i < Math.max(mempoolBlocks.length, prevBlocks.length); i++) {
|
for (let i = 0; i < Math.max(mempoolBlocks.length, prevBlocks.length); i++) {
|
||||||
let added: TransactionStripped[] = [];
|
let added: TransactionStripped[] = [];
|
||||||
let removed: string[] = [];
|
let removed: string[] = [];
|
||||||
|
const changed: { txid: string, rate: number | undefined }[] = [];
|
||||||
if (mempoolBlocks[i] && !prevBlocks[i]) {
|
if (mempoolBlocks[i] && !prevBlocks[i]) {
|
||||||
added = mempoolBlocks[i].transactions;
|
added = mempoolBlocks[i].transactions;
|
||||||
} else if (!mempoolBlocks[i] && prevBlocks[i]) {
|
} else if (!mempoolBlocks[i] && prevBlocks[i]) {
|
||||||
@ -146,7 +147,7 @@ class MempoolBlocks {
|
|||||||
const prevIds = {};
|
const prevIds = {};
|
||||||
const newIds = {};
|
const newIds = {};
|
||||||
prevBlocks[i].transactions.forEach(tx => {
|
prevBlocks[i].transactions.forEach(tx => {
|
||||||
prevIds[tx.txid] = true;
|
prevIds[tx.txid] = tx;
|
||||||
});
|
});
|
||||||
mempoolBlocks[i].transactions.forEach(tx => {
|
mempoolBlocks[i].transactions.forEach(tx => {
|
||||||
newIds[tx.txid] = true;
|
newIds[tx.txid] = true;
|
||||||
@ -159,12 +160,15 @@ class MempoolBlocks {
|
|||||||
mempoolBlocks[i].transactions.forEach(tx => {
|
mempoolBlocks[i].transactions.forEach(tx => {
|
||||||
if (!prevIds[tx.txid]) {
|
if (!prevIds[tx.txid]) {
|
||||||
added.push(tx);
|
added.push(tx);
|
||||||
|
} else if (tx.rate !== prevIds[tx.txid].rate) {
|
||||||
|
changed.push({ txid: tx.txid, rate: tx.rate });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
mempoolBlockDeltas.push({
|
mempoolBlockDeltas.push({
|
||||||
added,
|
added,
|
||||||
removed
|
removed,
|
||||||
|
changed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return mempoolBlockDeltas;
|
return mempoolBlockDeltas;
|
||||||
|
@ -58,6 +58,7 @@ export interface MempoolBlockWithTransactions extends MempoolBlock {
|
|||||||
export interface MempoolBlockDelta {
|
export interface MempoolBlockDelta {
|
||||||
added: TransactionStripped[];
|
added: TransactionStripped[];
|
||||||
removed: string[];
|
removed: string[];
|
||||||
|
changed: { txid: string, rate: number | undefined }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VinStrippedToScriptsig {
|
interface VinStrippedToScriptsig {
|
||||||
@ -149,6 +150,7 @@ export interface TransactionStripped {
|
|||||||
fee: number;
|
fee: number;
|
||||||
vsize: number;
|
vsize: number;
|
||||||
value: number;
|
value: number;
|
||||||
|
rate?: number; // effective fee rate
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlockExtension {
|
export interface BlockExtension {
|
||||||
|
@ -132,9 +132,9 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update(add: TransactionStripped[], remove: string[], direction: string = 'left', resetLayout: boolean = false): void {
|
update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined }[], direction: string = 'left', resetLayout: boolean = false): void {
|
||||||
if (this.scene) {
|
if (this.scene) {
|
||||||
this.scene.update(add, remove, direction, resetLayout);
|
this.scene.update(add, remove, change, direction, resetLayout);
|
||||||
this.start();
|
this.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ export default class BlockScene {
|
|||||||
this.updateAll(startTime, 200, direction);
|
this.updateAll(startTime, 200, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(add: TransactionStripped[], remove: string[], direction: string = 'left', resetLayout: boolean = false): void {
|
update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined }[], direction: string = 'left', resetLayout: boolean = false): void {
|
||||||
const startTime = performance.now();
|
const startTime = performance.now();
|
||||||
const removed = this.removeBatch(remove, startTime, direction);
|
const removed = this.removeBatch(remove, startTime, direction);
|
||||||
|
|
||||||
@ -172,6 +172,15 @@ export default class BlockScene {
|
|||||||
this.place(tx);
|
this.place(tx);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// update effective rates
|
||||||
|
change.forEach(tx => {
|
||||||
|
if (this.txs[tx.txid]) {
|
||||||
|
this.txs[tx.txid].feerate = tx.rate || (this.txs[tx.txid].fee / this.txs[tx.txid].vsize);
|
||||||
|
this.txs[tx.txid].rate = tx.rate;
|
||||||
|
this.txs[tx.txid].dirty = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// try to insert new txs directly
|
// try to insert new txs directly
|
||||||
const remaining = [];
|
const remaining = [];
|
||||||
add.map(tx => new TxView(tx, this)).sort(feeRateDescending).forEach(tx => {
|
add.map(tx => new TxView(tx, this)).sort(feeRateDescending).forEach(tx => {
|
||||||
|
@ -36,6 +36,7 @@ export default class TxView implements TransactionStripped {
|
|||||||
vsize: number;
|
vsize: number;
|
||||||
value: number;
|
value: number;
|
||||||
feerate: number;
|
feerate: number;
|
||||||
|
rate?: number;
|
||||||
status?: 'found' | 'missing' | 'fresh' | 'added' | 'censored' | 'selected';
|
status?: 'found' | 'missing' | 'fresh' | 'added' | 'censored' | 'selected';
|
||||||
context?: 'projected' | 'actual';
|
context?: 'projected' | 'actual';
|
||||||
scene?: BlockScene;
|
scene?: BlockScene;
|
||||||
@ -58,7 +59,8 @@ export default class TxView implements TransactionStripped {
|
|||||||
this.fee = tx.fee;
|
this.fee = tx.fee;
|
||||||
this.vsize = tx.vsize;
|
this.vsize = tx.vsize;
|
||||||
this.value = tx.value;
|
this.value = tx.value;
|
||||||
this.feerate = tx.fee / tx.vsize;
|
this.feerate = tx.rate || (tx.fee / tx.vsize); // sort by effective fee rate where available
|
||||||
|
this.rate = tx.rate;
|
||||||
this.status = tx.status;
|
this.status = tx.status;
|
||||||
this.initialised = false;
|
this.initialised = false;
|
||||||
this.vertexArray = scene.vertexArray;
|
this.vertexArray = scene.vertexArray;
|
||||||
@ -157,7 +159,8 @@ export default class TxView implements TransactionStripped {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getColor(): Color {
|
getColor(): Color {
|
||||||
const feeLevelIndex = feeLevels.findIndex((feeLvl) => Math.max(1, this.feerate) < feeLvl) - 1;
|
const rate = this.fee / this.vsize; // color by simple single-tx fee rate
|
||||||
|
const feeLevelIndex = feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1;
|
||||||
const feeLevelColor = feeColors[feeLevelIndex] || feeColors[mempoolFeeColors.length - 1];
|
const feeLevelColor = feeColors[feeLevelIndex] || feeColors[mempoolFeeColors.length - 1];
|
||||||
// Normal mode
|
// Normal mode
|
||||||
if (!this.scene?.highlightingEnabled) {
|
if (!this.scene?.highlightingEnabled) {
|
||||||
|
@ -28,6 +28,12 @@
|
|||||||
{{ feeRate | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
|
{{ feeRate | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr *ngIf="effectiveRate && effectiveRate !== feeRate">
|
||||||
|
<td class="td-width" i18n="transaction.effective-fee-rate|Effective transaction fee rate">Effective fee rate</td>
|
||||||
|
<td>
|
||||||
|
{{ effectiveRate | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="td-width" i18n="transaction.vsize|Transaction Virtual Size">Virtual size</td>
|
<td class="td-width" i18n="transaction.vsize|Transaction Virtual Size">Virtual size</td>
|
||||||
<td [innerHTML]="'‎' + (vsize | vbytes: 2)"></td>
|
<td [innerHTML]="'‎' + (vsize | vbytes: 2)"></td>
|
||||||
|
@ -20,6 +20,7 @@ export class BlockOverviewTooltipComponent implements OnChanges {
|
|||||||
value = 0;
|
value = 0;
|
||||||
vsize = 1;
|
vsize = 1;
|
||||||
feeRate = 0;
|
feeRate = 0;
|
||||||
|
effectiveRate;
|
||||||
|
|
||||||
tooltipPosition: Position = { x: 0, y: 0 };
|
tooltipPosition: Position = { x: 0, y: 0 };
|
||||||
|
|
||||||
@ -51,6 +52,7 @@ export class BlockOverviewTooltipComponent implements OnChanges {
|
|||||||
this.value = tx.value || 0;
|
this.value = tx.value || 0;
|
||||||
this.vsize = tx.vsize || 1;
|
this.vsize = tx.vsize || 1;
|
||||||
this.feeRate = this.fee / this.vsize;
|
this.feeRate = this.fee / this.vsize;
|
||||||
|
this.effectiveRate = tx.rate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ export class MempoolBlockOverviewComponent implements OnInit, OnDestroy, OnChang
|
|||||||
const direction = (this.blockIndex == null || this.index < this.blockIndex) ? this.poolDirection : this.chainDirection;
|
const direction = (this.blockIndex == null || this.index < this.blockIndex) ? this.poolDirection : this.chainDirection;
|
||||||
this.blockGraph.replace(delta.added, direction);
|
this.blockGraph.replace(delta.added, direction);
|
||||||
} else {
|
} else {
|
||||||
this.blockGraph.update(delta.added, delta.removed, blockMined ? this.chainDirection : this.poolDirection, blockMined);
|
this.blockGraph.update(delta.added, delta.removed, delta.changed || [], blockMined ? this.chainDirection : this.poolDirection, blockMined);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lastBlockHeight = this.stateService.latestBlockHeight;
|
this.lastBlockHeight = this.stateService.latestBlockHeight;
|
||||||
|
@ -57,6 +57,7 @@ export interface MempoolBlockWithTransactions extends MempoolBlock {
|
|||||||
export interface MempoolBlockDelta {
|
export interface MempoolBlockDelta {
|
||||||
added: TransactionStripped[],
|
added: TransactionStripped[],
|
||||||
removed: string[],
|
removed: string[],
|
||||||
|
changed?: { txid: string, rate: number | undefined }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MempoolInfo {
|
export interface MempoolInfo {
|
||||||
@ -74,6 +75,7 @@ export interface TransactionStripped {
|
|||||||
fee: number;
|
fee: number;
|
||||||
vsize: number;
|
vsize: number;
|
||||||
value: number;
|
value: number;
|
||||||
|
rate?: number; // effective fee rate
|
||||||
status?: 'found' | 'missing' | 'fresh' | 'added' | 'censored' | 'selected';
|
status?: 'found' | 'missing' | 'fresh' | 'added' | 'censored' | 'selected';
|
||||||
context?: 'projected' | 'actual';
|
context?: 'projected' | 'actual';
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user