@bsv/sdk 1.10.2 → 1.10.4

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 (93) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/auth/Peer.js +51 -1
  3. package/dist/cjs/src/auth/Peer.js.map +1 -1
  4. package/dist/cjs/src/auth/clients/AuthFetch.js +13 -3
  5. package/dist/cjs/src/auth/clients/AuthFetch.js.map +1 -1
  6. package/dist/cjs/src/primitives/ReaderUint8Array.js +180 -0
  7. package/dist/cjs/src/primitives/ReaderUint8Array.js.map +1 -0
  8. package/dist/cjs/src/primitives/WriterUint8Array.js +173 -0
  9. package/dist/cjs/src/primitives/WriterUint8Array.js.map +1 -0
  10. package/dist/cjs/src/primitives/utils.js +20 -2
  11. package/dist/cjs/src/primitives/utils.js.map +1 -1
  12. package/dist/cjs/src/script/templates/PushDrop.js +21 -7
  13. package/dist/cjs/src/script/templates/PushDrop.js.map +1 -1
  14. package/dist/cjs/src/transaction/Beef.js +85 -27
  15. package/dist/cjs/src/transaction/Beef.js.map +1 -1
  16. package/dist/cjs/src/transaction/BeefTx.js +32 -14
  17. package/dist/cjs/src/transaction/BeefTx.js.map +1 -1
  18. package/dist/cjs/src/transaction/MerklePath.js +25 -6
  19. package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
  20. package/dist/cjs/src/transaction/Transaction.js +77 -26
  21. package/dist/cjs/src/transaction/Transaction.js.map +1 -1
  22. package/dist/cjs/src/transaction/broadcasters/ARC.js +23 -0
  23. package/dist/cjs/src/transaction/broadcasters/ARC.js.map +1 -1
  24. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  25. package/dist/esm/src/auth/Peer.js +51 -1
  26. package/dist/esm/src/auth/Peer.js.map +1 -1
  27. package/dist/esm/src/auth/clients/AuthFetch.js +13 -3
  28. package/dist/esm/src/auth/clients/AuthFetch.js.map +1 -1
  29. package/dist/esm/src/primitives/ReaderUint8Array.js +176 -0
  30. package/dist/esm/src/primitives/ReaderUint8Array.js.map +1 -0
  31. package/dist/esm/src/primitives/WriterUint8Array.js +169 -0
  32. package/dist/esm/src/primitives/WriterUint8Array.js.map +1 -0
  33. package/dist/esm/src/primitives/utils.js +18 -1
  34. package/dist/esm/src/primitives/utils.js.map +1 -1
  35. package/dist/esm/src/script/templates/PushDrop.js +21 -7
  36. package/dist/esm/src/script/templates/PushDrop.js.map +1 -1
  37. package/dist/esm/src/transaction/Beef.js +86 -28
  38. package/dist/esm/src/transaction/Beef.js.map +1 -1
  39. package/dist/esm/src/transaction/BeefTx.js +33 -15
  40. package/dist/esm/src/transaction/BeefTx.js.map +1 -1
  41. package/dist/esm/src/transaction/MerklePath.js +26 -7
  42. package/dist/esm/src/transaction/MerklePath.js.map +1 -1
  43. package/dist/esm/src/transaction/Transaction.js +78 -27
  44. package/dist/esm/src/transaction/Transaction.js.map +1 -1
  45. package/dist/esm/src/transaction/broadcasters/ARC.js +23 -0
  46. package/dist/esm/src/transaction/broadcasters/ARC.js.map +1 -1
  47. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  48. package/dist/types/src/auth/Peer.d.ts +9 -0
  49. package/dist/types/src/auth/Peer.d.ts.map +1 -1
  50. package/dist/types/src/auth/clients/AuthFetch.d.ts.map +1 -1
  51. package/dist/types/src/primitives/ReaderUint8Array.d.ts +32 -0
  52. package/dist/types/src/primitives/ReaderUint8Array.d.ts.map +1 -0
  53. package/dist/types/src/primitives/WriterUint8Array.d.ts +54 -0
  54. package/dist/types/src/primitives/WriterUint8Array.d.ts.map +1 -0
  55. package/dist/types/src/primitives/utils.d.ts +15 -3
  56. package/dist/types/src/primitives/utils.d.ts.map +1 -1
  57. package/dist/types/src/script/templates/PushDrop.d.ts +3 -4
  58. package/dist/types/src/script/templates/PushDrop.d.ts.map +1 -1
  59. package/dist/types/src/transaction/Beef.d.ts +24 -7
  60. package/dist/types/src/transaction/Beef.d.ts.map +1 -1
  61. package/dist/types/src/transaction/BeefTx.d.ts +13 -6
  62. package/dist/types/src/transaction/BeefTx.d.ts.map +1 -1
  63. package/dist/types/src/transaction/MerklePath.d.ts +16 -3
  64. package/dist/types/src/transaction/MerklePath.d.ts.map +1 -1
  65. package/dist/types/src/transaction/Transaction.d.ts +44 -7
  66. package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
  67. package/dist/types/src/transaction/broadcasters/ARC.d.ts.map +1 -1
  68. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  69. package/dist/umd/bundle.js +3 -3
  70. package/dist/umd/bundle.js.map +1 -1
  71. package/docs/reference/primitives.md +167 -29
  72. package/docs/reference/script.md +1 -1
  73. package/docs/reference/transaction.md +177 -34
  74. package/package.json +1 -1
  75. package/src/auth/Peer.ts +65 -5
  76. package/src/auth/__tests/Peer.test.ts +8 -2
  77. package/src/auth/clients/AuthFetch.ts +18 -3
  78. package/src/overlay-tools/__tests/SHIPBroadcaster.test.ts +9 -0
  79. package/src/primitives/ReaderUint8Array.ts +196 -0
  80. package/src/primitives/WriterUint8Array.ts +195 -0
  81. package/src/primitives/__tests/ReaderUint8Array.test.ts +317 -0
  82. package/src/primitives/__tests/WriterUint8Array.test.ts +208 -0
  83. package/src/primitives/utils.ts +20 -2
  84. package/src/script/templates/PushDrop.ts +32 -17
  85. package/src/script/templates/__tests/PushDrop.test.ts +28 -0
  86. package/src/storage/__tests/StorageUploader.test.ts +1 -1
  87. package/src/transaction/Beef.ts +103 -40
  88. package/src/transaction/BeefTx.ts +38 -19
  89. package/src/transaction/MerklePath.ts +30 -9
  90. package/src/transaction/Transaction.ts +91 -38
  91. package/src/transaction/__tests/Beef.test.ts +75 -0
  92. package/src/transaction/broadcasters/ARC.ts +34 -7
  93. package/src/transaction/broadcasters/__tests/ARC.test.ts +98 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/sdk",
