@bsv/wallet-toolbox 1.7.19 → 1.7.22

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 (41) hide show
  1. package/docs/client.md +26 -2
  2. package/docs/services.md +13 -1
  3. package/docs/storage.md +13 -1
  4. package/docs/wallet.md +26 -2
  5. package/out/src/WalletPermissionsManager.d.ts +6 -0
  6. package/out/src/WalletPermissionsManager.d.ts.map +1 -1
  7. package/out/src/WalletPermissionsManager.js +241 -74
  8. package/out/src/WalletPermissionsManager.js.map +1 -1
  9. package/out/src/services/__tests/getRawTx.test.js +3 -0
  10. package/out/src/services/__tests/getRawTx.test.js.map +1 -1
  11. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.d.ts +1 -1
  12. package/out/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.js +3 -1
  13. package/out/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.js.map +1 -1
  14. package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.d.ts.map +1 -1
  15. package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.js +12 -0
  16. package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.js.map +1 -1
  17. package/out/src/storage/StorageProvider.d.ts +16 -2
  18. package/out/src/storage/StorageProvider.d.ts.map +1 -1
  19. package/out/src/storage/StorageProvider.js +33 -4
  20. package/out/src/storage/StorageProvider.js.map +1 -1
  21. package/out/src/storage/methods/__test/offsetKey.test.js +266 -100
  22. package/out/src/storage/methods/__test/offsetKey.test.js.map +1 -1
  23. package/out/src/storage/methods/getBeefForTransaction.js +1 -1
  24. package/out/src/storage/methods/getBeefForTransaction.js.map +1 -1
  25. package/out/src/storage/methods/internalizeAction.d.ts.map +1 -1
  26. package/out/src/storage/methods/internalizeAction.js +2 -2
  27. package/out/src/storage/methods/internalizeAction.js.map +1 -1
  28. package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js +4 -0
  29. package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js.map +1 -1
  30. package/out/tsconfig.all.tsbuildinfo +1 -1
  31. package/package.json +1 -1
  32. package/src/WalletPermissionsManager.ts +302 -71
  33. package/src/services/__tests/getRawTx.test.ts +2 -0
  34. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.ts +1 -1
  35. package/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.ts +2 -1
  36. package/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.ts +12 -0
  37. package/src/storage/StorageProvider.ts +38 -5
  38. package/src/storage/methods/__test/offsetKey.test.ts +299 -103
  39. package/src/storage/methods/getBeefForTransaction.ts +3 -1
  40. package/src/storage/methods/internalizeAction.ts +4 -3
  41. package/src/storage/schema/entities/__tests/ProvenTxTests.test.ts +2 -0
