Merge branch 'master' into orangeusurf/about-enterprise-update
This commit is contained in:
		
						commit
						263742132c
					
				| @ -323,6 +323,7 @@ class BitcoinApi implements AbstractBitcoinApi { | ||||
|       'witness_v1_taproot': 'v1_p2tr', | ||||
|       'nonstandard': 'nonstandard', | ||||
|       'multisig': 'multisig', | ||||
|       'anchor': 'anchor', | ||||
|       'nulldata': 'op_return' | ||||
|     }; | ||||
| 
 | ||||
|  | ||||
| @ -219,10 +219,10 @@ class Blocks { | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   public summarizeBlockTransactions(hash: string, transactions: TransactionExtended[]): BlockSummary { | ||||
|   public summarizeBlockTransactions(hash: string, height: number, transactions: TransactionExtended[]): BlockSummary { | ||||
|     return { | ||||
|       id: hash, | ||||
|       transactions: Common.classifyTransactions(transactions), | ||||
|       transactions: Common.classifyTransactions(transactions, height), | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
| @ -616,7 +616,7 @@ class Blocks { | ||||
|           // add CPFP
 | ||||
|           const cpfpSummary = calculateGoodBlockCpfp(height, txs, []); | ||||
|           // classify
 | ||||
|           const { transactions: classifiedTxs } = this.summarizeBlockTransactions(blockHash, cpfpSummary.transactions); | ||||
|           const { transactions: classifiedTxs } = this.summarizeBlockTransactions(blockHash, height, cpfpSummary.transactions); | ||||
|           await BlocksSummariesRepository.$saveTransactions(height, blockHash, classifiedTxs, 2); | ||||
|           if (unclassifiedBlocks[height].version < 2 && targetSummaryVersion === 2) { | ||||
|             const cpfpClusters = await CpfpRepository.$getClustersAt(height); | ||||
| @ -653,7 +653,7 @@ class Blocks { | ||||
|             } | ||||
|             const cpfpSummary = calculateGoodBlockCpfp(height, templateTxs?.filter(tx => tx['effectiveFeePerVsize'] != null) as MempoolTransactionExtended[], []); | ||||
|             // classify
 | ||||
|             const { transactions: classifiedTxs } = this.summarizeBlockTransactions(blockHash, cpfpSummary.transactions); | ||||
|             const { transactions: classifiedTxs } = this.summarizeBlockTransactions(blockHash, height, cpfpSummary.transactions); | ||||
|             const classifiedTxMap: { [txid: string]: TransactionClassified } = {}; | ||||
|             for (const tx of classifiedTxs) { | ||||
|               classifiedTxMap[tx.txid] = tx; | ||||
| @ -912,7 +912,7 @@ class Blocks { | ||||
|       } | ||||
|       const cpfpSummary: CpfpSummary = calculateGoodBlockCpfp(block.height, transactions, accelerations.map(a => ({ txid: a.txid, max_bid: a.feeDelta }))); | ||||
|       const blockExtended: BlockExtended = await this.$getBlockExtended(block, cpfpSummary.transactions); | ||||
|       const blockSummary: BlockSummary = this.summarizeBlockTransactions(block.id, cpfpSummary.transactions); | ||||
|       const blockSummary: BlockSummary = this.summarizeBlockTransactions(block.id, block.height, cpfpSummary.transactions); | ||||
|       this.updateTimerProgress(timer, `got block data for ${this.currentBlockHeight}`); | ||||
| 
 | ||||
|       if (Common.indexingEnabled()) { | ||||
| @ -1169,7 +1169,7 @@ class Blocks { | ||||
|         transactions: cpfpSummary.transactions.map(tx => { | ||||
|           let flags: number = 0; | ||||
|           try { | ||||
|             flags = Common.getTransactionFlags(tx); | ||||
|             flags = Common.getTransactionFlags(tx, height); | ||||
|           } catch (e) { | ||||
|             logger.warn('Failed to classify transaction: ' + (e instanceof Error ? e.message : e)); | ||||
|           } | ||||
| @ -1188,7 +1188,7 @@ class Blocks { | ||||
|     } else { | ||||
|       if (config.MEMPOOL.BACKEND === 'esplora') { | ||||
|         const txs = (await bitcoinApi.$getTxsForBlock(hash)).map(tx => transactionUtils.extendTransaction(tx)); | ||||
|         summary = this.summarizeBlockTransactions(hash, txs); | ||||
|         summary = this.summarizeBlockTransactions(hash, height || 0, txs); | ||||
|         summaryVersion = 1; | ||||
|       } else { | ||||
|         // Call Core RPC
 | ||||
| @ -1324,7 +1324,7 @@ class Blocks { | ||||
|           let summaryVersion = 0; | ||||
|           if (config.MEMPOOL.BACKEND === 'esplora') { | ||||
|             const txs = (await bitcoinApi.$getTxsForBlock(cleanBlock.hash)).map(tx => transactionUtils.extendTransaction(tx)); | ||||
|             summary = this.summarizeBlockTransactions(cleanBlock.hash, txs); | ||||
|             summary = this.summarizeBlockTransactions(cleanBlock.hash, cleanBlock.height, txs); | ||||
|             summaryVersion = 1; | ||||
|           } else { | ||||
|             // Call Core RPC
 | ||||
|  | ||||
| @ -10,7 +10,6 @@ import logger from '../logger'; | ||||
| import { getVarIntLength, opcodes, parseMultisigScript } from '../utils/bitcoin-script'; | ||||
| 
 | ||||
| // Bitcoin Core default policy settings
 | ||||
| const TX_MAX_STANDARD_VERSION = 2; | ||||
| const MAX_STANDARD_TX_WEIGHT = 400_000; | ||||
| const MAX_BLOCK_SIGOPS_COST = 80_000; | ||||
| const MAX_STANDARD_TX_SIGOPS_COST = (MAX_BLOCK_SIGOPS_COST / 5); | ||||
| @ -200,10 +199,13 @@ export class Common { | ||||
|    * | ||||
|    * returns true early if any standardness rule is violated, otherwise false | ||||
|    * (except for non-mandatory-script-verify-flag and p2sh script evaluation rules which are *not* enforced) | ||||
|    * | ||||
|    * As standardness rules change, we'll need to apply the rules in force *at the time* to older blocks. | ||||
|    * For now, just pull out individual rules into versioned functions where necessary. | ||||
|    */ | ||||
|   static isNonStandard(tx: TransactionExtended): boolean { | ||||
|   static isNonStandard(tx: TransactionExtended, height?: number): boolean { | ||||
|     // version
 | ||||
|     if (tx.version > TX_MAX_STANDARD_VERSION) { | ||||
|     if (this.isNonStandardVersion(tx, height)) { | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
| @ -250,6 +252,8 @@ export class Common { | ||||
|         } | ||||
|       } else if (['unknown', 'provably_unspendable', 'empty'].includes(vin.prevout?.scriptpubkey_type || '')) { | ||||
|         return true; | ||||
|       } else if (this.isNonStandardAnchor(tx, height)) { | ||||
|         return true; | ||||
|       } | ||||
|       // TODO: bad-witness-nonstandard
 | ||||
|     } | ||||
| @ -335,6 +339,49 @@ export class Common { | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   // Individual versioned standardness rules
 | ||||
| 
 | ||||
|   static V3_STANDARDNESS_ACTIVATION_HEIGHT = { | ||||
|     'testnet4': 42_000, | ||||
|     'testnet': 2_900_000, | ||||
|     'signet': 211_000, | ||||
|     '': 863_500, | ||||
|   }; | ||||
|   static isNonStandardVersion(tx: TransactionExtended, height?: number): boolean { | ||||
|     let TX_MAX_STANDARD_VERSION = 3; | ||||
|     if ( | ||||
|       height != null | ||||
|       && this.V3_STANDARDNESS_ACTIVATION_HEIGHT[config.MEMPOOL.NETWORK] | ||||
|       && height <= this.V3_STANDARDNESS_ACTIVATION_HEIGHT[config.MEMPOOL.NETWORK] | ||||
|     ) { | ||||
|       // V3 transactions were non-standard to spend before v28.x (scheduled for 2024/09/30 https://github.com/bitcoin/bitcoin/issues/29891)
 | ||||
|       TX_MAX_STANDARD_VERSION = 2; | ||||
|     } | ||||
| 
 | ||||
|     if (tx.version > TX_MAX_STANDARD_VERSION) { | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   static ANCHOR_STANDARDNESS_ACTIVATION_HEIGHT = { | ||||
|     'testnet4': 42_000, | ||||
|     'testnet': 2_900_000, | ||||
|     'signet': 211_000, | ||||
|     '': 863_500, | ||||
|   }; | ||||
|   static isNonStandardAnchor(tx: TransactionExtended, height?: number): boolean { | ||||
|     if ( | ||||
|       height != null | ||||
|       && this.ANCHOR_STANDARDNESS_ACTIVATION_HEIGHT[config.MEMPOOL.NETWORK] | ||||
|       && height <= this.ANCHOR_STANDARDNESS_ACTIVATION_HEIGHT[config.MEMPOOL.NETWORK] | ||||
|     ) { | ||||
|       // anchor outputs were non-standard to spend before v28.x (scheduled for 2024/09/30 https://github.com/bitcoin/bitcoin/issues/29891)
 | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   static getNonWitnessSize(tx: TransactionExtended): number { | ||||
|     let weight = tx.weight; | ||||
|     let hasWitness = false; | ||||
| @ -415,7 +462,7 @@ export class Common { | ||||
|     return flags; | ||||
|   } | ||||
| 
 | ||||
|   static getTransactionFlags(tx: TransactionExtended): number { | ||||
|   static getTransactionFlags(tx: TransactionExtended, height?: number): number { | ||||
|     let flags = tx.flags ? BigInt(tx.flags) : 0n; | ||||
| 
 | ||||
|     // Update variable flags (CPFP, RBF)
 | ||||
| @ -564,17 +611,17 @@ export class Common { | ||||
|       flags |= TransactionFlags.batch_payout; | ||||
|     } | ||||
| 
 | ||||
|     if (this.isNonStandard(tx)) { | ||||
|     if (this.isNonStandard(tx, height)) { | ||||
|       flags |= TransactionFlags.nonstandard; | ||||
|     } | ||||
| 
 | ||||
|     return Number(flags); | ||||
|   } | ||||
| 
 | ||||
|   static classifyTransaction(tx: TransactionExtended): TransactionClassified { | ||||
|   static classifyTransaction(tx: TransactionExtended, height?: number): TransactionClassified { | ||||
|     let flags = 0; | ||||
|     try { | ||||
|       flags = Common.getTransactionFlags(tx); | ||||
|       flags = Common.getTransactionFlags(tx, height); | ||||
|     } catch (e) { | ||||
|       logger.warn('Failed to add classification flags to transaction: ' + (e instanceof Error ? e.message : e)); | ||||
|     } | ||||
| @ -585,8 +632,8 @@ export class Common { | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   static classifyTransactions(txs: TransactionExtended[]): TransactionClassified[] { | ||||
|     return txs.map(Common.classifyTransaction); | ||||
|   static classifyTransactions(txs: TransactionExtended[], height?: number): TransactionClassified[] { | ||||
|     return txs.map(tx => Common.classifyTransaction(tx, height)); | ||||
|   } | ||||
| 
 | ||||
|   static stripTransaction(tx: TransactionExtended): TransactionStripped { | ||||
|  | ||||
| @ -1106,7 +1106,7 @@ class BlocksRepository { | ||||
|         let summaryVersion = 0; | ||||
|         if (config.MEMPOOL.BACKEND === 'esplora') { | ||||
|           const txs = (await bitcoinApi.$getTxsForBlock(dbBlk.id)).map(tx => transactionUtils.extendTransaction(tx)); | ||||
|           summary = blocks.summarizeBlockTransactions(dbBlk.id, txs); | ||||
|           summary = blocks.summarizeBlockTransactions(dbBlk.id, dbBlk.height, txs); | ||||
|           summaryVersion = 1; | ||||
|         } else { | ||||
|           // Call Core RPC
 | ||||
|  | ||||
| @ -158,7 +158,7 @@ export function parseMultisigScript(script: string): void | { m: number, n: numb | ||||
|   if (!opN) { | ||||
|     return; | ||||
|   } | ||||
|   if (!opN.startsWith('OP_PUSHNUM_')) { | ||||
|   if (opN !== 'OP_0' && !opN.startsWith('OP_PUSHNUM_')) { | ||||
|     return; | ||||
|   } | ||||
|   const n = parseInt(opN.match(/[0-9]+/)?.[0] || '', 10); | ||||
| @ -178,7 +178,7 @@ export function parseMultisigScript(script: string): void | { m: number, n: numb | ||||
|   if (!opM) { | ||||
|     return; | ||||
|   } | ||||
|   if (!opM.startsWith('OP_PUSHNUM_')) { | ||||
|   if (opM !== 'OP_0' && !opM.startsWith('OP_PUSHNUM_')) { | ||||
|     return; | ||||
|   } | ||||
|   const m = parseInt(opM.match(/[0-9]+/)?.[0] || '', 10); | ||||
|  | ||||
| @ -135,7 +135,7 @@ export function parseMultisigScript(script: string): void | { m: number, n: numb | ||||
|     return; | ||||
|   } | ||||
|   const opN = ops.pop(); | ||||
|   if (!opN.startsWith('OP_PUSHNUM_')) { | ||||
|   if (opN !== 'OP_0' && !opN.startsWith('OP_PUSHNUM_')) { | ||||
|     return; | ||||
|   } | ||||
|   const n = parseInt(opN.match(/[0-9]+/)[0], 10); | ||||
| @ -152,7 +152,7 @@ export function parseMultisigScript(script: string): void | { m: number, n: numb | ||||
|     } | ||||
|   } | ||||
|   const opM = ops.pop(); | ||||
|   if (!opM.startsWith('OP_PUSHNUM_')) { | ||||
|   if (opM !== 'OP_0' && !opM.startsWith('OP_PUSHNUM_')) { | ||||
|     return; | ||||
|   } | ||||
|   const m = parseInt(opM.match(/[0-9]+/)[0], 10); | ||||
|  | ||||
| @ -55,7 +55,7 @@ export class AddressLabelsComponent implements OnChanges { | ||||
|   } | ||||
| 
 | ||||
|   handleVin() { | ||||
|     const address = new AddressTypeInfo(this.network || 'mainnet', this.vin.prevout?.scriptpubkey_address, this.vin.prevout?.scriptpubkey_type as AddressType, [this.vin]) | ||||
|     const address = new AddressTypeInfo(this.network || 'mainnet', this.vin.prevout?.scriptpubkey_address, this.vin.prevout?.scriptpubkey_type as AddressType, [this.vin]); | ||||
|     if (address?.scripts.size) { | ||||
|       const script = address?.scripts.values().next().value; | ||||
|       if (script.template?.label) { | ||||
|  | ||||
| @ -747,7 +747,7 @@ export class TrackerComponent implements OnInit, OnDestroy { | ||||
| 
 | ||||
|   checkAccelerationEligibility() { | ||||
|     if (this.tx) { | ||||
|       this.tx.flags = getTransactionFlags(this.tx); | ||||
|       this.tx.flags = getTransactionFlags(this.tx, null, null, this.tx.status?.block_time, this.stateService.network); | ||||
|       const replaceableInputs = (this.tx.flags & (TransactionFlags.sighash_none | TransactionFlags.sighash_acp)) > 0n; | ||||
|       const highSigop = (this.tx.sigops * 20) > this.tx.weight; | ||||
|       this.eligibleForAcceleration = !replaceableInputs && !highSigop; | ||||
|  | ||||
| @ -901,7 +901,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | ||||
|       this.segwitEnabled = !this.tx.status.confirmed || isFeatureActive(this.stateService.network, this.tx.status.block_height, 'segwit'); | ||||
|       this.taprootEnabled = !this.tx.status.confirmed || isFeatureActive(this.stateService.network, this.tx.status.block_height, 'taproot'); | ||||
|       this.rbfEnabled = !this.tx.status.confirmed || isFeatureActive(this.stateService.network, this.tx.status.block_height, 'rbf'); | ||||
|       this.tx.flags = getTransactionFlags(this.tx); | ||||
|       this.tx.flags = getTransactionFlags(this.tx, null, null, this.tx.status?.block_time, this.stateService.network); | ||||
|       this.filters = this.tx.flags ? toFilters(this.tx.flags).filter(f => f.txPage) : []; | ||||
|       this.checkAccelerationEligibility(); | ||||
|     } else { | ||||
|  | ||||
| @ -17,6 +17,7 @@ export type AddressType = 'fee' | ||||
|   | 'v0_p2wsh' | ||||
|   | 'v1_p2tr' | ||||
|   | 'confidential' | ||||
|   | 'anchor' | ||||
|   | 'unknown' | ||||
| 
 | ||||
| const ADDRESS_PREFIXES = { | ||||
| @ -188,6 +189,12 @@ export class AddressTypeInfo { | ||||
|         const v = vin[0]; | ||||
|         this.processScript(new ScriptInfo('scriptpubkey', v.prevout.scriptpubkey, v.prevout.scriptpubkey_asm)); | ||||
|       } | ||||
|     } else if (this.type === 'unknown') { | ||||
|       for (const v of vin) { | ||||
|         if (v.prevout?.scriptpubkey === '51024e73') { | ||||
|           this.type = 'anchor'; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     // and there's nothing more to learn from processing inputs for other types
 | ||||
|   } | ||||
| @ -197,6 +204,10 @@ export class AddressTypeInfo { | ||||
|       if (!this.scripts.size) { | ||||
|         this.processScript(new ScriptInfo('scriptpubkey', output.scriptpubkey, output.scriptpubkey_asm)); | ||||
|       } | ||||
|     } else if (this.type === 'unknown') { | ||||
|       if (output.scriptpubkey === '51024e73') { | ||||
|         this.type = 'anchor'; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -20,6 +20,9 @@ | ||||
|   @case ('multisig') { | ||||
|     <span i18n="address.bare-multisig">bare multisig</span> | ||||
|   } | ||||
|   @case ('anchor') { | ||||
|     <span>anchor</span> | ||||
|   } | ||||
|   @case (null) { | ||||
|     <span>unknown</span> | ||||
|   } | ||||
|  | ||||
| @ -166,6 +166,7 @@ export const ScriptTemplates: { [type: string]: (...args: any) => ScriptTemplate | ||||
|   ln_anchor: () => ({ type: 'ln_anchor', label: 'Lightning Anchor' }), | ||||
|   ln_anchor_swept: () => ({ type: 'ln_anchor_swept', label: 'Swept Lightning Anchor' }), | ||||
|   multisig: (m: number, n: number) => ({ type: 'multisig', m, n, label: $localize`:@@address-label.multisig:Multisig ${m}:multisigM: of ${n}:multisigN:` }), | ||||
|   anchor: () => ({ type: 'anchor', label: 'anchor' }), | ||||
| }; | ||||
| 
 | ||||
| export class ScriptInfo { | ||||
| @ -266,7 +267,7 @@ export function parseMultisigScript(script: string): undefined | { m: number, n: | ||||
|   if (!opN) { | ||||
|     return; | ||||
|   } | ||||
|   if (!opN.startsWith('OP_PUSHNUM_')) { | ||||
|   if (opN !== 'OP_0' && !opN.startsWith('OP_PUSHNUM_')) { | ||||
|     return; | ||||
|   } | ||||
|   const n = parseInt(opN.match(/[0-9]+/)?.[0] || '', 10); | ||||
| @ -286,7 +287,7 @@ export function parseMultisigScript(script: string): undefined | { m: number, n: | ||||
|   if (!opM) { | ||||
|     return; | ||||
|   } | ||||
|   if (!opM.startsWith('OP_PUSHNUM_')) { | ||||
|   if (opM !== 'OP_0' && !opM.startsWith('OP_PUSHNUM_')) { | ||||
|     return; | ||||
|   } | ||||
|   const m = parseInt(opM.match(/[0-9]+/)?.[0] || '', 10); | ||||
|  | ||||
| @ -2,9 +2,9 @@ import { TransactionFlags } from './filters.utils'; | ||||
| import { getVarIntLength, opcodes, parseMultisigScript, isPoint } from './script.utils'; | ||||
| import { Transaction } from '../interfaces/electrs.interface'; | ||||
| import { CpfpInfo, RbfInfo, TransactionStripped } from '../interfaces/node-api.interface'; | ||||
| import { StateService } from '../services/state.service'; | ||||
| 
 | ||||
| // Bitcoin Core default policy settings
 | ||||
| const TX_MAX_STANDARD_VERSION = 2; | ||||
| const MAX_STANDARD_TX_WEIGHT = 400_000; | ||||
| const MAX_BLOCK_SIGOPS_COST = 80_000; | ||||
| const MAX_STANDARD_TX_SIGOPS_COST = (MAX_BLOCK_SIGOPS_COST / 5); | ||||
| @ -89,10 +89,13 @@ export function isDERSig(w: string): boolean { | ||||
|  * | ||||
|  * returns true early if any standardness rule is violated, otherwise false | ||||
|  * (except for non-mandatory-script-verify-flag and p2sh script evaluation rules which are *not* enforced) | ||||
|  * | ||||
|  * As standardness rules change, we'll need to apply the rules in force *at the time* to older blocks. | ||||
|  * For now, just pull out individual rules into versioned functions where necessary. | ||||
|  */ | ||||
| export function isNonStandard(tx: Transaction): boolean { | ||||
| export function isNonStandard(tx: Transaction, height?: number, network?: string): boolean { | ||||
|   // version
 | ||||
|   if (tx.version > TX_MAX_STANDARD_VERSION) { | ||||
|   if (isNonStandardVersion(tx, height, network)) { | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
| @ -139,6 +142,8 @@ export function isNonStandard(tx: Transaction): boolean { | ||||
|       } | ||||
|     } else if (['unknown', 'provably_unspendable', 'empty'].includes(vin.prevout?.scriptpubkey_type || '')) { | ||||
|       return true; | ||||
|     } else if (isNonStandardAnchor(tx, height, network)) { | ||||
|       return true; | ||||
|     } | ||||
|     // TODO: bad-witness-nonstandard
 | ||||
|   } | ||||
| @ -203,6 +208,51 @@ export function isNonStandard(tx: Transaction): boolean { | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| // Individual versioned standardness rules
 | ||||
| 
 | ||||
| const V3_STANDARDNESS_ACTIVATION_HEIGHT = { | ||||
|   'testnet4': 42_000, | ||||
|   'testnet': 2_900_000, | ||||
|   'signet': 211_000, | ||||
|   '': 863_500, | ||||
| }; | ||||
| function isNonStandardVersion(tx: Transaction, height?: number, network?: string): boolean { | ||||
|   let TX_MAX_STANDARD_VERSION = 3; | ||||
|   if ( | ||||
|     height != null | ||||
|     && network != null | ||||
|     && V3_STANDARDNESS_ACTIVATION_HEIGHT[network] | ||||
|     && height <= V3_STANDARDNESS_ACTIVATION_HEIGHT[network] | ||||
|   ) { | ||||
|     // V3 transactions were non-standard to spend before v28.x (scheduled for 2024/09/30 https://github.com/bitcoin/bitcoin/issues/29891)
 | ||||
|     TX_MAX_STANDARD_VERSION = 2; | ||||
|   } | ||||
| 
 | ||||
|   if (tx.version > TX_MAX_STANDARD_VERSION) { | ||||
|     return true; | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| const ANCHOR_STANDARDNESS_ACTIVATION_HEIGHT = { | ||||
|   'testnet4': 42_000, | ||||
|   'testnet': 2_900_000, | ||||
|   'signet': 211_000, | ||||
|   '': 863_500, | ||||
| }; | ||||
| function isNonStandardAnchor(tx: Transaction, height?: number, network?: string): boolean { | ||||
|   if ( | ||||
|     height != null | ||||
|     && network != null | ||||
|     && ANCHOR_STANDARDNESS_ACTIVATION_HEIGHT[network] | ||||
|     && height <= ANCHOR_STANDARDNESS_ACTIVATION_HEIGHT[network] | ||||
|   ) { | ||||
|     // anchor outputs were non-standard to spend before v28.x (scheduled for 2024/09/30 https://github.com/bitcoin/bitcoin/issues/29891)
 | ||||
|     return true; | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| // A witness program is any valid scriptpubkey that consists of a 1-byte push opcode
 | ||||
| // followed by a data push between 2 and 40 bytes.
 | ||||
| // https://github.com/bitcoin/bitcoin/blob/2c79abc7ad4850e9e3ba32a04c530155cda7f980/src/script/script.cpp#L224-L240
 | ||||
| @ -289,7 +339,7 @@ export function isBurnKey(pubkey: string): boolean { | ||||
|   ].includes(pubkey); | ||||
| } | ||||
| 
 | ||||
| export function getTransactionFlags(tx: Transaction, cpfpInfo?: CpfpInfo, replacement?: boolean): bigint { | ||||
| export function getTransactionFlags(tx: Transaction, cpfpInfo?: CpfpInfo, replacement?: boolean, height?: number, network?: string): bigint { | ||||
|   let flags = tx.flags ? BigInt(tx.flags) : 0n; | ||||
| 
 | ||||
|   // Update variable flags (CPFP, RBF)
 | ||||
| @ -439,7 +489,7 @@ export function getTransactionFlags(tx: Transaction, cpfpInfo?: CpfpInfo, replac | ||||
|     flags |= TransactionFlags.batch_payout; | ||||
|   } | ||||
| 
 | ||||
|   if (isNonStandard(tx)) { | ||||
|   if (isNonStandard(tx, height, network)) { | ||||
|     flags |= TransactionFlags.nonstandard; | ||||
|   } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user