@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
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import BigNumber from '../BigNumber'
|
|
2
|
+
import { Reader, encode, WriterUint8Array } from '../utils'
|
|
3
|
+
|
|
4
|
+
describe('WriterUint8Array', () => {
|
|
5
|
+
it('should create a new buffer writer', () => {
|
|
6
|
+
const bw = new WriterUint8Array()
|
|
7
|
+
expect(bw).toBeDefined()
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
describe('#getLength', () => {
|
|
11
|
+
it('should compute length correctly of two 2-byte buffers', () => {
|
|
12
|
+
const buf1 = Buffer.from('0000', 'hex')
|
|
13
|
+
const buf2 = Buffer.from('0000', 'hex')
|
|
14
|
+
const bw = new WriterUint8Array().write([...buf1]).write([...buf2])
|
|
15
|
+
expect(bw.getLength()).toEqual(4)
|
|
16
|
+
})
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
describe('#toArray', () => {
|
|
20
|
+
it('should concat these two bufs', () => {
|
|
21
|
+
const buf1 = [0]
|
|
22
|
+
const buf2 = [1]
|
|
23
|
+
const bw = new WriterUint8Array([buf1, buf2])
|
|
24
|
+
expect(encode(bw.toArray(), 'hex')).toEqual('0001')
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('#write', () => {
|
|
29
|
+
it('should write a buffer', () => {
|
|
30
|
+
const buf = [0]
|
|
31
|
+
const bw = new WriterUint8Array()
|
|
32
|
+
bw.write(buf)
|
|
33
|
+
expect(encode(bw.toArray(), 'hex')).toEqual('00')
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
describe('#writeReverse', () => {
|
|
38
|
+
it('should write a buffer in reverse', () => {
|
|
39
|
+
const buf = [0, 1]
|
|
40
|
+
const bw = new WriterUint8Array()
|
|
41
|
+
bw.writeReverse(buf)
|
|
42
|
+
expect(encode(bw.toArray(), 'hex')).toEqual('0100')
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe('#writeUInt8', () => {
|
|
47
|
+
it('should write 1', () => {
|
|
48
|
+
const bw = new WriterUint8Array()
|
|
49
|
+
expect(encode(bw.writeUInt8(1).toArray(), 'hex')).toEqual('01')
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
describe('#writeInt8', () => {
|
|
54
|
+
it('should write 1', () => {
|
|
55
|
+
const bw = new WriterUint8Array()
|
|
56
|
+
expect(encode(bw.writeInt8(1).toArray(), 'hex')).toEqual('01')
|
|
57
|
+
expect(encode(new WriterUint8Array().writeInt8(-1).toArray(), 'hex')).toEqual('ff')
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe('#writeUInt16BE', () => {
|
|
62
|
+
it('should write 1', () => {
|
|
63
|
+
const bw = new WriterUint8Array()
|
|
64
|
+
expect(encode(bw.writeUInt16BE(1).toArray(), 'hex')).toEqual('0001')
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
describe('#writeInt16BE', () => {
|
|
69
|
+
it('should write 1', () => {
|
|
70
|
+
const bw = new WriterUint8Array()
|
|
71
|
+
expect(encode(bw.writeInt16BE(1).toArray(), 'hex')).toEqual('0001')
|
|
72
|
+
expect(encode(new WriterUint8Array().writeInt16BE(-1).toArray(), 'hex')).toEqual(
|
|
73
|
+
'ffff'
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
describe('#writeUInt16LE', () => {
|
|
79
|
+
it('should write 1', () => {
|
|
80
|
+
const bw = new WriterUint8Array()
|
|
81
|
+
expect(encode(bw.writeUInt16LE(1).toArray(), 'hex')).toEqual('0100')
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
describe('#writeInt16LE', () => {
|
|
86
|
+
it('should write 1', () => {
|
|
87
|
+
const bw = new WriterUint8Array()
|
|
88
|
+
expect(encode(bw.writeInt16LE(1).toArray(), 'hex')).toEqual('0100')
|
|
89
|
+
expect(encode(new WriterUint8Array().writeInt16LE(-1).toArray(), 'hex')).toEqual(
|
|
90
|
+
'ffff'
|
|
91
|
+
)
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
describe('#writeUInt32BE', () => {
|
|
96
|
+
it('should write 1', () => {
|
|
97
|
+
const bw = new WriterUint8Array()
|
|
98
|
+
expect(encode(bw.writeUInt32BE(1).toArray(), 'hex')).toEqual('00000001')
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
describe('#writeInt32BE', () => {
|
|
103
|
+
it('should write 1', () => {
|
|
104
|
+
const bw = new WriterUint8Array()
|
|
105
|
+
expect(encode(bw.writeInt32BE(1).toArray(), 'hex')).toEqual('00000001')
|
|
106
|
+
expect(encode(new WriterUint8Array().writeInt32BE(-1).toArray(), 'hex')).toEqual(
|
|
107
|
+
'ffffffff'
|
|
108
|
+
)
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
describe('#writeUInt32LE', () => {
|
|
113
|
+
it('should write 1', () => {
|
|
114
|
+
const bw = new WriterUint8Array()
|
|
115
|
+
expect(encode(bw.writeUInt32LE(1).toArray(), 'hex')).toEqual('01000000')
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
describe('#writeInt32LE', () => {
|
|
120
|
+
it('should write 1', () => {
|
|
121
|
+
const bw = new WriterUint8Array()
|
|
122
|
+
expect(encode(bw.writeInt32LE(1).toArray(), 'hex')).toEqual('01000000')
|
|
123
|
+
expect(encode(new WriterUint8Array().writeInt32LE(-1).toArray(), 'hex')).toEqual(
|
|
124
|
+
'ffffffff'
|
|
125
|
+
)
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
describe('#writeUInt64BEBn', () => {
|
|
130
|
+
it('should write 1', () => {
|
|
131
|
+
const bw = new WriterUint8Array()
|
|
132
|
+
expect(
|
|
133
|
+
encode(bw.writeUInt64BEBn(new BigNumber(1)).toArray(), 'hex')
|
|
134
|
+
).toEqual('0000000000000001')
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
describe('#writeUInt64LEBn', () => {
|
|
139
|
+
it('should write 1', () => {
|
|
140
|
+
const bw = new WriterUint8Array()
|
|
141
|
+
expect(
|
|
142
|
+
encode(bw.writeUInt64LEBn(new BigNumber(1)).toArray(), 'hex')
|
|
143
|
+
).toEqual('0100000000000000')
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
describe('#writeVarInt', () => {
|
|
148
|
+
it('should write a 1 byte varInt', () => {
|
|
149
|
+
const bw = new WriterUint8Array()
|
|
150
|
+
bw.writeVarIntNum(1)
|
|
151
|
+
expect(bw.toArray().length).toEqual(1)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('should write a 3 byte varInt', () => {
|
|
155
|
+
const bw = new WriterUint8Array()
|
|
156
|
+
bw.writeVarIntNum(1000)
|
|
157
|
+
expect(bw.toArray().length).toEqual(3)
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
it('should write a 5 byte varInt', () => {
|
|
161
|
+
const bw = new WriterUint8Array()
|
|
162
|
+
bw.writeVarIntNum(Math.pow(2, 16 + 1))
|
|
163
|
+
expect(bw.toArray().length).toEqual(5)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
it('should write a 9 byte varInt', () => {
|
|
167
|
+
const bw = new WriterUint8Array()
|
|
168
|
+
bw.writeVarIntNum(Math.pow(2, 32 + 1))
|
|
169
|
+
expect(bw.toArray().length).toEqual(9)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('should read back the same value it wrote for a 9 byte varInt', () => {
|
|
173
|
+
const bw = new WriterUint8Array()
|
|
174
|
+
const n = Math.pow(2, 53)
|
|
175
|
+
expect(n).toEqual(n + 1) // javascript number precision limit
|
|
176
|
+
bw.writeVarIntNum(n)
|
|
177
|
+
const br = new Reader(bw.toArray())
|
|
178
|
+
expect(br.readVarIntBn().toHex()).toEqual('20000000000000')
|
|
179
|
+
})
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
describe('#writeVarIntBn', () => {
|
|
183
|
+
it('should write a 1 byte varInt', () => {
|
|
184
|
+
const bw = new WriterUint8Array()
|
|
185
|
+
bw.writeVarIntBn(new BigNumber(1))
|
|
186
|
+
expect(bw.toArray().length).toEqual(1)
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
it('should write a 3 byte varInt', () => {
|
|
190
|
+
const bw = new WriterUint8Array()
|
|
191
|
+
bw.writeVarIntBn(new BigNumber(1000))
|
|
192
|
+
expect(bw.toArray().length).toEqual(3)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it('should write a 5 byte varInt', () => {
|
|
196
|
+
const bw = new WriterUint8Array()
|
|
197
|
+
const bn = new BigNumber(Math.pow(2, 16 + 1))
|
|
198
|
+
bw.writeVarIntBn(bn)
|
|
199
|
+
expect(bw.toArray().length).toEqual(5)
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
it('should write a 9 byte varInt', () => {
|
|
203
|
+
const bw = new WriterUint8Array()
|
|
204
|
+
bw.writeVarIntBn(new BigNumber(Math.pow(2, 32 + 1)))
|
|
205
|
+
expect(bw.toArray().length).toEqual(9)
|
|
206
|
+
})
|
|
207
|
+
})
|
|
208
|
+
})
|
package/src/primitives/utils.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import BigNumber from './BigNumber.js'
|
|
2
2
|
import { hash256 } from './Hash.js'
|
|
3
3
|
import { assertValidHex } from './hex.js'
|
|
4
|
+
import { WriterUint8Array } from './WriterUint8Array.js'
|
|
5
|
+
import { ReaderUint8Array } from './ReaderUint8Array.js'
|
|
6
|
+
|
|
7
|
+
export { WriterUint8Array }
|
|
8
|
+
export { ReaderUint8Array }
|
|
4
9
|
|
|
5
10
|
const BufferCtor =
|
|
6
11
|
typeof globalThis !== 'undefined' ? (globalThis as any).Buffer : undefined
|
|
@@ -32,7 +37,7 @@ for (let i = 0; i < 256; i++) {
|
|
|
32
37
|
HEX_DIGITS[(i >> 4) & 0xf] + HEX_DIGITS[i & 0xf]
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
export const toHex = (msg: number[]): string => {
|
|
40
|
+
export const toHex = (msg: number[] | Uint8Array): string => {
|
|
36
41
|
if (CAN_USE_BUFFER) {
|
|
37
42
|
return BufferCtor.from(msg).toString('hex')
|
|
38
43
|
}
|
|
@@ -44,11 +49,24 @@ export const toHex = (msg: number[]): string => {
|
|
|
44
49
|
return out.join('')
|
|
45
50
|
}
|
|
46
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Converts various message formats into a Uint8Array.
|
|
54
|
+
* Supports Uint8Array, arrays of bytes, hexadecimal strings, base64 strings, and UTF-8 strings.
|
|
55
|
+
*
|
|
56
|
+
* @param {any} msg - The input message (Uint8Array, number[], Array or string).
|
|
57
|
+
* @param {('hex' | 'utf8' | 'base64')} enc - Specifies the string encoding, if applicable.
|
|
58
|
+
* @returns {Uint8Array}
|
|
59
|
+
*/
|
|
60
|
+
export const toUint8Array = (msg: any, enc?: 'hex' | 'utf8' | 'base64'): Uint8Array => {
|
|
61
|
+
if (msg instanceof Uint8Array) return msg
|
|
62
|
+
return new Uint8Array(toArray(msg, enc))
|
|
63
|
+
}
|
|
64
|
+
|
|
47
65
|
/**
|
|
48
66
|
* Converts various message formats into an array of numbers.
|
|
49
67
|
* Supports arrays, hexadecimal strings, base64 strings, and UTF-8 strings.
|
|
50
68
|
*
|
|
51
|
-
* @param {any} msg - The input message (
|
|
69
|
+
* @param {any} msg - The input message (Uint8Array, number[], Array or string).
|
|
52
70
|
* @param {('hex' | 'utf8' | 'base64')} enc - Specifies the string encoding, if applicable.
|
|
53
71
|
* @returns {any[]} - Array representation of the input.
|
|
54
72
|
*/
|
package/src/transaction/Beef.ts
CHANGED
|
@@ -2,12 +2,9 @@ import MerklePath from './MerklePath.js'
|
|
|
2
2
|
import Transaction from './Transaction.js'
|
|
3
3
|
import ChainTracker from './ChainTracker.js'
|
|
4
4
|
import BeefTx from './BeefTx.js'
|
|
5
|
-
import { Reader, Writer, toHex, toArray, verifyNotNull } from '../primitives/utils.js'
|
|
5
|
+
import { Reader, Writer, toHex, toArray, verifyNotNull, ReaderUint8Array, WriterUint8Array, toUint8Array } from '../primitives/utils.js'
|
|
6
6
|
import { hash256 } from '../primitives/Hash.js'
|
|
7
7
|
|
|
8
|
-
const BufferCtor =
|
|
9
|
-
typeof globalThis !== 'undefined' ? (globalThis as any).Buffer : undefined
|
|
10
|
-
|
|
11
8
|
export const BEEF_V1 = 4022206465 // 0100BEEF in LE order
|
|
12
9
|
export const BEEF_V2 = 4022206466 // 0200BEEF in LE order
|
|
13
10
|
export const ATOMIC_BEEF = 0x01010101 // 01010101
|
|
@@ -112,13 +109,37 @@ export class Beef {
|
|
|
112
109
|
this.ensureSerializableState()
|
|
113
110
|
if (this.rawBytesCache == null) {
|
|
114
111
|
this.ensureSortedForSerialization()
|
|
115
|
-
const writer = new
|
|
112
|
+
const writer = new WriterUint8Array()
|
|
116
113
|
this.toWriter(writer)
|
|
117
114
|
this.rawBytesCache = writer.toUint8Array()
|
|
118
115
|
}
|
|
119
116
|
return this.rawBytesCache
|
|
120
117
|
}
|
|
121
118
|
|
|
119
|
+
private getBeefForAtomic (txid: string): { beef: Beef, writer: WriterUint8Array } {
|
|
120
|
+
if (this.needsSort) {
|
|
121
|
+
this.sortTxs()
|
|
122
|
+
}
|
|
123
|
+
const tx = this.findTxid(txid)
|
|
124
|
+
if (tx == null) {
|
|
125
|
+
throw new Error(`${txid} does not exist in this Beef`)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// If the transaction is not the last one, clone and modify
|
|
129
|
+
const beef = (this.txs[this.txs.length - 1] === tx) ? this : this.clone()
|
|
130
|
+
|
|
131
|
+
if (beef !== this) {
|
|
132
|
+
const i = this.txs.findIndex((t) => t.txid === txid)
|
|
133
|
+
beef.txs.splice(i + 1)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const writer = new WriterUint8Array()
|
|
137
|
+
writer.writeUInt32LE(ATOMIC_BEEF)
|
|
138
|
+
writer.writeReverse(toArray(txid, 'hex'))
|
|
139
|
+
|
|
140
|
+
return { beef, writer }
|
|
141
|
+
}
|
|
142
|
+
|
|
122
143
|
/**
|
|
123
144
|
* @param txid of `beefTx` to find
|
|
124
145
|
* @returns `BeefTx` in `txs` with `txid`.
|
|
@@ -308,7 +329,7 @@ export class Beef {
|
|
|
308
329
|
* @param bumpIndex Optional. If a number, must be valid index into bumps array.
|
|
309
330
|
* @returns txid of rawTx
|
|
310
331
|
*/
|
|
311
|
-
mergeRawTx (rawTx: number[], bumpIndex?: number): BeefTx {
|
|
332
|
+
mergeRawTx (rawTx: number[] | Uint8Array, bumpIndex?: number): BeefTx {
|
|
312
333
|
this.markMutated(true)
|
|
313
334
|
const newTx: BeefTx = new BeefTx(rawTx, bumpIndex)
|
|
314
335
|
this.removeExistingTxid(newTx.txid)
|
|
@@ -394,8 +415,8 @@ export class Beef {
|
|
|
394
415
|
return beefTx
|
|
395
416
|
}
|
|
396
417
|
|
|
397
|
-
mergeBeef (beef: number[] |
|
|
398
|
-
const b: Beef =
|
|
418
|
+
mergeBeef (beef: Beef | number[] | Uint8Array): void {
|
|
419
|
+
const b: Beef = (beef instanceof Beef) ? beef : Beef.fromBinary(beef)
|
|
399
420
|
|
|
400
421
|
for (const bump of b.bumps) {
|
|
401
422
|
this.mergeBump(bump)
|
|
@@ -549,7 +570,7 @@ export class Beef {
|
|
|
549
570
|
* Serializes this data to `writer`
|
|
550
571
|
* @param writer
|
|
551
572
|
*/
|
|
552
|
-
toWriter (writer: Writer): void {
|
|
573
|
+
toWriter (writer: Writer | WriterUint8Array): void {
|
|
553
574
|
writer.writeUInt32LE(this.version)
|
|
554
575
|
|
|
555
576
|
writer.writeVarIntNum(this.bumps.length)
|
|
@@ -566,11 +587,16 @@ export class Beef {
|
|
|
566
587
|
/**
|
|
567
588
|
* Returns a binary array representing the serialized BEEF
|
|
568
589
|
* @returns A binary array representing the BEEF
|
|
590
|
+
* @returns An array of byte values containing binary serialization of the BEEF
|
|
569
591
|
*/
|
|
570
592
|
toBinary (): number[] {
|
|
571
593
|
return Array.from(this.getSerializedBytes())
|
|
572
594
|
}
|
|
573
595
|
|
|
596
|
+
/**
|
|
597
|
+
* Returns a binary array representing the serialized BEEF
|
|
598
|
+
* @returns A Uint8Array containing binary serialization of the BEEF
|
|
599
|
+
*/
|
|
574
600
|
toUint8Array (): Uint8Array {
|
|
575
601
|
return this.getSerializedBytes()
|
|
576
602
|
}
|
|
@@ -586,30 +612,31 @@ export class Beef {
|
|
|
586
612
|
* @returns serialized contents of this Beef with AtomicBEEF prefix.
|
|
587
613
|
*/
|
|
588
614
|
toBinaryAtomic (txid: string): number[] {
|
|
589
|
-
|
|
590
|
-
this.sortTxs()
|
|
591
|
-
}
|
|
592
|
-
const tx = this.findTxid(txid)
|
|
593
|
-
if (tx == null) {
|
|
594
|
-
throw new Error(`${txid} does not exist in this Beef`)
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// If the transaction is not the last one, clone and modify
|
|
598
|
-
const beef = (this.txs[this.txs.length - 1] === tx) ? this : this.clone()
|
|
599
|
-
|
|
600
|
-
if (beef !== this) {
|
|
601
|
-
const i = this.txs.findIndex((t) => t.txid === txid)
|
|
602
|
-
beef.txs.splice(i + 1)
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
const writer = new Writer()
|
|
606
|
-
writer.writeUInt32LE(ATOMIC_BEEF)
|
|
607
|
-
writer.writeReverse(toArray(txid, 'hex'))
|
|
615
|
+
const { beef, writer } = this.getBeefForAtomic(txid)
|
|
608
616
|
beef.toWriter(writer)
|
|
609
|
-
|
|
610
617
|
return writer.toArray()
|
|
611
618
|
}
|
|
612
619
|
|
|
620
|
+
/**
|
|
621
|
+
* Serialize this Beef as AtomicBEEF.
|
|
622
|
+
*
|
|
623
|
+
* `txid` must exist
|
|
624
|
+
*
|
|
625
|
+
* after sorting, if txid is not last txid, creates a clone and removes newer txs
|
|
626
|
+
*
|
|
627
|
+
* @param txid
|
|
628
|
+
* @returns serialized contents of this Beef with AtomicBEEF prefix.
|
|
629
|
+
*/
|
|
630
|
+
toUint8ArrayAtomic (txid: string): Uint8Array {
|
|
631
|
+
const { beef, writer } = this.getBeefForAtomic(txid)
|
|
632
|
+
const beefUint8 = beef.getSerializedBytes()
|
|
633
|
+
const prefix = writer.toUint8Array()
|
|
634
|
+
const atomic = new Uint8Array(prefix.length + beefUint8.length)
|
|
635
|
+
atomic.set(prefix, 0)
|
|
636
|
+
atomic.set(beefUint8, prefix.length)
|
|
637
|
+
return atomic
|
|
638
|
+
}
|
|
639
|
+
|
|
613
640
|
/**
|
|
614
641
|
* Returns a hex string representing the serialized BEEF
|
|
615
642
|
* @returns A hex string representing the BEEF
|
|
@@ -619,15 +646,12 @@ export class Beef {
|
|
|
619
646
|
return this.hexCache
|
|
620
647
|
}
|
|
621
648
|
const bytes = this.getSerializedBytes()
|
|
622
|
-
const hex =
|
|
623
|
-
BufferCtor != null
|
|
624
|
-
? BufferCtor.from(bytes).toString('hex')
|
|
625
|
-
: toHex(Array.from(bytes))
|
|
649
|
+
const hex = toHex(bytes)
|
|
626
650
|
this.hexCache = hex
|
|
627
651
|
return hex
|
|
628
652
|
}
|
|
629
653
|
|
|
630
|
-
static fromReader (br: Reader): Beef {
|
|
654
|
+
static fromReader (br: Reader | ReaderUint8Array): Beef {
|
|
631
655
|
let version = br.readUInt32LE()
|
|
632
656
|
let atomicTxid: string | undefined
|
|
633
657
|
if (version === ATOMIC_BEEF) {
|
|
@@ -657,11 +681,11 @@ export class Beef {
|
|
|
657
681
|
|
|
658
682
|
/**
|
|
659
683
|
* Constructs an instance of the Beef class based on the provided binary array
|
|
660
|
-
* @param bin The binary array from which to construct BEEF
|
|
684
|
+
* @param bin The binary array or Uint8Array from which to construct BEEF
|
|
661
685
|
* @returns An instance of the Beef class constructed from the binary data
|
|
662
686
|
*/
|
|
663
|
-
static fromBinary (bin: number[]): Beef {
|
|
664
|
-
const br =
|
|
687
|
+
static fromBinary (bin: number[] | Uint8Array): Beef {
|
|
688
|
+
const br = ReaderUint8Array.makeReader(bin)
|
|
665
689
|
return Beef.fromReader(br)
|
|
666
690
|
}
|
|
667
691
|
|
|
@@ -672,8 +696,8 @@ export class Beef {
|
|
|
672
696
|
* @returns An instance of the Beef class constructed from the string
|
|
673
697
|
*/
|
|
674
698
|
static fromString (s: string, enc: 'hex' | 'utf8' | 'base64' = 'hex'): Beef {
|
|
675
|
-
const bin =
|
|
676
|
-
const br = new
|
|
699
|
+
const bin = toUint8Array(s, enc)
|
|
700
|
+
const br = new ReaderUint8Array(bin)
|
|
677
701
|
return Beef.fromReader(br)
|
|
678
702
|
}
|
|
679
703
|
|
|
@@ -825,6 +849,8 @@ export class Beef {
|
|
|
825
849
|
c.txs = Array.from(this.txs)
|
|
826
850
|
c.txidIndex = undefined
|
|
827
851
|
c.needsSort = this.needsSort
|
|
852
|
+
c.hexCache = this.hexCache
|
|
853
|
+
c.rawBytesCache = this.rawBytesCache
|
|
828
854
|
return c
|
|
829
855
|
}
|
|
830
856
|
|
|
@@ -844,7 +870,44 @@ export class Beef {
|
|
|
844
870
|
i++
|
|
845
871
|
}
|
|
846
872
|
}
|
|
847
|
-
|
|
873
|
+
|
|
874
|
+
// Trim unreferenced bumps after removing known txids
|
|
875
|
+
const referencedBumpIndices = new Set<number>()
|
|
876
|
+
for (const tx of this.txs) {
|
|
877
|
+
if (tx.bumpIndex !== undefined) {
|
|
878
|
+
referencedBumpIndices.add(tx.bumpIndex)
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// Check if there are any unreferenced bumps to remove
|
|
883
|
+
if (referencedBumpIndices.size < this.bumps.length) {
|
|
884
|
+
// Build mapping of old indices to new indices after removal
|
|
885
|
+
const indexMap = new Map<number, number>()
|
|
886
|
+
let newIndex = 0
|
|
887
|
+
for (let i = 0; i < this.bumps.length; i++) {
|
|
888
|
+
if (referencedBumpIndices.has(i)) {
|
|
889
|
+
indexMap.set(i, newIndex)
|
|
890
|
+
newIndex++
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// Remove unreferenced bumps
|
|
895
|
+
this.bumps = this.bumps.filter((_, i) => referencedBumpIndices.has(i))
|
|
896
|
+
|
|
897
|
+
// Update all transaction bumpIndex references
|
|
898
|
+
for (const tx of this.txs) {
|
|
899
|
+
if (tx.bumpIndex !== undefined) {
|
|
900
|
+
const newIndex = indexMap.get(tx.bumpIndex)
|
|
901
|
+
if (newIndex === undefined) {
|
|
902
|
+
throw new Error(`Internal error: bumpIndex ${tx.bumpIndex} not found in indexMap`)
|
|
903
|
+
}
|
|
904
|
+
tx.bumpIndex = newIndex
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
mutated = true
|
|
909
|
+
}
|
|
910
|
+
|
|
848
911
|
if (mutated) {
|
|
849
912
|
this.markMutated(true)
|
|
850
913
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { hash256 } from '../primitives/Hash.js'
|
|
2
|
-
import { Reader, Writer, toHex, toArray } from '../primitives/utils.js'
|
|
2
|
+
import { Reader, Writer, toHex, toArray, ReaderUint8Array, WriterUint8Array } from '../primitives/utils.js'
|
|
3
3
|
import Transaction from './Transaction.js'
|
|
4
4
|
import { BEEF_V2, TX_DATA_FORMAT } from './Beef.js'
|
|
5
5
|
|
|
@@ -15,7 +15,7 @@ import { BEEF_V2, TX_DATA_FORMAT } from './Beef.js'
|
|
|
15
15
|
export default class BeefTx {
|
|
16
16
|
_bumpIndex?: number
|
|
17
17
|
_tx?: Transaction
|
|
18
|
-
_rawTx?:
|
|
18
|
+
_rawTx?: Uint8Array // ← changed to Uint8Array internally
|
|
19
19
|
_txid?: string
|
|
20
20
|
inputTxids: string[] = []
|
|
21
21
|
/**
|
|
@@ -64,10 +64,28 @@ export default class BeefTx {
|
|
|
64
64
|
return undefined
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Legacy compatibility getter — returns number[] (Byte[])
|
|
69
|
+
*/
|
|
67
70
|
get rawTx (): number[] | undefined {
|
|
71
|
+
if (this._rawTx != null) {
|
|
72
|
+
return Array.from(this._rawTx)
|
|
73
|
+
}
|
|
74
|
+
if (this._tx != null) {
|
|
75
|
+
const bytes = this._tx.toUint8Array()
|
|
76
|
+
this._rawTx = bytes // cache
|
|
77
|
+
return Array.from(bytes)
|
|
78
|
+
}
|
|
79
|
+
return undefined
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Preferred modern getter — returns Uint8Array (zero-copy where possible)
|
|
84
|
+
*/
|
|
85
|
+
get rawTxUint8Array (): Uint8Array | undefined {
|
|
68
86
|
if (this._rawTx != null) return this._rawTx
|
|
69
87
|
if (this._tx != null) {
|
|
70
|
-
this._rawTx = this._tx.
|
|
88
|
+
this._rawTx = this._tx.toUint8Array()
|
|
71
89
|
return this._rawTx
|
|
72
90
|
}
|
|
73
91
|
return undefined
|
|
@@ -77,13 +95,17 @@ export default class BeefTx {
|
|
|
77
95
|
* @param tx If string, must be a valid txid. If `number[]` must be a valid serialized transaction.
|
|
78
96
|
* @param bumpIndex If transaction already has a proof in the beef to which it will be added.
|
|
79
97
|
*/
|
|
80
|
-
constructor (tx: Transaction | number[] | string, bumpIndex?: number) {
|
|
98
|
+
constructor (tx: Transaction | Uint8Array | number[] | string, bumpIndex?: number) {
|
|
81
99
|
if (typeof tx === 'string') {
|
|
82
100
|
this._txid = tx
|
|
83
|
-
} else if (
|
|
101
|
+
} else if (tx instanceof Uint8Array) {
|
|
84
102
|
this._rawTx = tx
|
|
85
|
-
} else {
|
|
103
|
+
} else if (Array.isArray(tx)) {
|
|
104
|
+
this._rawTx = new Uint8Array(tx)
|
|
105
|
+
} else if (tx instanceof Transaction) {
|
|
86
106
|
this._tx = tx
|
|
107
|
+
} else {
|
|
108
|
+
throw new Error('Invalid transaction data type')
|
|
87
109
|
}
|
|
88
110
|
this.bumpIndex = bumpIndex
|
|
89
111
|
this.updateInputTxids()
|
|
@@ -93,7 +115,7 @@ export default class BeefTx {
|
|
|
93
115
|
return new BeefTx(tx, bumpIndex)
|
|
94
116
|
}
|
|
95
117
|
|
|
96
|
-
static fromRawTx (rawTx: number[], bumpIndex?: number): BeefTx {
|
|
118
|
+
static fromRawTx (rawTx: Uint8Array | number[], bumpIndex?: number): BeefTx {
|
|
97
119
|
return new BeefTx(rawTx, bumpIndex)
|
|
98
120
|
}
|
|
99
121
|
|
|
@@ -106,18 +128,17 @@ export default class BeefTx {
|
|
|
106
128
|
// If we have a proof, or don't have a parsed transaction
|
|
107
129
|
this.inputTxids = []
|
|
108
130
|
} else {
|
|
109
|
-
const inputTxids:
|
|
131
|
+
const inputTxids: Set<string> = new Set() // minor perf improvement
|
|
110
132
|
for (const input of this.tx.inputs) {
|
|
111
133
|
if (input.sourceTXID !== undefined && input.sourceTXID !== null && input.sourceTXID !== '') {
|
|
112
|
-
|
|
113
|
-
inputTxids[input.sourceTXID] = true
|
|
134
|
+
inputTxids.add(input.sourceTXID)
|
|
114
135
|
}
|
|
115
136
|
}
|
|
116
|
-
this.inputTxids =
|
|
137
|
+
this.inputTxids = Array.from(inputTxids)
|
|
117
138
|
}
|
|
118
139
|
}
|
|
119
140
|
|
|
120
|
-
toWriter (writer: Writer, version: number): void {
|
|
141
|
+
toWriter (writer: Writer | WriterUint8Array, version: number): void {
|
|
121
142
|
const writeByte = (bb: number): void => {
|
|
122
143
|
writer.writeUInt8(bb)
|
|
123
144
|
}
|
|
@@ -130,13 +151,11 @@ export default class BeefTx {
|
|
|
130
151
|
}
|
|
131
152
|
|
|
132
153
|
const writeTx = (): void => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
} else if (this._tx != null) {
|
|
136
|
-
writer.write(this._tx.toUint8Array())
|
|
137
|
-
} else {
|
|
154
|
+
const bytes = this.rawTxUint8Array
|
|
155
|
+
if (bytes == null) {
|
|
138
156
|
throw new Error('a valid serialized Transaction is expected')
|
|
139
157
|
}
|
|
158
|
+
writer.write(bytes)
|
|
140
159
|
}
|
|
141
160
|
|
|
142
161
|
const writeBumpIndex = (): void => {
|
|
@@ -166,8 +185,8 @@ export default class BeefTx {
|
|
|
166
185
|
}
|
|
167
186
|
}
|
|
168
187
|
|
|
169
|
-
static fromReader (br: Reader, version: number): BeefTx {
|
|
170
|
-
let data: Transaction |
|
|
188
|
+
static fromReader (br: Reader | ReaderUint8Array, version: number): BeefTx {
|
|
189
|
+
let data: Transaction | undefined
|
|
171
190
|
let bumpIndex: number | undefined
|
|
172
191
|
let beefTx: BeefTx | undefined
|
|
173
192
|
if (version === BEEF_V2) {
|