@bsv/sdk 1.10.1 → 1.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/identity/IdentityClient.js +124 -20
- package/dist/cjs/src/identity/IdentityClient.js.map +1 -1
- package/dist/cjs/src/primitives/ReaderUint8Array.js +180 -0
- package/dist/cjs/src/primitives/ReaderUint8Array.js.map +1 -0
- package/dist/cjs/src/primitives/WriterUint8Array.js +173 -0
- package/dist/cjs/src/primitives/WriterUint8Array.js.map +1 -0
- package/dist/cjs/src/primitives/utils.js +20 -2
- package/dist/cjs/src/primitives/utils.js.map +1 -1
- package/dist/cjs/src/transaction/Beef.js +85 -27
- package/dist/cjs/src/transaction/Beef.js.map +1 -1
- package/dist/cjs/src/transaction/BeefTx.js +32 -14
- package/dist/cjs/src/transaction/BeefTx.js.map +1 -1
- package/dist/cjs/src/transaction/MerklePath.js +25 -6
- package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
- package/dist/cjs/src/transaction/Transaction.js +77 -26
- package/dist/cjs/src/transaction/Transaction.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/identity/IdentityClient.js +124 -20
- package/dist/esm/src/identity/IdentityClient.js.map +1 -1
- package/dist/esm/src/primitives/ReaderUint8Array.js +176 -0
- package/dist/esm/src/primitives/ReaderUint8Array.js.map +1 -0
- package/dist/esm/src/primitives/WriterUint8Array.js +169 -0
- package/dist/esm/src/primitives/WriterUint8Array.js.map +1 -0
- package/dist/esm/src/primitives/utils.js +18 -1
- package/dist/esm/src/primitives/utils.js.map +1 -1
- package/dist/esm/src/transaction/Beef.js +86 -28
- package/dist/esm/src/transaction/Beef.js.map +1 -1
- package/dist/esm/src/transaction/BeefTx.js +33 -15
- package/dist/esm/src/transaction/BeefTx.js.map +1 -1
- package/dist/esm/src/transaction/MerklePath.js +26 -7
- package/dist/esm/src/transaction/MerklePath.js.map +1 -1
- package/dist/esm/src/transaction/Transaction.js +78 -27
- package/dist/esm/src/transaction/Transaction.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/identity/IdentityClient.d.ts +8 -0
- package/dist/types/src/identity/IdentityClient.d.ts.map +1 -1
- package/dist/types/src/primitives/ReaderUint8Array.d.ts +32 -0
- package/dist/types/src/primitives/ReaderUint8Array.d.ts.map +1 -0
- package/dist/types/src/primitives/WriterUint8Array.d.ts +54 -0
- package/dist/types/src/primitives/WriterUint8Array.d.ts.map +1 -0
- package/dist/types/src/primitives/utils.d.ts +15 -3
- package/dist/types/src/primitives/utils.d.ts.map +1 -1
- package/dist/types/src/transaction/Beef.d.ts +24 -7
- package/dist/types/src/transaction/Beef.d.ts.map +1 -1
- package/dist/types/src/transaction/BeefTx.d.ts +13 -6
- package/dist/types/src/transaction/BeefTx.d.ts.map +1 -1
- package/dist/types/src/transaction/MerklePath.d.ts +16 -3
- package/dist/types/src/transaction/MerklePath.d.ts.map +1 -1
- package/dist/types/src/transaction/Transaction.d.ts +44 -7
- package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +3 -3
- package/dist/umd/bundle.js.map +1 -1
- package/docs/reference/primitives.md +167 -29
- package/docs/reference/script.md +1 -1
- package/docs/reference/transaction.md +177 -34
- package/package.json +1 -1
- package/src/identity/IdentityClient.ts +153 -29
- package/src/identity/__tests/IdentityClient.test.ts +289 -1
- package/src/overlay-tools/__tests/SHIPBroadcaster.test.ts +9 -0
- package/src/primitives/ReaderUint8Array.ts +196 -0
- package/src/primitives/WriterUint8Array.ts +195 -0
- package/src/primitives/__tests/ReaderUint8Array.test.ts +317 -0
- package/src/primitives/__tests/WriterUint8Array.test.ts +208 -0
- package/src/primitives/utils.ts +20 -2
- package/src/transaction/Beef.ts +103 -40
- package/src/transaction/BeefTx.ts +38 -19
- package/src/transaction/MerklePath.ts +30 -9
- package/src/transaction/Transaction.ts +91 -38
- package/src/transaction/__tests/Beef.test.ts +75 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
import { Reader, Writer, toHex, toArray } from '../primitives/utils.js'
|
|
2
|
+
import { Reader, Writer, toHex, toArray, WriterUint8Array } from '../primitives/utils.js'
|
|
3
3
|
import { hash256 } from '../primitives/Hash.js'
|
|
4
4
|
import ChainTracker from './ChainTracker.js'
|
|
5
|
+
import { ReaderUint8Array } from '../primitives/ReaderUint8Array.js'
|
|
5
6
|
|
|
6
7
|
export interface MerklePathLeaf {
|
|
7
8
|
offset: number
|
|
@@ -54,7 +55,7 @@ export default class MerklePath {
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
static fromReader (
|
|
57
|
-
reader: Reader,
|
|
58
|
+
reader: Reader | ReaderUint8Array,
|
|
58
59
|
legalOffsetsOnly: boolean = true
|
|
59
60
|
): MerklePath {
|
|
60
61
|
const blockHeight = reader.readVarIntNum()
|
|
@@ -103,8 +104,8 @@ export default class MerklePath {
|
|
|
103
104
|
* @param {number[]} bump - The binary array representation of the Merkle Path.
|
|
104
105
|
* @returns {MerklePath} - A new MerklePath instance.
|
|
105
106
|
*/
|
|
106
|
-
static fromBinary (bump: number[]): MerklePath {
|
|
107
|
-
const reader = new
|
|
107
|
+
static fromBinary (bump: number[] | Uint8Array): MerklePath {
|
|
108
|
+
const reader = new ReaderUint8Array(bump)
|
|
108
109
|
return MerklePath.fromReader(reader)
|
|
109
110
|
}
|
|
110
111
|
|
|
@@ -181,12 +182,11 @@ export default class MerklePath {
|
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
/**
|
|
184
|
-
*
|
|
185
|
+
* Serializes the MerklePath to the writer provided.
|
|
185
186
|
*
|
|
186
|
-
* @
|
|
187
|
+
* @param writer - The writer to which the Merkle Path will be serialized.
|
|
187
188
|
*/
|
|
188
|
-
|
|
189
|
-
const writer = new Writer()
|
|
189
|
+
toWriter (writer: Writer | WriterUint8Array): void {
|
|
190
190
|
writer.writeVarIntNum(this.blockHeight)
|
|
191
191
|
const treeHeight = this.path.length
|
|
192
192
|
writer.writeUInt8(treeHeight)
|
|
@@ -208,16 +208,37 @@ export default class MerklePath {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Converts the MerklePath to a binary array format.
|
|
215
|
+
*
|
|
216
|
+
* @returns {number[]} - The binary array representation of the Merkle Path.
|
|
217
|
+
*/
|
|
218
|
+
toBinary (): number[] {
|
|
219
|
+
const writer = new Writer()
|
|
220
|
+
this.toWriter(writer)
|
|
211
221
|
return writer.toArray()
|
|
212
222
|
}
|
|
213
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Converts the MerklePath to a binary array format.
|
|
226
|
+
*
|
|
227
|
+
* @returns {Uint8Array} - The binary array representation of the Merkle Path.
|
|
228
|
+
*/
|
|
229
|
+
toBinaryUint8Array (): Uint8Array {
|
|
230
|
+
const writer = new WriterUint8Array()
|
|
231
|
+
this.toWriter(writer)
|
|
232
|
+
return writer.toUint8Array()
|
|
233
|
+
}
|
|
234
|
+
|
|
214
235
|
/**
|
|
215
236
|
* Converts the MerklePath to a hexadecimal string format.
|
|
216
237
|
*
|
|
217
238
|
* @returns {string} - The hexadecimal string representation of the Merkle Path.
|
|
218
239
|
*/
|
|
219
240
|
toHex (): string {
|
|
220
|
-
return toHex(this.
|
|
241
|
+
return toHex(this.toBinaryUint8Array())
|
|
221
242
|
}
|
|
222
243
|
|
|
223
244
|
//
|
|
@@ -3,7 +3,7 @@ import TransactionInput from './TransactionInput.js'
|
|
|
3
3
|
import TransactionOutput from './TransactionOutput.js'
|
|
4
4
|
import UnlockingScript from '../script/UnlockingScript.js'
|
|
5
5
|
import LockingScript from '../script/LockingScript.js'
|
|
6
|
-
import { Reader, Writer, toHex, toArray } from '../primitives/utils.js'
|
|
6
|
+
import { Reader, Writer, toHex, toArray, ReaderUint8Array, toUint8Array, WriterUint8Array } from '../primitives/utils.js'
|
|
7
7
|
import { hash256 } from '../primitives/Hash.js'
|
|
8
8
|
import FeeModel from './FeeModel.js'
|
|
9
9
|
import LivePolicy from './fee-models/LivePolicy.js'
|
|
@@ -16,9 +16,6 @@ import { defaultChainTracker } from './chaintrackers/DefaultChainTracker.js'
|
|
|
16
16
|
import { Beef, BEEF_V1 } from './Beef.js'
|
|
17
17
|
import P2PKH from '../script/templates/P2PKH.js'
|
|
18
18
|
|
|
19
|
-
const BufferCtor =
|
|
20
|
-
typeof globalThis !== 'undefined' ? (globalThis as any).Buffer : undefined
|
|
21
|
-
|
|
22
19
|
/**
|
|
23
20
|
* Represents a complete Bitcoin transaction. This class encapsulates all the details
|
|
24
21
|
* required for creating, signing, and processing a Bitcoin transaction, including
|
|
@@ -109,7 +106,7 @@ export default class Transaction {
|
|
|
109
106
|
* @param txid Optional TXID of the transaction to retrieve from the BEEF data.
|
|
110
107
|
* @returns An anchored transaction, linked to its associated inputs populated with merkle paths.
|
|
111
108
|
*/
|
|
112
|
-
static fromBEEF (beef: number[], txid?: string): Transaction {
|
|
109
|
+
static fromBEEF (beef: number[] | Uint8Array, txid?: string): Transaction {
|
|
113
110
|
const { tx } = Transaction.fromAnyBeef(beef, txid)
|
|
114
111
|
return tx
|
|
115
112
|
}
|
|
@@ -121,7 +118,7 @@ export default class Transaction {
|
|
|
121
118
|
* @param beef A binary representation of an Atomic BEEF structure.
|
|
122
119
|
* @returns The subject transaction, linked to its associated inputs populated with merkle paths.
|
|
123
120
|
*/
|
|
124
|
-
static fromAtomicBEEF (beef: number[]): Transaction {
|
|
121
|
+
static fromAtomicBEEF (beef: number[] | Uint8Array): Transaction {
|
|
125
122
|
const { tx, txid, beef: b } = Transaction.fromAnyBeef(beef)
|
|
126
123
|
if (txid !== b.atomicTxid) {
|
|
127
124
|
if (b.atomicTxid != null) {
|
|
@@ -133,7 +130,7 @@ export default class Transaction {
|
|
|
133
130
|
return tx
|
|
134
131
|
}
|
|
135
132
|
|
|
136
|
-
private static fromAnyBeef (beef: number[], txid?: string): { tx: Transaction, beef: Beef, txid: string } {
|
|
133
|
+
private static fromAnyBeef (beef: number[] | Uint8Array, txid?: string): { tx: Transaction, beef: Beef, txid: string } {
|
|
137
134
|
const b = Beef.fromBinary(beef)
|
|
138
135
|
if (b.txs.length < 1) {
|
|
139
136
|
throw new Error('beef must include at least one transaction.')
|
|
@@ -155,8 +152,8 @@ export default class Transaction {
|
|
|
155
152
|
* @param ef A binary representation of a transaction in EF format.
|
|
156
153
|
* @returns An extended transaction, linked to its associated inputs by locking script and satoshis amounts only.
|
|
157
154
|
*/
|
|
158
|
-
static fromEF (ef: number[]): Transaction {
|
|
159
|
-
const br =
|
|
155
|
+
static fromEF (ef: number[] | Uint8Array): Transaction {
|
|
156
|
+
const br = ReaderUint8Array.makeReader(ef)
|
|
160
157
|
const version = br.readUInt32LE()
|
|
161
158
|
if (toHex(br.read(6)) !== '0000000000ef') { throw new Error('Invalid EF marker') }
|
|
162
159
|
const inputsLength = br.readVarIntNum()
|
|
@@ -217,11 +214,11 @@ export default class Transaction {
|
|
|
217
214
|
* outputs: { vout: number, offset: number, length: number }[]
|
|
218
215
|
* }
|
|
219
216
|
*/
|
|
220
|
-
static parseScriptOffsets (bin: number[]): {
|
|
217
|
+
static parseScriptOffsets (bin: number[] | Uint8Array): {
|
|
221
218
|
inputs: Array<{ vin: number, offset: number, length: number }>
|
|
222
219
|
outputs: Array<{ vout: number, offset: number, length: number }>
|
|
223
220
|
} {
|
|
224
|
-
const br =
|
|
221
|
+
const br = ReaderUint8Array.makeReader(bin)
|
|
225
222
|
const inputs: Array<{ vin: number, offset: number, length: number }> = []
|
|
226
223
|
const outputs: Array<{ vout: number, offset: number, length: number }> = []
|
|
227
224
|
|
|
@@ -243,7 +240,7 @@ export default class Transaction {
|
|
|
243
240
|
return { inputs, outputs }
|
|
244
241
|
}
|
|
245
242
|
|
|
246
|
-
static fromReader (br: Reader): Transaction {
|
|
243
|
+
static fromReader (br: Reader | ReaderUint8Array): Transaction {
|
|
247
244
|
const version = br.readUInt32LE()
|
|
248
245
|
const inputsLength = br.readVarIntNum()
|
|
249
246
|
const inputs: TransactionInput[] = []
|
|
@@ -284,10 +281,10 @@ export default class Transaction {
|
|
|
284
281
|
* @param {number[]} bin - The binary array representation of the transaction.
|
|
285
282
|
* @returns {Transaction} - A new Transaction instance.
|
|
286
283
|
*/
|
|
287
|
-
static fromBinary (bin: number[]): Transaction {
|
|
284
|
+
static fromBinary (bin: number[] | Uint8Array): Transaction {
|
|
288
285
|
const copy = bin.slice()
|
|
289
286
|
const rawBytes = Uint8Array.from(copy)
|
|
290
|
-
const br = new
|
|
287
|
+
const br = new ReaderUint8Array(rawBytes)
|
|
291
288
|
const tx = Transaction.fromReader(br)
|
|
292
289
|
tx.rawBytesCache = rawBytes
|
|
293
290
|
return tx
|
|
@@ -301,15 +298,11 @@ export default class Transaction {
|
|
|
301
298
|
* @returns {Transaction} - A new Transaction instance.
|
|
302
299
|
*/
|
|
303
300
|
static fromHex (hex: string): Transaction {
|
|
304
|
-
const
|
|
305
|
-
const
|
|
306
|
-
const br = new Reader(bin)
|
|
301
|
+
const rawBytes = toUint8Array(hex, 'hex')
|
|
302
|
+
const br = new ReaderUint8Array(rawBytes)
|
|
307
303
|
const tx = Transaction.fromReader(br)
|
|
308
304
|
tx.rawBytesCache = rawBytes
|
|
309
|
-
tx.hexCache =
|
|
310
|
-
BufferCtor != null
|
|
311
|
-
? BufferCtor.from(rawBytes).toString('hex')
|
|
312
|
-
: toHex(bin)
|
|
305
|
+
tx.hexCache = toHex(rawBytes)
|
|
313
306
|
return tx
|
|
314
307
|
}
|
|
315
308
|
|
|
@@ -321,7 +314,7 @@ export default class Transaction {
|
|
|
321
314
|
* @returns {Transaction} - A new Transaction instance.
|
|
322
315
|
*/
|
|
323
316
|
static fromHexEF (hex: string): Transaction {
|
|
324
|
-
return Transaction.fromEF(
|
|
317
|
+
return Transaction.fromEF(toUint8Array(hex, 'hex'))
|
|
325
318
|
}
|
|
326
319
|
|
|
327
320
|
/**
|
|
@@ -616,7 +609,7 @@ export default class Transaction {
|
|
|
616
609
|
return await broadcaster.broadcast(this)
|
|
617
610
|
}
|
|
618
611
|
|
|
619
|
-
private writeTransactionBody (writer: Writer): void {
|
|
612
|
+
private writeTransactionBody (writer: Writer | WriterUint8Array): void {
|
|
620
613
|
writer.writeUInt32LE(this.version)
|
|
621
614
|
writer.writeVarIntNum(this.inputs.length)
|
|
622
615
|
for (const i of this.inputs) {
|
|
@@ -649,7 +642,7 @@ export default class Transaction {
|
|
|
649
642
|
}
|
|
650
643
|
|
|
651
644
|
private buildSerializedBytes (): Uint8Array {
|
|
652
|
-
const writer = new
|
|
645
|
+
const writer = new WriterUint8Array()
|
|
653
646
|
this.writeTransactionBody(writer)
|
|
654
647
|
return writer.toUint8Array()
|
|
655
648
|
}
|
|
@@ -674,13 +667,7 @@ export default class Transaction {
|
|
|
674
667
|
return this.getSerializedBytes()
|
|
675
668
|
}
|
|
676
669
|
|
|
677
|
-
|
|
678
|
-
* Converts the transaction to a BRC-30 EF format.
|
|
679
|
-
*
|
|
680
|
-
* @returns {number[]} - The BRC-30 EF representation of the transaction.
|
|
681
|
-
*/
|
|
682
|
-
toEF (): number[] {
|
|
683
|
-
const writer = new Writer()
|
|
670
|
+
private writeEF (writer: Writer | WriterUint8Array): void {
|
|
684
671
|
writer.writeUInt32LE(this.version)
|
|
685
672
|
writer.write([0, 0, 0, 0, 0, 0xef])
|
|
686
673
|
writer.writeVarIntNum(this.inputs.length)
|
|
@@ -721,16 +708,37 @@ export default class Transaction {
|
|
|
721
708
|
writer.write(scriptBin)
|
|
722
709
|
}
|
|
723
710
|
writer.writeUInt32LE(this.lockTime)
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Converts the transaction to a BRC-30 EF format.
|
|
715
|
+
*
|
|
716
|
+
* @returns {number[]} - The BRC-30 EF representation of the transaction.
|
|
717
|
+
*/
|
|
718
|
+
toEF (): number[] {
|
|
719
|
+
const writer = new Writer()
|
|
720
|
+
this.writeEF(writer)
|
|
724
721
|
return writer.toArray()
|
|
725
722
|
}
|
|
726
723
|
|
|
724
|
+
/**
|
|
725
|
+
* Converts the transaction to a BRC-30 EF format.
|
|
726
|
+
*
|
|
727
|
+
* @returns {Uint8Array} - The BRC-30 EF representation of the transaction.
|
|
728
|
+
*/
|
|
729
|
+
toEFUint8Array (): Uint8Array {
|
|
730
|
+
const writer = new WriterUint8Array()
|
|
731
|
+
this.writeEF(writer)
|
|
732
|
+
return writer.toUint8Array()
|
|
733
|
+
}
|
|
734
|
+
|
|
727
735
|
/**
|
|
728
736
|
* Converts the transaction to a hexadecimal string EF.
|
|
729
737
|
*
|
|
730
738
|
* @returns {string} - The hexadecimal string representation of the transaction EF.
|
|
731
739
|
*/
|
|
732
740
|
toHexEF (): string {
|
|
733
|
-
return toHex(this.
|
|
741
|
+
return toHex(this.toEFUint8Array())
|
|
734
742
|
}
|
|
735
743
|
|
|
736
744
|
/**
|
|
@@ -743,10 +751,7 @@ export default class Transaction {
|
|
|
743
751
|
return this.hexCache
|
|
744
752
|
}
|
|
745
753
|
const bytes = this.getSerializedBytes()
|
|
746
|
-
const hex =
|
|
747
|
-
BufferCtor != null
|
|
748
|
-
? BufferCtor.from(bytes).toString('hex')
|
|
749
|
-
: toHex(Array.from(bytes))
|
|
754
|
+
const hex = toHex(bytes)
|
|
750
755
|
this.hexCache = hex
|
|
751
756
|
return hex
|
|
752
757
|
}
|
|
@@ -956,8 +961,7 @@ export default class Transaction {
|
|
|
956
961
|
* @returns The serialized BEEF structure
|
|
957
962
|
* @throws Error if there are any missing sourceTransactions unless `allowPartial` is true.
|
|
958
963
|
*/
|
|
959
|
-
|
|
960
|
-
const writer = new Writer()
|
|
964
|
+
writeSerializedBEEF (writer: Writer | WriterUint8Array, allowPartial?: boolean): void {
|
|
961
965
|
writer.writeUInt32LE(BEEF_V1)
|
|
962
966
|
const BUMPs: MerklePath[] = []
|
|
963
967
|
const bumpIndexByInstance = new Map<MerklePath, number>()
|
|
@@ -1035,6 +1039,34 @@ export default class Transaction {
|
|
|
1035
1039
|
return writer.toArray()
|
|
1036
1040
|
}
|
|
1037
1041
|
|
|
1042
|
+
/**
|
|
1043
|
+
* Serializes this transaction, together with its inputs and the respective merkle proofs, into the BEEF (BRC-62) format. This enables efficient verification of its compliance with the rules of SPV.
|
|
1044
|
+
*
|
|
1045
|
+
* @param allowPartial If true, error will not be thrown if there are any missing sourceTransactions.
|
|
1046
|
+
*
|
|
1047
|
+
* @returns {number[]} The serialized BEEF structure
|
|
1048
|
+
* @throws Error if there are any missing sourceTransactions unless `allowPartial` is true.
|
|
1049
|
+
*/
|
|
1050
|
+
toBEEF (allowPartial?: boolean): number[] {
|
|
1051
|
+
const writer = new Writer()
|
|
1052
|
+
this.writeSerializedBEEF(writer, allowPartial)
|
|
1053
|
+
return writer.toArray()
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
/**
|
|
1057
|
+
* Serializes this transaction, together with its inputs and the respective merkle proofs, into the BEEF (BRC-62) format. This enables efficient verification of its compliance with the rules of SPV.
|
|
1058
|
+
*
|
|
1059
|
+
* @param allowPartial If true, error will not be thrown if there are any missing sourceTransactions.
|
|
1060
|
+
*
|
|
1061
|
+
* @returns {number[]} The serialized BEEF structure
|
|
1062
|
+
* @throws Error if there are any missing sourceTransactions unless `allowPartial` is true.
|
|
1063
|
+
*/
|
|
1064
|
+
toBEEFUint8Array (allowPartial?: boolean): Uint8Array {
|
|
1065
|
+
const writer = new WriterUint8Array()
|
|
1066
|
+
this.writeSerializedBEEF(writer, allowPartial)
|
|
1067
|
+
return writer.toArray()
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1038
1070
|
/**
|
|
1039
1071
|
* Serializes this transaction and its inputs into the Atomic BEEF (BRC-95) format.
|
|
1040
1072
|
* The Atomic BEEF format starts with a 4-byte prefix `0x01010101`, followed by the TXID of the subject transaction,
|
|
@@ -1052,4 +1084,25 @@ export default class Transaction {
|
|
|
1052
1084
|
const beefData = this.toBEEF(allowPartial)
|
|
1053
1085
|
return prefix.concat(txHash, beefData)
|
|
1054
1086
|
}
|
|
1087
|
+
|
|
1088
|
+
/**
|
|
1089
|
+
* Serializes this transaction and its inputs into the Atomic BEEF (BRC-95) format.
|
|
1090
|
+
* The Atomic BEEF format starts with a 4-byte prefix `0x01010101`, followed by the TXID of the subject transaction,
|
|
1091
|
+
* and then the BEEF data containing only the subject transaction and its dependencies.
|
|
1092
|
+
* This format ensures that the BEEF structure is atomic and contains no unrelated transactions.
|
|
1093
|
+
*
|
|
1094
|
+
* @param allowPartial If true, error will not be thrown if there are any missing sourceTransactions.
|
|
1095
|
+
*
|
|
1096
|
+
* @returns {number[]} - The serialized Atomic BEEF structure.
|
|
1097
|
+
* @throws Error if there are any missing sourceTransactions unless `allowPartial` is true.
|
|
1098
|
+
*/
|
|
1099
|
+
toAtomicBEEFUint8Array (allowPartial?: boolean): Uint8Array {
|
|
1100
|
+
const writer = new WriterUint8Array()
|
|
1101
|
+
const prefix = [1, 1, 1, 1]
|
|
1102
|
+
writer.write(prefix)
|
|
1103
|
+
const txHash = this.hash() as number[]
|
|
1104
|
+
writer.write(txHash)
|
|
1105
|
+
this.writeSerializedBEEF(writer, allowPartial)
|
|
1106
|
+
return writer.toUint8Array()
|
|
1107
|
+
}
|
|
1055
1108
|
}
|
|
@@ -324,6 +324,81 @@ describe('Beef tests', () => {
|
|
|
324
324
|
}
|
|
325
325
|
})
|
|
326
326
|
|
|
327
|
+
test('6b_trimKnownTxids_removes_unreferenced_bumps', async () => {
|
|
328
|
+
// Create a beef with multiple transactions and bumps
|
|
329
|
+
const beef = Beef.fromString(beefs[0])
|
|
330
|
+
|
|
331
|
+
// Verify initial state
|
|
332
|
+
const initialBumpCount = beef.bumps.length
|
|
333
|
+
const initialTxCount = beef.txs.length
|
|
334
|
+
expect(initialBumpCount).toBe(1)
|
|
335
|
+
expect(initialTxCount).toBe(1)
|
|
336
|
+
|
|
337
|
+
// Add some txid-only transactions that don't have bumps
|
|
338
|
+
beef.mergeTxidOnly('txid1')
|
|
339
|
+
beef.mergeTxidOnly('txid2')
|
|
340
|
+
beef.mergeTxidOnly('txid3')
|
|
341
|
+
|
|
342
|
+
expect(beef.txs.length).toBe(4)
|
|
343
|
+
expect(beef.bumps.length).toBe(1)
|
|
344
|
+
|
|
345
|
+
// Get the txid of the transaction with a bump
|
|
346
|
+
const txWithBump = beef.txs.find(tx => tx.bumpIndex !== undefined)
|
|
347
|
+
expect(txWithBump).toBeTruthy()
|
|
348
|
+
|
|
349
|
+
// Trim all txid-only transactions
|
|
350
|
+
beef.trimKnownTxids(['txid1', 'txid2', 'txid3'])
|
|
351
|
+
|
|
352
|
+
// Verify txids were removed
|
|
353
|
+
expect(beef.txs.length).toBe(1)
|
|
354
|
+
expect(beef.bumps.length).toBe(1) // Bump should still be there because it's referenced
|
|
355
|
+
|
|
356
|
+
// Now test removing the transaction that has the bump
|
|
357
|
+
// First, make it txidOnly
|
|
358
|
+
const originalTxid = txWithBump!.txid
|
|
359
|
+
beef.makeTxidOnly(originalTxid)
|
|
360
|
+
|
|
361
|
+
// Now trim it
|
|
362
|
+
beef.trimKnownTxids([originalTxid])
|
|
363
|
+
|
|
364
|
+
// The bump should be removed since no transactions reference it anymore
|
|
365
|
+
expect(beef.txs.length).toBe(0)
|
|
366
|
+
expect(beef.bumps.length).toBe(0)
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
test('6c_trimKnownTxids_updates_bump_indices', async () => {
|
|
370
|
+
// Use existing beef with bumps
|
|
371
|
+
const beef = Beef.fromString(beefs[0])
|
|
372
|
+
|
|
373
|
+
const initialBumpCount = beef.bumps.length
|
|
374
|
+
const initialTxCount = beef.txs.length
|
|
375
|
+
|
|
376
|
+
// Find transaction with bump
|
|
377
|
+
const txWithBump = beef.txs.find(tx => tx.bumpIndex !== undefined)
|
|
378
|
+
expect(txWithBump).toBeTruthy()
|
|
379
|
+
const originalBumpIndex = txWithBump!.bumpIndex
|
|
380
|
+
|
|
381
|
+
// Add some txid-only transactions
|
|
382
|
+
beef.mergeTxidOnly('known1')
|
|
383
|
+
beef.mergeTxidOnly('known2')
|
|
384
|
+
|
|
385
|
+
expect(beef.txs.length).toBe(initialTxCount + 2)
|
|
386
|
+
expect(beef.bumps.length).toBe(initialBumpCount)
|
|
387
|
+
|
|
388
|
+
// Trim the known txids
|
|
389
|
+
beef.trimKnownTxids(['known1', 'known2'])
|
|
390
|
+
|
|
391
|
+
// Verify bump count didn't change (all bumps are still referenced)
|
|
392
|
+
expect(beef.bumps.length).toBe(initialBumpCount)
|
|
393
|
+
|
|
394
|
+
// Verify transaction count decreased
|
|
395
|
+
expect(beef.txs.length).toBe(initialTxCount)
|
|
396
|
+
|
|
397
|
+
// Verify bumpIndex is still correct
|
|
398
|
+
const txAfterTrim = beef.txs.find(tx => tx.txid === txWithBump!.txid)
|
|
399
|
+
expect(txAfterTrim?.bumpIndex).toBe(originalBumpIndex)
|
|
400
|
+
})
|
|
401
|
+
|
|
327
402
|
test('7_AtomicBeef', async () => {
|
|
328
403
|
{
|
|
329
404
|
const beef = Beef.fromString(beefs[0])
|