@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/out/src/storage/WalletStorageManager.d.ts.map +1 -1
- package/out/src/storage/WalletStorageManager.js +23 -20
- package/out/src/storage/WalletStorageManager.js.map +1 -1
- package/out/src/storage/schema/entities/SyncState.js +1 -1
- package/out/test/Wallet/sync/setActive.test.js +78 -7
- package/out/test/Wallet/sync/setActive.test.js.map +1 -1
- package/out/test/examples/pushdrop.test.d.ts.map +1 -1
- package/out/test/examples/pushdrop.test.js +2 -6
- package/out/test/examples/pushdrop.test.js.map +1 -1
- package/out/test/utils/TestUtilsWalletStorage.d.ts +4 -0
- package/out/test/utils/TestUtilsWalletStorage.d.ts.map +1 -1
- package/out/test/utils/TestUtilsWalletStorage.js +5 -1
- package/out/test/utils/TestUtilsWalletStorage.js.map +1 -1
- package/out/test/wallet/sync/Wallet.sync.test.js +24 -7
- package/out/test/wallet/sync/Wallet.sync.test.js.map +1 -1
- package/out/tsconfig.all.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/storage/WalletStorageManager.ts +33 -24
- package/src/storage/schema/entities/SyncState.ts +1 -1
- package/test/Wallet/sync/setActive.test.ts +88 -8
- package/test/examples/pushdrop.test.ts +3 -8
- package/test/utils/TestUtilsWalletStorage.ts +10 -1
- package/test/wallet/sync/Wallet.sync.test.ts +29 -7
package/package.json
CHANGED
|
@@ -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 =
|
|
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 (
|
|
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
|
-
//
|
|
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.
|
|
725
|
-
identityKey,
|
|
726
|
-
|
|
727
|
-
|
|
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
|
-
|
|
742
|
-
if (
|
|
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
|
-
|
|
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 ||
|
|
312
|
+
maxRoughSize: maxRoughSize || 10000000,
|
|
313
313
|
maxItems: maxItems || 1000,
|
|
314
314
|
offsets: [],
|
|
315
315
|
since: this.when,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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.
|
|
32
|
-
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
}
|