@bsv/sdk 1.1.24 → 1.1.26

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.
Files changed (53) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/totp/totp.js +1 -1
  3. package/dist/cjs/src/totp/totp.js.map +1 -1
  4. package/dist/cjs/src/transaction/Beef.js +492 -0
  5. package/dist/cjs/src/transaction/Beef.js.map +1 -0
  6. package/dist/cjs/src/transaction/BeefParty.js +97 -0
  7. package/dist/cjs/src/transaction/BeefParty.js.map +1 -0
  8. package/dist/cjs/src/transaction/BeefTx.js +123 -0
  9. package/dist/cjs/src/transaction/BeefTx.js.map +1 -0
  10. package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
  11. package/dist/cjs/src/transaction/Transaction.js +156 -35
  12. package/dist/cjs/src/transaction/Transaction.js.map +1 -1
  13. package/dist/cjs/src/transaction/index.js +7 -1
  14. package/dist/cjs/src/transaction/index.js.map +1 -1
  15. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  16. package/dist/esm/src/totp/totp.js +1 -1
  17. package/dist/esm/src/totp/totp.js.map +1 -1
  18. package/dist/esm/src/transaction/Beef.js +485 -0
  19. package/dist/esm/src/transaction/Beef.js.map +1 -0
  20. package/dist/esm/src/transaction/BeefParty.js +93 -0
  21. package/dist/esm/src/transaction/BeefParty.js.map +1 -0
  22. package/dist/esm/src/transaction/BeefTx.js +121 -0
  23. package/dist/esm/src/transaction/BeefTx.js.map +1 -0
  24. package/dist/esm/src/transaction/MerklePath.js.map +1 -1
  25. package/dist/esm/src/transaction/Transaction.js +156 -35
  26. package/dist/esm/src/transaction/Transaction.js.map +1 -1
  27. package/dist/esm/src/transaction/index.js +3 -0
  28. package/dist/esm/src/transaction/index.js.map +1 -1
  29. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  30. package/dist/types/src/transaction/Beef.d.ts +143 -0
  31. package/dist/types/src/transaction/Beef.d.ts.map +1 -0
  32. package/dist/types/src/transaction/BeefParty.d.ts +62 -0
  33. package/dist/types/src/transaction/BeefParty.d.ts.map +1 -0
  34. package/dist/types/src/transaction/BeefTx.d.ts +35 -0
  35. package/dist/types/src/transaction/BeefTx.d.ts.map +1 -0
  36. package/dist/types/src/transaction/MerklePath.d.ts.map +1 -1
  37. package/dist/types/src/transaction/Transaction.d.ts +44 -4
  38. package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
  39. package/dist/types/src/transaction/index.d.ts +3 -0
  40. package/dist/types/src/transaction/index.d.ts.map +1 -1
  41. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  42. package/docs/primitives.md +372 -55
  43. package/docs/transaction.md +531 -5
  44. package/package.json +1 -1
  45. package/src/totp/totp.ts +1 -1
  46. package/src/transaction/Beef.ts +533 -0
  47. package/src/transaction/BeefParty.ts +100 -0
  48. package/src/transaction/BeefTx.ts +121 -0
  49. package/src/transaction/MerklePath.ts +11 -11
  50. package/src/transaction/Transaction.ts +196 -59
  51. package/src/transaction/__tests/Beef.test.ts +290 -0
  52. package/src/transaction/__tests/Transaction.test.ts +222 -3
  53. package/src/transaction/index.ts +3 -0
