From 5ade6e3b514427b2a22c879e11d9b0d63d879259 Mon Sep 17 00:00:00 2001 From: Jackson Miller Date: Tue, 1 Oct 2024 11:40:43 +0900 Subject: [PATCH 1/3] Duplicating changes made to master to the V6 branch --- src/transaction.d.ts | 2 +- src/transaction.js | 936 ++++++++++++++++++--------------------- test/transaction.spec.ts | 10 + ts_src/transaction.ts | 6 + 4 files changed, 458 insertions(+), 496 deletions(-) diff --git a/src/transaction.d.ts b/src/transaction.d.ts index 118fa57f1..d0a1cbedc 100644 --- a/src/transaction.d.ts +++ b/src/transaction.d.ts @@ -1,4 +1,3 @@ -/// export interface Output { script: Buffer; value: number; @@ -35,6 +34,7 @@ export declare class Transaction { addInput(hash: Buffer, index: number, sequence?: number, scriptSig?: Buffer): number; addOutput(scriptPubKey: Buffer, value: number): number; hasWitnesses(): boolean; + stripWitnesses(): void; weight(): number; virtualSize(): number; byteLength(_ALLOW_WITNESS?: boolean): number; diff --git a/src/transaction.js b/src/transaction.js index 2b74f3788..8181031f9 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -1,536 +1,482 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); exports.Transaction = void 0; -const bufferutils_1 = require('./bufferutils'); -const bcrypto = require('./crypto'); -const bscript = require('./script'); -const script_1 = require('./script'); -const types = require('./types'); +const bufferutils_1 = require("./bufferutils"); +const bcrypto = require("./crypto"); +const bscript = require("./script"); +const script_1 = require("./script"); +const types = require("./types"); const { typeforce } = types; function varSliceSize(someScript) { - const length = someScript.length; - return bufferutils_1.varuint.encodingLength(length) + length; + const length = someScript.length; + return bufferutils_1.varuint.encodingLength(length) + length; } function vectorSize(someVector) { - const length = someVector.length; - return ( - bufferutils_1.varuint.encodingLength(length) + - someVector.reduce((sum, witness) => { - return sum + varSliceSize(witness); - }, 0) - ); + const length = someVector.length; + return (bufferutils_1.varuint.encodingLength(length) + + someVector.reduce((sum, witness) => { + return sum + varSliceSize(witness); + }, 0)); } const EMPTY_BUFFER = Buffer.allocUnsafe(0); const EMPTY_WITNESS = []; -const ZERO = Buffer.from( - '0000000000000000000000000000000000000000000000000000000000000000', - 'hex', -); -const ONE = Buffer.from( - '0000000000000000000000000000000000000000000000000000000000000001', - 'hex', -); +const ZERO = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); +const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex'); const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex'); const BLANK_OUTPUT = { - script: EMPTY_BUFFER, - valueBuffer: VALUE_UINT64_MAX, + script: EMPTY_BUFFER, + valueBuffer: VALUE_UINT64_MAX, }; function isOutput(out) { - return out.value !== undefined; + return out.value !== undefined; } /** * Represents a Bitcoin transaction. */ class Transaction { - constructor() { - this.version = 1; - this.locktime = 0; - this.ins = []; - this.outs = []; - } - static fromBuffer(buffer, _NO_STRICT) { - const bufferReader = new bufferutils_1.BufferReader(buffer); - const tx = new Transaction(); - tx.version = bufferReader.readInt32(); - const marker = bufferReader.readUInt8(); - const flag = bufferReader.readUInt8(); - let hasWitnesses = false; - if ( - marker === Transaction.ADVANCED_TRANSACTION_MARKER && - flag === Transaction.ADVANCED_TRANSACTION_FLAG - ) { - hasWitnesses = true; - } else { - bufferReader.offset -= 2; + constructor() { + this.version = 1; + this.locktime = 0; + this.ins = []; + this.outs = []; } - const vinLen = bufferReader.readVarInt(); - for (let i = 0; i < vinLen; ++i) { - tx.ins.push({ - hash: bufferReader.readSlice(32), - index: bufferReader.readUInt32(), - script: bufferReader.readVarSlice(), - sequence: bufferReader.readUInt32(), - witness: EMPTY_WITNESS, - }); + static fromBuffer(buffer, _NO_STRICT) { + const bufferReader = new bufferutils_1.BufferReader(buffer); + const tx = new Transaction(); + tx.version = bufferReader.readInt32(); + const marker = bufferReader.readUInt8(); + const flag = bufferReader.readUInt8(); + let hasWitnesses = false; + if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && + flag === Transaction.ADVANCED_TRANSACTION_FLAG) { + hasWitnesses = true; + } + else { + bufferReader.offset -= 2; + } + const vinLen = bufferReader.readVarInt(); + for (let i = 0; i < vinLen; ++i) { + tx.ins.push({ + hash: bufferReader.readSlice(32), + index: bufferReader.readUInt32(), + script: bufferReader.readVarSlice(), + sequence: bufferReader.readUInt32(), + witness: EMPTY_WITNESS, + }); + } + const voutLen = bufferReader.readVarInt(); + for (let i = 0; i < voutLen; ++i) { + tx.outs.push({ + value: bufferReader.readUInt64(), + script: bufferReader.readVarSlice(), + }); + } + if (hasWitnesses) { + for (let i = 0; i < vinLen; ++i) { + tx.ins[i].witness = bufferReader.readVector(); + } + // was this pointless? + if (!tx.hasWitnesses()) + throw new Error('Transaction has superfluous witness data'); + } + tx.locktime = bufferReader.readUInt32(); + if (_NO_STRICT) + return tx; + if (bufferReader.offset !== buffer.length) + throw new Error('Transaction has unexpected data'); + return tx; } - const voutLen = bufferReader.readVarInt(); - for (let i = 0; i < voutLen; ++i) { - tx.outs.push({ - value: bufferReader.readUInt64(), - script: bufferReader.readVarSlice(), - }); + static fromHex(hex) { + return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); } - if (hasWitnesses) { - for (let i = 0; i < vinLen; ++i) { - tx.ins[i].witness = bufferReader.readVector(); - } - // was this pointless? - if (!tx.hasWitnesses()) - throw new Error('Transaction has superfluous witness data'); + static isCoinbaseHash(buffer) { + typeforce(types.Hash256bit, buffer); + for (let i = 0; i < 32; ++i) { + if (buffer[i] !== 0) + return false; + } + return true; } - tx.locktime = bufferReader.readUInt32(); - if (_NO_STRICT) return tx; - if (bufferReader.offset !== buffer.length) - throw new Error('Transaction has unexpected data'); - return tx; - } - static fromHex(hex) { - return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); - } - static isCoinbaseHash(buffer) { - typeforce(types.Hash256bit, buffer); - for (let i = 0; i < 32; ++i) { - if (buffer[i] !== 0) return false; + isCoinbase() { + return (this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash)); } - return true; - } - isCoinbase() { - return ( - this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) - ); - } - addInput(hash, index, sequence, scriptSig) { - typeforce( - types.tuple( - types.Hash256bit, - types.UInt32, - types.maybe(types.UInt32), - types.maybe(types.Buffer), - ), - arguments, - ); - if (types.Null(sequence)) { - sequence = Transaction.DEFAULT_SEQUENCE; + addInput(hash, index, sequence, scriptSig) { + typeforce(types.tuple(types.Hash256bit, types.UInt32, types.maybe(types.UInt32), types.maybe(types.Buffer)), arguments); + if (types.Null(sequence)) { + sequence = Transaction.DEFAULT_SEQUENCE; + } + // Add the input and return the input's index + return (this.ins.push({ + hash, + index, + script: scriptSig || EMPTY_BUFFER, + sequence: sequence, + witness: EMPTY_WITNESS, + }) - 1); } - // Add the input and return the input's index - return ( - this.ins.push({ - hash, - index, - script: scriptSig || EMPTY_BUFFER, - sequence: sequence, - witness: EMPTY_WITNESS, - }) - 1 - ); - } - addOutput(scriptPubKey, value) { - typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); - // Add the output and return the output's index - return ( - this.outs.push({ - script: scriptPubKey, - value, - }) - 1 - ); - } - hasWitnesses() { - return this.ins.some(x => { - return x.witness.length !== 0; - }); - } - weight() { - const base = this.byteLength(false); - const total = this.byteLength(true); - return base * 3 + total; - } - virtualSize() { - return Math.ceil(this.weight() / 4); - } - byteLength(_ALLOW_WITNESS = true) { - const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); - return ( - (hasWitnesses ? 10 : 8) + - bufferutils_1.varuint.encodingLength(this.ins.length) + - bufferutils_1.varuint.encodingLength(this.outs.length) + - this.ins.reduce((sum, input) => { - return sum + 40 + varSliceSize(input.script); - }, 0) + - this.outs.reduce((sum, output) => { - return sum + 8 + varSliceSize(output.script); - }, 0) + - (hasWitnesses - ? this.ins.reduce((sum, input) => { - return sum + vectorSize(input.witness); - }, 0) - : 0) - ); - } - clone() { - const newTx = new Transaction(); - newTx.version = this.version; - newTx.locktime = this.locktime; - newTx.ins = this.ins.map(txIn => { - return { - hash: txIn.hash, - index: txIn.index, - script: txIn.script, - sequence: txIn.sequence, - witness: txIn.witness, - }; - }); - newTx.outs = this.outs.map(txOut => { - return { - script: txOut.script, - value: txOut.value, - }; - }); - return newTx; - } - /** - * Hash transaction for signing a specific input. - * - * Bitcoin uses a different hash for each signed transaction input. - * This method copies the transaction, makes the necessary changes based on the - * hashType, and then hashes the result. - * This hash can then be used to sign the provided transaction input. - */ - hashForSignature(inIndex, prevOutScript, hashType) { - typeforce( - types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), - arguments, - ); - // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 - if (inIndex >= this.ins.length) return ONE; - // ignore OP_CODESEPARATOR - const ourScript = bscript.compile( - bscript.decompile(prevOutScript).filter(x => { - return x !== script_1.OPS.OP_CODESEPARATOR; - }), - ); - const txTmp = this.clone(); - // SIGHASH_NONE: ignore all outputs? (wildcard payee) - if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { - txTmp.outs = []; - // ignore sequence numbers (except at inIndex) - txTmp.ins.forEach((input, i) => { - if (i === inIndex) return; - input.sequence = 0; - }); - // SIGHASH_SINGLE: ignore all outputs, except at the same index? - } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { - // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 - if (inIndex >= this.outs.length) return ONE; - // truncate outputs after - txTmp.outs.length = inIndex + 1; - // "blank" outputs before - for (let i = 0; i < inIndex; i++) { - txTmp.outs[i] = BLANK_OUTPUT; - } - // ignore sequence numbers (except at inIndex) - txTmp.ins.forEach((input, y) => { - if (y === inIndex) return; - input.sequence = 0; - }); + addOutput(scriptPubKey, value) { + typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); + // Add the output and return the output's index + return (this.outs.push({ + script: scriptPubKey, + value, + }) - 1); } - // SIGHASH_ANYONECANPAY: ignore inputs entirely? - if (hashType & Transaction.SIGHASH_ANYONECANPAY) { - txTmp.ins = [txTmp.ins[inIndex]]; - txTmp.ins[0].script = ourScript; - // SIGHASH_ALL: only ignore input scripts - } else { - // "blank" others input scripts - txTmp.ins.forEach(input => { - input.script = EMPTY_BUFFER; - }); - txTmp.ins[inIndex].script = ourScript; + hasWitnesses() { + return this.ins.some(x => { + return x.witness.length !== 0; + }); } - // serialize and hash - const buffer = Buffer.allocUnsafe(txTmp.byteLength(false) + 4); - buffer.writeInt32LE(hashType, buffer.length - 4); - txTmp.__toBuffer(buffer, 0, false); - return bcrypto.hash256(buffer); - } - hashForWitnessV1(inIndex, prevOutScripts, values, hashType, leafHash, annex) { - // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message - typeforce( - types.tuple( - types.UInt32, - typeforce.arrayOf(types.Buffer), - typeforce.arrayOf(types.Satoshi), - types.UInt32, - ), - arguments, - ); - if ( - values.length !== this.ins.length || - prevOutScripts.length !== this.ins.length - ) { - throw new Error('Must supply prevout script and value for all inputs'); + stripWitnesses() { + this.ins.forEach(input => { + input.witness = EMPTY_WITNESS; // Set witness data to an empty array + }); } - const outputType = - hashType === Transaction.SIGHASH_DEFAULT - ? Transaction.SIGHASH_ALL - : hashType & Transaction.SIGHASH_OUTPUT_MASK; - const inputType = hashType & Transaction.SIGHASH_INPUT_MASK; - const isAnyoneCanPay = inputType === Transaction.SIGHASH_ANYONECANPAY; - const isNone = outputType === Transaction.SIGHASH_NONE; - const isSingle = outputType === Transaction.SIGHASH_SINGLE; - let hashPrevouts = EMPTY_BUFFER; - let hashAmounts = EMPTY_BUFFER; - let hashScriptPubKeys = EMPTY_BUFFER; - let hashSequences = EMPTY_BUFFER; - let hashOutputs = EMPTY_BUFFER; - if (!isAnyoneCanPay) { - let bufferWriter = bufferutils_1.BufferWriter.withCapacity( - 36 * this.ins.length, - ); - this.ins.forEach(txIn => { - bufferWriter.writeSlice(txIn.hash); - bufferWriter.writeUInt32(txIn.index); - }); - hashPrevouts = bcrypto.sha256(bufferWriter.end()); - bufferWriter = bufferutils_1.BufferWriter.withCapacity( - 8 * this.ins.length, - ); - values.forEach(value => bufferWriter.writeUInt64(value)); - hashAmounts = bcrypto.sha256(bufferWriter.end()); - bufferWriter = bufferutils_1.BufferWriter.withCapacity( - prevOutScripts.map(varSliceSize).reduce((a, b) => a + b), - ); - prevOutScripts.forEach(prevOutScript => - bufferWriter.writeVarSlice(prevOutScript), - ); - hashScriptPubKeys = bcrypto.sha256(bufferWriter.end()); - bufferWriter = bufferutils_1.BufferWriter.withCapacity( - 4 * this.ins.length, - ); - this.ins.forEach(txIn => bufferWriter.writeUInt32(txIn.sequence)); - hashSequences = bcrypto.sha256(bufferWriter.end()); + weight() { + const base = this.byteLength(false); + const total = this.byteLength(true); + return base * 3 + total; } - if (!(isNone || isSingle)) { - const txOutsSize = this.outs - .map(output => 8 + varSliceSize(output.script)) - .reduce((a, b) => a + b); - const bufferWriter = bufferutils_1.BufferWriter.withCapacity(txOutsSize); - this.outs.forEach(out => { - bufferWriter.writeUInt64(out.value); - bufferWriter.writeVarSlice(out.script); - }); - hashOutputs = bcrypto.sha256(bufferWriter.end()); - } else if (isSingle && inIndex < this.outs.length) { - const output = this.outs[inIndex]; - const bufferWriter = bufferutils_1.BufferWriter.withCapacity( - 8 + varSliceSize(output.script), - ); - bufferWriter.writeUInt64(output.value); - bufferWriter.writeVarSlice(output.script); - hashOutputs = bcrypto.sha256(bufferWriter.end()); + virtualSize() { + return Math.ceil(this.weight() / 4); } - const spendType = (leafHash ? 2 : 0) + (annex ? 1 : 0); - // Length calculation from: - // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-14 - // With extension from: - // https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#signature-validation - const sigMsgSize = - 174 - - (isAnyoneCanPay ? 49 : 0) - - (isNone ? 32 : 0) + - (annex ? 32 : 0) + - (leafHash ? 37 : 0); - const sigMsgWriter = bufferutils_1.BufferWriter.withCapacity(sigMsgSize); - sigMsgWriter.writeUInt8(hashType); - // Transaction - sigMsgWriter.writeInt32(this.version); - sigMsgWriter.writeUInt32(this.locktime); - sigMsgWriter.writeSlice(hashPrevouts); - sigMsgWriter.writeSlice(hashAmounts); - sigMsgWriter.writeSlice(hashScriptPubKeys); - sigMsgWriter.writeSlice(hashSequences); - if (!(isNone || isSingle)) { - sigMsgWriter.writeSlice(hashOutputs); + byteLength(_ALLOW_WITNESS = true) { + const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); + return ((hasWitnesses ? 10 : 8) + + bufferutils_1.varuint.encodingLength(this.ins.length) + + bufferutils_1.varuint.encodingLength(this.outs.length) + + this.ins.reduce((sum, input) => { + return sum + 40 + varSliceSize(input.script); + }, 0) + + this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script); + }, 0) + + (hasWitnesses + ? this.ins.reduce((sum, input) => { + return sum + vectorSize(input.witness); + }, 0) + : 0)); } - // Input - sigMsgWriter.writeUInt8(spendType); - if (isAnyoneCanPay) { - const input = this.ins[inIndex]; - sigMsgWriter.writeSlice(input.hash); - sigMsgWriter.writeUInt32(input.index); - sigMsgWriter.writeUInt64(values[inIndex]); - sigMsgWriter.writeVarSlice(prevOutScripts[inIndex]); - sigMsgWriter.writeUInt32(input.sequence); - } else { - sigMsgWriter.writeUInt32(inIndex); + clone() { + const newTx = new Transaction(); + newTx.version = this.version; + newTx.locktime = this.locktime; + newTx.ins = this.ins.map(txIn => { + return { + hash: txIn.hash, + index: txIn.index, + script: txIn.script, + sequence: txIn.sequence, + witness: txIn.witness, + }; + }); + newTx.outs = this.outs.map(txOut => { + return { + script: txOut.script, + value: txOut.value, + }; + }); + return newTx; } - if (annex) { - const bufferWriter = bufferutils_1.BufferWriter.withCapacity( - varSliceSize(annex), - ); - bufferWriter.writeVarSlice(annex); - sigMsgWriter.writeSlice(bcrypto.sha256(bufferWriter.end())); + /** + * Hash transaction for signing a specific input. + * + * Bitcoin uses a different hash for each signed transaction input. + * This method copies the transaction, makes the necessary changes based on the + * hashType, and then hashes the result. + * This hash can then be used to sign the provided transaction input. + */ + hashForSignature(inIndex, prevOutScript, hashType) { + typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments); + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 + if (inIndex >= this.ins.length) + return ONE; + // ignore OP_CODESEPARATOR + const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter(x => { + return x !== script_1.OPS.OP_CODESEPARATOR; + })); + const txTmp = this.clone(); + // SIGHASH_NONE: ignore all outputs? (wildcard payee) + if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { + txTmp.outs = []; + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, i) => { + if (i === inIndex) + return; + input.sequence = 0; + }); + // SIGHASH_SINGLE: ignore all outputs, except at the same index? + } + else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 + if (inIndex >= this.outs.length) + return ONE; + // truncate outputs after + txTmp.outs.length = inIndex + 1; + // "blank" outputs before + for (let i = 0; i < inIndex; i++) { + txTmp.outs[i] = BLANK_OUTPUT; + } + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, y) => { + if (y === inIndex) + return; + input.sequence = 0; + }); + } + // SIGHASH_ANYONECANPAY: ignore inputs entirely? + if (hashType & Transaction.SIGHASH_ANYONECANPAY) { + txTmp.ins = [txTmp.ins[inIndex]]; + txTmp.ins[0].script = ourScript; + // SIGHASH_ALL: only ignore input scripts + } + else { + // "blank" others input scripts + txTmp.ins.forEach(input => { + input.script = EMPTY_BUFFER; + }); + txTmp.ins[inIndex].script = ourScript; + } + // serialize and hash + const buffer = Buffer.allocUnsafe(txTmp.byteLength(false) + 4); + buffer.writeInt32LE(hashType, buffer.length - 4); + txTmp.__toBuffer(buffer, 0, false); + return bcrypto.hash256(buffer); } - // Output - if (isSingle) { - sigMsgWriter.writeSlice(hashOutputs); + hashForWitnessV1(inIndex, prevOutScripts, values, hashType, leafHash, annex) { + // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message + typeforce(types.tuple(types.UInt32, typeforce.arrayOf(types.Buffer), typeforce.arrayOf(types.Satoshi), types.UInt32), arguments); + if (values.length !== this.ins.length || + prevOutScripts.length !== this.ins.length) { + throw new Error('Must supply prevout script and value for all inputs'); + } + const outputType = hashType === Transaction.SIGHASH_DEFAULT + ? Transaction.SIGHASH_ALL + : hashType & Transaction.SIGHASH_OUTPUT_MASK; + const inputType = hashType & Transaction.SIGHASH_INPUT_MASK; + const isAnyoneCanPay = inputType === Transaction.SIGHASH_ANYONECANPAY; + const isNone = outputType === Transaction.SIGHASH_NONE; + const isSingle = outputType === Transaction.SIGHASH_SINGLE; + let hashPrevouts = EMPTY_BUFFER; + let hashAmounts = EMPTY_BUFFER; + let hashScriptPubKeys = EMPTY_BUFFER; + let hashSequences = EMPTY_BUFFER; + let hashOutputs = EMPTY_BUFFER; + if (!isAnyoneCanPay) { + let bufferWriter = bufferutils_1.BufferWriter.withCapacity(36 * this.ins.length); + this.ins.forEach(txIn => { + bufferWriter.writeSlice(txIn.hash); + bufferWriter.writeUInt32(txIn.index); + }); + hashPrevouts = bcrypto.sha256(bufferWriter.end()); + bufferWriter = bufferutils_1.BufferWriter.withCapacity(8 * this.ins.length); + values.forEach(value => bufferWriter.writeUInt64(value)); + hashAmounts = bcrypto.sha256(bufferWriter.end()); + bufferWriter = bufferutils_1.BufferWriter.withCapacity(prevOutScripts.map(varSliceSize).reduce((a, b) => a + b)); + prevOutScripts.forEach(prevOutScript => bufferWriter.writeVarSlice(prevOutScript)); + hashScriptPubKeys = bcrypto.sha256(bufferWriter.end()); + bufferWriter = bufferutils_1.BufferWriter.withCapacity(4 * this.ins.length); + this.ins.forEach(txIn => bufferWriter.writeUInt32(txIn.sequence)); + hashSequences = bcrypto.sha256(bufferWriter.end()); + } + if (!(isNone || isSingle)) { + const txOutsSize = this.outs + .map(output => 8 + varSliceSize(output.script)) + .reduce((a, b) => a + b); + const bufferWriter = bufferutils_1.BufferWriter.withCapacity(txOutsSize); + this.outs.forEach(out => { + bufferWriter.writeUInt64(out.value); + bufferWriter.writeVarSlice(out.script); + }); + hashOutputs = bcrypto.sha256(bufferWriter.end()); + } + else if (isSingle && inIndex < this.outs.length) { + const output = this.outs[inIndex]; + const bufferWriter = bufferutils_1.BufferWriter.withCapacity(8 + varSliceSize(output.script)); + bufferWriter.writeUInt64(output.value); + bufferWriter.writeVarSlice(output.script); + hashOutputs = bcrypto.sha256(bufferWriter.end()); + } + const spendType = (leafHash ? 2 : 0) + (annex ? 1 : 0); + // Length calculation from: + // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-14 + // With extension from: + // https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#signature-validation + const sigMsgSize = 174 - + (isAnyoneCanPay ? 49 : 0) - + (isNone ? 32 : 0) + + (annex ? 32 : 0) + + (leafHash ? 37 : 0); + const sigMsgWriter = bufferutils_1.BufferWriter.withCapacity(sigMsgSize); + sigMsgWriter.writeUInt8(hashType); + // Transaction + sigMsgWriter.writeInt32(this.version); + sigMsgWriter.writeUInt32(this.locktime); + sigMsgWriter.writeSlice(hashPrevouts); + sigMsgWriter.writeSlice(hashAmounts); + sigMsgWriter.writeSlice(hashScriptPubKeys); + sigMsgWriter.writeSlice(hashSequences); + if (!(isNone || isSingle)) { + sigMsgWriter.writeSlice(hashOutputs); + } + // Input + sigMsgWriter.writeUInt8(spendType); + if (isAnyoneCanPay) { + const input = this.ins[inIndex]; + sigMsgWriter.writeSlice(input.hash); + sigMsgWriter.writeUInt32(input.index); + sigMsgWriter.writeUInt64(values[inIndex]); + sigMsgWriter.writeVarSlice(prevOutScripts[inIndex]); + sigMsgWriter.writeUInt32(input.sequence); + } + else { + sigMsgWriter.writeUInt32(inIndex); + } + if (annex) { + const bufferWriter = bufferutils_1.BufferWriter.withCapacity(varSliceSize(annex)); + bufferWriter.writeVarSlice(annex); + sigMsgWriter.writeSlice(bcrypto.sha256(bufferWriter.end())); + } + // Output + if (isSingle) { + sigMsgWriter.writeSlice(hashOutputs); + } + // BIP342 extension + if (leafHash) { + sigMsgWriter.writeSlice(leafHash); + sigMsgWriter.writeUInt8(0); + sigMsgWriter.writeUInt32(0xffffffff); + } + // Extra zero byte because: + // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19 + return bcrypto.taggedHash('TapSighash', Buffer.concat([Buffer.from([0x00]), sigMsgWriter.end()])); } - // BIP342 extension - if (leafHash) { - sigMsgWriter.writeSlice(leafHash); - sigMsgWriter.writeUInt8(0); - sigMsgWriter.writeUInt32(0xffffffff); + hashForWitnessV0(inIndex, prevOutScript, value, hashType) { + typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments); + let tbuffer = Buffer.from([]); + let bufferWriter; + let hashOutputs = ZERO; + let hashPrevouts = ZERO; + let hashSequence = ZERO; + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { + tbuffer = Buffer.allocUnsafe(36 * this.ins.length); + bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + this.ins.forEach(txIn => { + bufferWriter.writeSlice(txIn.hash); + bufferWriter.writeUInt32(txIn.index); + }); + hashPrevouts = bcrypto.hash256(tbuffer); + } + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && + (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { + tbuffer = Buffer.allocUnsafe(4 * this.ins.length); + bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + this.ins.forEach(txIn => { + bufferWriter.writeUInt32(txIn.sequence); + }); + hashSequence = bcrypto.hash256(tbuffer); + } + if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { + const txOutsSize = this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script); + }, 0); + tbuffer = Buffer.allocUnsafe(txOutsSize); + bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + this.outs.forEach(out => { + bufferWriter.writeUInt64(out.value); + bufferWriter.writeVarSlice(out.script); + }); + hashOutputs = bcrypto.hash256(tbuffer); + } + else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && + inIndex < this.outs.length) { + const output = this.outs[inIndex]; + tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); + bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + bufferWriter.writeUInt64(output.value); + bufferWriter.writeVarSlice(output.script); + hashOutputs = bcrypto.hash256(tbuffer); + } + tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); + bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + const input = this.ins[inIndex]; + bufferWriter.writeInt32(this.version); + bufferWriter.writeSlice(hashPrevouts); + bufferWriter.writeSlice(hashSequence); + bufferWriter.writeSlice(input.hash); + bufferWriter.writeUInt32(input.index); + bufferWriter.writeVarSlice(prevOutScript); + bufferWriter.writeUInt64(value); + bufferWriter.writeUInt32(input.sequence); + bufferWriter.writeSlice(hashOutputs); + bufferWriter.writeUInt32(this.locktime); + bufferWriter.writeUInt32(hashType); + return bcrypto.hash256(tbuffer); } - // Extra zero byte because: - // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19 - return bcrypto.taggedHash( - 'TapSighash', - Buffer.concat([Buffer.from([0x00]), sigMsgWriter.end()]), - ); - } - hashForWitnessV0(inIndex, prevOutScript, value, hashType) { - typeforce( - types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), - arguments, - ); - let tbuffer = Buffer.from([]); - let bufferWriter; - let hashOutputs = ZERO; - let hashPrevouts = ZERO; - let hashSequence = ZERO; - if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { - tbuffer = Buffer.allocUnsafe(36 * this.ins.length); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); - this.ins.forEach(txIn => { - bufferWriter.writeSlice(txIn.hash); - bufferWriter.writeUInt32(txIn.index); - }); - hashPrevouts = bcrypto.hash256(tbuffer); + getHash(forWitness) { + // wtxid for coinbase is always 32 bytes of 0x00 + if (forWitness && this.isCoinbase()) + return Buffer.alloc(32, 0); + return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); } - if ( - !(hashType & Transaction.SIGHASH_ANYONECANPAY) && - (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE - ) { - tbuffer = Buffer.allocUnsafe(4 * this.ins.length); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); - this.ins.forEach(txIn => { - bufferWriter.writeUInt32(txIn.sequence); - }); - hashSequence = bcrypto.hash256(tbuffer); + getId() { + // transaction hash's are displayed in reverse order + return (0, bufferutils_1.reverseBuffer)(this.getHash(false)).toString('hex'); } - if ( - (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE - ) { - const txOutsSize = this.outs.reduce((sum, output) => { - return sum + 8 + varSliceSize(output.script); - }, 0); - tbuffer = Buffer.allocUnsafe(txOutsSize); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); - this.outs.forEach(out => { - bufferWriter.writeUInt64(out.value); - bufferWriter.writeVarSlice(out.script); - }); - hashOutputs = bcrypto.hash256(tbuffer); - } else if ( - (hashType & 0x1f) === Transaction.SIGHASH_SINGLE && - inIndex < this.outs.length - ) { - const output = this.outs[inIndex]; - tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); - bufferWriter.writeUInt64(output.value); - bufferWriter.writeVarSlice(output.script); - hashOutputs = bcrypto.hash256(tbuffer); + toBuffer(buffer, initialOffset) { + return this.__toBuffer(buffer, initialOffset, true); } - tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); - const input = this.ins[inIndex]; - bufferWriter.writeInt32(this.version); - bufferWriter.writeSlice(hashPrevouts); - bufferWriter.writeSlice(hashSequence); - bufferWriter.writeSlice(input.hash); - bufferWriter.writeUInt32(input.index); - bufferWriter.writeVarSlice(prevOutScript); - bufferWriter.writeUInt64(value); - bufferWriter.writeUInt32(input.sequence); - bufferWriter.writeSlice(hashOutputs); - bufferWriter.writeUInt32(this.locktime); - bufferWriter.writeUInt32(hashType); - return bcrypto.hash256(tbuffer); - } - getHash(forWitness) { - // wtxid for coinbase is always 32 bytes of 0x00 - if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0); - return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); - } - getId() { - // transaction hash's are displayed in reverse order - return (0, bufferutils_1.reverseBuffer)(this.getHash(false)).toString( - 'hex', - ); - } - toBuffer(buffer, initialOffset) { - return this.__toBuffer(buffer, initialOffset, true); - } - toHex() { - return this.toBuffer(undefined, undefined).toString('hex'); - } - setInputScript(index, scriptSig) { - typeforce(types.tuple(types.Number, types.Buffer), arguments); - this.ins[index].script = scriptSig; - } - setWitness(index, witness) { - typeforce(types.tuple(types.Number, [types.Buffer]), arguments); - this.ins[index].witness = witness; - } - __toBuffer(buffer, initialOffset, _ALLOW_WITNESS = false) { - if (!buffer) buffer = Buffer.allocUnsafe(this.byteLength(_ALLOW_WITNESS)); - const bufferWriter = new bufferutils_1.BufferWriter( - buffer, - initialOffset || 0, - ); - bufferWriter.writeInt32(this.version); - const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); - if (hasWitnesses) { - bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); - bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); + toHex() { + return this.toBuffer(undefined, undefined).toString('hex'); } - bufferWriter.writeVarInt(this.ins.length); - this.ins.forEach(txIn => { - bufferWriter.writeSlice(txIn.hash); - bufferWriter.writeUInt32(txIn.index); - bufferWriter.writeVarSlice(txIn.script); - bufferWriter.writeUInt32(txIn.sequence); - }); - bufferWriter.writeVarInt(this.outs.length); - this.outs.forEach(txOut => { - if (isOutput(txOut)) { - bufferWriter.writeUInt64(txOut.value); - } else { - bufferWriter.writeSlice(txOut.valueBuffer); - } - bufferWriter.writeVarSlice(txOut.script); - }); - if (hasWitnesses) { - this.ins.forEach(input => { - bufferWriter.writeVector(input.witness); - }); + setInputScript(index, scriptSig) { + typeforce(types.tuple(types.Number, types.Buffer), arguments); + this.ins[index].script = scriptSig; + } + setWitness(index, witness) { + typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + this.ins[index].witness = witness; + } + __toBuffer(buffer, initialOffset, _ALLOW_WITNESS = false) { + if (!buffer) + buffer = Buffer.allocUnsafe(this.byteLength(_ALLOW_WITNESS)); + const bufferWriter = new bufferutils_1.BufferWriter(buffer, initialOffset || 0); + bufferWriter.writeInt32(this.version); + const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); + if (hasWitnesses) { + bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); + bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); + } + bufferWriter.writeVarInt(this.ins.length); + this.ins.forEach(txIn => { + bufferWriter.writeSlice(txIn.hash); + bufferWriter.writeUInt32(txIn.index); + bufferWriter.writeVarSlice(txIn.script); + bufferWriter.writeUInt32(txIn.sequence); + }); + bufferWriter.writeVarInt(this.outs.length); + this.outs.forEach(txOut => { + if (isOutput(txOut)) { + bufferWriter.writeUInt64(txOut.value); + } + else { + bufferWriter.writeSlice(txOut.valueBuffer); + } + bufferWriter.writeVarSlice(txOut.script); + }); + if (hasWitnesses) { + this.ins.forEach(input => { + bufferWriter.writeVector(input.witness); + }); + } + bufferWriter.writeUInt32(this.locktime); + // avoid slicing unless necessary + if (initialOffset !== undefined) + return buffer.slice(initialOffset, bufferWriter.offset); + return buffer; } - bufferWriter.writeUInt32(this.locktime); - // avoid slicing unless necessary - if (initialOffset !== undefined) - return buffer.slice(initialOffset, bufferWriter.offset); - return buffer; - } } exports.Transaction = Transaction; Transaction.DEFAULT_SEQUENCE = 0xffffffff; diff --git a/test/transaction.spec.ts b/test/transaction.spec.ts index 991557ba3..fcc23e477 100644 --- a/test/transaction.spec.ts +++ b/test/transaction.spec.ts @@ -135,6 +135,16 @@ describe('Transaction', () => { }); }); + describe('stripWitnesses', () => { + fixtures.valid.forEach(f => { + it('removes witness from the transaction if it exists', () => { + const T = Transaction.fromHex(f.whex ? f.whex : f.hex); + T.stripWitnesses(); + assert.strictEqual(T.hasWitnesses(), false); + }); + }); + }); + describe('weight/virtualSize', () => { it('computes virtual size', () => { fixtures.valid.forEach(f => { diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts index 665583ec5..7161083cf 100644 --- a/ts_src/transaction.ts +++ b/ts_src/transaction.ts @@ -205,6 +205,12 @@ export class Transaction { }); } + stripWitnesses(): void { + this.ins.forEach(input => { + input.witness = EMPTY_WITNESS; // Set witness data to an empty array + }); + } + weight(): number { const base = this.byteLength(false); const total = this.byteLength(true); From 8bef8ddfdc7cf4db07cc1c29efcfe33009074fc4 Mon Sep 17 00:00:00 2001 From: Jackson Miller Date: Tue, 1 Oct 2024 15:00:23 +0900 Subject: [PATCH 2/3] Doh! forgot to update modules --- src/transaction.d.ts | 1 + src/transaction.js | 941 +++++++++++++++++++++++-------------------- 2 files changed, 501 insertions(+), 441 deletions(-) diff --git a/src/transaction.d.ts b/src/transaction.d.ts index d0a1cbedc..af512ee8e 100644 --- a/src/transaction.d.ts +++ b/src/transaction.d.ts @@ -1,3 +1,4 @@ +/// export interface Output { script: Buffer; value: number; diff --git a/src/transaction.js b/src/transaction.js index 8181031f9..13863aca9 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -1,482 +1,541 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); exports.Transaction = void 0; -const bufferutils_1 = require("./bufferutils"); -const bcrypto = require("./crypto"); -const bscript = require("./script"); -const script_1 = require("./script"); -const types = require("./types"); +const bufferutils_1 = require('./bufferutils'); +const bcrypto = require('./crypto'); +const bscript = require('./script'); +const script_1 = require('./script'); +const types = require('./types'); const { typeforce } = types; function varSliceSize(someScript) { - const length = someScript.length; - return bufferutils_1.varuint.encodingLength(length) + length; + const length = someScript.length; + return bufferutils_1.varuint.encodingLength(length) + length; } function vectorSize(someVector) { - const length = someVector.length; - return (bufferutils_1.varuint.encodingLength(length) + - someVector.reduce((sum, witness) => { - return sum + varSliceSize(witness); - }, 0)); + const length = someVector.length; + return ( + bufferutils_1.varuint.encodingLength(length) + + someVector.reduce((sum, witness) => { + return sum + varSliceSize(witness); + }, 0) + ); } const EMPTY_BUFFER = Buffer.allocUnsafe(0); const EMPTY_WITNESS = []; -const ZERO = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); -const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex'); +const ZERO = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', +); +const ONE = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000001', + 'hex', +); const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex'); const BLANK_OUTPUT = { - script: EMPTY_BUFFER, - valueBuffer: VALUE_UINT64_MAX, + script: EMPTY_BUFFER, + valueBuffer: VALUE_UINT64_MAX, }; function isOutput(out) { - return out.value !== undefined; + return out.value !== undefined; } /** * Represents a Bitcoin transaction. */ class Transaction { - constructor() { - this.version = 1; - this.locktime = 0; - this.ins = []; - this.outs = []; + constructor() { + this.version = 1; + this.locktime = 0; + this.ins = []; + this.outs = []; + } + static fromBuffer(buffer, _NO_STRICT) { + const bufferReader = new bufferutils_1.BufferReader(buffer); + const tx = new Transaction(); + tx.version = bufferReader.readInt32(); + const marker = bufferReader.readUInt8(); + const flag = bufferReader.readUInt8(); + let hasWitnesses = false; + if ( + marker === Transaction.ADVANCED_TRANSACTION_MARKER && + flag === Transaction.ADVANCED_TRANSACTION_FLAG + ) { + hasWitnesses = true; + } else { + bufferReader.offset -= 2; } - static fromBuffer(buffer, _NO_STRICT) { - const bufferReader = new bufferutils_1.BufferReader(buffer); - const tx = new Transaction(); - tx.version = bufferReader.readInt32(); - const marker = bufferReader.readUInt8(); - const flag = bufferReader.readUInt8(); - let hasWitnesses = false; - if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && - flag === Transaction.ADVANCED_TRANSACTION_FLAG) { - hasWitnesses = true; - } - else { - bufferReader.offset -= 2; - } - const vinLen = bufferReader.readVarInt(); - for (let i = 0; i < vinLen; ++i) { - tx.ins.push({ - hash: bufferReader.readSlice(32), - index: bufferReader.readUInt32(), - script: bufferReader.readVarSlice(), - sequence: bufferReader.readUInt32(), - witness: EMPTY_WITNESS, - }); - } - const voutLen = bufferReader.readVarInt(); - for (let i = 0; i < voutLen; ++i) { - tx.outs.push({ - value: bufferReader.readUInt64(), - script: bufferReader.readVarSlice(), - }); - } - if (hasWitnesses) { - for (let i = 0; i < vinLen; ++i) { - tx.ins[i].witness = bufferReader.readVector(); - } - // was this pointless? - if (!tx.hasWitnesses()) - throw new Error('Transaction has superfluous witness data'); - } - tx.locktime = bufferReader.readUInt32(); - if (_NO_STRICT) - return tx; - if (bufferReader.offset !== buffer.length) - throw new Error('Transaction has unexpected data'); - return tx; + const vinLen = bufferReader.readVarInt(); + for (let i = 0; i < vinLen; ++i) { + tx.ins.push({ + hash: bufferReader.readSlice(32), + index: bufferReader.readUInt32(), + script: bufferReader.readVarSlice(), + sequence: bufferReader.readUInt32(), + witness: EMPTY_WITNESS, + }); } - static fromHex(hex) { - return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); + const voutLen = bufferReader.readVarInt(); + for (let i = 0; i < voutLen; ++i) { + tx.outs.push({ + value: bufferReader.readUInt64(), + script: bufferReader.readVarSlice(), + }); } - static isCoinbaseHash(buffer) { - typeforce(types.Hash256bit, buffer); - for (let i = 0; i < 32; ++i) { - if (buffer[i] !== 0) - return false; - } - return true; + if (hasWitnesses) { + for (let i = 0; i < vinLen; ++i) { + tx.ins[i].witness = bufferReader.readVector(); + } + // was this pointless? + if (!tx.hasWitnesses()) + throw new Error('Transaction has superfluous witness data'); } - isCoinbase() { - return (this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash)); + tx.locktime = bufferReader.readUInt32(); + if (_NO_STRICT) return tx; + if (bufferReader.offset !== buffer.length) + throw new Error('Transaction has unexpected data'); + return tx; + } + static fromHex(hex) { + return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); + } + static isCoinbaseHash(buffer) { + typeforce(types.Hash256bit, buffer); + for (let i = 0; i < 32; ++i) { + if (buffer[i] !== 0) return false; } - addInput(hash, index, sequence, scriptSig) { - typeforce(types.tuple(types.Hash256bit, types.UInt32, types.maybe(types.UInt32), types.maybe(types.Buffer)), arguments); - if (types.Null(sequence)) { - sequence = Transaction.DEFAULT_SEQUENCE; - } - // Add the input and return the input's index - return (this.ins.push({ - hash, - index, - script: scriptSig || EMPTY_BUFFER, - sequence: sequence, - witness: EMPTY_WITNESS, - }) - 1); + return true; + } + isCoinbase() { + return ( + this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) + ); + } + addInput(hash, index, sequence, scriptSig) { + typeforce( + types.tuple( + types.Hash256bit, + types.UInt32, + types.maybe(types.UInt32), + types.maybe(types.Buffer), + ), + arguments, + ); + if (types.Null(sequence)) { + sequence = Transaction.DEFAULT_SEQUENCE; } - addOutput(scriptPubKey, value) { - typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); - // Add the output and return the output's index - return (this.outs.push({ - script: scriptPubKey, - value, - }) - 1); + // Add the input and return the input's index + return ( + this.ins.push({ + hash, + index, + script: scriptSig || EMPTY_BUFFER, + sequence: sequence, + witness: EMPTY_WITNESS, + }) - 1 + ); + } + addOutput(scriptPubKey, value) { + typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); + // Add the output and return the output's index + return ( + this.outs.push({ + script: scriptPubKey, + value, + }) - 1 + ); + } + hasWitnesses() { + return this.ins.some(x => { + return x.witness.length !== 0; + }); + } + stripWitnesses() { + this.ins.forEach(input => { + input.witness = EMPTY_WITNESS; // Set witness data to an empty array + }); + } + weight() { + const base = this.byteLength(false); + const total = this.byteLength(true); + return base * 3 + total; + } + virtualSize() { + return Math.ceil(this.weight() / 4); + } + byteLength(_ALLOW_WITNESS = true) { + const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); + return ( + (hasWitnesses ? 10 : 8) + + bufferutils_1.varuint.encodingLength(this.ins.length) + + bufferutils_1.varuint.encodingLength(this.outs.length) + + this.ins.reduce((sum, input) => { + return sum + 40 + varSliceSize(input.script); + }, 0) + + this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script); + }, 0) + + (hasWitnesses + ? this.ins.reduce((sum, input) => { + return sum + vectorSize(input.witness); + }, 0) + : 0) + ); + } + clone() { + const newTx = new Transaction(); + newTx.version = this.version; + newTx.locktime = this.locktime; + newTx.ins = this.ins.map(txIn => { + return { + hash: txIn.hash, + index: txIn.index, + script: txIn.script, + sequence: txIn.sequence, + witness: txIn.witness, + }; + }); + newTx.outs = this.outs.map(txOut => { + return { + script: txOut.script, + value: txOut.value, + }; + }); + return newTx; + } + /** + * Hash transaction for signing a specific input. + * + * Bitcoin uses a different hash for each signed transaction input. + * This method copies the transaction, makes the necessary changes based on the + * hashType, and then hashes the result. + * This hash can then be used to sign the provided transaction input. + */ + hashForSignature(inIndex, prevOutScript, hashType) { + typeforce( + types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), + arguments, + ); + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 + if (inIndex >= this.ins.length) return ONE; + // ignore OP_CODESEPARATOR + const ourScript = bscript.compile( + bscript.decompile(prevOutScript).filter(x => { + return x !== script_1.OPS.OP_CODESEPARATOR; + }), + ); + const txTmp = this.clone(); + // SIGHASH_NONE: ignore all outputs? (wildcard payee) + if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { + txTmp.outs = []; + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, i) => { + if (i === inIndex) return; + input.sequence = 0; + }); + // SIGHASH_SINGLE: ignore all outputs, except at the same index? + } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 + if (inIndex >= this.outs.length) return ONE; + // truncate outputs after + txTmp.outs.length = inIndex + 1; + // "blank" outputs before + for (let i = 0; i < inIndex; i++) { + txTmp.outs[i] = BLANK_OUTPUT; + } + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, y) => { + if (y === inIndex) return; + input.sequence = 0; + }); } - hasWitnesses() { - return this.ins.some(x => { - return x.witness.length !== 0; - }); + // SIGHASH_ANYONECANPAY: ignore inputs entirely? + if (hashType & Transaction.SIGHASH_ANYONECANPAY) { + txTmp.ins = [txTmp.ins[inIndex]]; + txTmp.ins[0].script = ourScript; + // SIGHASH_ALL: only ignore input scripts + } else { + // "blank" others input scripts + txTmp.ins.forEach(input => { + input.script = EMPTY_BUFFER; + }); + txTmp.ins[inIndex].script = ourScript; } - stripWitnesses() { - this.ins.forEach(input => { - input.witness = EMPTY_WITNESS; // Set witness data to an empty array - }); + // serialize and hash + const buffer = Buffer.allocUnsafe(txTmp.byteLength(false) + 4); + buffer.writeInt32LE(hashType, buffer.length - 4); + txTmp.__toBuffer(buffer, 0, false); + return bcrypto.hash256(buffer); + } + hashForWitnessV1(inIndex, prevOutScripts, values, hashType, leafHash, annex) { + // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message + typeforce( + types.tuple( + types.UInt32, + typeforce.arrayOf(types.Buffer), + typeforce.arrayOf(types.Satoshi), + types.UInt32, + ), + arguments, + ); + if ( + values.length !== this.ins.length || + prevOutScripts.length !== this.ins.length + ) { + throw new Error('Must supply prevout script and value for all inputs'); } - weight() { - const base = this.byteLength(false); - const total = this.byteLength(true); - return base * 3 + total; + const outputType = + hashType === Transaction.SIGHASH_DEFAULT + ? Transaction.SIGHASH_ALL + : hashType & Transaction.SIGHASH_OUTPUT_MASK; + const inputType = hashType & Transaction.SIGHASH_INPUT_MASK; + const isAnyoneCanPay = inputType === Transaction.SIGHASH_ANYONECANPAY; + const isNone = outputType === Transaction.SIGHASH_NONE; + const isSingle = outputType === Transaction.SIGHASH_SINGLE; + let hashPrevouts = EMPTY_BUFFER; + let hashAmounts = EMPTY_BUFFER; + let hashScriptPubKeys = EMPTY_BUFFER; + let hashSequences = EMPTY_BUFFER; + let hashOutputs = EMPTY_BUFFER; + if (!isAnyoneCanPay) { + let bufferWriter = bufferutils_1.BufferWriter.withCapacity( + 36 * this.ins.length, + ); + this.ins.forEach(txIn => { + bufferWriter.writeSlice(txIn.hash); + bufferWriter.writeUInt32(txIn.index); + }); + hashPrevouts = bcrypto.sha256(bufferWriter.end()); + bufferWriter = bufferutils_1.BufferWriter.withCapacity( + 8 * this.ins.length, + ); + values.forEach(value => bufferWriter.writeUInt64(value)); + hashAmounts = bcrypto.sha256(bufferWriter.end()); + bufferWriter = bufferutils_1.BufferWriter.withCapacity( + prevOutScripts.map(varSliceSize).reduce((a, b) => a + b), + ); + prevOutScripts.forEach(prevOutScript => + bufferWriter.writeVarSlice(prevOutScript), + ); + hashScriptPubKeys = bcrypto.sha256(bufferWriter.end()); + bufferWriter = bufferutils_1.BufferWriter.withCapacity( + 4 * this.ins.length, + ); + this.ins.forEach(txIn => bufferWriter.writeUInt32(txIn.sequence)); + hashSequences = bcrypto.sha256(bufferWriter.end()); } - virtualSize() { - return Math.ceil(this.weight() / 4); + if (!(isNone || isSingle)) { + const txOutsSize = this.outs + .map(output => 8 + varSliceSize(output.script)) + .reduce((a, b) => a + b); + const bufferWriter = bufferutils_1.BufferWriter.withCapacity(txOutsSize); + this.outs.forEach(out => { + bufferWriter.writeUInt64(out.value); + bufferWriter.writeVarSlice(out.script); + }); + hashOutputs = bcrypto.sha256(bufferWriter.end()); + } else if (isSingle && inIndex < this.outs.length) { + const output = this.outs[inIndex]; + const bufferWriter = bufferutils_1.BufferWriter.withCapacity( + 8 + varSliceSize(output.script), + ); + bufferWriter.writeUInt64(output.value); + bufferWriter.writeVarSlice(output.script); + hashOutputs = bcrypto.sha256(bufferWriter.end()); } - byteLength(_ALLOW_WITNESS = true) { - const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); - return ((hasWitnesses ? 10 : 8) + - bufferutils_1.varuint.encodingLength(this.ins.length) + - bufferutils_1.varuint.encodingLength(this.outs.length) + - this.ins.reduce((sum, input) => { - return sum + 40 + varSliceSize(input.script); - }, 0) + - this.outs.reduce((sum, output) => { - return sum + 8 + varSliceSize(output.script); - }, 0) + - (hasWitnesses - ? this.ins.reduce((sum, input) => { - return sum + vectorSize(input.witness); - }, 0) - : 0)); + const spendType = (leafHash ? 2 : 0) + (annex ? 1 : 0); + // Length calculation from: + // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-14 + // With extension from: + // https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#signature-validation + const sigMsgSize = + 174 - + (isAnyoneCanPay ? 49 : 0) - + (isNone ? 32 : 0) + + (annex ? 32 : 0) + + (leafHash ? 37 : 0); + const sigMsgWriter = bufferutils_1.BufferWriter.withCapacity(sigMsgSize); + sigMsgWriter.writeUInt8(hashType); + // Transaction + sigMsgWriter.writeInt32(this.version); + sigMsgWriter.writeUInt32(this.locktime); + sigMsgWriter.writeSlice(hashPrevouts); + sigMsgWriter.writeSlice(hashAmounts); + sigMsgWriter.writeSlice(hashScriptPubKeys); + sigMsgWriter.writeSlice(hashSequences); + if (!(isNone || isSingle)) { + sigMsgWriter.writeSlice(hashOutputs); } - clone() { - const newTx = new Transaction(); - newTx.version = this.version; - newTx.locktime = this.locktime; - newTx.ins = this.ins.map(txIn => { - return { - hash: txIn.hash, - index: txIn.index, - script: txIn.script, - sequence: txIn.sequence, - witness: txIn.witness, - }; - }); - newTx.outs = this.outs.map(txOut => { - return { - script: txOut.script, - value: txOut.value, - }; - }); - return newTx; + // Input + sigMsgWriter.writeUInt8(spendType); + if (isAnyoneCanPay) { + const input = this.ins[inIndex]; + sigMsgWriter.writeSlice(input.hash); + sigMsgWriter.writeUInt32(input.index); + sigMsgWriter.writeUInt64(values[inIndex]); + sigMsgWriter.writeVarSlice(prevOutScripts[inIndex]); + sigMsgWriter.writeUInt32(input.sequence); + } else { + sigMsgWriter.writeUInt32(inIndex); } - /** - * Hash transaction for signing a specific input. - * - * Bitcoin uses a different hash for each signed transaction input. - * This method copies the transaction, makes the necessary changes based on the - * hashType, and then hashes the result. - * This hash can then be used to sign the provided transaction input. - */ - hashForSignature(inIndex, prevOutScript, hashType) { - typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments); - // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 - if (inIndex >= this.ins.length) - return ONE; - // ignore OP_CODESEPARATOR - const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter(x => { - return x !== script_1.OPS.OP_CODESEPARATOR; - })); - const txTmp = this.clone(); - // SIGHASH_NONE: ignore all outputs? (wildcard payee) - if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { - txTmp.outs = []; - // ignore sequence numbers (except at inIndex) - txTmp.ins.forEach((input, i) => { - if (i === inIndex) - return; - input.sequence = 0; - }); - // SIGHASH_SINGLE: ignore all outputs, except at the same index? - } - else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { - // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 - if (inIndex >= this.outs.length) - return ONE; - // truncate outputs after - txTmp.outs.length = inIndex + 1; - // "blank" outputs before - for (let i = 0; i < inIndex; i++) { - txTmp.outs[i] = BLANK_OUTPUT; - } - // ignore sequence numbers (except at inIndex) - txTmp.ins.forEach((input, y) => { - if (y === inIndex) - return; - input.sequence = 0; - }); - } - // SIGHASH_ANYONECANPAY: ignore inputs entirely? - if (hashType & Transaction.SIGHASH_ANYONECANPAY) { - txTmp.ins = [txTmp.ins[inIndex]]; - txTmp.ins[0].script = ourScript; - // SIGHASH_ALL: only ignore input scripts - } - else { - // "blank" others input scripts - txTmp.ins.forEach(input => { - input.script = EMPTY_BUFFER; - }); - txTmp.ins[inIndex].script = ourScript; - } - // serialize and hash - const buffer = Buffer.allocUnsafe(txTmp.byteLength(false) + 4); - buffer.writeInt32LE(hashType, buffer.length - 4); - txTmp.__toBuffer(buffer, 0, false); - return bcrypto.hash256(buffer); + if (annex) { + const bufferWriter = bufferutils_1.BufferWriter.withCapacity( + varSliceSize(annex), + ); + bufferWriter.writeVarSlice(annex); + sigMsgWriter.writeSlice(bcrypto.sha256(bufferWriter.end())); } - hashForWitnessV1(inIndex, prevOutScripts, values, hashType, leafHash, annex) { - // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message - typeforce(types.tuple(types.UInt32, typeforce.arrayOf(types.Buffer), typeforce.arrayOf(types.Satoshi), types.UInt32), arguments); - if (values.length !== this.ins.length || - prevOutScripts.length !== this.ins.length) { - throw new Error('Must supply prevout script and value for all inputs'); - } - const outputType = hashType === Transaction.SIGHASH_DEFAULT - ? Transaction.SIGHASH_ALL - : hashType & Transaction.SIGHASH_OUTPUT_MASK; - const inputType = hashType & Transaction.SIGHASH_INPUT_MASK; - const isAnyoneCanPay = inputType === Transaction.SIGHASH_ANYONECANPAY; - const isNone = outputType === Transaction.SIGHASH_NONE; - const isSingle = outputType === Transaction.SIGHASH_SINGLE; - let hashPrevouts = EMPTY_BUFFER; - let hashAmounts = EMPTY_BUFFER; - let hashScriptPubKeys = EMPTY_BUFFER; - let hashSequences = EMPTY_BUFFER; - let hashOutputs = EMPTY_BUFFER; - if (!isAnyoneCanPay) { - let bufferWriter = bufferutils_1.BufferWriter.withCapacity(36 * this.ins.length); - this.ins.forEach(txIn => { - bufferWriter.writeSlice(txIn.hash); - bufferWriter.writeUInt32(txIn.index); - }); - hashPrevouts = bcrypto.sha256(bufferWriter.end()); - bufferWriter = bufferutils_1.BufferWriter.withCapacity(8 * this.ins.length); - values.forEach(value => bufferWriter.writeUInt64(value)); - hashAmounts = bcrypto.sha256(bufferWriter.end()); - bufferWriter = bufferutils_1.BufferWriter.withCapacity(prevOutScripts.map(varSliceSize).reduce((a, b) => a + b)); - prevOutScripts.forEach(prevOutScript => bufferWriter.writeVarSlice(prevOutScript)); - hashScriptPubKeys = bcrypto.sha256(bufferWriter.end()); - bufferWriter = bufferutils_1.BufferWriter.withCapacity(4 * this.ins.length); - this.ins.forEach(txIn => bufferWriter.writeUInt32(txIn.sequence)); - hashSequences = bcrypto.sha256(bufferWriter.end()); - } - if (!(isNone || isSingle)) { - const txOutsSize = this.outs - .map(output => 8 + varSliceSize(output.script)) - .reduce((a, b) => a + b); - const bufferWriter = bufferutils_1.BufferWriter.withCapacity(txOutsSize); - this.outs.forEach(out => { - bufferWriter.writeUInt64(out.value); - bufferWriter.writeVarSlice(out.script); - }); - hashOutputs = bcrypto.sha256(bufferWriter.end()); - } - else if (isSingle && inIndex < this.outs.length) { - const output = this.outs[inIndex]; - const bufferWriter = bufferutils_1.BufferWriter.withCapacity(8 + varSliceSize(output.script)); - bufferWriter.writeUInt64(output.value); - bufferWriter.writeVarSlice(output.script); - hashOutputs = bcrypto.sha256(bufferWriter.end()); - } - const spendType = (leafHash ? 2 : 0) + (annex ? 1 : 0); - // Length calculation from: - // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-14 - // With extension from: - // https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#signature-validation - const sigMsgSize = 174 - - (isAnyoneCanPay ? 49 : 0) - - (isNone ? 32 : 0) + - (annex ? 32 : 0) + - (leafHash ? 37 : 0); - const sigMsgWriter = bufferutils_1.BufferWriter.withCapacity(sigMsgSize); - sigMsgWriter.writeUInt8(hashType); - // Transaction - sigMsgWriter.writeInt32(this.version); - sigMsgWriter.writeUInt32(this.locktime); - sigMsgWriter.writeSlice(hashPrevouts); - sigMsgWriter.writeSlice(hashAmounts); - sigMsgWriter.writeSlice(hashScriptPubKeys); - sigMsgWriter.writeSlice(hashSequences); - if (!(isNone || isSingle)) { - sigMsgWriter.writeSlice(hashOutputs); - } - // Input - sigMsgWriter.writeUInt8(spendType); - if (isAnyoneCanPay) { - const input = this.ins[inIndex]; - sigMsgWriter.writeSlice(input.hash); - sigMsgWriter.writeUInt32(input.index); - sigMsgWriter.writeUInt64(values[inIndex]); - sigMsgWriter.writeVarSlice(prevOutScripts[inIndex]); - sigMsgWriter.writeUInt32(input.sequence); - } - else { - sigMsgWriter.writeUInt32(inIndex); - } - if (annex) { - const bufferWriter = bufferutils_1.BufferWriter.withCapacity(varSliceSize(annex)); - bufferWriter.writeVarSlice(annex); - sigMsgWriter.writeSlice(bcrypto.sha256(bufferWriter.end())); - } - // Output - if (isSingle) { - sigMsgWriter.writeSlice(hashOutputs); - } - // BIP342 extension - if (leafHash) { - sigMsgWriter.writeSlice(leafHash); - sigMsgWriter.writeUInt8(0); - sigMsgWriter.writeUInt32(0xffffffff); - } - // Extra zero byte because: - // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19 - return bcrypto.taggedHash('TapSighash', Buffer.concat([Buffer.from([0x00]), sigMsgWriter.end()])); + // Output + if (isSingle) { + sigMsgWriter.writeSlice(hashOutputs); } - hashForWitnessV0(inIndex, prevOutScript, value, hashType) { - typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments); - let tbuffer = Buffer.from([]); - let bufferWriter; - let hashOutputs = ZERO; - let hashPrevouts = ZERO; - let hashSequence = ZERO; - if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { - tbuffer = Buffer.allocUnsafe(36 * this.ins.length); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); - this.ins.forEach(txIn => { - bufferWriter.writeSlice(txIn.hash); - bufferWriter.writeUInt32(txIn.index); - }); - hashPrevouts = bcrypto.hash256(tbuffer); - } - if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && - (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { - tbuffer = Buffer.allocUnsafe(4 * this.ins.length); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); - this.ins.forEach(txIn => { - bufferWriter.writeUInt32(txIn.sequence); - }); - hashSequence = bcrypto.hash256(tbuffer); - } - if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { - const txOutsSize = this.outs.reduce((sum, output) => { - return sum + 8 + varSliceSize(output.script); - }, 0); - tbuffer = Buffer.allocUnsafe(txOutsSize); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); - this.outs.forEach(out => { - bufferWriter.writeUInt64(out.value); - bufferWriter.writeVarSlice(out.script); - }); - hashOutputs = bcrypto.hash256(tbuffer); - } - else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && - inIndex < this.outs.length) { - const output = this.outs[inIndex]; - tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); - bufferWriter.writeUInt64(output.value); - bufferWriter.writeVarSlice(output.script); - hashOutputs = bcrypto.hash256(tbuffer); - } - tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); - const input = this.ins[inIndex]; - bufferWriter.writeInt32(this.version); - bufferWriter.writeSlice(hashPrevouts); - bufferWriter.writeSlice(hashSequence); - bufferWriter.writeSlice(input.hash); - bufferWriter.writeUInt32(input.index); - bufferWriter.writeVarSlice(prevOutScript); - bufferWriter.writeUInt64(value); - bufferWriter.writeUInt32(input.sequence); - bufferWriter.writeSlice(hashOutputs); - bufferWriter.writeUInt32(this.locktime); - bufferWriter.writeUInt32(hashType); - return bcrypto.hash256(tbuffer); + // BIP342 extension + if (leafHash) { + sigMsgWriter.writeSlice(leafHash); + sigMsgWriter.writeUInt8(0); + sigMsgWriter.writeUInt32(0xffffffff); } - getHash(forWitness) { - // wtxid for coinbase is always 32 bytes of 0x00 - if (forWitness && this.isCoinbase()) - return Buffer.alloc(32, 0); - return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); + // Extra zero byte because: + // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19 + return bcrypto.taggedHash( + 'TapSighash', + Buffer.concat([Buffer.from([0x00]), sigMsgWriter.end()]), + ); + } + hashForWitnessV0(inIndex, prevOutScript, value, hashType) { + typeforce( + types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), + arguments, + ); + let tbuffer = Buffer.from([]); + let bufferWriter; + let hashOutputs = ZERO; + let hashPrevouts = ZERO; + let hashSequence = ZERO; + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { + tbuffer = Buffer.allocUnsafe(36 * this.ins.length); + bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + this.ins.forEach(txIn => { + bufferWriter.writeSlice(txIn.hash); + bufferWriter.writeUInt32(txIn.index); + }); + hashPrevouts = bcrypto.hash256(tbuffer); } - getId() { - // transaction hash's are displayed in reverse order - return (0, bufferutils_1.reverseBuffer)(this.getHash(false)).toString('hex'); + if ( + !(hashType & Transaction.SIGHASH_ANYONECANPAY) && + (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE + ) { + tbuffer = Buffer.allocUnsafe(4 * this.ins.length); + bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + this.ins.forEach(txIn => { + bufferWriter.writeUInt32(txIn.sequence); + }); + hashSequence = bcrypto.hash256(tbuffer); } - toBuffer(buffer, initialOffset) { - return this.__toBuffer(buffer, initialOffset, true); + if ( + (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE + ) { + const txOutsSize = this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script); + }, 0); + tbuffer = Buffer.allocUnsafe(txOutsSize); + bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + this.outs.forEach(out => { + bufferWriter.writeUInt64(out.value); + bufferWriter.writeVarSlice(out.script); + }); + hashOutputs = bcrypto.hash256(tbuffer); + } else if ( + (hashType & 0x1f) === Transaction.SIGHASH_SINGLE && + inIndex < this.outs.length + ) { + const output = this.outs[inIndex]; + tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); + bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + bufferWriter.writeUInt64(output.value); + bufferWriter.writeVarSlice(output.script); + hashOutputs = bcrypto.hash256(tbuffer); } - toHex() { - return this.toBuffer(undefined, undefined).toString('hex'); + tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); + bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + const input = this.ins[inIndex]; + bufferWriter.writeInt32(this.version); + bufferWriter.writeSlice(hashPrevouts); + bufferWriter.writeSlice(hashSequence); + bufferWriter.writeSlice(input.hash); + bufferWriter.writeUInt32(input.index); + bufferWriter.writeVarSlice(prevOutScript); + bufferWriter.writeUInt64(value); + bufferWriter.writeUInt32(input.sequence); + bufferWriter.writeSlice(hashOutputs); + bufferWriter.writeUInt32(this.locktime); + bufferWriter.writeUInt32(hashType); + return bcrypto.hash256(tbuffer); + } + getHash(forWitness) { + // wtxid for coinbase is always 32 bytes of 0x00 + if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0); + return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); + } + getId() { + // transaction hash's are displayed in reverse order + return (0, bufferutils_1.reverseBuffer)(this.getHash(false)).toString( + 'hex', + ); + } + toBuffer(buffer, initialOffset) { + return this.__toBuffer(buffer, initialOffset, true); + } + toHex() { + return this.toBuffer(undefined, undefined).toString('hex'); + } + setInputScript(index, scriptSig) { + typeforce(types.tuple(types.Number, types.Buffer), arguments); + this.ins[index].script = scriptSig; + } + setWitness(index, witness) { + typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + this.ins[index].witness = witness; + } + __toBuffer(buffer, initialOffset, _ALLOW_WITNESS = false) { + if (!buffer) buffer = Buffer.allocUnsafe(this.byteLength(_ALLOW_WITNESS)); + const bufferWriter = new bufferutils_1.BufferWriter( + buffer, + initialOffset || 0, + ); + bufferWriter.writeInt32(this.version); + const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); + if (hasWitnesses) { + bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); + bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); } - setInputScript(index, scriptSig) { - typeforce(types.tuple(types.Number, types.Buffer), arguments); - this.ins[index].script = scriptSig; - } - setWitness(index, witness) { - typeforce(types.tuple(types.Number, [types.Buffer]), arguments); - this.ins[index].witness = witness; - } - __toBuffer(buffer, initialOffset, _ALLOW_WITNESS = false) { - if (!buffer) - buffer = Buffer.allocUnsafe(this.byteLength(_ALLOW_WITNESS)); - const bufferWriter = new bufferutils_1.BufferWriter(buffer, initialOffset || 0); - bufferWriter.writeInt32(this.version); - const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); - if (hasWitnesses) { - bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); - bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); - } - bufferWriter.writeVarInt(this.ins.length); - this.ins.forEach(txIn => { - bufferWriter.writeSlice(txIn.hash); - bufferWriter.writeUInt32(txIn.index); - bufferWriter.writeVarSlice(txIn.script); - bufferWriter.writeUInt32(txIn.sequence); - }); - bufferWriter.writeVarInt(this.outs.length); - this.outs.forEach(txOut => { - if (isOutput(txOut)) { - bufferWriter.writeUInt64(txOut.value); - } - else { - bufferWriter.writeSlice(txOut.valueBuffer); - } - bufferWriter.writeVarSlice(txOut.script); - }); - if (hasWitnesses) { - this.ins.forEach(input => { - bufferWriter.writeVector(input.witness); - }); - } - bufferWriter.writeUInt32(this.locktime); - // avoid slicing unless necessary - if (initialOffset !== undefined) - return buffer.slice(initialOffset, bufferWriter.offset); - return buffer; + bufferWriter.writeVarInt(this.ins.length); + this.ins.forEach(txIn => { + bufferWriter.writeSlice(txIn.hash); + bufferWriter.writeUInt32(txIn.index); + bufferWriter.writeVarSlice(txIn.script); + bufferWriter.writeUInt32(txIn.sequence); + }); + bufferWriter.writeVarInt(this.outs.length); + this.outs.forEach(txOut => { + if (isOutput(txOut)) { + bufferWriter.writeUInt64(txOut.value); + } else { + bufferWriter.writeSlice(txOut.valueBuffer); + } + bufferWriter.writeVarSlice(txOut.script); + }); + if (hasWitnesses) { + this.ins.forEach(input => { + bufferWriter.writeVector(input.witness); + }); } + bufferWriter.writeUInt32(this.locktime); + // avoid slicing unless necessary + if (initialOffset !== undefined) + return buffer.slice(initialOffset, bufferWriter.offset); + return buffer; + } } exports.Transaction = Transaction; Transaction.DEFAULT_SEQUENCE = 0xffffffff; From c463f5f455b7260db5c17dd71875296d1b68b5fc Mon Sep 17 00:00:00 2001 From: Jackson Miller Date: Tue, 1 Oct 2024 15:09:24 +0900 Subject: [PATCH 3/3] Remove the audit package we no longer use. --- .github/workflows/main_ci.yml | 11 -- package-lock.json | 211 ---------------------------------- package.json | 2 - 3 files changed, 224 deletions(-) diff --git a/.github/workflows/main_ci.yml b/.github/workflows/main_ci.yml index 2e197b4e6..e44dfc726 100644 --- a/.github/workflows/main_ci.yml +++ b/.github/workflows/main_ci.yml @@ -61,17 +61,6 @@ jobs: ##################### # Jobs without matrix ##################### - audit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2 - - uses: actions/setup-node@eeb10cff27034e7acf239c5d29f62154018672fd # v3 - with: - node-version: 'lts/*' - registry-url: https://registry.npmjs.org/ - cache: 'npm' - - run: npm ci - - run: npm run audit coverage: runs-on: ubuntu-latest steps: diff --git a/package-lock.json b/package-lock.json index e0a146dbb..057cebca1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,6 @@ "@types/randombytes": "^2.0.0", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", - "better-npm-audit": "^3.7.3", "bip32": "^4.0.0", "bip39": "^3.1.0", "bip65": "^1.0.1", @@ -1194,15 +1193,6 @@ "node": ">=8" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1223,24 +1213,6 @@ "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" }, - "node_modules/better-npm-audit": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/better-npm-audit/-/better-npm-audit-3.7.3.tgz", - "integrity": "sha512-zsSiidlP5n7KpCYdAmkellu4JYA4IoRUUwrBMv/R7TwT8vcRfk5CQ2zTg7yUy4bdWkKtAj7VVdPQttdMbx+n5Q==", - "dev": true, - "dependencies": { - "commander": "^8.0.0", - "dayjs": "^1.10.6", - "lodash.get": "^4.4.2", - "table": "^6.7.1" - }, - "bin": { - "better-npm-audit": "index.js" - }, - "engines": { - "node": ">= 8.12" - } - }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -1551,15 +1523,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -1605,12 +1568,6 @@ "node": ">= 8" } }, - "node_modules/dayjs": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", - "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==", - "dev": true - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2840,24 +2797,12 @@ "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -3738,15 +3683,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -3944,23 +3880,6 @@ "node": ">=8" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -4107,44 +4026,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -5458,12 +5339,6 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -5484,18 +5359,6 @@ "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" }, - "better-npm-audit": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/better-npm-audit/-/better-npm-audit-3.7.3.tgz", - "integrity": "sha512-zsSiidlP5n7KpCYdAmkellu4JYA4IoRUUwrBMv/R7TwT8vcRfk5CQ2zTg7yUy4bdWkKtAj7VVdPQttdMbx+n5Q==", - "dev": true, - "requires": { - "commander": "^8.0.0", - "dayjs": "^1.10.6", - "lodash.get": "^4.4.2", - "table": "^6.7.1" - } - }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -5731,12 +5594,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true - }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -5779,12 +5636,6 @@ "which": "^2.0.1" } }, - "dayjs": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", - "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==", - "dev": true - }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -6683,24 +6534,12 @@ "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -7371,12 +7210,6 @@ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -7512,17 +7345,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -7632,39 +7454,6 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, - "table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", diff --git a/package.json b/package.json index c061f5881..77f8bce1a 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "bitcoinjs" ], "scripts": { - "audit": "better-npm-audit audit -l high", "build": "npm run clean && tsc -p ./tsconfig.json && npm run formatjs", "build:tests": "npm run clean:jstests && tsc -p ./test/tsconfig.json", "clean": "rimraf src", @@ -66,7 +65,6 @@ "@types/randombytes": "^2.0.0", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", - "better-npm-audit": "^3.7.3", "bip32": "^4.0.0", "bip39": "^3.1.0", "bip65": "^1.0.1",