mirror of
https://github.com/mempool/mempool.git
synced 2025-04-23 23:10:45 +02:00
simple sighash highlighting
This commit is contained in:
parent
86a99d871a
commit
47b28035eb
@ -147,7 +147,7 @@
|
||||
</div>
|
||||
|
||||
|
||||
<app-transactions-list #txList [transactions]="[transaction]" [transactionPage]="true" [txPreview]="true"></app-transactions-list>
|
||||
<app-transactions-list #txList [transactions]="[transaction]" [transactionPage]="true" [txPreview]="true" [signatures]="true"></app-transactions-list>
|
||||
|
||||
<div class="title text-left">
|
||||
<h2 i18n="transaction.details|Transaction Details">Details</h2>
|
||||
|
@ -28,7 +28,8 @@
|
||||
<ng-template ngFor let-vin let-vindex="index" [ngForOf]="tx.vin.slice(0, getVinLimit(tx))" [ngForTrackBy]="trackByIndexFn">
|
||||
<tr [ngClass]="{
|
||||
'assetBox': (assetsMinimal && vin.prevout && assetsMinimal[vin.prevout.asset] && !vin.is_coinbase && vin.prevout.scriptpubkey_address && tx._unblinded) || inputIndex === vindex,
|
||||
'highlight': this.addresses.length && ((vin.prevout?.scriptpubkey_type !== 'p2pk' && addresses.includes(vin.prevout?.scriptpubkey_address)) || this.addresses.includes(vin.prevout?.scriptpubkey.slice(2, -2)))
|
||||
'highlight': this.addresses.length && ((vin.prevout?.scriptpubkey_type !== 'p2pk' && addresses.includes(vin.prevout?.scriptpubkey_address)) || this.addresses.includes(vin.prevout?.scriptpubkey.slice(2, -2))),
|
||||
'sigged': selectedSig && selectedSig.txIndex === i && sigHighlights.vin[vindex],
|
||||
}">
|
||||
<td class="arrow-td">
|
||||
<ng-template [ngIf]="vin.prevout === null && !vin.is_pegin" [ngIfElse]="hasPrevout">
|
||||
@ -54,6 +55,30 @@
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</td>
|
||||
@if (signatures) {
|
||||
<td class="sig-td">
|
||||
<div class="sig-stack">
|
||||
@if (tx['_sigs'][vindex].length === 0) {
|
||||
<span class="sig-key sig-no-lock" title="unsigned">
|
||||
<fa-icon [icon]="['fas', 'lock-open']" [fixedWidth]="true"></fa-icon>
|
||||
</span>
|
||||
} @else {
|
||||
@for (sig of tx['_sigs'][vindex]; track sig.signature; let idx = $index) {
|
||||
@if (idx < 10) {
|
||||
<span class="sig-key sighash-{{sig.sighash}}" (mouseenter)="showSigInfo(i, vindex, sig)" (mouseleave)="hideSigInfo()" [title]="sighashLabels[sig.sighash]">
|
||||
<fa-icon [icon]="['fas', 'key']" [fixedWidth]="true"></fa-icon>
|
||||
</span>
|
||||
}
|
||||
}
|
||||
@if (tx['_sigs'][vindex].length > 10) {
|
||||
<span class="sig-key sig-overflow">
|
||||
+{{ tx['_sigs'][vindex].length - 10 }}
|
||||
</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
}
|
||||
<td class="address-cell">
|
||||
<div [ngSwitch]="true">
|
||||
<ng-container *ngSwitchCase="vin.is_coinbase"><span i18n="transactions-list.coinbase">Coinbase</span><ng-template [ngIf]="network !== 'liquid' && network !== 'liquidtestnet'"> <span i18n="transactions-list.newly-generated-coins">(Newly Generated Coins)</span></ng-template><br /><a placement="bottom" [ngbTooltip]="vin.scriptsig | hex2ascii"><span class="badge badge-secondary scriptmessage longer">{{ vin.scriptsig | hex2ascii }}</span></a></ng-container>
|
||||
@ -106,15 +131,19 @@
|
||||
</tr>
|
||||
<tr *ngIf="showOrdData[tx.txid + '-vin-' + vindex]?.show" [ngClass]="{
|
||||
'assetBox': (assetsMinimal && vin.prevout && assetsMinimal[vin.prevout.asset] && !vin.is_coinbase && vin.prevout.scriptpubkey_address && tx._unblinded) || inputIndex === vindex,
|
||||
'highlight': addresses?.length && (addresses.includes(vin.prevout?.scriptpubkey_address) || (vin.prevout?.scriptpubkey_type === 'p2pk' && addresses.includes(vin.prevout?.scriptpubkey.slice(2, -2))))
|
||||
'highlight': addresses?.length && (addresses.includes(vin.prevout?.scriptpubkey_address) || (vin.prevout?.scriptpubkey_type === 'p2pk' && addresses.includes(vin.prevout?.scriptpubkey.slice(2, -2)))),
|
||||
'sigged': selectedSig && selectedSig.txIndex === i && sigHighlights.vin[vindex],
|
||||
}">
|
||||
<td></td>
|
||||
@if (signatures) {
|
||||
<td></td>
|
||||
}
|
||||
<td colspan="2">
|
||||
<app-ord-data [inscriptions]="showOrdData[tx.txid + '-vin-' + vindex]['inscriptions']" [type]="'vin'"></app-ord-data>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngIf="(showDetails$ | async) === true">
|
||||
<td colspan="3" class="details-container" >
|
||||
<td [attr.colspan]="signatures ? 4 : 3" class="details-container" >
|
||||
<table class="table table-striped table-fixed table-borderless details-table mb-3">
|
||||
<tbody>
|
||||
<ng-template [ngIf]="vin.scriptsig">
|
||||
@ -201,7 +230,7 @@
|
||||
</tr>
|
||||
</ng-template>
|
||||
<tr *ngIf="tx.vin.length > getVinLimit(tx)">
|
||||
<td colspan="3" class="text-center">
|
||||
<td [attr.colspan]="signatures ? 4 : 3" class="text-center">
|
||||
<button class="btn btn-sm btn-primary mt-2" (click)="showMoreInputs(tx)">
|
||||
<span *ngIf="getVinLimit(tx, true) >= tx.vin.length; else showMoreInputsLabel" i18n="show-all">Show all</span>
|
||||
<ng-template #showMoreInputsLabel>
|
||||
@ -221,7 +250,8 @@
|
||||
<ng-template ngFor let-vout let-vindex="index" [ngForOf]="tx.vout.slice(0, getVoutLimit(tx))" [ngForTrackBy]="trackByIndexFn">
|
||||
<tr [ngClass]="{
|
||||
'assetBox': assetsMinimal && assetsMinimal[vout.asset] && vout.scriptpubkey_address && tx.vin && !tx.vin[0].is_coinbase && tx._unblinded || outputIndex === vindex,
|
||||
'highlight': this.addresses.length && ((vout.scriptpubkey_type !== 'p2pk' && addresses.includes(vout.scriptpubkey_address)) || this.addresses.includes(vout.scriptpubkey.slice(2, -2)))
|
||||
'highlight': this.addresses.length && ((vout.scriptpubkey_type !== 'p2pk' && addresses.includes(vout.scriptpubkey_address)) || this.addresses.includes(vout.scriptpubkey.slice(2, -2))),
|
||||
'sigged': selectedSig && selectedSig.txIndex === i && sigHighlights.vout[vindex],
|
||||
}">
|
||||
<td class="address-cell">
|
||||
<app-address-text
|
||||
@ -303,14 +333,15 @@
|
||||
|
||||
<tr *ngIf="showOrdData[tx.txid + '-vout-' + vindex]?.show" [ngClass]="{
|
||||
'assetBox': assetsMinimal && assetsMinimal[vout.asset] && vout.scriptpubkey_address && tx.vin && !tx.vin[0].is_coinbase && tx._unblinded || outputIndex === vindex,
|
||||
'highlight': addresses?.length && (addresses.includes(vout.scriptpubkey_address) || (vout.scriptpubkey_type === 'p2pk' && addresses.includes(vout.scriptpubkey.slice(2, -2))))
|
||||
'highlight': addresses?.length && (addresses.includes(vout.scriptpubkey_address) || (vout.scriptpubkey_type === 'p2pk' && addresses.includes(vout.scriptpubkey.slice(2, -2)))),
|
||||
'sigged': selectedSig && selectedSig.txIndex === i && sigHighlights.vout[vindex],
|
||||
}">
|
||||
<td colspan="3">
|
||||
<app-ord-data [runestone]="showOrdData[tx.txid + '-vout-' + vindex]['runestone']" [runeInfo]="showOrdData[tx.txid + '-vout-' + vindex]['runeInfo']" [type]="'vout'"></app-ord-data>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngIf="(showDetails$ | async) === true">
|
||||
<td colspan="3" class=" details-container" >
|
||||
<td [attr.colspan]="signatures ? 4 : 3" class=" details-container" >
|
||||
<table class="table table-striped table-borderless details-table mb-3">
|
||||
<tbody>
|
||||
<tr>
|
||||
@ -335,7 +366,7 @@
|
||||
</tr>
|
||||
</ng-template>
|
||||
<tr *ngIf="tx.vout.length > getVoutLimit(tx)">
|
||||
<td colspan="3" class="text-center">
|
||||
<td [attr.colspan]="3" class="text-center">
|
||||
<button class="btn btn-sm btn-primary mt-2" (click)="showMoreOutputs(tx)">
|
||||
<span *ngIf="getVoutLimit(tx, true) >= tx.vout.length; else showMoreOutputsLabel" i18n="show-all">Show all</span>
|
||||
<ng-template #showMoreOutputsLabel>
|
||||
|
@ -1,3 +1,17 @@
|
||||
.col {
|
||||
&:first-child {
|
||||
padding-right: 0;
|
||||
td:last-child {
|
||||
padding-right: calc(0.3em + 15px);
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
padding-left: 0;
|
||||
td:first-child {
|
||||
padding-left: calc(0.3em + 15px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.arrow-td {
|
||||
width: 30px;
|
||||
@ -24,6 +38,103 @@
|
||||
color: var(--grey);
|
||||
}
|
||||
|
||||
.sig-td {
|
||||
width: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sig-stack {
|
||||
position: relative;
|
||||
width: 30px;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.sig-td:hover {
|
||||
.sig-stack {
|
||||
.sig-key {
|
||||
@for $i from 1 through 10 {
|
||||
&:nth-child(#{$i}) {
|
||||
transform: translate(#{($i - 1) * 6}px, #{($i - 1) * 6}px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sig-key {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease;
|
||||
pointer-events: none;
|
||||
// opacity: 0.8;
|
||||
|
||||
&.sighash-0 {
|
||||
--keycolor: var(--green);
|
||||
}
|
||||
&.sighash-1 {
|
||||
--keycolor: var(--green);
|
||||
}
|
||||
&.sighash-2 {
|
||||
--keycolor: gold;
|
||||
}
|
||||
&.sighash-3 {
|
||||
--keycolor: cornflowerblue;
|
||||
}
|
||||
&.sighash-129 {
|
||||
--keycolor: darkviolet;
|
||||
}
|
||||
&.sighash-130 {
|
||||
--keycolor: darkorange;
|
||||
}
|
||||
&.sighash-131 {
|
||||
--keycolor: var(--pink);
|
||||
}
|
||||
&.sig-no-lock {
|
||||
--keycolor: var(--red);
|
||||
}
|
||||
color: var(--keycolor);
|
||||
|
||||
@for $i from 1 through 3 {
|
||||
&:nth-child(#{$i}) {
|
||||
transform: translate(#{($i - 1) * 3}px, #{($i - 1) * 3}px);
|
||||
color: color-mix(in srgb, var(--keycolor) #{100 - ($i - 1) * 20} + '%', white);
|
||||
z-index: #{10 - $i};
|
||||
}
|
||||
}
|
||||
@for $i from 4 through 10 {
|
||||
&:nth-child(#{$i}) {
|
||||
transform: translate(9px, 9px);
|
||||
color: color-mix(in srgb, var(--keycolor) 60%, white);
|
||||
z-index: #{10 - $i};
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
// opacity: 1;
|
||||
color: color-mix(in srgb, var(--keycolor) 80%, black);
|
||||
}
|
||||
|
||||
::ng-deep svg path {
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.sig-overflow {
|
||||
// background-color: var(--tertiary);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.mobile-bottomcol {
|
||||
margin-top: 15px;
|
||||
@media (min-width: 992px) {
|
||||
@ -142,6 +253,10 @@ h2 {
|
||||
background-color: var(--stat-box-bg);
|
||||
}
|
||||
|
||||
.sigged {
|
||||
background-color: #ffffff22;
|
||||
}
|
||||
|
||||
.summary {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import { OrdApiService } from '@app/services/ord-api.service';
|
||||
import { Inscription } from '@app/shared/ord/inscription.utils';
|
||||
import { Etching, Runestone } from '@app/shared/ord/rune.utils';
|
||||
import { ADDRESS_SIMILARITY_THRESHOLD, AddressMatch, AddressSimilarity, AddressType, AddressTypeInfo, checkedCompareAddressStrings, detectAddressType } from '@app/shared/address-utils';
|
||||
import { processInputSignatures, Sighash, SigInfo } from '../../shared/transaction.utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-transactions-list',
|
||||
@ -39,6 +40,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
||||
@Input() rowLimit = 12;
|
||||
@Input() blockTime: number = 0; // Used for price calculation if all the transactions are in the same block
|
||||
@Input() txPreview = false;
|
||||
@Input() signatures = true;
|
||||
|
||||
@Output() loadMore = new EventEmitter();
|
||||
|
||||
@ -58,6 +60,18 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
||||
showOrdData: { [key: string]: { show: boolean; inscriptions?: Inscription[]; runestone?: Runestone, runeInfo?: { [id: string]: { etching: Etching; txid: string; } }; } } = {};
|
||||
similarityMatches: Map<string, Map<string, { score: number, match: AddressMatch, group: number }>> = new Map();
|
||||
|
||||
selectedSig: { txIndex: number, vindex: number, sig: SigInfo } | null = null;
|
||||
sigHighlights: { vin: boolean[], vout: boolean[] } = { vin: [], vout: [] };
|
||||
sighashLabels: { [sighash: string]: string } = {
|
||||
'0': 'SIGHASH_DEFAULT',
|
||||
'1': 'SIGHASH_ALL',
|
||||
'2': 'SIGHASH_NONE',
|
||||
'3': 'SIGHASH_SINGLE',
|
||||
'129': 'SIGHASH_ALL | ACP',
|
||||
'130': 'SIGHASH_NONE | ACP',
|
||||
'131': 'SIGHASH_SINGLE | ACP',
|
||||
};
|
||||
|
||||
constructor(
|
||||
public stateService: StateService,
|
||||
private cacheService: CacheService,
|
||||
@ -278,6 +292,9 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// process signature data
|
||||
tx['_sigs'] = tx.vin.map(vin => processInputSignatures(vin));
|
||||
}
|
||||
|
||||
tx.largeInput = tx.largeInput || tx.vin.some(vin => (vin?.prevout?.value > 1000000000));
|
||||
@ -500,6 +517,32 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
showSigInfo(txIndex: number, vindex: number, sig: SigInfo): void {
|
||||
this.selectedSig = { txIndex, vindex, sig };
|
||||
this.sigHighlights = { vin: [], vout: [] };
|
||||
for (let i = 0; i < this.transactions[txIndex].vin.length; i++) {
|
||||
this.sigHighlights.vin.push(
|
||||
i === vindex ||
|
||||
!(Sighash.isACP(sig.sighash))
|
||||
);
|
||||
}
|
||||
for (let i = 0; i < this.transactions[txIndex].vout.length; i++) {
|
||||
this.sigHighlights.vout.push(
|
||||
!(Sighash.isNone(sig.sighash)) && (
|
||||
!(Sighash.isSingle(sig.sighash)) ||
|
||||
i === vindex
|
||||
)
|
||||
);
|
||||
}
|
||||
this.ref.markForCheck();
|
||||
}
|
||||
|
||||
hideSigInfo(): void {
|
||||
this.selectedSig = null;
|
||||
this.sigHighlights = { vin: [], vout: [] };
|
||||
this.ref.markForCheck();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.outspendsSubscription.unsubscribe();
|
||||
this.currencyChangeSubscription?.unsubscribe();
|
||||
|
@ -1,3 +1,6 @@
|
||||
import { Vin } from "../interfaces/electrs.interface";
|
||||
import { AddressType, detectAddressType } from "./address-utils";
|
||||
|
||||
const opcodes = {
|
||||
OP_FALSE: 0,
|
||||
OP_0: 0,
|
||||
|
@ -7,7 +7,7 @@ import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, fa
|
||||
faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft,
|
||||
faFastForward, faWallet, faUserClock, faWrench, faUserFriends, faQuestionCircle, faHistory, faSignOutAlt, faKey, faSuitcase, faIdCardAlt, faNetworkWired, faUserCheck,
|
||||
faCircleCheck, faUserCircle, faCheck, faRocket, faScaleBalanced, faHourglassStart, faHourglassHalf, faHourglassEnd, faWandMagicSparkles, faFaucetDrip, faTimeline,
|
||||
faCircleXmark, faCalendarCheck, faMoneyBillTrendUp, faRobot, faShareNodes, faCreditCard, faMicroscope, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
|
||||
faCircleXmark, faCalendarCheck, faMoneyBillTrendUp, faRobot, faShareNodes, faCreditCard, faMicroscope, faExclamationTriangle, faLockOpen } from '@fortawesome/free-solid-svg-icons';
|
||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
||||
import { MenuComponent } from '@components/menu/menu.component';
|
||||
import { PreviewTitleComponent } from '@components/master-page-preview/preview-title.component';
|
||||
@ -467,5 +467,6 @@ export class SharedModule {
|
||||
library.addIcons(faCreditCard);
|
||||
library.addIcons(faMicroscope);
|
||||
library.addIcons(faExclamationTriangle);
|
||||
library.addIcons(faLockOpen);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import { Transaction, Vin } from '@interfaces/electrs.interface';
|
||||
import { CpfpInfo, RbfInfo, TransactionStripped } from '@interfaces/node-api.interface';
|
||||
import { StateService } from '@app/services/state.service';
|
||||
import { hash, Hash } from './sha256';
|
||||
import { AddressType } from './address-utils';
|
||||
|
||||
// Bitcoin Core default policy settings
|
||||
const MAX_STANDARD_TX_WEIGHT = 400_000;
|
||||
@ -85,6 +86,154 @@ export function isDERSig(w: string): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
export enum SighashFlag {
|
||||
DEFAULT = 0,
|
||||
ALL = 1,
|
||||
NONE = 2,
|
||||
SINGLE = 3,
|
||||
ANYONECANPAY = 0x80
|
||||
}
|
||||
|
||||
export type SighashValue =
|
||||
SighashFlag.DEFAULT |
|
||||
SighashFlag.ALL |
|
||||
SighashFlag.NONE |
|
||||
SighashFlag.SINGLE |
|
||||
(SighashFlag.ALL & SighashFlag.ANYONECANPAY) |
|
||||
(SighashFlag.NONE & SighashFlag.ANYONECANPAY) |
|
||||
(SighashFlag.SINGLE & SighashFlag.ANYONECANPAY) |
|
||||
(SighashFlag.ALL & SighashFlag.NONE);
|
||||
|
||||
export interface SigInfo {
|
||||
signature: string;
|
||||
sighash: SighashValue;
|
||||
}
|
||||
|
||||
export class Sighash {
|
||||
static isACP(val: SighashValue): boolean {
|
||||
return val >= SighashFlag.ANYONECANPAY;
|
||||
}
|
||||
|
||||
static isNone(val: SighashValue): boolean {
|
||||
return (val & 0x7F) === SighashFlag.NONE;
|
||||
}
|
||||
|
||||
static isSingle(val: SighashValue): boolean {
|
||||
return (val & 0x7F) === SighashFlag.SINGLE;
|
||||
}
|
||||
|
||||
static isAll(val: SighashValue): boolean {
|
||||
return (val & 0x7F) === SighashFlag.ALL;
|
||||
}
|
||||
|
||||
static isDefault(val: SighashValue): boolean {
|
||||
return val === SighashFlag.DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
export function decodeSighashFlag(sighash: number): SighashValue {
|
||||
if (sighash >= 0 && sighash <= 0x03 || sighash > 0x80 && sighash <= 0x83) {
|
||||
return sighash as SighashValue;
|
||||
}
|
||||
return SighashFlag.DEFAULT;
|
||||
}
|
||||
|
||||
export function extractDERSignaturesWitness(witness: string[]): SigInfo[] {
|
||||
if (!witness?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const signatures: SigInfo[] = [];
|
||||
|
||||
for (const w of witness) {
|
||||
if (isDERSig(w)) {
|
||||
signatures.push({
|
||||
signature: w,
|
||||
sighash: decodeSighashFlag(parseInt(w.slice(-2), 16)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return signatures;
|
||||
}
|
||||
|
||||
export function extractDERSignaturesASM(script_asm: string): SigInfo[] {
|
||||
if (!script_asm) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const signatures: SigInfo[] = [];
|
||||
const ops = script_asm.split(' ');
|
||||
|
||||
for (let i = 0; i < ops.length - 1; i++) {
|
||||
// Look for OP_PUSHBYTES_N followed by a hex string
|
||||
if (ops[i].startsWith('OP_PUSHBYTES_')) {
|
||||
const hexData = ops[i + 1];
|
||||
if (isDERSig(hexData)) {
|
||||
const sighash = decodeSighashFlag(parseInt(hexData.slice(-2), 16));
|
||||
signatures.push({
|
||||
signature: hexData.slice(0, -2), // Remove sighash byte
|
||||
sighash
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return signatures;
|
||||
}
|
||||
|
||||
export function extractSchnorrSignatures(witnesses: string[]): SigInfo[] {
|
||||
if (!witnesses?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const signatures: SigInfo[] = [];
|
||||
|
||||
for (const witness of witnesses) {
|
||||
if (witness.length === 130) {
|
||||
signatures.push({
|
||||
signature: witness,
|
||||
sighash: decodeSighashFlag(parseInt(witness.slice(-2), 16)),
|
||||
});
|
||||
} else if (witness.length === 128) {
|
||||
signatures.push({
|
||||
signature: witness,
|
||||
sighash: SighashFlag.DEFAULT,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return signatures;
|
||||
}
|
||||
|
||||
export function processInputSignatures(vin: Vin): SigInfo[] {
|
||||
const addressType = vin.prevout?.scriptpubkey_type as AddressType;
|
||||
let signatures: SigInfo[] = [];
|
||||
switch(addressType) {
|
||||
case 'p2pk':
|
||||
case 'multisig':
|
||||
case 'p2pkh':
|
||||
signatures = extractDERSignaturesASM(vin.scriptsig_asm);
|
||||
break;
|
||||
case 'p2sh':
|
||||
signatures = [...extractDERSignaturesASM(vin.scriptsig_asm), ...extractDERSignaturesASM(vin.inner_redeemscript_asm), ...extractDERSignaturesWitness(vin.witness || [])];
|
||||
break;
|
||||
case 'v0_p2wpkh':
|
||||
signatures = extractDERSignaturesWitness(vin.witness || []);
|
||||
break;
|
||||
case 'v0_p2wsh':
|
||||
signatures = extractDERSignaturesWitness(vin.witness || []);
|
||||
break;
|
||||
case 'v1_p2tr':
|
||||
signatures = extractSchnorrSignatures(vin.witness.slice(0, vin.witness.length - ((vin.witness.length > 1 && vin.witness[vin.witness.length - 1].startsWith('50')) ? 1 : 0)));
|
||||
break;
|
||||
default:
|
||||
// non-signed input types?
|
||||
break;
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates most standardness rules
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user