[Refactor] Unify CLTV decode fn.

This commit is contained in:
PortlandHODL 2026-02-23 07:40:56 +00:00
parent de0ddf1b5e
commit 792c5d7509
3 changed files with 47 additions and 56 deletions

View file

@ -1,5 +1,6 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, SimpleChanges } from '@angular/core';
import { SigInfo, SighashLabels } from '@app/shared/transaction.utils';
import { detectCltvTimestamps, formatCltvTimestamp } from '@app/shared/script.utils';
@Component({
selector: 'app-asm',
@ -39,25 +40,7 @@ export class AsmComponent {
parseASM(): void {
const allInstructions = this.asm.split('OP_').filter(instruction => instruction.trim() !== '');
const cltvTimestamps: Map<number, number> = new Map();
allInstructions.forEach((instruction, index, arr) => {
const parts = instruction.split(' ');
const instructionName = parts[0];
const args = parts.slice(1);
if (instructionName === 'PUSHBYTES_4' && args.length > 0 && args[0].length === 8 && /^[0-9a-fA-F]+$/.test(args[0])) {
if (index + 1 < arr.length) {
const nextInstruction = arr[index + 1].split(' ')[0];
if (nextInstruction === 'CLTV') {
const bytes = args[0].match(/.{2}/g) || [];
const littleEndianValue = bytes.reverse().join('');
const timestamp = parseInt(littleEndianValue, 16);
cltvTimestamps.set(index, timestamp);
cltvTimestamps.set(index + 1, timestamp);
}
}
}
});
const cltvTimestamps = detectCltvTimestamps(allInstructions);
let instructions = allInstructions;
if (this.crop && this.asm.length > this.crop) {
@ -110,14 +93,7 @@ export class AsmComponent {
}
formatTimestamp(timestamp: number): string {
if (timestamp < 500000000) {
return `Block height: ${timestamp}`;
}
if (timestamp > 4294967295) {
return `Invalid timestamp: ${timestamp}`;
}
const date = new Date(timestamp * 1000);
return date.toISOString().replace('T', ' ').replace(/\.\d{3}Z$/, ' UTC');
return formatCltvTimestamp(timestamp);
}
readonly opcodeStyles: Map<string, string> = new Map([

View file

@ -1,4 +1,5 @@
import { Pipe, PipeTransform } from '@angular/core';
import { detectCltvTimestamps, formatCltvTimestamp } from '@app/shared/script.utils';
@Pipe({
name: 'asmStyler',
@ -11,27 +12,7 @@ export class AsmStylerPipe implements PipeTransform {
let out = '';
let chars = -3;
// First pass: find CLTV timestamps
const cltvTimestamps: Map<number, number> = new Map();
for (let i = 0; i < instructions.length; i++) {
const instruction = instructions[i];
const parts = instruction.split(' ');
const opcode = parts[0];
const args = parts.slice(1);
if (opcode === 'PUSHBYTES_4' && args.length > 0 && args[0].length === 8 && /^[0-9a-fA-F]+$/.test(args[0])) {
if (i + 1 < instructions.length) {
const nextOpcode = instructions[i + 1].split(' ')[0];
if (nextOpcode === 'CLTV') {
const bytes = args[0].match(/.{2}/g) || [];
const littleEndianValue = bytes.reverse().join('');
const timestamp = parseInt(littleEndianValue, 16);
cltvTimestamps.set(i, timestamp);
cltvTimestamps.set(i + 1, timestamp);
}
}
}
}
const cltvTimestamps = detectCltvTimestamps(instructions);
for (let i = 0; i < instructions.length; i++) {
const instruction = instructions[i];
@ -349,14 +330,7 @@ export class AsmStylerPipe implements PipeTransform {
}
formatTimestamp(timestamp: number): string {
if (timestamp < 500000000) {
return `Block height: ${timestamp}`;
}
if (timestamp > 4294967295) {
return `Invalid timestamp: ${timestamp}`;
}
const date = new Date(timestamp * 1000);
return date.toISOString().replace('T', ' ').replace(/\.\d{3}Z$/, ' UTC');
return formatCltvTimestamp(timestamp);
}
}

View file

@ -555,4 +555,45 @@ export function isPoint(pointHex: string): boolean {
// If we square and it's equal, then it was a perfect root and valid point.
return (y * y) % curveP === ySquared;
}
}
export function detectCltvTimestamps(instructions: string[]): Map<number, number> {
const cltvTimestamps: Map<number, number> = new Map();
for (let i = 0; i < instructions.length; i++) {
const instruction = instructions[i];
const parts = instruction.split(' ');
const opcode = parts[0];
const args = parts.slice(1);
const pushMatch = opcode.match(/^PUSHBYTES_([1-4])$/);
if (pushMatch && args.length > 0) {
const byteCount = parseInt(pushMatch[1], 10);
const expectedLength = byteCount * 2;
if (args[0].length === expectedLength && /^[0-9a-fA-F]+$/.test(args[0])) {
if (i + 1 < instructions.length) {
const nextOpcode = instructions[i + 1].split(' ')[0];
if (nextOpcode === 'CLTV') {
const bytes = args[0].match(/.{2}/g) || [];
const littleEndianValue = bytes.reverse().join('');
const timestamp = parseInt(littleEndianValue, 16);
cltvTimestamps.set(i, timestamp);
cltvTimestamps.set(i + 1, timestamp);
}
}
}
}
}
return cltvTimestamps;
}
export function formatCltvTimestamp(timestamp: number): string {
if (timestamp < 500000000) {
return `Block height: ${timestamp}`;
}
if (timestamp > 4294967295) {
return `Invalid timestamp: ${timestamp}`;
}
const date = new Date(timestamp * 1000);
return date.toISOString().replace('T', ' ').replace(/\.\d{3}Z$/, ' UTC');
}