@bsv/sdk 1.2.15 → 1.2.18
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 +2 -2
- package/dist/cjs/src/primitives/BigNumber.js +85 -89
- package/dist/cjs/src/primitives/BigNumber.js.map +1 -1
- package/dist/cjs/src/primitives/PublicKey.js +5 -2
- package/dist/cjs/src/primitives/PublicKey.js.map +1 -1
- package/dist/cjs/src/primitives/Random.js +3 -2
- package/dist/cjs/src/primitives/Random.js.map +1 -1
- package/dist/cjs/src/primitives/utils.js +71 -62
- package/dist/cjs/src/primitives/utils.js.map +1 -1
- package/dist/cjs/src/totp/totp.js +0 -1
- package/dist/cjs/src/totp/totp.js.map +1 -1
- package/dist/cjs/src/transaction/Beef.js +61 -49
- package/dist/cjs/src/transaction/Beef.js.map +1 -1
- package/dist/cjs/src/transaction/BeefParty.js +1 -1
- package/dist/cjs/src/transaction/BeefTx.js +75 -73
- package/dist/cjs/src/transaction/BeefTx.js.map +1 -1
- package/dist/cjs/src/transaction/MerklePath.js +4 -4
- package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
- package/dist/cjs/src/transaction/Transaction.js +70 -96
- package/dist/cjs/src/transaction/Transaction.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/primitives/BigNumber.js +85 -89
- package/dist/esm/src/primitives/BigNumber.js.map +1 -1
- package/dist/esm/src/primitives/PublicKey.js +5 -2
- package/dist/esm/src/primitives/PublicKey.js.map +1 -1
- package/dist/esm/src/primitives/Random.js +2 -2
- package/dist/esm/src/primitives/Random.js.map +1 -1
- package/dist/esm/src/primitives/utils.js +70 -61
- package/dist/esm/src/primitives/utils.js.map +1 -1
- package/dist/esm/src/totp/totp.js +0 -1
- package/dist/esm/src/totp/totp.js.map +1 -1
- package/dist/esm/src/transaction/Beef.js +60 -48
- package/dist/esm/src/transaction/Beef.js.map +1 -1
- package/dist/esm/src/transaction/BeefParty.js +1 -1
- package/dist/esm/src/transaction/BeefTx.js +76 -74
- package/dist/esm/src/transaction/BeefTx.js.map +1 -1
- package/dist/esm/src/transaction/MerklePath.js +4 -4
- package/dist/esm/src/transaction/MerklePath.js.map +1 -1
- package/dist/esm/src/transaction/Transaction.js +71 -97
- package/dist/esm/src/transaction/Transaction.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/primitives/BigNumber.d.ts +24 -22
- package/dist/types/src/primitives/BigNumber.d.ts.map +1 -1
- package/dist/types/src/primitives/PublicKey.d.ts.map +1 -1
- package/dist/types/src/primitives/utils.d.ts +17 -17
- package/dist/types/src/primitives/utils.d.ts.map +1 -1
- package/dist/types/src/transaction/Beef.d.ts +17 -14
- package/dist/types/src/transaction/Beef.d.ts.map +1 -1
- package/dist/types/src/transaction/BeefParty.d.ts +1 -1
- package/dist/types/src/transaction/BeefTx.d.ts +5 -2
- package/dist/types/src/transaction/BeefTx.d.ts.map +1 -1
- package/dist/types/src/transaction/MerklePath.d.ts +2 -2
- package/dist/types/src/transaction/MerklePath.d.ts.map +1 -1
- package/dist/types/src/transaction/Transaction.d.ts +6 -0
- 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/compat.md +13 -11
- package/docs/primitives.md +152 -188
- package/docs/transaction.md +87 -79
- package/docs/wallet-substrates.md +1410 -1
- package/package.json +2 -2
- package/src/primitives/BigNumber.ts +111 -111
- package/src/primitives/PublicKey.ts +5 -2
- package/src/primitives/Random.ts +2 -2
- package/src/primitives/utils.ts +92 -77
- package/src/totp/totp.ts +0 -1
- package/src/transaction/Beef.ts +60 -42
- package/src/transaction/BeefParty.ts +1 -1
- package/src/transaction/BeefTx.ts +89 -57
- package/src/transaction/MerklePath.ts +4 -4
- package/src/transaction/Transaction.ts +77 -100
- package/src/transaction/__tests/Beef.test.ts +32 -13
- package/src/transaction/__tests/Transaction.benchmarks.test.ts +1 -1
- package/src/transaction/__tests/Transaction.test.ts +3 -3
- package/src/transaction/broadcasters/__tests/WhatsOnChainBroadcaster.test.ts +2 -2
package/src/primitives/utils.ts
CHANGED
|
@@ -21,8 +21,8 @@ export const zero2 = (word: string): string => {
|
|
|
21
21
|
*/
|
|
22
22
|
export const toHex = (msg: number[]): string => {
|
|
23
23
|
let res = ''
|
|
24
|
-
for (
|
|
25
|
-
res += zero2(
|
|
24
|
+
for (const num of msg) {
|
|
25
|
+
res += zero2(num.toString(16))
|
|
26
26
|
}
|
|
27
27
|
return res
|
|
28
28
|
}
|
|
@@ -36,59 +36,63 @@ export const toHex = (msg: number[]): string => {
|
|
|
36
36
|
* @returns {any[]} - Array representation of the input.
|
|
37
37
|
*/
|
|
38
38
|
export const toArray = (msg: any, enc?: 'hex' | 'utf8' | 'base64'): any[] => {
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
// Return empty array for falsy values
|
|
43
|
-
if (!(msg as boolean)) { return [] }
|
|
44
|
-
const res: any[] = []
|
|
39
|
+
if (Array.isArray(msg)) return msg.slice()
|
|
40
|
+
if (!msg) return []
|
|
45
41
|
|
|
46
|
-
// Convert non-string messages to numbers
|
|
47
42
|
if (typeof msg !== 'string') {
|
|
48
|
-
|
|
49
|
-
return res
|
|
43
|
+
return Array.from(msg, (item: any) => item | 0)
|
|
50
44
|
}
|
|
51
45
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
46
|
+
switch (enc) {
|
|
47
|
+
case 'hex':
|
|
48
|
+
return hexToArray(msg)
|
|
49
|
+
case 'base64':
|
|
50
|
+
return base64ToArray(msg)
|
|
51
|
+
default:
|
|
52
|
+
return utf8ToArray(msg)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
61
55
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
56
|
+
const hexToArray = (msg: string): number[] => {
|
|
57
|
+
msg = msg.replace(/[^a-z0-9]+/ig, '')
|
|
58
|
+
if (msg.length % 2 !== 0) msg = '0' + msg
|
|
59
|
+
const res: number[] = []
|
|
60
|
+
for (let i = 0; i < msg.length; i += 2) {
|
|
61
|
+
res.push(parseInt(msg[i] + msg[i + 1], 16))
|
|
62
|
+
}
|
|
63
|
+
return res
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const base64ToArray = (msg: string): number[] => {
|
|
67
|
+
const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
|
68
|
+
const result: number[] = []
|
|
69
|
+
let currentBit = 0
|
|
70
|
+
let currentByte = 0
|
|
71
|
+
|
|
72
|
+
for (const char of msg.replace(/=+$/, '')) {
|
|
73
|
+
currentBit = (currentBit << 6) | base64Chars.indexOf(char)
|
|
74
|
+
currentByte += 6
|
|
75
|
+
|
|
76
|
+
if (currentByte >= 8) {
|
|
77
|
+
currentByte -= 8
|
|
78
|
+
result.push((currentBit >> currentByte) & 0xFF)
|
|
79
|
+
currentBit &= (1 << currentByte) - 1
|
|
78
80
|
}
|
|
81
|
+
}
|
|
79
82
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
83
|
+
return result
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const utf8ToArray = (msg: string): number[] => {
|
|
87
|
+
const res: number[] = []
|
|
88
|
+
for (let i = 0; i < msg.length; i++) {
|
|
89
|
+
const c = msg.charCodeAt(i)
|
|
90
|
+
const hi = c >> 8
|
|
91
|
+
const lo = c & 0xff
|
|
92
|
+
if (hi) {
|
|
93
|
+
res.push(hi, lo)
|
|
94
|
+
} else {
|
|
95
|
+
res.push(lo)
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
98
|
return res
|
|
@@ -101,32 +105,43 @@ export const toArray = (msg: any, enc?: 'hex' | 'utf8' | 'base64'): any[] => {
|
|
|
101
105
|
*/
|
|
102
106
|
export const toUTF8 = (arr: number[]): string => {
|
|
103
107
|
let result = ''
|
|
108
|
+
let skip = 0
|
|
104
109
|
|
|
105
110
|
for (let i = 0; i < arr.length; i++) {
|
|
106
111
|
const byte = arr[i]
|
|
107
112
|
|
|
113
|
+
// this byte is part of a multi-byte sequence, skip it
|
|
114
|
+
// added to avoid modifying i within the loop which is considered unsafe.
|
|
115
|
+
if (skip > 0) {
|
|
116
|
+
skip--
|
|
117
|
+
continue
|
|
118
|
+
}
|
|
119
|
+
|
|
108
120
|
// 1-byte sequence (0xxxxxxx)
|
|
109
121
|
if (byte <= 0x7F) {
|
|
110
122
|
result += String.fromCharCode(byte)
|
|
111
123
|
}
|
|
112
124
|
// 2-byte sequence (110xxxxx 10xxxxxx)
|
|
113
125
|
else if (byte >= 0xC0 && byte <= 0xDF) {
|
|
114
|
-
const byte2 = arr[
|
|
126
|
+
const byte2 = arr[i + 1]
|
|
127
|
+
skip = 1
|
|
115
128
|
const codePoint = ((byte & 0x1F) << 6) | (byte2 & 0x3F)
|
|
116
129
|
result += String.fromCharCode(codePoint)
|
|
117
130
|
}
|
|
118
131
|
// 3-byte sequence (1110xxxx 10xxxxxx 10xxxxxx)
|
|
119
132
|
else if (byte >= 0xE0 && byte <= 0xEF) {
|
|
120
|
-
const byte2 = arr[
|
|
121
|
-
const byte3 = arr[
|
|
133
|
+
const byte2 = arr[i + 1]
|
|
134
|
+
const byte3 = arr[i + 2]
|
|
135
|
+
skip = 2
|
|
122
136
|
const codePoint = ((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F)
|
|
123
137
|
result += String.fromCharCode(codePoint)
|
|
124
138
|
}
|
|
125
139
|
// 4-byte sequence (11110xxx 10xxxxxx 10xxxxxx 10xxxxxx)
|
|
126
140
|
else if (byte >= 0xF0 && byte <= 0xF7) {
|
|
127
|
-
const byte2 = arr[
|
|
128
|
-
const byte3 = arr[
|
|
129
|
-
const byte4 = arr[
|
|
141
|
+
const byte2 = arr[i + 1]
|
|
142
|
+
const byte3 = arr[i + 2]
|
|
143
|
+
const byte4 = arr[i + 3]
|
|
144
|
+
skip = 3
|
|
130
145
|
const codePoint = ((byte & 0x07) << 18) | ((byte2 & 0x3F) << 12) | ((byte3 & 0x3F) << 6) | (byte4 & 0x3F)
|
|
131
146
|
|
|
132
147
|
// Convert to UTF-16 surrogate pair
|
|
@@ -212,7 +227,7 @@ export const fromBase58 = (str: string): number[] => {
|
|
|
212
227
|
const uint8 = new Uint8Array([
|
|
213
228
|
...new Uint8Array(psz),
|
|
214
229
|
...str
|
|
215
|
-
.match(
|
|
230
|
+
.match(/./gmu)
|
|
216
231
|
.map((i) => base58chars.indexOf(i))
|
|
217
232
|
.reduce((acc, i) => {
|
|
218
233
|
acc = acc.map((j) => {
|
|
@@ -324,19 +339,19 @@ export class Writer {
|
|
|
324
339
|
const ret = new Array(totalLength)
|
|
325
340
|
let offset = 0
|
|
326
341
|
for (const buf of this.bufs) {
|
|
327
|
-
for (
|
|
328
|
-
ret[offset++] =
|
|
342
|
+
for (const value of buf) {
|
|
343
|
+
ret[offset++] = value
|
|
329
344
|
}
|
|
330
345
|
}
|
|
331
346
|
return ret
|
|
332
347
|
}
|
|
333
348
|
|
|
334
|
-
write (buf: number[]):
|
|
349
|
+
write (buf: number[]): this {
|
|
335
350
|
this.bufs.push(buf)
|
|
336
351
|
return this
|
|
337
352
|
}
|
|
338
353
|
|
|
339
|
-
writeReverse (buf: number[]):
|
|
354
|
+
writeReverse (buf: number[]): this {
|
|
340
355
|
const buf2: number[] = new Array(buf.length)
|
|
341
356
|
for (let i = 0; i < buf2.length; i++) {
|
|
342
357
|
buf2[i] = buf[buf.length - 1 - i]
|
|
@@ -345,21 +360,21 @@ export class Writer {
|
|
|
345
360
|
return this
|
|
346
361
|
}
|
|
347
362
|
|
|
348
|
-
writeUInt8 (n: number):
|
|
363
|
+
writeUInt8 (n: number): this {
|
|
349
364
|
const buf = new Array(1)
|
|
350
365
|
buf[0] = n
|
|
351
366
|
this.write(buf)
|
|
352
367
|
return this
|
|
353
368
|
}
|
|
354
369
|
|
|
355
|
-
writeInt8 (n: number):
|
|
370
|
+
writeInt8 (n: number): this {
|
|
356
371
|
const buf = new Array(1)
|
|
357
372
|
buf[0] = n & 0xFF
|
|
358
373
|
this.write(buf)
|
|
359
374
|
return this
|
|
360
375
|
}
|
|
361
376
|
|
|
362
|
-
writeUInt16BE (n: number):
|
|
377
|
+
writeUInt16BE (n: number): this {
|
|
363
378
|
this.bufs.push([
|
|
364
379
|
(n >> 8) & 0xFF, // shift right 8 bits to get the high byte
|
|
365
380
|
n & 0xFF // low byte is just the last 8 bits
|
|
@@ -367,11 +382,11 @@ export class Writer {
|
|
|
367
382
|
return this
|
|
368
383
|
}
|
|
369
384
|
|
|
370
|
-
writeInt16BE (n: number):
|
|
385
|
+
writeInt16BE (n: number): this {
|
|
371
386
|
return this.writeUInt16BE(n & 0xFFFF) // Mask with 0xFFFF to get the lower 16 bits
|
|
372
387
|
}
|
|
373
388
|
|
|
374
|
-
writeUInt16LE (n: number):
|
|
389
|
+
writeUInt16LE (n: number): this {
|
|
375
390
|
this.bufs.push([
|
|
376
391
|
n & 0xFF, // low byte is just the last 8 bits
|
|
377
392
|
(n >> 8) & 0xFF // shift right 8 bits to get the high byte
|
|
@@ -379,11 +394,11 @@ export class Writer {
|
|
|
379
394
|
return this
|
|
380
395
|
}
|
|
381
396
|
|
|
382
|
-
writeInt16LE (n: number):
|
|
397
|
+
writeInt16LE (n: number): this {
|
|
383
398
|
return this.writeUInt16LE(n & 0xFFFF) // Mask with 0xFFFF to get the lower 16 bits
|
|
384
399
|
}
|
|
385
400
|
|
|
386
|
-
writeUInt32BE (n: number):
|
|
401
|
+
writeUInt32BE (n: number): this {
|
|
387
402
|
this.bufs.push([
|
|
388
403
|
(n >> 24) & 0xFF, // highest byte
|
|
389
404
|
(n >> 16) & 0xFF,
|
|
@@ -393,11 +408,11 @@ export class Writer {
|
|
|
393
408
|
return this
|
|
394
409
|
}
|
|
395
410
|
|
|
396
|
-
writeInt32BE (n: number):
|
|
411
|
+
writeInt32BE (n: number): this {
|
|
397
412
|
return this.writeUInt32BE(n >>> 0) // Using unsigned right shift to handle negative numbers
|
|
398
413
|
}
|
|
399
414
|
|
|
400
|
-
writeUInt32LE (n: number):
|
|
415
|
+
writeUInt32LE (n: number): this {
|
|
401
416
|
this.bufs.push([
|
|
402
417
|
n & 0xFF, // lowest byte
|
|
403
418
|
(n >> 8) & 0xFF,
|
|
@@ -407,35 +422,35 @@ export class Writer {
|
|
|
407
422
|
return this
|
|
408
423
|
}
|
|
409
424
|
|
|
410
|
-
writeInt32LE (n: number):
|
|
425
|
+
writeInt32LE (n: number): this {
|
|
411
426
|
return this.writeUInt32LE(n >>> 0) // Using unsigned right shift to handle negative numbers
|
|
412
427
|
}
|
|
413
428
|
|
|
414
|
-
writeUInt64BEBn (bn: BigNumber):
|
|
429
|
+
writeUInt64BEBn (bn: BigNumber): this {
|
|
415
430
|
const buf = bn.toArray('be', 8)
|
|
416
431
|
this.write(buf)
|
|
417
432
|
return this
|
|
418
433
|
}
|
|
419
434
|
|
|
420
|
-
writeUInt64LEBn (bn: BigNumber):
|
|
435
|
+
writeUInt64LEBn (bn: BigNumber): this {
|
|
421
436
|
const buf = bn.toArray('be', 8)
|
|
422
437
|
this.writeReverse(buf)
|
|
423
438
|
return this
|
|
424
439
|
}
|
|
425
440
|
|
|
426
|
-
writeUInt64LE (n: number):
|
|
441
|
+
writeUInt64LE (n: number): this {
|
|
427
442
|
const buf = new BigNumber(n).toArray('be', 8)
|
|
428
443
|
this.writeReverse(buf)
|
|
429
444
|
return this
|
|
430
445
|
}
|
|
431
446
|
|
|
432
|
-
writeVarIntNum (n: number):
|
|
447
|
+
writeVarIntNum (n: number): this {
|
|
433
448
|
const buf = Writer.varIntNum(n)
|
|
434
449
|
this.write(buf)
|
|
435
450
|
return this
|
|
436
451
|
}
|
|
437
452
|
|
|
438
|
-
writeVarIntBn (bn: BigNumber):
|
|
453
|
+
writeVarIntBn (bn: BigNumber): this {
|
|
439
454
|
const buf = Writer.varIntBn(bn)
|
|
440
455
|
this.write(buf)
|
|
441
456
|
return this
|
|
@@ -696,13 +711,13 @@ export const minimallyEncode = (buf: number[]): number[] => {
|
|
|
696
711
|
if ((buf[i - 1] & 0x80) !== 0) {
|
|
697
712
|
// We found a byte with it sign bit set so we need one more
|
|
698
713
|
// byte.
|
|
699
|
-
buf[i
|
|
714
|
+
buf[i] = last
|
|
715
|
+
return buf.slice(0, i + 1)
|
|
700
716
|
} else {
|
|
701
717
|
// the sign bit is clear, we can use it.
|
|
702
718
|
buf[i - 1] |= last
|
|
719
|
+
return buf.slice(0, i)
|
|
703
720
|
}
|
|
704
|
-
|
|
705
|
-
return buf.slice(0, i)
|
|
706
721
|
}
|
|
707
722
|
}
|
|
708
723
|
|
package/src/totp/totp.ts
CHANGED
|
@@ -106,7 +106,6 @@ function generateHOTP (
|
|
|
106
106
|
options: Required<TOTPOptions>
|
|
107
107
|
): string {
|
|
108
108
|
const timePad = new BigNumber(counter).toArray('be', 8)
|
|
109
|
-
// console.log({ timePad })
|
|
110
109
|
const hmac = calcHMAC(secret, timePad, options.algorithm)
|
|
111
110
|
const signature = hmac.digest()
|
|
112
111
|
|
package/src/transaction/Beef.ts
CHANGED
|
@@ -3,13 +3,16 @@ import Transaction from './Transaction.js'
|
|
|
3
3
|
import ChainTracker from './ChainTracker.js'
|
|
4
4
|
import BeefTx from './BeefTx.js'
|
|
5
5
|
import { Reader, Writer, toHex, toArray } from '../primitives/utils.js'
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export const
|
|
9
|
-
export const
|
|
10
|
-
export const ATOMIC_BEEF = 0x01010101 //
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
import { hash256 } from '../primitives/Hash.js'
|
|
7
|
+
|
|
8
|
+
export const BEEF_V1 = 4022206465 // 0100BEEF in LE order
|
|
9
|
+
export const BEEF_V2 = 4022206466 // 0200BEEF in LE order
|
|
10
|
+
export const ATOMIC_BEEF = 0x01010101 // 01010101
|
|
11
|
+
export enum TX_DATA_FORMAT {
|
|
12
|
+
RAWTX = 0, // rawtx without BUMP
|
|
13
|
+
RAWTX_AND_BUMP_INDEX = 1, // rawtx with bump index
|
|
14
|
+
TXID_ONLY = 2, // txid only
|
|
15
|
+
}
|
|
13
16
|
|
|
14
17
|
/*
|
|
15
18
|
* BEEF standard: BRC-62: Background Evaluation Extended Format (BEEF) Transactions
|
|
@@ -67,29 +70,13 @@ export type BeefVersion = undefined | 'V1' | 'V2'
|
|
|
67
70
|
export class Beef {
|
|
68
71
|
bumps: MerklePath[] = []
|
|
69
72
|
txs: BeefTx[] = []
|
|
70
|
-
version:
|
|
73
|
+
version: number = BEEF_V2
|
|
71
74
|
atomicTxid: string | undefined = undefined
|
|
72
75
|
|
|
73
|
-
constructor (version
|
|
76
|
+
constructor (version: number = BEEF_V2) {
|
|
74
77
|
this.version = version
|
|
75
78
|
}
|
|
76
79
|
|
|
77
|
-
/**
|
|
78
|
-
* BEEF_MAGIC is the original V1 version.
|
|
79
|
-
* BEEF_MAGIC_V2 includes support for txidOnly transactions in serialized beefs.
|
|
80
|
-
* @returns version magic value based on current contents and constructor version parameter.
|
|
81
|
-
*/
|
|
82
|
-
get magic (): number {
|
|
83
|
-
if (this.version === 'V1') { return BEEF_MAGIC }
|
|
84
|
-
|
|
85
|
-
if (this.version === 'V2') { return BEEF_MAGIC_V2 }
|
|
86
|
-
|
|
87
|
-
const hasTxidOnly = this.txs.findIndex(tx => tx.isTxidOnly) > -1
|
|
88
|
-
if (hasTxidOnly) { return BEEF_MAGIC_V2 }
|
|
89
|
-
|
|
90
|
-
return BEEF_MAGIC
|
|
91
|
-
}
|
|
92
|
-
|
|
93
80
|
/**
|
|
94
81
|
* @param txid of `beefTx` to find
|
|
95
82
|
* @returns `BeefTx` in `txs` with `txid`.
|
|
@@ -113,7 +100,7 @@ export class Beef {
|
|
|
113
100
|
if (i === -1) return undefined
|
|
114
101
|
let btx = this.txs[i]
|
|
115
102
|
if (btx.isTxidOnly) { return btx }
|
|
116
|
-
this.txs.
|
|
103
|
+
this.txs.splice(i, 1)
|
|
117
104
|
btx = this.mergeTxidOnly(txid)
|
|
118
105
|
return btx
|
|
119
106
|
}
|
|
@@ -295,8 +282,6 @@ export class Beef {
|
|
|
295
282
|
}
|
|
296
283
|
|
|
297
284
|
mergeTxidOnly (txid: string): BeefTx {
|
|
298
|
-
if (this.version === 'V1') { throw new Error('BEEF V1 format does not support txid only transactions.') }
|
|
299
|
-
|
|
300
285
|
let tx = this.txs.find(t => t.txid === txid)
|
|
301
286
|
if (!tx) {
|
|
302
287
|
tx = new BeefTx(txid)
|
|
@@ -308,9 +293,7 @@ export class Beef {
|
|
|
308
293
|
|
|
309
294
|
mergeBeefTx (btx: BeefTx): BeefTx {
|
|
310
295
|
let beefTx = this.findTxid(btx.txid)
|
|
311
|
-
if (!beefTx
|
|
312
|
-
if (btx._tx) { beefTx = this.mergeTransaction(btx._tx) } else { beefTx = this.mergeRawTx(btx._rawTx) }
|
|
313
|
-
}
|
|
296
|
+
if (btx.isTxidOnly && !beefTx) { beefTx = this.mergeTxidOnly(btx.txid) } else if (btx._tx && (!beefTx || beefTx.isTxidOnly)) { beefTx = this.mergeTransaction(btx._tx) } else if (btx._rawTx && (!beefTx || beefTx.isTxidOnly)) { beefTx = this.mergeRawTx(btx._rawTx) }
|
|
314
297
|
return beefTx
|
|
315
298
|
}
|
|
316
299
|
|
|
@@ -416,7 +399,7 @@ export class Beef {
|
|
|
416
399
|
* @param writer
|
|
417
400
|
*/
|
|
418
401
|
toWriter (writer: Writer) {
|
|
419
|
-
writer.writeUInt32LE(this.
|
|
402
|
+
writer.writeUInt32LE(this.version)
|
|
420
403
|
|
|
421
404
|
writer.writeVarIntNum(this.bumps.length)
|
|
422
405
|
for (const b of this.bumps) {
|
|
@@ -425,7 +408,7 @@ export class Beef {
|
|
|
425
408
|
|
|
426
409
|
writer.writeVarIntNum(this.txs.length)
|
|
427
410
|
for (const tx of this.txs) {
|
|
428
|
-
tx.toWriter(writer, this.
|
|
411
|
+
tx.toWriter(writer, this.version)
|
|
429
412
|
}
|
|
430
413
|
}
|
|
431
414
|
|
|
@@ -442,8 +425,9 @@ export class Beef {
|
|
|
442
425
|
/**
|
|
443
426
|
* Serialize this Beef as AtomicBEEF.
|
|
444
427
|
*
|
|
445
|
-
* `txid` must exist
|
|
446
|
-
*
|
|
428
|
+
* `txid` must exist
|
|
429
|
+
*
|
|
430
|
+
* after sorting, if txid is not last txid, creates a clone and removes newer txs
|
|
447
431
|
*
|
|
448
432
|
* @param txid
|
|
449
433
|
* @returns serialized contents of this Beef with AtomicBEEF prefix.
|
|
@@ -452,11 +436,16 @@ export class Beef {
|
|
|
452
436
|
this.sortTxs()
|
|
453
437
|
const tx = this.findTxid(txid)
|
|
454
438
|
if (!tx) { throw new Error(`${txid} does not exist in this Beef`) }
|
|
455
|
-
|
|
439
|
+
let beef: Beef = this
|
|
440
|
+
if (this.txs[this.txs.length - 1] !== tx) {
|
|
441
|
+
beef = this.clone()
|
|
442
|
+
const i = this.txs.findIndex(t => t.txid === txid)
|
|
443
|
+
beef.txs.splice(i + 1)
|
|
444
|
+
}
|
|
456
445
|
const writer = new Writer()
|
|
457
446
|
writer.writeUInt32LE(ATOMIC_BEEF)
|
|
458
447
|
writer.write(toArray(txid, 'hex'))
|
|
459
|
-
|
|
448
|
+
beef.toWriter(writer)
|
|
460
449
|
return writer.toArray()
|
|
461
450
|
}
|
|
462
451
|
|
|
@@ -476,11 +465,11 @@ export class Beef {
|
|
|
476
465
|
atomicTxid = toHex(br.read(32))
|
|
477
466
|
version = br.readUInt32LE()
|
|
478
467
|
}
|
|
479
|
-
if (version !==
|
|
480
|
-
const beef = new Beef(version
|
|
468
|
+
if (version !== BEEF_V1 && version !== BEEF_V2) { throw new Error(`Serialized BEEF must start with ${BEEF_V1} or ${BEEF_V2} but starts with ${version}`) }
|
|
469
|
+
const beef = new Beef(version)
|
|
481
470
|
const bumpsLength = br.readVarIntNum()
|
|
482
471
|
for (let i = 0; i < bumpsLength; i++) {
|
|
483
|
-
const bump = MerklePath.fromReader(br)
|
|
472
|
+
const bump = MerklePath.fromReader(br, false)
|
|
484
473
|
beef.bumps.push(bump)
|
|
485
474
|
}
|
|
486
475
|
const txsLength = br.readVarIntNum()
|
|
@@ -508,8 +497,7 @@ export class Beef {
|
|
|
508
497
|
* @param enc The encoding of the string value from which BEEF should be constructed
|
|
509
498
|
* @returns An instance of the Beef class constructed from the string
|
|
510
499
|
*/
|
|
511
|
-
static fromString (s: string, enc
|
|
512
|
-
enc ||= 'hex'
|
|
500
|
+
static fromString (s: string, enc: 'hex' | 'utf8' | 'base64' = 'hex'): Beef {
|
|
513
501
|
const bin = toArray(s, enc)
|
|
514
502
|
const br = new Reader(bin)
|
|
515
503
|
return Beef.fromReader(br)
|
|
@@ -697,6 +685,36 @@ export class Beef {
|
|
|
697
685
|
}
|
|
698
686
|
return log
|
|
699
687
|
}
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* In some circumstances it may be helpful for the BUMP MerkePaths to include
|
|
691
|
+
* leaves that can be computed from row zero.
|
|
692
|
+
*/
|
|
693
|
+
addComputedLeaves () {
|
|
694
|
+
const beef = this
|
|
695
|
+
const hash = (m: string): string => toHex((
|
|
696
|
+
hash256(toArray(m, 'hex').reverse())
|
|
697
|
+
).reverse())
|
|
698
|
+
|
|
699
|
+
for (const bump of beef.bumps) {
|
|
700
|
+
for (let row = 1; row < bump.path.length; row++) {
|
|
701
|
+
for (const leafL of bump.path[row - 1]) {
|
|
702
|
+
if (leafL.hash && (leafL.offset & 1) === 0) {
|
|
703
|
+
const leafR = bump.path[row - 1].find(l => l.offset === leafL.offset + 1)
|
|
704
|
+
const offsetOnRow = leafL.offset >> 1
|
|
705
|
+
if (leafR && leafR.hash && bump.path[row].findIndex(l => l.offset === offsetOnRow) === -1) {
|
|
706
|
+
// computable leaf is missing... add it.
|
|
707
|
+
bump.path[row].push({
|
|
708
|
+
offset: offsetOnRow,
|
|
709
|
+
// string concatenation puts the right leaf on the left of the left leaf hash :-)
|
|
710
|
+
hash: hash(leafR.hash + leafL.hash)
|
|
711
|
+
})
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
700
718
|
}
|
|
701
719
|
|
|
702
720
|
export default Beef
|
|
@@ -41,7 +41,7 @@ export class BeefParty extends Beef {
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* @param party
|
|
44
|
-
* @returns `true` if `party` has already
|
|
44
|
+
* @returns `true` if `party` has already been added to this `BeefParty`.
|
|
45
45
|
*/
|
|
46
46
|
isParty (party: string) {
|
|
47
47
|
const r = Object.keys(this.knownTo).includes(party)
|