@@ -0,0 +1,121 @@
1
+ import { hash256 } from "../primitives/Hash.js"
2
+ import { Reader, Writer, toHex, toArray } from "../primitives/utils.js"
3
+ import Transaction from "./Transaction.js"
4
+ import { BEEF_MAGIC_TXID_ONLY_EXTENSION } from "./Beef.js"
5
+
6
+ /**
7
+ * A single bitcoin transaction associated with a `Beef` validity proof set.
8
+ *
9
+ * Simple case is transaction data included directly, either as raw bytes or fully parsed data, or both.
10
+ *
11
+ * Supports 'known' transactions which are represented by just their txid.
12
+ * It is assumed that intended consumer of this beef already has validity proof for such a transaction,
13
+ * which they can merge if necessary to create a valid beef.
14
+ */
15
+ export default class BeefTx {
16
+ _bumpIndex?: number
17
+ _tx?: Transaction
18
+ _rawTx?: number[]
19
+ _txid?: string
20
+ inputTxids: string[] = []
21
+ degree: number = 0
22
+
23
+ get bumpIndex() : number | undefined { return this._bumpIndex}
24
+
25
+ set bumpIndex(v: number | undefined) {
26
+ this._bumpIndex = v
27
+ this.updateInputTxids()
28
+ }
29
+
30
+ get hasProof() : boolean {
31
+ return this._bumpIndex !== undefined
32
+ }
33
+
34
+ get isTxidOnly() : boolean {
35
+ return !!this._txid && !this._rawTx && !this._tx
36
+ }
37
+
38
+ get txid() {
39
+ if (this._txid) return this._txid
40
+ if (this._tx) return this._txid = this._tx.id('hex')
41
+ if (this._rawTx) return this._txid = toHex(hash256(this._rawTx))
42
+ throw new Error('Internal')
43
+ }
44
+
45
+ get tx() {
46
+ if (this._tx) return this._tx
47
+ if (this._rawTx) return this._tx = Transaction.fromBinary(this._rawTx)
48
+ return undefined
49
+ }
50
+
51
+ get rawTx() {
52
+ if (this._rawTx) return this._rawTx
53
+ if (this._tx) return this._rawTx = this._tx.toBinary()
54
+ return undefined
55
+ }
56
+
57
+ /**
58
+ * @param tx If string, must be a valid txid. If `number[]` must be a valid serialized transaction.
59
+ * @param bumpIndex If transaction already has a proof in the beef to which it will be added.
60
+ */
61
+ constructor (tx: Transaction | number[] | string, bumpIndex?: number) {
62
+ if (typeof tx === 'string') {
63
+ this._txid = tx
64
+ } else {
65
+ if (Array.isArray(tx)) {
66
+ this._rawTx = tx
67
+ } else {
68
+ this._tx = <Transaction>tx
69
+ }
70
+ }
71
+ this.bumpIndex = bumpIndex
72
+ this.updateInputTxids()
73
+ }
74
+
75
+ private updateInputTxids() {
76
+ if (this.hasProof || !this.tx)
77
+ // If we have a proof, or don't have a parsed transaction
78
+ this.inputTxids = []
79
+ else {
80
+ const inputTxids = {};
81
+ for (const input of this.tx.inputs)
82
+ inputTxids[input.sourceTXID!] = true;
83
+ this.inputTxids = Object.keys(inputTxids);
84
+ }
85
+ }
86
+
87
+ toWriter(writer: Writer) : void {
88
+ if (this.isTxidOnly) {
89
+ // Encode just the txid of a known transaction using the txid
90
+ writer.writeUInt32LE(BEEF_MAGIC_TXID_ONLY_EXTENSION)
91
+ writer.writeReverse(toArray(this._txid, 'hex'))
92
+ } else if (this._rawTx)
93
+ writer.write(this._rawTx)
94
+ else if (this._tx)
95
+ writer.write(this._tx.toBinary())
96
+ else
97
+ throw new Error('a valid serialized Transaction is expected')
98
+ if (this.bumpIndex === undefined) {
99
+ writer.writeUInt8(0)
100
+ } else {
101
+ writer.writeUInt8(1)
102
+ writer.writeVarIntNum(this.bumpIndex)
103
+ }
104
+ }
105
+
106
+ static fromReader (br: Reader): BeefTx {
107
+ let tx: Transaction | number[] | string | undefined = undefined
108
+ const version = br.readUInt32LE()
109
+ if (version === BEEF_MAGIC_TXID_ONLY_EXTENSION) {
110
+ // This is the extension to support known transactions
111
+ tx = toHex(br.readReverse(32))
112
+ } else {
113
+ br.pos -= 4 // Unread the version...
114
+ tx = Transaction.fromReader(br)
115
+ }
116
+ const bumpIndex = br.readUInt8() ? br.readVarIntNum() : undefined
117
+ const beefTx = new BeefTx(tx, bumpIndex)
118
+ return beefTx
119
+ }
120
+
121
+ }
@@ -46,11 +46,11 @@ export default class MerklePath {
46
46
  * @param {string} hex - The hexadecimal string representation of the Merkle Path.
47
47
  * @returns {MerklePath} - A new MerklePath instance.
48
48
  */
49
- static fromHex (hex: string): MerklePath {
49
+ static fromHex(hex: string): MerklePath {
50
50
  return MerklePath.fromBinary(toArray(hex, 'hex'))
51
51
  }
52
52
 
53
- static fromReader (reader: Reader): MerklePath {
53
+ static fromReader(reader: Reader): MerklePath {
54
54
  const blockHeight = reader.readVarIntNum()
55
55
  const treeHeight = reader.readUInt8()
56
56
  const path = Array(treeHeight).fill(0).map(() => ([]))
@@ -89,12 +89,12 @@ export default class MerklePath {
89
89
  * @param {number[]} bump - The binary array representation of the Merkle Path.
90
90
  * @returns {MerklePath} - A new MerklePath instance.
91
91
  */
92
- static fromBinary (bump: number[]): MerklePath {
92
+ static fromBinary(bump: number[]): MerklePath {
93
93
  const reader = new Reader(bump)
94
94
  return MerklePath.fromReader(reader)
95
95
  }
96
96
 
97
- constructor (blockHeight: number, path: Array<Array<{
97
+ constructor(blockHeight: number, path: Array<Array<{
98
98
  offset: number
99
99
  hash?: string
100
100
  txid?: boolean
@@ -142,7 +142,7 @@ export default class MerklePath {
142
142
  *
143
143
  * @returns {number[]} - The binary array representation of the Merkle Path.
144
144
  */
145
- toBinary (): number[] {
145
+ toBinary(): number[] {
146
146
  const writer = new Writer()
147
147
  writer.writeVarIntNum(this.blockHeight)
148
148
  const treeHeight = this.path.length
@@ -173,7 +173,7 @@ export default class MerklePath {
173
173
  *
174
174
  * @returns {string} - The hexadecimal string representation of the Merkle Path.
175
175
  */
176
- toHex (): string {
176
+ toHex(): string {
177
177
  return toHex(this.toBinary())
178
178
  }
179
179
 
@@ -184,7 +184,7 @@ export default class MerklePath {
184
184
  * @returns {string} - The computed Merkle root as a hexadecimal string.
185
185
  * @throws {Error} - If the transaction ID is not part of the Merkle Path.
186
186
  */
187
- computeRoot (txid?: string): string {
187
+ computeRoot(txid?: string): string {
188
188
  if (typeof txid !== 'string') {
189
189
  txid = this.path[0].find(leaf => Boolean(leaf?.hash)).hash
190
190
  }
@@ -224,7 +224,7 @@ export default class MerklePath {
224
224
  * @param height
225
225
  * @param offset
226
226
  */
227
- findOrComputeLeaf (height: number, offset: number): MerklePathLeaf | undefined {
227
+ findOrComputeLeaf(height: number, offset: number): MerklePathLeaf | undefined {
228
228
  const hash = (m: string): string => toHex((
229
229
  hash256(toArray(m, 'hex').reverse())
230
230
  ).reverse())
@@ -261,7 +261,7 @@ export default class MerklePath {
261
261
  * @param {ChainTracker} chainTracker - The ChainTracker instance used to verify the Merkle root.
262
262
  * @returns {boolean} - True if the transaction ID is valid within the Merkle Path at the specified block height.
263
263
  */
264
- async verify (txid: string, chainTracker: ChainTracker): Promise<boolean> {
264
+ async verify(txid: string, chainTracker: ChainTracker): Promise<boolean> {
265
265
  const root = this.computeRoot(txid)
266
266
  // Use the chain tracker to determine whether this is a valid merkle root at the given block height
267
267
  return await chainTracker.isValidRootForHeight(root, this.blockHeight)
@@ -273,7 +273,7 @@ export default class MerklePath {
273
273
  * @param {MerklePath} other - Another MerklePath to combine with this path.
274
274
  * @throws {Error} - If the paths have different block heights or roots.
275
275
  */
276
- combine (other: MerklePath): void {
276
+ combine(other: MerklePath): void {
277
277
  if (this.blockHeight !== other.blockHeight) {
278
278
  throw new Error('You cannot combine paths which do not have the same block height.')
279
279
  }
@@ -309,7 +309,7 @@ export default class MerklePath {
309
309
  * Assumes that at least all required nodes are present.
310
310
  * Leaves all levels sorted by increasing offset.
311
311
  */
312
- trim () {
312
+ trim() {
313
313
  const pushIfNew = (v: number, a: number[]) => {
314
314
  if (a.length === 0 || a.slice(-1)[0] !== v) { a.push(v) }
315
315
  }