@bsv/wallet-toolbox 1.1.35 → 1.1.36

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/wallet-toolbox",
3
- "version": "1.1.35",
3
+ "version": "1.1.36",
4
4
  "description": "BRC100 conforming wallet, wallet storage and wallet signer components",
5
5
  "main": "./out/src/index.js",
6
6
  "types": "./out/src/index.d.ts",
@@ -179,7 +179,7 @@ export class WalletStorageManager implements sdk.WalletStorage {
179
179
  let i = -1
180
180
  for (const store of this._stores) {
181
181
  i++
182
- if (!store.isAvailable || !store.settings) {
182
+ if (!store.isAvailable || !store.settings || !store.user) {
183
183
  // Validate all ManagedStorage properties.
184
184
  store.settings = await store.storage.makeAvailable()
185
185
  const r = await store.storage.findOrInsertUser(this._authId.identityKey)
@@ -633,7 +633,7 @@ export class WalletStorageManager implements sdk.WalletStorage {
633
633
 
634
634
  log = await this.runAsSync(async sync => {
635
635
  const reader = sync
636
- const readerSettings = this.getSettings()
636
+ const readerSettings = reader.getSettings()
637
637
 
638
638
  log += `syncToWriter from ${readerSettings.storageName} to ${writerSettings.storageName}\n`
639
639
 
@@ -697,39 +697,45 @@ export class WalletStorageManager implements sdk.WalletStorage {
697
697
 
698
698
  let log = `setActive to ${newActive.settings!.storageName}`
699
699
 
700
- if (newActiveIndex === 0 && this.isActiveEnabled)
700
+ if (storageIdentityKey === this.getActiveStore() && this.isActiveEnabled)
701
701
  /** Setting the current active as the new active is a permitted no-op. */
702
- return ` unchanged\n`
702
+ return log + ` unchanged\n`
703
703
 
704
704
  log += '\n'
705
705
 
706
706
  log += await this.runAsSync(async sync => {
707
707
  let log = ''
708
708
 
709
- // Handle case where new active is current active to resolve conflicts.
710
- // And where new active is one of the current conflict actives.
711
- this._conflictingActives!.push(this._active!)
712
- // Remove the new active from conflicting actives and
713
- // set new active as the conflicting active that matches the target `storageIdentityKey`
714
- this._conflictingActives = this._conflictingActives!.filter(ca => {
715
- const isNewActive =
716
- ca.settings!.storageIdentityKey === storageIdentityKey
717
- if (isNewActive) this._active = ca
718
- return !isNewActive
719
- })
720
-
721
709
  if (this._conflictingActives!.length > 0) {
722
- // Merge state from conflicting actives into `_active`.
710
+ // Handle case where new active is current active to resolve conflicts.
711
+ // And where new active is one of the current conflict actives.
712
+ this._conflictingActives!.push(this._active!)
713
+ // Remove the new active from conflicting actives and
714
+ // set new active as the conflicting active that matches the target `storageIdentityKey`
715
+ this._conflictingActives = this._conflictingActives!.filter(ca => {
716
+ const isNewActive =
717
+ ca.settings!.storageIdentityKey === storageIdentityKey
718
+ return !isNewActive
719
+ })
720
+
721
+ // Merge state from conflicting actives into `newActive`.
723
722
  for (const conflict of this._conflictingActives) {
724
- const sfr = await this.syncFromReader(
725
- identityKey,
726
- conflict.storage,
727
- newActive.storage
723
+ const sfr = await this.syncToWriter(
724
+ { identityKey, userId: newActive.user!.userId, isActive: false },
725
+ newActive.storage,
726
+ conflict.storage
728
727
  )
729
728
  log += sfr.log
730
729
  }
731
730
  }
732
731
 
732
+ // If there were conflicting actives,
733
+ // Push state merged from all merged actives into newActive to all stores other than the now single active.
734
+ // Otherwise,
735
+ // Push state from current active to all other stores.
736
+ const backupSource =
737
+ this._conflictingActives!.length > 0 ? newActive : this._active!
738
+
733
739
  for (const store of this._stores) {
734
740
  // Update all store's user records to reflect new active store
735
741
  await store.storage.setActive(
@@ -738,12 +744,15 @@ export class WalletStorageManager implements sdk.WalletStorage {
738
744
  )
739
745
  // Update cached user.activeStorage of all stores
740
746
  store.user!.activeStorage = storageIdentityKey
741
- // Push state merged from all conflicting actives to all non-active stores.
742
- if (store.settings!.storageIdentityKey !== storageIdentityKey) {
747
+
748
+ if (
749
+ store.settings!.storageIdentityKey !==
750
+ backupSource.settings!.storageIdentityKey
751
+ ) {
743
752
  const stwr = await this.syncToWriter(
744
753
  { identityKey, userId: store.user!.userId, isActive: false },
745
754
  store.storage,
746
- newActive.storage
755
+ backupSource.storage
747
756
  )
748
757
  log += stwr.log
749
758
  }
@@ -309,7 +309,7 @@ export class EntitySyncState extends EntityBase<TableSyncState> {
309
309
  ): sdk.RequestSyncChunkArgs {
310
310
  const a: sdk.RequestSyncChunkArgs = {
311
311
  identityKey: forIdentityKey,
312
- maxRoughSize: maxRoughSize || 20000000,
312
+ maxRoughSize: maxRoughSize || 10000000,
313
313
  maxItems: maxItems || 1000,
314
314
  offsets: [],
315
315
  since: this.when,
@@ -1,5 +1,7 @@
1
- import { StorageKnex } from '../../../src'
1
+ import knex from 'knex'
2
+ import { Setup, StorageKnex } from '../../../src'
2
3
  import { _tu, TestWalletNoSetup } from '../../utils/TestUtilsWalletStorage'
4
+ import { Database } from 'sqlite3'
3
5
 
4
6
  describe('setActive tests', () => {
5
7
  jest.setTimeout(99999999)
@@ -50,18 +52,96 @@ describe('setActive tests', () => {
50
52
  await setup.c.wallet.destroy()
51
53
  })
52
54
 
53
- test('0', async () => {
55
+ test('0 cycle active over three new sqlite wallets', async () => {
54
56
  const s = await _tu.createWalletOnly({
55
57
  chain,
56
58
  rootKeyHex,
57
59
  active: store.a,
58
60
  backups: [store.b, store.c]
59
61
  })
60
- expect(s.storage.isAvailable() === true)
61
- expect(s.storage.isActiveEnabled === false)
62
- const log = await s.storage.setActive(storeKey.b)
63
- console.log(log)
64
- expect(s.storage.getActiveStore()).toBe(storeKey.b)
65
- expect(s.storage.isActiveEnabled === true)
62
+ let first: boolean = true
63
+ for (const active of [storeKey.b, storeKey.c, storeKey.a]) {
64
+ expect(s.storage.isAvailable() === true)
65
+ expect(s.storage.isActiveEnabled === !first)
66
+ const log = await s.storage.setActive(active)
67
+ console.log(log)
68
+ expect(s.storage.getActiveStore()).toBe(active)
69
+ expect(s.storage.isActiveEnabled === true)
70
+ first = false
71
+ }
72
+ })
73
+
74
+ test('1 setActive on main storage wallet with local backup', async () => {
75
+ if (Setup.noEnv('main')) return
76
+ const env = _tu.getEnv('main')
77
+ const s = await _tu.createTestWalletWithStorageClient({
78
+ chain: env.chain,
79
+ rootKeyHex: env.devKeys[env.identityKey]
80
+ })
81
+ const cloudStorageIdentityKey = s.storage.getActiveStore()
82
+ //const filePath = '/Users/tone/Kz/tone42_backup.sqlite' // env.filePath
83
+ const filePath = env.filePath
84
+ if (filePath) {
85
+ const localStore = (
86
+ await _tu.createKnexTestWallet({
87
+ knex: _tu.createLocalSQLite(filePath),
88
+ databaseName: `sqlite for ${env.identityKey}`,
89
+ chain: env.chain
90
+ })
91
+ ).activeStorage
92
+ await s.storage.addWalletStorageProvider(localStore)
93
+ {
94
+ const log = await s.storage.setActive(cloudStorageIdentityKey)
95
+ console.log(log)
96
+ }
97
+ {
98
+ const log = await s.storage.setActive(
99
+ localStore._settings!.storageIdentityKey
100
+ )
101
+ console.log(log)
102
+ }
103
+ {
104
+ const log = await s.storage.setActive(cloudStorageIdentityKey)
105
+ console.log(log)
106
+ }
107
+ expect(s.storage.isActiveEnabled)
108
+ }
109
+ await s.wallet.destroy()
110
+ })
111
+
112
+ test('2 setActive between two local backups', async () => {
113
+ if (Setup.noEnv('main')) return
114
+ const env = _tu.getEnv('main')
115
+ const s = await _tu.createKnexTestWallet({
116
+ knex: _tu.createLocalSQLite(env.filePath!),
117
+ databaseName: `envFilePath for ${env.identityKey}`,
118
+ chain: env.chain
119
+ })
120
+ const envStorageIdentityKey = s.storage.getActiveStore()
121
+ const filePath = '/Users/tone/Kz/tone42_backup.sqlite'
122
+ const localStore = (
123
+ await _tu.createKnexTestWallet({
124
+ knex: _tu.createLocalSQLite(filePath),
125
+ databaseName: `sqlite for ${env.identityKey}`,
126
+ chain: env.chain
127
+ })
128
+ ).activeStorage
129
+ await s.storage.addWalletStorageProvider(localStore)
130
+ {
131
+ const log = await s.storage.setActive(envStorageIdentityKey)
132
+ console.log(log)
133
+ }
134
+ {
135
+ const log = await s.storage.setActive(
136
+ localStore._settings!.storageIdentityKey
137
+ )
138
+ console.log(log)
139
+ }
140
+ {
141
+ const log = await s.storage.setActive(envStorageIdentityKey)
142
+ console.log(log)
143
+ }
144
+ expect(s.storage.isActiveEnabled)
145
+ await s.wallet.destroy()
66
146
  })
67
147
  })
@@ -28,11 +28,8 @@ export async function transferPushDrop() {
28
28
  // obtain the secrets environment for the testnet network.
29
29
  const env = Setup.getEnv('main')
30
30
  // setup1 will be the sending wallet using the rootKey associated with identityKey, which is the default.
31
- const setup1 = await Setup.createWalletSQLite({
32
- env,
33
- filePath: env.filePath!,
34
- databaseName: 'exists'
35
- })
31
+ const setup1 = await Setup.createWalletClient({ env })
32
+
36
33
  // setup2 will be the receiving wallet using the rootKey associated with identityKey2
37
34
  const setup2 = setup1
38
35
 
@@ -254,9 +251,7 @@ export async function inputPushDrop(
254
251
  */
255
252
  const st = car.signableTransaction!
256
253
  const beef = Beef.fromBinary(st.tx)
257
- const tx = setup.wallet.beef.findAtomicTransaction(
258
- beef.txs.slice(-1)[0].txid
259
- )!
254
+ const tx = beef.findAtomicTransaction(beef.txs.slice(-1)[0].txid)!
260
255
  tx.inputs[0].unlockingScriptTemplate = unlock
261
256
  await tx.sign()
262
257
  const unlockingScript = tx.inputs[0].unlockingScript!.toHex()
@@ -71,6 +71,10 @@ export interface TuEnv {
71
71
  runMySQL: boolean
72
72
  runSlowTests: boolean
73
73
  logTests: boolean
74
+ /**
75
+ * file path to local sqlite file for identityKey
76
+ */
77
+ filePath?: string
74
78
  }
75
79
 
76
80
  export abstract class TestUtilsWalletStorage {
@@ -80,6 +84,10 @@ export abstract class TestUtilsWalletStorage {
80
84
  (chain === 'main'
81
85
  ? process.env.MY_MAIN_IDENTITY
82
86
  : process.env.MY_TEST_IDENTITY) || ''
87
+ const filePath =
88
+ chain === 'main'
89
+ ? process.env.MY_MAIN_FILEPATH
90
+ : process.env.MY_TEST_FILEPATH
83
91
  const identityKey2 =
84
92
  (chain === 'main'
85
93
  ? process.env.MY_MAIN_IDENTITY2
@@ -98,7 +106,8 @@ export abstract class TestUtilsWalletStorage {
98
106
  devKeys: JSON.parse(DEV_KEYS) as Record<string, string>,
99
107
  runMySQL,
100
108
  runSlowTests,
101
- logTests
109
+ logTests,
110
+ filePath
102
111
  }
103
112
  }
104
113
 
@@ -9,7 +9,7 @@ import {
9
9
  import { StorageKnex } from '../../../src/storage/StorageKnex'
10
10
  import { _tu, TestWalletNoSetup } from '../../utils/TestUtilsWalletStorage'
11
11
 
12
- describe.skip('Wallet sync tests', () => {
12
+ describe('Wallet sync tests', () => {
13
13
  jest.setTimeout(99999999)
14
14
 
15
15
  const env = _tu.getEnv('test')
@@ -115,7 +115,11 @@ async function setActiveTwice(
115
115
  } = ctx
116
116
 
117
117
  if (withBackupFirst) {
118
- await storageManager.updateBackups()
118
+ if (storageManager.isActiveEnabled) await storageManager.updateBackups()
119
+ else
120
+ await expect(storageManager.updateBackups()).rejects.toThrow(
121
+ `WalletStorageManager is not accessing user's active storage or there are conflicting active stores configured.`
122
+ )
119
123
  }
120
124
 
121
125
  const backupIdentityKey = (await backup.makeAvailable()).storageIdentityKey
@@ -123,7 +127,7 @@ async function setActiveTwice(
123
127
  .storageIdentityKey
124
128
  expect(backupIdentityKey).not.toBe(originalIdentityKey)
125
129
 
126
- const originalAuth = await storageManager.getAuth()
130
+ const originalAuth = { ...(await storageManager.getAuth()) }
127
131
  expect(originalAuth.userId).toBe(originalUserId)
128
132
  const originalTransactions = await original.findTransactions({
129
133
  partial: { userId: originalAuth.userId }
@@ -150,8 +154,16 @@ async function setActiveTwice(
150
154
  true
151
155
  )
152
156
 
157
+ expect(storageManager.getActiveStore()).toBe(originalIdentityKey)
158
+ expect(storageManager.getActiveUser().activeStorage).toBe(originalIdentityKey)
159
+
153
160
  // sync to backup and make it active.
154
- await storageManager.setActive(backupIdentityKey)
161
+ const log = await storageManager.setActive(backupIdentityKey)
162
+ console.log(log)
163
+
164
+ expect(storageManager.getActiveStore()).toBe(backupIdentityKey)
165
+ expect(storageManager.getActiveUser().activeStorage).toBe(backupIdentityKey)
166
+ expect(storageManager.getBackupStores()).toEqual([originalIdentityKey])
155
167
 
156
168
  let originalUserAfter = verifyTruthy(
157
169
  await original.findUserById(originalAuth.userId!)
@@ -173,13 +185,17 @@ async function setActiveTwice(
173
185
  output: `${'1'.repeat(64)}.42`
174
186
  })
175
187
  ).rejects.toThrow('Result must exist and be unique.')
176
- if (backupWallet)
188
+ if (backupWallet) {
189
+ backupWallet.storage._isAvailable = false
190
+ backupWallet.storage._active!.user = undefined
191
+ await backupWallet.storage.makeAvailable()
177
192
  await expect(
178
193
  backupWallet.relinquishOutput({
179
194
  basket: 'xyzzy',
180
195
  output: `${'1'.repeat(64)}.42`
181
196
  })
182
197
  ).rejects.toThrow('Result must exist and be unique.')
198
+ }
183
199
 
184
200
  const backupAuth = await storageManager.getAuth()
185
201
  const backupTransactions = await backup.findTransactions({
@@ -189,7 +205,10 @@ async function setActiveTwice(
189
205
  now = Date.now()
190
206
 
191
207
  // sync back to original and make it active.
192
- await storageManager.setActive(original.getSettings().storageIdentityKey)
208
+ const log2 = await storageManager.setActive(
209
+ original.getSettings().storageIdentityKey
210
+ )
211
+ console.log(log2)
193
212
 
194
213
  originalUserAfter = verifyTruthy(
195
214
  await original.findUserById(originalAuth.userId!)
@@ -212,13 +231,16 @@ async function setActiveTwice(
212
231
  })
213
232
  ).rejects.toThrow('Result must exist and be unique.')
214
233
  if (backupWallet) {
234
+ backupWallet.storage._isAvailable = false
235
+ backupWallet.storage._active!.user = undefined
236
+ await backupWallet.storage.makeAvailable()
215
237
  await expect(
216
238
  backupWallet.relinquishOutput({
217
239
  basket: 'xyzzy',
218
240
  output: `${'1'.repeat(64)}.42`
219
241
  })
220
242
  ).rejects.toThrow(
221
- `WalletStorageManager is not accessing user's active storage.`
243
+ `WalletStorageManager is not accessing user's active storage or there are conflicting active stores configured.`
222
244
  )
223
245
  }
224
246
  }