@bsv/sdk 1.6.6 → 1.6.8
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/kvstore/LocalKVStore.js +74 -45
- package/dist/cjs/src/kvstore/LocalKVStore.js.map +1 -1
- package/dist/cjs/src/primitives/utils.js +18 -2
- package/dist/cjs/src/primitives/utils.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/kvstore/LocalKVStore.js +74 -45
- package/dist/esm/src/kvstore/LocalKVStore.js.map +1 -1
- package/dist/esm/src/primitives/utils.js +18 -2
- package/dist/esm/src/primitives/utils.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/kvstore/LocalKVStore.d.ts +2 -0
- package/dist/types/src/kvstore/LocalKVStore.d.ts.map +1 -1
- package/dist/types/src/primitives/utils.d.ts +2 -1
- package/dist/types/src/primitives/utils.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/docs/primitives.md +2 -1
- package/package.json +1 -1
- package/src/kvstore/LocalKVStore.ts +76 -44
- package/src/primitives/utils.ts +20 -2
package/docs/primitives.md
CHANGED
|
@@ -3229,7 +3229,8 @@ export class Reader {
|
|
|
3229
3229
|
public readInt32LE(): number
|
|
3230
3230
|
public readUInt64BEBn(): BigNumber
|
|
3231
3231
|
public readUInt64LEBn(): BigNumber
|
|
3232
|
-
public
|
|
3232
|
+
public readInt64LEBn(): BigNumber
|
|
3233
|
+
public readVarIntNum(signed: boolean = true): number
|
|
3233
3234
|
public readVarInt(): number[]
|
|
3234
3235
|
public readVarIntBn(): BigNumber
|
|
3235
3236
|
}
|
package/package.json
CHANGED
|
@@ -44,7 +44,7 @@ export default class LocalKVStore {
|
|
|
44
44
|
* A map to store locks for each key to ensure atomic updates.
|
|
45
45
|
* @private
|
|
46
46
|
*/
|
|
47
|
-
private readonly keyLocks: Map<string,
|
|
47
|
+
private readonly keyLocks: Map<string, Array<(value: void | PromiseLike<void>) => void>> = new Map()
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Creates an instance of the localKVStore.
|
|
@@ -72,6 +72,38 @@ export default class LocalKVStore {
|
|
|
72
72
|
this.acceptDelayedBroadcast = acceptDelayedBroadcast
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
private async queueOperationOnKey (key: string): Promise<Array<(value: void | PromiseLike<void>) => void>> {
|
|
76
|
+
// Check if a lock exists for this key and wait for it to resolve
|
|
77
|
+
let lockQueue = this.keyLocks.get(key)
|
|
78
|
+
if (lockQueue == null) {
|
|
79
|
+
lockQueue = []
|
|
80
|
+
this.keyLocks.set(key, lockQueue)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let resolveNewLock: () => void = () => {}
|
|
84
|
+
const newLock = new Promise<void>((resolve) => {
|
|
85
|
+
resolveNewLock = resolve
|
|
86
|
+
if (lockQueue != null) { lockQueue.push(resolve) }
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// If we are the only request, resolve the lock immediately, queue remains at 1 item until request ends.
|
|
90
|
+
if (lockQueue.length === 1) {
|
|
91
|
+
resolveNewLock()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
await newLock
|
|
95
|
+
|
|
96
|
+
return lockQueue
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private finishOperationOnKey (key: string, lockQueue: Array<(value: void | PromiseLike<void>) => void>): void {
|
|
100
|
+
lockQueue.shift() // Remove the current lock from the queue
|
|
101
|
+
if (lockQueue.length > 0) {
|
|
102
|
+
// If there are more locks waiting, resolve the next one
|
|
103
|
+
lockQueue[0]()
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
75
107
|
private getProtocol (key: string): { protocolID: WalletProtocol, keyID: string } {
|
|
76
108
|
return { protocolID: [2, this.context], keyID: key }
|
|
77
109
|
}
|
|
@@ -98,8 +130,14 @@ export default class LocalKVStore {
|
|
|
98
130
|
* @throws {Error} If the found output's locking script cannot be decoded or represents an invalid token format.
|
|
99
131
|
*/
|
|
100
132
|
async get (key: string, defaultValue: string | undefined = undefined): Promise<string | undefined> {
|
|
101
|
-
const
|
|
102
|
-
|
|
133
|
+
const lockQueue = await this.queueOperationOnKey(key)
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const r = await this.lookupValue(key, defaultValue, 5)
|
|
137
|
+
return r.value
|
|
138
|
+
} finally {
|
|
139
|
+
this.finishOperationOnKey(key, lockQueue)
|
|
140
|
+
}
|
|
103
141
|
}
|
|
104
142
|
|
|
105
143
|
private getLockingScript (output: WalletOutput, beef: Beef): LockingScript {
|
|
@@ -185,17 +223,7 @@ export default class LocalKVStore {
|
|
|
185
223
|
* @returns {Promise<OutpointString>} A promise that resolves to the outpoint string (txid.vout) of the new or updated token output.
|
|
186
224
|
*/
|
|
187
225
|
async set (key: string, value: string): Promise<OutpointString> {
|
|
188
|
-
|
|
189
|
-
const existingLock = this.keyLocks.get(key)
|
|
190
|
-
if (existingLock != null) {
|
|
191
|
-
await existingLock
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
let resolveNewLock: () => void = () => {}
|
|
195
|
-
const newLock = new Promise<void>((resolve) => {
|
|
196
|
-
resolveNewLock = resolve
|
|
197
|
-
})
|
|
198
|
-
this.keyLocks.set(key, newLock)
|
|
226
|
+
const lockQueue = await this.queueOperationOnKey(key)
|
|
199
227
|
|
|
200
228
|
try {
|
|
201
229
|
const current = await this.lookupValue(key, undefined, 10)
|
|
@@ -266,9 +294,7 @@ export default class LocalKVStore {
|
|
|
266
294
|
|
|
267
295
|
return outpoint
|
|
268
296
|
} finally {
|
|
269
|
-
|
|
270
|
-
this.keyLocks.delete(key)
|
|
271
|
-
resolveNewLock()
|
|
297
|
+
this.finishOperationOnKey(key, lockQueue)
|
|
272
298
|
}
|
|
273
299
|
}
|
|
274
300
|
|
|
@@ -283,38 +309,44 @@ export default class LocalKVStore {
|
|
|
283
309
|
* @returns {Promise<string[]>} A promise that resolves to the txids of the removal transactions if successful.
|
|
284
310
|
*/
|
|
285
311
|
async remove (key: string): Promise<string[]> {
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
312
|
+
const lockQueue = await this.queueOperationOnKey(key)
|
|
313
|
+
|
|
314
|
+
try {
|
|
315
|
+
const txids: string[] = []
|
|
316
|
+
for (; ;) {
|
|
317
|
+
const { outputs, BEEF: inputBEEF, totalOutputs } = await this.getOutputs(key)
|
|
318
|
+
if (outputs.length > 0) {
|
|
319
|
+
const pushdrop = new PushDrop(this.wallet, this.originator)
|
|
320
|
+
try {
|
|
321
|
+
const inputs = this.getInputs(outputs)
|
|
322
|
+
const { signableTransaction } = await this.wallet.createAction({
|
|
323
|
+
description: `Remove ${key} in ${this.context}`,
|
|
324
|
+
inputBEEF,
|
|
325
|
+
inputs,
|
|
326
|
+
options: {
|
|
327
|
+
acceptDelayedBroadcast: this.acceptDelayedBroadcast
|
|
328
|
+
}
|
|
329
|
+
})
|
|
330
|
+
if (typeof signableTransaction !== 'object') {
|
|
331
|
+
throw new Error('Wallet did not return a signable transaction when expected.')
|
|
299
332
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
333
|
+
const spends = await this.getSpends(key, outputs, pushdrop, signableTransaction.tx)
|
|
334
|
+
const { txid } = await this.wallet.signAction({
|
|
335
|
+
reference: signableTransaction.reference,
|
|
336
|
+
spends
|
|
337
|
+
})
|
|
338
|
+
if (txid === undefined) { throw new Error('signAction must return a valid txid') }
|
|
339
|
+
txids.push(txid)
|
|
340
|
+
} catch (_) {
|
|
341
|
+
throw new Error(`There are ${totalOutputs} outputs with tag ${key} that cannot be unlocked.`)
|
|
303
342
|
}
|
|
304
|
-
const spends = await this.getSpends(key, outputs, pushdrop, signableTransaction.tx)
|
|
305
|
-
const { txid } = await this.wallet.signAction({
|
|
306
|
-
reference: signableTransaction.reference,
|
|
307
|
-
spends
|
|
308
|
-
})
|
|
309
|
-
if (txid === undefined) { throw new Error('signAction must return a valid txid') }
|
|
310
|
-
txids.push(txid)
|
|
311
|
-
} catch (_) {
|
|
312
|
-
throw new Error(`There are ${totalOutputs} outputs with tag ${key} that cannot be unlocked.`)
|
|
313
343
|
}
|
|
344
|
+
if (outputs.length === totalOutputs) { break }
|
|
314
345
|
}
|
|
315
|
-
|
|
346
|
+
return txids
|
|
347
|
+
} finally {
|
|
348
|
+
this.finishOperationOnKey(key, lockQueue)
|
|
316
349
|
}
|
|
317
|
-
return txids
|
|
318
350
|
}
|
|
319
351
|
}
|
|
320
352
|
|
package/src/primitives/utils.ts
CHANGED
|
@@ -525,6 +525,9 @@ export class Writer {
|
|
|
525
525
|
|
|
526
526
|
static varIntNum (n: number): number[] {
|
|
527
527
|
let buf: number[]
|
|
528
|
+
if (n < 0) {
|
|
529
|
+
return this.varIntBn(new BigNumber(n))
|
|
530
|
+
}
|
|
528
531
|
if (n < 253) {
|
|
529
532
|
buf = [n] // 1 byte
|
|
530
533
|
} else if (n < 0x10000) {
|
|
@@ -565,6 +568,9 @@ export class Writer {
|
|
|
565
568
|
|
|
566
569
|
static varIntBn (bn: BigNumber): number[] {
|
|
567
570
|
let buf: number[]
|
|
571
|
+
if (bn.isNeg()) {
|
|
572
|
+
bn = bn.add(OverflowUint64) // Adjust for negative numbers
|
|
573
|
+
}
|
|
568
574
|
if (bn.ltn(253)) {
|
|
569
575
|
const n = bn.toNumber()
|
|
570
576
|
// No need for bitwise operation as the value is within a byte's range
|
|
@@ -708,7 +714,16 @@ export class Reader {
|
|
|
708
714
|
return bn
|
|
709
715
|
}
|
|
710
716
|
|
|
711
|
-
public
|
|
717
|
+
public readInt64LEBn (): BigNumber {
|
|
718
|
+
const bin = this.readReverse(8)
|
|
719
|
+
let bn = new BigNumber(bin)
|
|
720
|
+
if (bn.gte(OverflowInt64)) {
|
|
721
|
+
bn = bn.sub(OverflowUint64) // Adjust for negative numbers
|
|
722
|
+
}
|
|
723
|
+
return bn
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
public readVarIntNum (signed: boolean = true): number {
|
|
712
727
|
const first = this.readUInt8()
|
|
713
728
|
let bn: BigNumber
|
|
714
729
|
switch (first) {
|
|
@@ -717,7 +732,7 @@ export class Reader {
|
|
|
717
732
|
case 0xfe:
|
|
718
733
|
return this.readUInt32LE()
|
|
719
734
|
case 0xff:
|
|
720
|
-
bn = this.readUInt64LEBn()
|
|
735
|
+
bn = signed ? this.readInt64LEBn() : this.readUInt64LEBn()
|
|
721
736
|
if (bn.lte(new BigNumber(2).pow(new BigNumber(53)))) {
|
|
722
737
|
return bn.toNumber()
|
|
723
738
|
} else {
|
|
@@ -801,3 +816,6 @@ export const minimallyEncode = (buf: number[]): number[] => {
|
|
|
801
816
|
// If we found the whole thing is zeros, then we have a zero.
|
|
802
817
|
return []
|
|
803
818
|
}
|
|
819
|
+
|
|
820
|
+
const OverflowInt64 = new BigNumber(2).pow(new BigNumber(63))
|
|
821
|
+
const OverflowUint64 = new BigNumber(2).pow(new BigNumber(64))
|