highlight & tag fullrbf replacements in RBF timeline

This commit is contained in:
Mononaut
2023-07-13 10:42:33 +09:00
parent 9cf961c667
commit 3287c62f91
7 changed files with 69 additions and 26 deletions

View File

@@ -1,15 +1,20 @@
import { Component, Input, OnInit, OnChanges, Inject, LOCALE_ID, HostListener } from '@angular/core';
import { Router } from '@angular/router';
import { RbfInfo, RbfTree } from '../../interfaces/node-api.interface';
import { RbfTree, RbfTransaction } from '../../interfaces/node-api.interface';
import { StateService } from '../../services/state.service';
import { ApiService } from '../../services/api.service';
type Connector = 'pipe' | 'corner';
interface TimelineCell {
replacement?: RbfInfo,
replacement?: RbfTree,
connector?: Connector,
first?: boolean,
fullRbf?: boolean,
}
function isTimelineCell(val: RbfTree | TimelineCell): boolean {
return !val || !('tx' in val);
}
@Component({
@@ -22,7 +27,7 @@ export class RbfTimelineComponent implements OnInit, OnChanges {
@Input() txid: string;
rows: TimelineCell[][] = [];
hoverInfo: RbfInfo | void = null;
hoverInfo: RbfTree | null = null;
tooltipPosition = null;
dir: 'rtl' | 'ltr' = 'ltr';
@@ -53,13 +58,27 @@ export class RbfTimelineComponent implements OnInit, OnChanges {
buildTimelines(tree: RbfTree): TimelineCell[][] {
if (!tree) return [];
this.flagFullRbf(tree);
const split = this.splitTimelines(tree);
const timelines = this.prepareTimelines(split);
return this.connectTimelines(timelines);
}
// sets the fullRbf flag on each transaction in the tree
flagFullRbf(tree: RbfTree): void {
let fullRbf = false;
for (const replaced of tree.replaces) {
if (!replaced.tx.rbf) {
fullRbf = true;
}
replaced.replacedBy = tree.tx;
this.flagFullRbf(replaced);
}
tree.tx.fullRbf = fullRbf;
}
// splits a tree into N leaf-to-root paths
splitTimelines(tree: RbfTree, tail: RbfInfo[] = []): RbfInfo[][] {
splitTimelines(tree: RbfTree, tail: RbfTree[] = []): RbfTree[][] {
const replacements = [...tail, tree];
if (tree.replaces.length) {
return [].concat(...tree.replaces.map(subtree => this.splitTimelines(subtree, replacements)));
@@ -70,7 +89,7 @@ export class RbfTimelineComponent implements OnInit, OnChanges {
// merges separate leaf-to-root paths into a coherent forking timeline
// represented as a 2D array of Rbf events
prepareTimelines(lines: RbfInfo[][]): RbfInfo[][] {
prepareTimelines(lines: RbfTree[][]): (RbfTree | TimelineCell)[][] {
lines.sort((a, b) => b.length - a.length);
const rows = lines.map(() => []);
@@ -85,7 +104,7 @@ export class RbfTimelineComponent implements OnInit, OnChanges {
let emptyCount = 0;
const nextGroups = [];
for (const group of lineGroups) {
const toMerge: { [txid: string]: RbfInfo[][] } = {};
const toMerge: { [txid: string]: RbfTree[][] } = {};
let emptyInGroup = 0;
let first = true;
for (const line of group) {
@@ -97,7 +116,7 @@ export class RbfTimelineComponent implements OnInit, OnChanges {
} else {
// substitute duplicates with empty cells
// (we'll fill these in with connecting lines later)
rows[index].unshift(null);
rows[index].unshift({ connector: true, replacement: head });
}
// group the tails of the remaining lines for the next iteration
if (line.length) {
@@ -127,7 +146,7 @@ export class RbfTimelineComponent implements OnInit, OnChanges {
}
// annotates a 2D timeline array with info needed to draw connecting lines for multi-replacements
connectTimelines(timelines: RbfInfo[][]): TimelineCell[][] {
connectTimelines(timelines: (RbfTree | TimelineCell)[][]): TimelineCell[][] {
const rows: TimelineCell[][] = [];
timelines.forEach((lines, row) => {
rows.push([]);
@@ -135,11 +154,12 @@ export class RbfTimelineComponent implements OnInit, OnChanges {
let finished = false;
lines.forEach((replacement, column) => {
const cell: TimelineCell = {};
if (replacement) {
cell.replacement = replacement;
if (!isTimelineCell(replacement)) {
cell.replacement = replacement as RbfTree;
cell.fullRbf = (replacement as RbfTree).replacedBy?.fullRbf;
}
rows[row].push(cell);
if (replacement) {
if (!isTimelineCell(replacement)) {
if (!started) {
cell.first = true;
started = true;
@@ -153,11 +173,13 @@ export class RbfTimelineComponent implements OnInit, OnChanges {
matched = true;
} else if (i === row) {
rows[i][column] = {
connector: 'corner'
connector: 'corner',
fullRbf: (replacement as TimelineCell).replacement.tx.fullRbf,
};
} else if (nextCell.connector !== 'corner') {
rows[i][column] = {
connector: 'pipe'
connector: 'pipe',
fullRbf: (replacement as TimelineCell).replacement.tx.fullRbf,
};
}
}