3
- "version": "1.10.2",
3
+ "version": "1.10.4",
4
4
  "type": "module",
5
5
  "description": "BSV Blockchain Software Development Kit",
6
6
  "main": "dist/cjs/mod.js",
package/src/auth/Peer.ts CHANGED
@@ -55,6 +55,12 @@ export class Peer {
55
55
  { callback: (sessionNonce: string) => void, sessionNonce: string }
56
56
  > = new Map()
57
57
 
58
+ // Promise-based mechanism for waiting on certificate validation
59
+ private readonly certificateValidationPromises: Map<
60
+ string,
61
+ { resolve: () => void, reject: (error: Error) => void }
62
+ > = new Map()
63
+
58
64
  // Single shared counter for all callback types
59
65
  private callbackIdCounter: number = 0
60
66
 
@@ -644,6 +650,11 @@ export class Peer {
644
650
  peerSession.lastUpdate = Date.now()
645
651
  this.sessionManager.updateSession(peerSession)
646
652
 
653
+ // Resolve any promises waiting for certificate validation
654
+ if (peerSession.sessionNonce != null) {
655
+ this.resolveCertificateValidation(peerSession.sessionNonce)
656
+ }
657
+
647
658
  this.onCertificatesReceivedCallbacks.forEach(cb =>
648
659
  cb(message.identityKey, message.certificates as VerifiableCertificate[])
649
660
  )
@@ -834,6 +845,11 @@ export class Peer {
834
845
  peerSession.lastUpdate = Date.now()
835
846
  this.sessionManager.updateSession(peerSession)
836
847
 
848
+ // Resolve any promises waiting for certificate validation
849
+ if (peerSession.sessionNonce != null) {
850
+ this.resolveCertificateValidation(peerSession.sessionNonce)
851
+ }
852
+
837
853
  // Notify any listeners
838
854
  this.onCertificatesReceivedCallbacks.forEach(cb => {
839
855
  cb(message.identityKey, message.certificates ?? [])
@@ -869,12 +885,41 @@ export class Peer {
869
885
  const certificatesRequired = peerSession.certificatesRequired === true
870
886
  const certificatesValidated = peerSession.certificatesValidated === true
871
887
 
888
+ // If certificates are required but not yet validated, wait for them with a timeout
872
889
  if (certificatesRequired && !certificatesValidated) {
873
- throw new Error(
874
- `Received general message before certificate validation from peer ${
875
- peerSession.peerIdentityKey ?? 'unknown'
876
- }`
877
- )
890
+ const CERTIFICATE_WAIT_TIMEOUT_MS = 30000
891
+ const sessionNonce = peerSession.sessionNonce
892
+
893
+ if (sessionNonce == null) {
894
+ throw new Error('Session nonce is required for certificate validation')
895
+ }
896
+
897
+ await new Promise<void>((resolve, reject) => {
898
+ // Set timeout to reject if certificates don't arrive
899
+ const timeoutId = setTimeout(() => {
900
+ const promise = this.certificateValidationPromises.get(sessionNonce)
901
+ if (promise != null) {
902
+ this.certificateValidationPromises.delete(sessionNonce)
903
+ reject(new Error(
904
+ `Timeout waiting for certificate validation from peer ${
905
+ peerSession.peerIdentityKey ?? 'unknown'
906
+ }`
907
+ ))
908
+ }
909
+ }, CERTIFICATE_WAIT_TIMEOUT_MS)
910
+
911
+ // Store the promise resolvers with timeout cleanup
912
+ this.certificateValidationPromises.set(sessionNonce, {
913
+ resolve: () => {
914
+ clearTimeout(timeoutId)
915
+ resolve()
916
+ },
917
+ reject: (error: Error) => {
918
+ clearTimeout(timeoutId)
919
+ reject(error)
920
+ }
921
+ })
922
+ })
878
923
  }
879
924
 
880
925
  const { valid } = await this.wallet.verifySignature({
@@ -904,6 +949,21 @@ export class Peer {
904
949
  })
905
950
  }
906
951
 
952
+ /**
953
+ * Resolves any pending certificate validation promises for the given session nonce.
954
+ * This should be called when certificates have been successfully validated.
955
+ *
956
+ * @private
957
+ * @param {string} sessionNonce - The session nonce to resolve promises for.
958
+ */
959
+ private resolveCertificateValidation (sessionNonce: string): void {
960
+ const promise = this.certificateValidationPromises.get(sessionNonce)
961
+ if (promise != null) {
962
+ promise.resolve()
963
+ this.certificateValidationPromises.delete(sessionNonce)
964
+ }
965
+ }
966
+
907
967
  private async getIdentityPublicKey (): Promise<string> {
908
968
  if (this.identityPublicKey != null) {
909
969
  return this.identityPublicKey
@@ -894,12 +894,18 @@ describe('Peer class mutual authentication and certificate exchange', () => {
894
894
 
895
895
  setupPeers(false, true) // Bob requires certs
896
896
 
897
+ // Prevent Alice from auto-sending certificate response
898
+ // This keeps Bob in "certs required but not validated" state
899
+ alice.listenForCertificatesRequested(() => {
900
+ // Intentionally do nothing (no auto-response)
901
+ })
902
+
897
903
  let received = false
898
904
  bob.listenForGeneralMessages(() => {
899
905
  received = true
900
906
  })
901
907
 
902
- // Send message — error is thrown internally
908
+ // Send message — Bob will wait for certificates that never arrive
903
909
  try {
904
910
  await alice.toPeer(Utils.toArray('Hello Bob!'), bobPubKey)
905
911
  } catch {
@@ -909,7 +915,7 @@ describe('Peer class mutual authentication and certificate exchange', () => {
909
915
  // Allow transport handlers to run
910
916
  await new Promise(r => setTimeout(r, 50))
911
917
 
912
- // Message must NOT be delivered
918
+ // Message must NOT be delivered since certificates haven't been validated
913
919
  expect(received).toBe(false)
914
920
  })
915
921
 
@@ -237,12 +237,27 @@ export class AuthFetch {
237
237
  // If the server has a resource that requires certificates to be sent before access would be granted,
238
238
  // this makes sure the user has a chance to send the certificates before the resource is requested.
239
239
  if (peerToUse.pendingCertificateRequests.length > 0) {
240
- await new Promise(resolve => {
241
- setInterval(() => {
240
+ const CERTIFICATE_WAIT_TIMEOUT_MS = 30000
241
+ const CHECK_INTERVAL_MS = 100
242
+
243
+ await new Promise<void>((resolve, reject) => {
244
+ const startTime = Date.now()
245
+
246
+ const checkPending = (): void => {
242
247
  if (peerToUse.pendingCertificateRequests.length === 0) {
243
248
  resolve()
249
+ return
250
+ }
251
+
252
+ if (Date.now() - startTime > CERTIFICATE_WAIT_TIMEOUT_MS) {
253
+ reject(new Error('Timeout waiting for certificate request to complete'))
254
+ return
244
255
  }
245
- }, 100) // Check every 100 ms for the user to finish responding
256
+
257
+ setTimeout(checkPending, CHECK_INTERVAL_MS)
258
+ }
259
+
260
+ checkPending()
246
261
  })
247
262
  }
248
263
 
@@ -339,8 +339,12 @@ describe('SHIPCast', () => {
339
339
  })
340
340
  const testTx = new Transaction(1, [], [], 0)
341
341
 
342
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { })
343
+
342
344
  const result = await b.broadcast(testTx)
343
345
 
346
+ expect(consoleErrorSpy).toHaveBeenCalled()
347
+
344
348
  expect(result).toEqual({
345
349
  status: 'error',
346
350
  code: 'ERR_ALL_HOSTS_REJECTED',
@@ -1076,8 +1080,13 @@ describe('SHIPCast', () => {
1076
1080
  resolver: mockResolver as unknown as LookupResolver
1077
1081
  })
1078
1082
  const testTx = new Transaction(1, [], [], 0)
1083
+
1084
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { })
1085
+
1079
1086
  const response = await b.broadcast(testTx)
1080
1087
 
1088
+ expect(consoleErrorSpy).toHaveBeenCalled()
1089
+
1081
1090
  // Since the host responded (successfully in terms of HTTP), but with invalid data, we should consider it a failure
1082
1091
  expect(response).toEqual({
1083
1092
  status: 'error',
@@ -0,0 +1,196 @@
1
+ import BigNumber from './BigNumber.js'
2
+ import { Reader } from './utils.js'
3
+
4
+ /**
5
+ * Reader for serialized Uint8Array binary data.
6
+ */
7
+ export class ReaderUint8Array {
8
+ public bin: Uint8Array
9
+ public pos: number
10
+ private readonly length: number
11
+
12
+ static makeReader (bin: Uint8Array | number[], pos: number = 0): Reader | ReaderUint8Array {
13
+ if (bin instanceof Uint8Array) {
14
+ return new ReaderUint8Array(bin, pos)
15
+ }
16
+ if (Array.isArray(bin)) {
17
+ return new Reader(bin, pos)
18
+ }
19
+ throw new Error('ReaderUint8Array.makeReader: bin must be Uint8Array or number[]')
20
+ }
21
+
22
+ constructor (bin: Uint8Array | number[] = new Uint8Array(0), pos: number = 0) {
23
+ if (bin instanceof Uint8Array) {
24
+ this.bin = bin
25
+ } else if (Array.isArray(bin)) {
26
+ this.bin = new Uint8Array(bin)
27
+ } else {
28
+ throw new Error('ReaderUint8Array constructor: bin must be Uint8Array or number[]')
29
+ }
30
+ this.pos = pos
31
+ this.length = this.bin.length
32
+ }
33
+
34
+ public eof (): boolean {
35
+ return this.pos >= this.length
36
+ }
37
+
38
+ public read (len = this.length): Uint8Array {
39
+ const start = this.pos
40
+ const end = this.pos + len
41
+ this.pos = end
42
+ return this.bin.slice(start, end)
43
+ }
44
+
45
+ public readReverse (len = this.length): Uint8Array {
46
+ const buf2 = new Uint8Array(len)
47
+ for (let i = 0; i < len; i++) {
48
+ buf2[i] = this.bin[this.pos + len - 1 - i]
49
+ }
50
+ this.pos += len
51
+ return buf2
52
+ }
53
+
54
+ public readUInt8 (): number {
55
+ const val = this.bin[this.pos]
56
+ this.pos += 1
57
+ return val
58
+ }
59
+
60
+ public readInt8 (): number {
61
+ const val = this.bin[this.pos]
62
+ this.pos += 1
63
+ // If the sign bit is set, convert to negative value
64
+ return (val & 0x80) !== 0 ? val - 0x100 : val
65
+ }
66
+
67
+ public readUInt16BE (): number {
68
+ const val = (this.bin[this.pos] << 8) | this.bin[this.pos + 1]
69
+ this.pos += 2
70
+ return val
71
+ }
72
+
73
+ public readInt16BE (): number {
74
+ const val = this.readUInt16BE()
75
+ // If the sign bit is set, convert to negative value
76
+ return (val & 0x8000) !== 0 ? val - 0x10000 : val
77
+ }
78
+
79
+ public readUInt16LE (): number {
80
+ const val = this.bin[this.pos] | (this.bin[this.pos + 1] << 8)
81
+ this.pos += 2
82
+ return val
83
+ }
84
+
85
+ public readInt16LE (): number {
86
+ const val = this.readUInt16LE()
87
+ // If the sign bit is set, convert to negative value
88
+ const x = (val & 0x8000) !== 0 ? val - 0x10000 : val
89
+ return x
90
+ }
91
+
92
+ public readUInt32BE (): number {
93
+ const val =
94
+ this.bin[this.pos] * 0x1000000 + // Shift the first byte by 24 bits
95
+ ((this.bin[this.pos + 1] << 16) | // Shift the second byte by 16 bits
96
+ (this.bin[this.pos + 2] << 8) | // Shift the third byte by 8 bits
97
+ this.bin[this.pos + 3]) // The fourth byte
98
+ this.pos += 4
99
+ return val
100
+ }
101
+
102
+ public readInt32BE (): number {
103
+ const val = this.readUInt32BE()
104
+ // If the sign bit is set, convert to negative value
105
+ return (val & 0x80000000) !== 0 ? val - 0x100000000 : val
106
+ }
107
+
108
+ public readUInt32LE (): number {
109
+ const val =
110
+ (this.bin[this.pos] |
111
+ (this.bin[this.pos + 1] << 8) |
112
+ (this.bin[this.pos + 2] << 16) |
113
+ (this.bin[this.pos + 3] << 24)) >>>
114
+ 0
115
+ this.pos += 4
116
+ return val
117
+ }
118
+
119
+ public readInt32LE (): number {
120
+ const val = this.readUInt32LE()
121
+ // Explicitly check if the sign bit is set and then convert to a negative value
122
+ return (val & 0x80000000) !== 0 ? val - 0x100000000 : val
123
+ }
124
+
125
+ public readUInt64BEBn (): BigNumber {
126
+ const bin = Array.from(this.bin.slice(this.pos, this.pos + 8))
127
+ const bn = new BigNumber(bin)
128
+ this.pos = this.pos + 8
129
+ return bn
130
+ }
131
+
132
+ public readUInt64LEBn (): BigNumber {
133
+ const bin = Array.from(this.readReverse(8))
134
+ const bn = new BigNumber(bin)
135
+ return bn
136
+ }
137
+
138
+ public readInt64LEBn (): BigNumber {
139
+ const OverflowInt64 = new BigNumber(2).pow(new BigNumber(63))
140
+ const OverflowUint64 = new BigNumber(2).pow(new BigNumber(64))
141
+ const bin = Array.from(this.readReverse(8))
142
+ let bn = new BigNumber(bin)
143
+ if (bn.gte(OverflowInt64)) {
144
+ bn = bn.sub(OverflowUint64) // Adjust for negative numbers
145
+ }
146
+ return bn
147
+ }
148
+
149
+ public readVarIntNum (signed: boolean = true): number {
150
+ const first = this.readUInt8()
151
+ let bn: BigNumber
152
+ switch (first) {
153
+ case 0xfd:
154
+ return this.readUInt16LE()
155
+ case 0xfe:
156
+ return this.readUInt32LE()
157
+ case 0xff:
158
+ bn = signed ? this.readInt64LEBn() : this.readUInt64LEBn()
159
+ if (bn.lte(new BigNumber(2).pow(new BigNumber(53)))) {
160
+ return bn.toNumber()
161
+ } else {
162
+ throw new Error('number too large to retain precision - use readVarIntBn')
163
+ }
164
+ default:
165
+ return first
166
+ }
167
+ }
168
+
169
+ public readVarInt (): Uint8Array {
170
+ const first = this.bin[this.pos]
171
+ switch (first) {
172
+ case 0xfd:
173
+ return this.read(1 + 2)
174
+ case 0xfe:
175
+ return this.read(1 + 4)
176
+ case 0xff:
177
+ return this.read(1 + 8)
178
+ default:
179
+ return this.read(1)
180
+ }
181
+ }
182
+
183
+ public readVarIntBn (): BigNumber {
184
+ const first = this.readUInt8()
185
+ switch (first) {
186
+ case 0xfd:
187
+ return new BigNumber(this.readUInt16LE())
188
+ case 0xfe:
189
+ return new BigNumber(this.readUInt32LE())
190
+ case 0xff:
191
+ return this.readUInt64LEBn()
192
+ default:
193
+ return new BigNumber(first)
194
+ }
195
+ }
196
+ }
@@ -0,0 +1,195 @@
1
+ import BigNumber from './BigNumber.js'
2
+ import { Writer } from './utils.js'
3
+
4
+ type WriterChunk = readonly number[] | Uint8Array
5
+
6
+ /**
7
+ * WriterUint8Array is a utility class for writing binary data into a dynamically
8
+ * growing Uint8Array buffer. It provides methods to write various integer types
9
+ * and variable-length integers, similar to the Writer class but optimized for
10
+ * Uint8Array usage.
11
+ */
12
+ export class WriterUint8Array {
13
+ private buffer: Uint8Array
14
+ private pos: number
15
+ private capacity: number
16
+
17
+ constructor (bufs?: WriterChunk[], initialCapacity: number = 256) {
18
+ if ((bufs != null) && bufs.length > 0) {
19
+ const totalLength = bufs.reduce((sum, buf) => sum + buf.length, 0)
20
+ initialCapacity = Math.max(initialCapacity, totalLength)
21
+ }
22
+ this.buffer = new Uint8Array(initialCapacity)
23
+ this.pos = 0
24
+ this.capacity = initialCapacity
25
+ if (bufs != null) {
26
+ for (const buf of bufs) {
27
+ this.write(buf)
28
+ }
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Returns the current length of written data
34
+ */
35
+ getLength (): number {
36
+ return this.pos
37
+ }
38
+
39
+ /**
40
+ * @return the written data as Uint8Array copy of the internal buffer
41
+ */
42
+ toUint8Array (): Uint8Array {
43
+ return this.buffer.slice(0, this.pos)
44
+ }
45
+
46
+ /**
47
+ * Legacy compatibility method – returns number[] (Byte[])
48
+ */
49
+ toArray (): number[] {
50
+ return Array.from(this.toUint8Array())
51
+ }
52
+
53
+ /**
54
+ * @return the written data as Uint8Array. CAUTION: This is zero-copy subarray of the internal buffer).
55
+ */
56
+ toUint8ArrayZeroCopy (): Uint8Array {
57
+ return this.buffer.subarray(0, this.pos)
58
+ }
59
+
60
+ private ensureCapacity (needed: number): void {
61
+ if (this.pos + needed > this.capacity) {
62
+ let newCapacity = this.capacity * 2
63
+ while (this.pos + needed > newCapacity) {
64
+ newCapacity *= 2
65
+ }
66
+ const newBuffer = new Uint8Array(newCapacity)
67
+ newBuffer.set(this.buffer)
68
+ this.buffer = newBuffer
69
+ this.capacity = newCapacity
70
+ }
71
+ }
72
+
73
+ write (bytes: WriterChunk): this {
74
+ const data = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes)
75
+ this.ensureCapacity(data.length)
76
+ this.buffer.set(data, this.pos)
77
+ this.pos += data.length
78
+ return this
79
+ }
80
+
81
+ writeReverse (buf: WriterChunk): this {
82
+ const data = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
83
+ this.ensureCapacity(data.length)
84
+ for (let i = data.length - 1; i >= 0; i--) {
85
+ this.buffer[this.pos] = data[i]
86
+ this.pos += 1
87
+ }
88
+ return this
89
+ }
90
+
91
+ writeUInt8 (value: number): this {
92
+ this.ensureCapacity(1)
93
+ this.buffer[this.pos] = value & 0xff
94
+ this.pos += 1
95
+ return this
96
+ }
97
+
98
+ writeInt8 (value: number): this {
99
+ this.writeUInt8(value)
100
+ return this
101
+ }
102
+
103
+ writeUInt16LE (value: number): this {
104
+ this.ensureCapacity(2)
105
+ this.buffer[this.pos] = value & 0xff
106
+ this.buffer[this.pos + 1] = (value >> 8) & 0xff
107
+ this.pos += 2
108
+ return this
109
+ }
110
+
111
+ writeUInt16BE (value: number): this {
112
+ this.ensureCapacity(2)
113
+ this.buffer[this.pos] = (value >> 8) & 0xff
114
+ this.buffer[this.pos + 1] = value & 0xff
115
+ this.pos += 2
116
+ return this
117
+ }
118
+
119
+ writeInt16LE (value: number): this {
120
+ this.writeUInt16LE(value & 0xffff)
121
+ return this
122
+ }
123
+
124
+ writeInt16BE (value: number): this {
125
+ this.writeUInt16BE(value & 0xffff)
126
+ return this
127
+ }
128
+
129
+ writeUInt32LE (value: number): this {
130
+ this.ensureCapacity(4)
131
+ this.buffer[this.pos] = value & 0xff
132
+ this.buffer[this.pos + 1] = (value >> 8) & 0xff
133
+ this.buffer[this.pos + 2] = (value >> 16) & 0xff
134
+ this.buffer[this.pos + 3] = (value >> 24) & 0xff
135
+ this.pos += 4
136
+ return this
137
+ }
138
+
139
+ writeUInt32BE (value: number): this {
140
+ this.ensureCapacity(4)
141
+ this.buffer[this.pos] = (value >> 24) & 0xff
142
+ this.buffer[this.pos + 1] = (value >> 16) & 0xff
143
+ this.buffer[this.pos + 2] = (value >> 8) & 0xff
144
+ this.buffer[this.pos + 3] = value & 0xff
145
+ this.pos += 4
146
+ return this
147
+ }
148
+
149
+ writeInt32LE (value: number): this {
150
+ this.writeUInt32LE(value >>> 0)
151
+ return this
152
+ }
153
+
154
+ writeInt32BE (value: number): this {
155
+ this.writeUInt32BE(value >>> 0)
156
+ return this
157
+ }
158
+
159
+ writeUInt64BEBn (bn: BigNumber): this {
160
+ const buf = bn.toArray('be', 8)
161
+ this.write(buf)
162
+ return this
163
+ }
164
+
165
+ writeUInt64LEBn (bn: BigNumber): this {
166
+ const buf = bn.toArray('be', 8)
167
+ this.writeReverse(buf)
168
+ return this
169
+ }
170
+
171
+ writeUInt64LE (n: number): this {
172
+ const buf = new BigNumber(n).toArray('be', 8)
173
+ this.writeReverse(buf)
174
+ return this
175
+ }
176
+
177
+ writeVarIntNum (n: number): this {
178
+ const buf = Writer.varIntNum(n)
179
+ this.write(buf)
180
+ return this
181
+ }
182
+
183
+ writeVarIntBn (bn: BigNumber): this {
184
+ const buf = Writer.varIntBn(bn)
185
+ this.write(buf)
186
+ return this
187
+ }
188
+
189
+ /**
190
+ * Resets the writer to empty state (reuses the buffer)
191
+ */
192
+ reset (): void {
193
+ this.pos = 0
194
+ }
195
+ }