@bsv/sdk 1.1.30 → 1.1.33
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/transaction/Beef.js +195 -50
- package/dist/cjs/src/transaction/Beef.js.map +1 -1
- package/dist/cjs/src/transaction/BeefParty.js +16 -0
- package/dist/cjs/src/transaction/BeefParty.js.map +1 -1
- package/dist/cjs/src/transaction/BeefTx.js +6 -1
- package/dist/cjs/src/transaction/BeefTx.js.map +1 -1
- package/dist/cjs/src/transaction/Transaction.js +25 -10
- package/dist/cjs/src/transaction/Transaction.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/transaction/Beef.js +194 -49
- package/dist/esm/src/transaction/Beef.js.map +1 -1
- package/dist/esm/src/transaction/BeefParty.js +16 -0
- package/dist/esm/src/transaction/BeefParty.js.map +1 -1
- package/dist/esm/src/transaction/BeefTx.js +6 -1
- package/dist/esm/src/transaction/BeefTx.js.map +1 -1
- package/dist/esm/src/transaction/Transaction.js +25 -10
- package/dist/esm/src/transaction/Transaction.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/transaction/Beef.d.ts +60 -4
- package/dist/types/src/transaction/Beef.d.ts.map +1 -1
- package/dist/types/src/transaction/BeefParty.d.ts +11 -0
- package/dist/types/src/transaction/BeefParty.d.ts.map +1 -1
- package/dist/types/src/transaction/BeefTx.d.ts +6 -1
- package/dist/types/src/transaction/BeefTx.d.ts.map +1 -1
- package/dist/types/src/transaction/Transaction.d.ts +8 -2
- package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/docs/transaction.md +166 -9
- package/package.json +1 -1
- package/src/transaction/Beef.ts +221 -52
- package/src/transaction/BeefParty.ts +17 -0
- package/src/transaction/BeefTx.ts +6 -1
- package/src/transaction/Transaction.ts +25 -10
- package/src/transaction/__tests/Beef.test.ts +74 -15
|
@@ -18,7 +18,12 @@ export default class BeefTx {
|
|
|
18
18
|
_rawTx?: number[]
|
|
19
19
|
_txid?: string
|
|
20
20
|
inputTxids: string[] = []
|
|
21
|
-
|
|
21
|
+
/**
|
|
22
|
+
* true if `hasProof` or all inputs chain to `hasProof`.
|
|
23
|
+
*
|
|
24
|
+
* Typically set by sorting transactions by proven dependency chains.
|
|
25
|
+
*/
|
|
26
|
+
isValid?: boolean = undefined
|
|
22
27
|
|
|
23
28
|
get bumpIndex (): number | undefined { return this._bumpIndex }
|
|
24
29
|
|
|
@@ -138,7 +138,18 @@ export default class Transaction {
|
|
|
138
138
|
|
|
139
139
|
// Ensure that all transactions are part of the dependency graph of the subject transaction
|
|
140
140
|
const validTxids = new Set<string>()
|
|
141
|
+
// All BUMP level 0 hashes are valid.
|
|
142
|
+
for (const bump of BUMPs) {
|
|
143
|
+
for (const n of bump.path[0])
|
|
144
|
+
if (n.hash)
|
|
145
|
+
validTxids.add(n.hash)
|
|
146
|
+
}
|
|
147
|
+
// To keep track of which transactions were used.
|
|
148
|
+
const unusedTxTxids = new Set<string>()
|
|
149
|
+
for (const txid of Object.keys(transactions)) unusedTxTxids.add(txid)
|
|
150
|
+
|
|
141
151
|
const traverseDependencies = (txid: string) => {
|
|
152
|
+
unusedTxTxids.delete(txid)
|
|
142
153
|
if (validTxids.has(txid)) {
|
|
143
154
|
return
|
|
144
155
|
}
|
|
@@ -156,10 +167,8 @@ export default class Transaction {
|
|
|
156
167
|
traverseDependencies(subjectTXID)
|
|
157
168
|
|
|
158
169
|
// Check for any unrelated transactions
|
|
159
|
-
for (const txid
|
|
160
|
-
|
|
161
|
-
throw new Error(`Unrelated transaction with TXID ${txid} found in Atomic BEEF data.`)
|
|
162
|
-
}
|
|
170
|
+
for (const txid of unusedTxTxids) {
|
|
171
|
+
throw new Error(`Unrelated transaction with TXID ${txid} found in Atomic BEEF data.`)
|
|
163
172
|
}
|
|
164
173
|
|
|
165
174
|
// Build the transaction by linking inputs and merkle paths
|
|
@@ -859,10 +868,13 @@ export default class Transaction {
|
|
|
859
868
|
|
|
860
869
|
/**
|
|
861
870
|
* 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.
|
|
871
|
+
*
|
|
872
|
+
* @param allowPartial If true, error will not be thrown if there are any missing sourceTransactions.
|
|
862
873
|
*
|
|
863
874
|
* @returns The serialized BEEF structure
|
|
875
|
+
* @throws Error if there are any missing sourceTransactions unless `allowPartial` is true.
|
|
864
876
|
*/
|
|
865
|
-
toBEEF (): number[] {
|
|
877
|
+
toBEEF (allowPartial?: boolean): number[] {
|
|
866
878
|
const writer = new Writer()
|
|
867
879
|
writer.writeUInt32LE(4022206465)
|
|
868
880
|
const BUMPs: MerklePath[] = []
|
|
@@ -907,10 +919,10 @@ export default class Transaction {
|
|
|
907
919
|
if (!hasProof) {
|
|
908
920
|
for (let i = 0; i < tx.inputs.length; i++) {
|
|
909
921
|
const input = tx.inputs[i]
|
|
910
|
-
if (typeof input.sourceTransaction
|
|
922
|
+
if (typeof input.sourceTransaction === 'object')
|
|
923
|
+
addPathsAndInputs(input.sourceTransaction)
|
|
924
|
+
else if (!allowPartial)
|
|
911
925
|
throw new Error('A required source transaction is missing!')
|
|
912
|
-
}
|
|
913
|
-
addPathsAndInputs(input.sourceTransaction)
|
|
914
926
|
}
|
|
915
927
|
}
|
|
916
928
|
}
|
|
@@ -940,16 +952,19 @@ export default class Transaction {
|
|
|
940
952
|
* and then the BEEF data containing only the subject transaction and its dependencies.
|
|
941
953
|
* This format ensures that the BEEF structure is atomic and contains no unrelated transactions.
|
|
942
954
|
*
|
|
955
|
+
* @param allowPartial If true, error will not be thrown if there are any missing sourceTransactions.
|
|
956
|
+
*
|
|
943
957
|
* @returns {number[]} - The serialized Atomic BEEF structure.
|
|
958
|
+
* @throws Error if there are any missing sourceTransactions unless `allowPartial` is true.
|
|
944
959
|
*/
|
|
945
|
-
toAtomicBEEF (): number[] {
|
|
960
|
+
toAtomicBEEF (allowPartial?: boolean): number[] {
|
|
946
961
|
const writer = new Writer()
|
|
947
962
|
// Write the Atomic BEEF prefix
|
|
948
963
|
writer.writeUInt32LE(0x01010101)
|
|
949
964
|
// Write the subject TXID (big-endian)
|
|
950
965
|
writer.write(this.id())
|
|
951
966
|
// Append the BEEF data
|
|
952
|
-
const beefData = this.toBEEF()
|
|
967
|
+
const beefData = this.toBEEF(allowPartial)
|
|
953
968
|
writer.write(beefData)
|
|
954
969
|
return writer.toArray()
|
|
955
970
|
}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
// The following imports allow flag a large number type checking errors by the VsCode editor due to missing type information:
|
|
1
2
|
import BeefTx from "../../../dist/cjs/src/transaction/BeefTx"
|
|
2
3
|
import Beef from "../../../dist/cjs/src/transaction/Beef"
|
|
3
4
|
import BeefParty from "../../../dist/cjs/src/transaction/BeefParty"
|
|
4
5
|
import { BEEF_MAGIC, BEEF_MAGIC_V2 } from "../../../dist/cjs/src/transaction/Beef"
|
|
5
6
|
import Transaction from "../../../dist/cjs/src/transaction/Transaction"
|
|
6
7
|
|
|
8
|
+
// The following imports allow full type checking by the VsCode editor, but tests will fail to run:
|
|
9
|
+
//import BeefTx from '../BeefTx'
|
|
10
|
+
//import Beef from '../Beef'
|
|
11
|
+
//import BeefParty from "../BeefParty"
|
|
12
|
+
//import { BEEF_MAGIC, BEEF_MAGIC_V2 } from "../Beef"
|
|
13
|
+
//import Transaction from "../Transaction"
|
|
14
|
+
|
|
7
15
|
describe('Beef tests', () => {
|
|
8
16
|
jest.setTimeout(99999999)
|
|
9
17
|
|
|
@@ -56,8 +64,8 @@ describe('Beef tests', () => {
|
|
|
56
64
|
expect(btx.rawTx).toBe(undefined)
|
|
57
65
|
}
|
|
58
66
|
|
|
59
|
-
const
|
|
60
|
-
expect(
|
|
67
|
+
const r = beef.sortTxs()
|
|
68
|
+
expect(r.missingInputs.length).toBe(0)
|
|
61
69
|
expect(beef.toLogString()).toBe(log2)
|
|
62
70
|
|
|
63
71
|
{
|
|
@@ -72,8 +80,8 @@ describe('Beef tests', () => {
|
|
|
72
80
|
{
|
|
73
81
|
const beef = new Beef()
|
|
74
82
|
beef.mergeTransaction(Transaction.fromHex(txs[0]))
|
|
75
|
-
const
|
|
76
|
-
expect(
|
|
83
|
+
const { missingInputs } = beef.sortTxs()
|
|
84
|
+
expect(missingInputs).toEqual(['bd4a39c6dce3bdd982be3c67eb04b83934fd431f8bcb64f9da4413c91c634d07'])
|
|
77
85
|
const beef0 = Beef.fromString(beefs[0])
|
|
78
86
|
beef.mergeBump(beef0.bumps[0])
|
|
79
87
|
beef.mergeRawTx(beef0.txs[0].rawTx!, undefined)
|
|
@@ -93,7 +101,7 @@ describe('Beef tests', () => {
|
|
|
93
101
|
}
|
|
94
102
|
})
|
|
95
103
|
|
|
96
|
-
test('
|
|
104
|
+
test('1_all merkleRoots equal', async () => {
|
|
97
105
|
{
|
|
98
106
|
const beef = Beef.fromString(beefs[0])
|
|
99
107
|
expect(beef.isValid(undefined)).toBe(true)
|
|
@@ -107,7 +115,7 @@ describe('Beef tests', () => {
|
|
|
107
115
|
}
|
|
108
116
|
})
|
|
109
117
|
|
|
110
|
-
test('
|
|
118
|
+
test('2_allowTxidOnly', async () => {
|
|
111
119
|
{
|
|
112
120
|
const beef = Beef.fromString(beefs[0])
|
|
113
121
|
expect(beef.isValid(undefined)).toBe(true)
|
|
@@ -117,7 +125,7 @@ describe('Beef tests', () => {
|
|
|
117
125
|
}
|
|
118
126
|
})
|
|
119
127
|
|
|
120
|
-
test('
|
|
128
|
+
test('3_removeExistingTxid', async () => {
|
|
121
129
|
{
|
|
122
130
|
const beef = Beef.fromString(beefs[0])
|
|
123
131
|
expect(beef.isValid(undefined)).toBe(true)
|
|
@@ -157,7 +165,7 @@ describe('Beef tests', () => {
|
|
|
157
165
|
}
|
|
158
166
|
})
|
|
159
167
|
|
|
160
|
-
test('
|
|
168
|
+
test('5_mergeBeef', async () => {
|
|
161
169
|
{
|
|
162
170
|
const beef = Beef.fromString(beefs[0])
|
|
163
171
|
const beefB = Beef.fromString(beefs[0])
|
|
@@ -193,7 +201,7 @@ describe('Beef tests', () => {
|
|
|
193
201
|
}
|
|
194
202
|
})
|
|
195
203
|
|
|
196
|
-
test('
|
|
204
|
+
test('6_BeefParty', async () => {
|
|
197
205
|
|
|
198
206
|
const bp = new BeefParty(['b', 'c'])
|
|
199
207
|
expect(bp.isParty('a')).toBe(false)
|
|
@@ -215,10 +223,10 @@ describe('Beef tests', () => {
|
|
|
215
223
|
const v = bp.getTrimmedBeefForParty('a').toLogString()
|
|
216
224
|
expect(v).toBe(`BEEF with 0 BUMPS and 2 Transactions, isValid false
|
|
217
225
|
TX 0
|
|
218
|
-
txid:
|
|
226
|
+
txid: 3
|
|
219
227
|
txidOnly
|
|
220
228
|
TX 1
|
|
221
|
-
txid:
|
|
229
|
+
txid: 4
|
|
222
230
|
txidOnly
|
|
223
231
|
`)
|
|
224
232
|
}
|
|
@@ -226,10 +234,10 @@ describe('Beef tests', () => {
|
|
|
226
234
|
const v = bp.getTrimmedBeefForParty('b').toLogString()
|
|
227
235
|
expect(v).toBe(`BEEF with 0 BUMPS and 2 Transactions, isValid false
|
|
228
236
|
TX 0
|
|
229
|
-
txid:
|
|
237
|
+
txid: 1
|
|
230
238
|
txidOnly
|
|
231
239
|
TX 1
|
|
232
|
-
txid:
|
|
240
|
+
txid: 2
|
|
233
241
|
txidOnly
|
|
234
242
|
`)
|
|
235
243
|
}
|
|
@@ -237,15 +245,66 @@ describe('Beef tests', () => {
|
|
|
237
245
|
const v = bp.getTrimmedBeefForParty('c').toLogString()
|
|
238
246
|
expect(v).toBe(`BEEF with 0 BUMPS and 2 Transactions, isValid false
|
|
239
247
|
TX 0
|
|
240
|
-
txid:
|
|
248
|
+
txid: 1
|
|
241
249
|
txidOnly
|
|
242
250
|
TX 1
|
|
243
|
-
txid:
|
|
251
|
+
txid: 4
|
|
244
252
|
txidOnly
|
|
245
253
|
`)
|
|
246
254
|
}
|
|
247
255
|
})
|
|
248
256
|
|
|
257
|
+
test('7_AtomicBeef', async () => {
|
|
258
|
+
{
|
|
259
|
+
const beef = Beef.fromString(beefs[0])
|
|
260
|
+
expect(beef.toHex()).toBe(beefs[0])
|
|
261
|
+
const sr = beef.sortTxs()
|
|
262
|
+
const beefHex = beef.toHex()
|
|
263
|
+
const tx = beef.txs[beef.txs.length - 1].tx!
|
|
264
|
+
expect(tx).toBeTruthy()
|
|
265
|
+
const atomic = tx.toAtomicBEEF(true)
|
|
266
|
+
// Verify that atomic BEEF can be deserialized.
|
|
267
|
+
const beef2 = Beef.fromBinary(atomic)
|
|
268
|
+
// The merkle path isn't linked to tx by default.
|
|
269
|
+
expect(beef2.toHex()).not.toBe(beefHex)
|
|
270
|
+
{
|
|
271
|
+
const atx = beef.findAtomicTransaction(tx.id('hex'))
|
|
272
|
+
const atomic = atx.toAtomicBEEF(true)
|
|
273
|
+
// Verify that atomic BEEF can be deserialized.
|
|
274
|
+
const beef2 = Beef.fromBinary(atomic)
|
|
275
|
+
// The merkle path now is linked to tx by default.
|
|
276
|
+
expect(beef2.toHex()).toBe(beefHex)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
{
|
|
280
|
+
const beef = Beef.fromString(beefs[0])
|
|
281
|
+
expect(beef.toHex()).toBe(beefs[0])
|
|
282
|
+
beef.mergeTransaction(Transaction.fromHex(txs[0]))
|
|
283
|
+
const sr = beef.sortTxs()
|
|
284
|
+
const beefHex = beef.toHex()
|
|
285
|
+
const tx = beef.txs[beef.txs.length - 1].tx!
|
|
286
|
+
expect(tx).toBeTruthy()
|
|
287
|
+
const atx = beef.findAtomicTransaction(tx.id('hex'))
|
|
288
|
+
const atomic = atx.toAtomicBEEF()
|
|
289
|
+
// Verify that atomic BEEF can be deserialized.
|
|
290
|
+
const beef2 = Beef.fromBinary(atomic)
|
|
291
|
+
expect(beef2.toHex()).toBe(beefHex)
|
|
292
|
+
}
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
test('8_toBinaryAtomic', async () => {
|
|
296
|
+
{
|
|
297
|
+
const beef = Beef.fromString(beefs[0])
|
|
298
|
+
const tx = Transaction.fromHex(txs[0])
|
|
299
|
+
beef.mergeTransaction(tx)
|
|
300
|
+
const sr = beef.sortTxs()
|
|
301
|
+
const log = beef.toLogString()
|
|
302
|
+
const atomic = beef.toBinaryAtomic(tx.id('hex'))
|
|
303
|
+
const t2 = Transaction.fromAtomicBEEF(atomic)
|
|
304
|
+
const beef2 = t2.toAtomicBEEF()
|
|
305
|
+
expect(atomic).toEqual(beef2)
|
|
306
|
+
}
|
|
307
|
+
})
|
|
249
308
|
})
|
|
250
309
|
|
|
251
310
|
const txs: string[] = [
|