@@ -128,139 +128,335 @@ describe('offsetKey tests', () => {
128
128
 
129
129
  // txid b6f72df4224efbacab42a16e1e88f48c217f03929c36987b9067d2556de47c10
130
130
  // height 922107
131
- // hash 00000000000000001957bfadf841d1709d5039b3243c33ba58e4a6a97b44d2a8
131
+ // incorrect hash 000000000000000014d97d19bf82956c1f7ce3977da10b7fbdab9a10653c02e7
132
+ // correct hash 00000000000000001957bfadf841d1709d5039b3243c33ba58e4a6a97b44d2a8
132
133
  const sm = new WalletStorageManager(setup.identityKey, storage)
133
134
  sm.setServices(setup.services)
135
+ // This should correct invalid merkle proofs in proven_txs but currently does not because WoC returns invalid header info.
134
136
  await sm.reproveHeader('000000000000000014d97d19bf82956c1f7ce3977da10b7fbdab9a10653c02e7')
135
137
 
136
- const comms: TableCommission[] = []
137
- const beef = new Beef()
138
- const chainTracker = await setup.services.getChainTracker()
139
- const inputs: CreateActionInput[] = []
140
-
141
138
  const fca: FindCommissionsArgs = {
142
139
  partial: { isRedeemed: false },
143
- paged: { limit: 200, offset: 0 }
140
+ paged: { limit: 400, offset: 0 }
144
141
  }
145
142
 
146
- for (; comms.length < fca.paged!.limit; ) {
147
- const unredeemedComms = await storage.findCommissions(fca)
148
- if (unredeemedComms.length === 0) break
149
- for (const comm of unredeemedComms) {
150
- const tt = verifyTruthy(await storage.findTransactionById(comm.transactionId, undefined, true))
151
- if (tt.provenTxId && tt.txid) {
152
- // Only add merge valid beefs...
153
- try {
154
- await storage.getBeefForTransaction(tt.txid, { mergeToBeef: beef, chainTracker })
155
- } catch (e) {
156
- // Ignore errors in merging beefs
143
+ for (;;) {
144
+ const comms: TableCommission[] = []
145
+ let beef = new Beef()
146
+ const chainTracker = await setup.services.getChainTracker()
147
+ const inputs: CreateActionInput[] = []
148
+
149
+ for (; comms.length < fca.paged!.limit; ) {
150
+ const unredeemedComms = await storage.findCommissions(fca)
151
+ if (unredeemedComms.length < 1) break
152
+
153
+ for (const comm of unredeemedComms) {
154
+ fca.paged!.offset! += 1
155
+ const tt = verifyTruthy(await storage.findTransactionById(comm.transactionId, undefined, true))
156
+ if (tt.provenTxId && tt.txid) {
157
+ await storage.getBeefForTransaction(tt.txid, { mergeToBeef: beef, chainTracker, skipInvalidProofs: true })
158
+ const tx = verifyTruthy(beef.findTxid(tt.txid)).tx!
159
+ const commVOut = tx.outputs.findIndex(
160
+ o => o.satoshis === comm.satoshis && o.lockingScript.toHex() === Utils.toHex(comm.lockingScript)
161
+ )
162
+ const commOut = tx.outputs[commVOut]
163
+ const input: CreateActionInput = {
164
+ outpoint: `${tt.txid}.${commVOut}`,
165
+ inputDescription: `commId:${comm.commissionId}`,
166
+ unlockingScriptLength: 108
167
+ }
168
+ inputs.push(input)
169
+ comms.push(comm)
170
+ if (comms.length === fca.paged!.limit) break
171
+ }
172
+ }
173
+ }
174
+
175
+ if (comms.length < fca.paged!.limit)
176
+ // Only redeem full quota of commissions per cycle to avoid paying higher percentage of fees.
177
+ break
178
+
179
+ if (comms.length > 0) {
180
+ fca.paged!.offset! -= comms.length
181
+
182
+ console.log(beef.toLogString())
183
+ const verified = await beef.verify(chainTracker, false)
184
+ expect(verified).toBe(true)
185
+
186
+ const cao: CreateActionOptions = {
187
+ randomizeOutputs: false,
188
+ //signAndProcess: false,
189
+ noSend: true
190
+ }
191
+ const ca: CreateActionArgs = {
192
+ description: 'redeem commissions',
193
+ inputs: inputs,
194
+ inputBEEF: beef.toBinary(),
195
+ options: cao
196
+ }
197
+
198
+ const car = await setup.wallet.createAction(ca)
199
+ expect(car.signableTransaction).toBeTruthy()
200
+
201
+ const st = car.signableTransaction!
202
+ expect(st.reference).toBeTruthy()
203
+ const atomicBeef = Beef.fromBinary(st.tx)
204
+ const txid = atomicBeef.txs[atomicBeef.txs.length - 1].txid!
205
+ const tx = atomicBeef.findTransactionForSigning(txid)!
206
+
207
+ const priv = PrivateKey.fromHex(env.devKeys[env.commissionsIdentity])
208
+ const pub = priv.toPublicKey()
209
+ const curve = new Curve()
210
+ const p2pkh = new P2PKH()
211
+ const spends: Record<PositiveIntegerOrZero, SignActionSpend> = {}
212
+ let vin = 0
213
+ // set an unlockingScriptTemplate for each commission input being redeemed in unsigned tx
214
+ for (const comm of comms) {
215
+ const { hashedSecret } = keyOffsetToHashedSecret(pub, comm.keyOffset)
216
+ const bn = priv.add(hashedSecret).mod(curve.n)
217
+ const offsetPrivKey = new PrivateKey(bn)
218
+ const unlock = p2pkh.unlock(offsetPrivKey, 'all', false)
219
+ tx.inputs[vin].unlockingScriptTemplate = unlock
220
+ vin++
221
+ }
222
+
223
+ // sign each input
224
+ await tx.sign()
225
+
226
+ vin = 0
227
+ // extract all the signed unlocking scripts
228
+ for (const comm of comms) {
229
+ const script = tx.inputs[vin].unlockingScript!
230
+ const unlockingScript = script.toHex()
231
+ spends[vin] = { unlockingScript }
232
+ vin++
233
+ }
234
+
235
+ const signArgs: SignActionArgs = {
236
+ reference: st.reference,
237
+ spends,
238
+ options: {
239
+ returnTXIDOnly: true,
240
+ noSend: true
157
241
  }
158
- const tx = verifyTruthy(beef.findTxid(tt.txid)).tx!
159
- const commVOut = tx.outputs.findIndex(
160
- o => o.satoshis === comm.satoshis && o.lockingScript.toHex() === Utils.toHex(comm.lockingScript)
161
- )
162
- const commOut = tx.outputs[commVOut]
163
- const input: CreateActionInput = {
164
- outpoint: `${tt.txid}.${commVOut}`,
165
- inputDescription: `commId:${comm.commissionId}`,
166
- unlockingScriptLength: 108
242
+ }
243
+
244
+ // Forward all the unlocking scripts to storage and create the ProvenTxReq for the noSend txid.
245
+ const sr = await setup.wallet.signAction(signArgs)
246
+ expect(sr.txid).toBeTruthy()
247
+
248
+ // Update the commissions as redeemed in storage
249
+ for (const comm of comms) {
250
+ await storage.updateCommission(comm.commissionId, { isRedeemed: true })
251
+ }
252
+
253
+ {
254
+ // Get the transaction broadcast
255
+ const createArgs: CreateActionArgs = {
256
+ description: `broadcasting noSend`,
257
+ options: {
258
+ acceptDelayedBroadcast: false,
259
+ sendWith: [sr.txid!]
260
+ }
167
261
  }
168
- inputs.push(input)
169
- comms.push(comm)
170
- if (comms.length >= fca.paged!.limit) break
262
+
263
+ const cr = await setup.wallet.createAction(createArgs)
264
+
265
+ expect(cr.noSendChange).not.toBeTruthy()
266
+ expect(cr.sendWithResults?.length).toBe(1)
267
+ const [swr] = cr.sendWithResults!
268
+ expect(swr.status !== 'failed').toBe(true)
171
269
  }
172
270
  }
173
- fca.paged!.offset! += unredeemedComms.length
174
271
  }
272
+ } catch (err) {
273
+ console.error('Error in 4_redeemServiceCharges test:', err)
274
+ throw err
275
+ }
175
276
 
176
- if (comms.length > 0) {
177
- console.log(beef.toLogString())
178
- const verified = await beef.verify(await setup.services.getChainTracker(), false)
179
- expect(verified).toBe(true)
277
+ await storage.destroy()
278
+ await setup.wallet.destroy()
279
+ })
180
280
 
181
- const cao: CreateActionOptions = {
182
- randomizeOutputs: false,
183
- //signAndProcess: false,
184
- noSend: true
185
- }
186
- const ca: CreateActionArgs = {
187
- description: 'redeem commissions',
188
- inputs: inputs,
189
- inputBEEF: beef.toBinary(),
190
- options: cao
191
- }
281
+ test('4a_redeemServiceCharges optimized', async () => {
282
+ if (_tu.noEnv('main')) return
192
283
 
193
- const car = await setup.wallet.createAction(ca)
194
- expect(car.signableTransaction).toBeTruthy()
195
-
196
- const st = car.signableTransaction!
197
- expect(st.reference).toBeTruthy()
198
- const atomicBeef = Beef.fromBinary(st.tx)
199
- const txid = atomicBeef.txs[atomicBeef.txs.length - 1].txid!
200
- const tx = atomicBeef.findTransactionForSigning(txid)!
201
-
202
- const priv = PrivateKey.fromHex(env.devKeys[env.commissionsIdentity])
203
- const pub = priv.toPublicKey()
204
- const curve = new Curve()
205
- const p2pkh = new P2PKH()
206
- const spends: Record<PositiveIntegerOrZero, SignActionSpend> = {}
207
- let vin = 0
208
- // set an unlockingScriptTemplate for each commission input being redeemed in unsigned tx
209
- for (const comm of comms) {
210
- const { hashedSecret } = keyOffsetToHashedSecret(pub, comm.keyOffset)
211
- const bn = priv.add(hashedSecret).mod(curve.n)
212
- const offsetPrivKey = new PrivateKey(bn)
213
- const unlock = p2pkh.unlock(offsetPrivKey, 'all', false)
214
- tx.inputs[vin].unlockingScriptTemplate = unlock
215
- vin++
216
- }
284
+ const env = _tu.getEnv('main')
285
+ if (!env.devKeys[env.commissionsIdentity]) {
286
+ throw new Error('No dev key for commissions identity')
287
+ }
217
288
 
218
- // sign each input
219
- await tx.sign()
289
+ const knex = Setup.createMySQLKnex(process.env.MAIN_CLOUD_MYSQL_CONNECTION!)
290
+ const storage = new StorageKnex({
291
+ chain: env.chain,
292
+ knex: knex,
293
+ commissionSatoshis: 0,
294
+ commissionPubKeyHex: undefined,
295
+ feeModel: { model: 'sat/kb', value: 1 }
296
+ })
297
+
298
+ let setup: TestWalletOnly
299
+ await storage.makeAvailable()
300
+
301
+ setup = await _tu.createTestWalletWithStorageClient({
302
+ chain: 'main',
303
+ rootKeyHex: env.devKeys[env.commissionsIdentity]
304
+ })
305
+ storage.setServices(setup.services)
220
306
 
221
- vin = 0
222
- // extract all the signed unlocking scripts
223
- for (const comm of comms) {
224
- const script = tx.inputs[vin].unlockingScript!
225
- const unlockingScript = script.toHex()
226
- spends[vin] = { unlockingScript }
227
- vin++
307
+ try {
308
+ const fca: FindCommissionsArgs = {
309
+ partial: { isRedeemed: false },
310
+ paged: { limit: 400, offset: 0 }
311
+ }
312
+
313
+ for (;;) {
314
+ const comms: TableCommission[] = []
315
+ let beef = new Beef()
316
+ const chainTracker = await setup.services.getChainTracker()
317
+ const inputs: CreateActionInput[] = []
318
+
319
+ // This query would be much faster and allow valid proofs to be merged into beef directly...
320
+ // but will blow up if rawTx are large.
321
+ // This is really a case where a full Beef isn't needed.
322
+ // All the inputs will be from proven txs.
323
+ // Processors should accept the aggregate rawTx without any other input rawTxs or merkle proofs.
324
+ // i.e. All the input txids should be "known"
325
+ const r = await storage.knex.raw(
326
+ `
327
+ SELECT c.*, t.provenTxId, p.height, p.index, p.merklePath, p.rawTx, p.blockHash, p.merkleRoot
328
+ FROM commissions c
329
+ JOIN transactions t ON c.transactionId = t.transactionId
330
+ JOIN proven_txs p ON t.provenTxId = p.provenTxId
331
+ WHERE c.isRedeemed = 0
332
+ AND NOT t.provenTxId IS NOT NULL
333
+ ORDER BY c.commissionId
334
+ LIMIT ? OFFSET ?;
335
+ `,
336
+ [fca.paged!.limit, fca.paged!.offset!]
337
+ )
338
+
339
+ for (; comms.length < fca.paged!.limit; ) {
340
+ const unredeemedComms = await storage.findCommissions(fca)
341
+ if (unredeemedComms.length < 1) break
342
+
343
+ for (const comm of unredeemedComms) {
344
+ fca.paged!.offset! += 1
345
+ const tt = verifyTruthy(await storage.findTransactionById(comm.transactionId, undefined, true))
346
+ if (tt.provenTxId && tt.txid) {
347
+ await storage.getBeefForTransaction(tt.txid, { mergeToBeef: beef, chainTracker, skipInvalidProofs: true })
348
+ const tx = verifyTruthy(beef.findTxid(tt.txid)).tx!
349
+ const commVOut = tx.outputs.findIndex(
350
+ o => o.satoshis === comm.satoshis && o.lockingScript.toHex() === Utils.toHex(comm.lockingScript)
351
+ )
352
+ const commOut = tx.outputs[commVOut]
353
+ const input: CreateActionInput = {
354
+ outpoint: `${tt.txid}.${commVOut}`,
355
+ inputDescription: `commId:${comm.commissionId}`,
356
+ unlockingScriptLength: 108
357
+ }
358
+ inputs.push(input)
359
+ comms.push(comm)
360
+ if (comms.length === fca.paged!.limit) break
361
+ }
362
+ }
228
363
  }
229
364
 
230
- const signArgs: SignActionArgs = {
231
- reference: st.reference,
232
- spends,
233
- options: {
234
- returnTXIDOnly: true,
365
+ if (comms.length < fca.paged!.limit)
366
+ // Only redeem full quota of commissions per cycle to avoid paying higher percentage of fees.
367
+ break
368
+
369
+ if (comms.length > 0) {
370
+ fca.paged!.offset! -= comms.length
371
+
372
+ console.log(beef.toLogString())
373
+ const verified = await beef.verify(chainTracker, false)
374
+ expect(verified).toBe(true)
375
+
376
+ const cao: CreateActionOptions = {
377
+ randomizeOutputs: false,
378
+ //signAndProcess: false,
235
379
  noSend: true
236
380
  }
237
- }
381
+ const ca: CreateActionArgs = {
382
+ description: 'redeem commissions',
383
+ inputs: inputs,
384
+ inputBEEF: beef.toBinary(),
385
+ options: cao
386
+ }
238
387
 
239
- // Forward all the unlocking scripts to storage and create the ProvenTxReq for the noSend txid.
240
- const sr = await setup.wallet.signAction(signArgs)
241
- expect(sr.txid).toBeTruthy()
388
+ const car = await setup.wallet.createAction(ca)
389
+ expect(car.signableTransaction).toBeTruthy()
390
+
391
+ const st = car.signableTransaction!
392
+ expect(st.reference).toBeTruthy()
393
+ const atomicBeef = Beef.fromBinary(st.tx)
394
+ const txid = atomicBeef.txs[atomicBeef.txs.length - 1].txid!
395
+ const tx = atomicBeef.findTransactionForSigning(txid)!
396
+
397
+ const priv = PrivateKey.fromHex(env.devKeys[env.commissionsIdentity])
398
+ const pub = priv.toPublicKey()
399
+ const curve = new Curve()
400
+ const p2pkh = new P2PKH()
401
+ const spends: Record<PositiveIntegerOrZero, SignActionSpend> = {}
402
+ let vin = 0
403
+ // set an unlockingScriptTemplate for each commission input being redeemed in unsigned tx
404
+ for (const comm of comms) {
405
+ const { hashedSecret } = keyOffsetToHashedSecret(pub, comm.keyOffset)
406
+ const bn = priv.add(hashedSecret).mod(curve.n)
407
+ const offsetPrivKey = new PrivateKey(bn)
408
+ const unlock = p2pkh.unlock(offsetPrivKey, 'all', false)
409
+ tx.inputs[vin].unlockingScriptTemplate = unlock
410
+ vin++
411
+ }
242
412
 
243
- // Update the commissions as redeemed in storage
244
- for (const comm of comms) {
245
- await storage.updateCommission(comm.commissionId, { isRedeemed: true })
246
- }
413
+ // sign each input
414
+ await tx.sign()
415
+
416
+ vin = 0
417
+ // extract all the signed unlocking scripts
418
+ for (const comm of comms) {
419
+ const script = tx.inputs[vin].unlockingScript!
420
+ const unlockingScript = script.toHex()
421
+ spends[vin] = { unlockingScript }
422
+ vin++
423
+ }
247
424
 
248
- {
249
- // Get the transaction broadcast
250
- const createArgs: CreateActionArgs = {
251
- description: `broadcasting noSend`,
425
+ const signArgs: SignActionArgs = {
426
+ reference: st.reference,
427
+ spends,
252
428
  options: {
253
- acceptDelayedBroadcast: false,
254
- sendWith: [sr.txid!]
429
+ returnTXIDOnly: true,
430
+ noSend: true
255
431
  }
256
432
  }
257
433
 
258
- const cr = await setup.wallet.createAction(createArgs)
434
+ // Forward all the unlocking scripts to storage and create the ProvenTxReq for the noSend txid.
435
+ const sr = await setup.wallet.signAction(signArgs)
436
+ expect(sr.txid).toBeTruthy()
437
+
438
+ // Update the commissions as redeemed in storage
439
+ for (const comm of comms) {
440
+ await storage.updateCommission(comm.commissionId, { isRedeemed: true })
441
+ }
259
442
 
260
- expect(cr.noSendChange).not.toBeTruthy()
261
- expect(cr.sendWithResults?.length).toBe(1)
262
- const [swr] = cr.sendWithResults!
263
- expect(swr.status !== 'failed').toBe(true)
443
+ {
444
+ // Get the transaction broadcast
445
+ const createArgs: CreateActionArgs = {
446
+ description: `broadcasting noSend`,
447
+ options: {
448
+ acceptDelayedBroadcast: false,
449
+ sendWith: [sr.txid!]
450
+ }
451
+ }
452
+
453
+ const cr = await setup.wallet.createAction(createArgs)
454
+
455
+ expect(cr.noSendChange).not.toBeTruthy()
456
+ expect(cr.sendWithResults?.length).toBe(1)
457
+ const [swr] = cr.sendWithResults!
458
+ expect(swr.status !== 'failed').toBe(true)
459
+ }
264
460
  }
265
461
  }
266
462
  } catch (err) {
@@ -82,7 +82,9 @@ async function mergeBeefForTransactionRecurse(
82
82
  options.trustSelf,
83
83
  options.knownTxids,
84
84
  undefined,
85
- requiredLevels
85
+ requiredLevels,
86
+ options.chainTracker,
87
+ options.skipInvalidProofs
86
88
  )
87
89
  if (knownBeef) return knownBeef
88
90
  }
@@ -5,7 +5,8 @@ import {
5
5
  InternalizeActionArgs,
6
6
  TransactionOutput,
7
7
  Beef,
8
- Validation
8
+ Validation,
9
+ Utils
9
10
  } from '@bsv/sdk'
10
11
  import { GetReqsAndBeefResult, shareReqsWithWorld } from './processAction'
11
12
  import { StorageProvider } from '../StorageProvider'
@@ -152,7 +153,7 @@ class InternalizeActionContext {
152
153
  }
153
154
 
154
155
  async asyncSetup() {
155
- ;({ ab: this.ab, tx: this.tx, txid: this.txid } = await this.validateAtomicBeef(this.args.tx))
156
+ ;({ ab: this.ab, tx: this.tx, txid: this.txid } = await this.validateAtomicBeef(Utils.toArray(this.args.tx)))
156
157
 
157
158
  for (const o of this.args.outputs) {
158
159
  if (o.outputIndex < 0 || o.outputIndex >= this.tx.outputs.length)
@@ -405,7 +406,7 @@ class InternalizeActionContext {
405
406
  //
406
407
  // Attempt to create a provenTxReq record for the txid to obtain a proof,
407
408
  // while allowing for possible race conditions...
408
- const newReq = EntityProvenTxReq.fromTxid(this.txid, this.tx.toBinary(), this.args.tx)
409
+ const newReq = EntityProvenTxReq.fromTxid(this.txid, this.tx.toBinary(), Utils.toArray(this.args.tx))
409
410
  newReq.status = 'unsent'
410
411
  // this history and notify will be merged into an existing req if it exists.
411
412
  newReq.addHistoryNote({ what: 'internalizeAction', userId: this.userId })
@@ -168,6 +168,7 @@ describe('ProvenTx class method tests', () => {
168
168
  })
169
169
 
170
170
  test('1_fromTxid: txid with no rawTx available', async () => {
171
+ if (_tu.noEnv('test')) return
171
172
  const ctx = ctxs[0]
172
173
  const txid = 'missing-txid'
173
174
 
@@ -182,6 +183,7 @@ describe('ProvenTx class method tests', () => {
182
183
  })
183
184
 
184
185
  test('2_fromTxid: txid with no Merkle proof available', async () => {
186
+ if (_tu.noEnv('test')) return
185
187
  const ctx = ctxs[0]
186
188
  const txid = 'no-merkle-proof-txid'
187
189
  const services: sdk.WalletServices = ctx.services