@bsv/wallet-toolbox 1.6.32 → 1.6.34
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/CHANGELOG.md +11 -0
- package/docs/client.md +340 -93
- package/docs/monitor.md +34 -12
- package/docs/storage.md +49 -1
- package/docs/wallet.md +340 -93
- package/mobile/out/src/monitor/Monitor.d.ts +8 -0
- package/mobile/out/src/monitor/Monitor.d.ts.map +1 -1
- package/mobile/out/src/monitor/Monitor.js +8 -0
- package/mobile/out/src/monitor/Monitor.js.map +1 -1
- package/mobile/out/src/monitor/tasks/TaskReorg.d.ts +8 -12
- package/mobile/out/src/monitor/tasks/TaskReorg.d.ts.map +1 -1
- package/mobile/out/src/monitor/tasks/TaskReorg.js +20 -73
- package/mobile/out/src/monitor/tasks/TaskReorg.js.map +1 -1
- package/mobile/out/src/sdk/WERR_errors.d.ts +8 -0
- package/mobile/out/src/sdk/WERR_errors.d.ts.map +1 -1
- package/mobile/out/src/sdk/WERR_errors.js +33 -0
- package/mobile/out/src/sdk/WERR_errors.js.map +1 -1
- package/mobile/out/src/sdk/WalletError.d.ts +19 -0
- package/mobile/out/src/sdk/WalletError.d.ts.map +1 -1
- package/mobile/out/src/sdk/WalletError.js +42 -1
- package/mobile/out/src/sdk/WalletError.js.map +1 -1
- package/mobile/out/src/sdk/WalletErrorFromJson.d.ts +12 -0
- package/mobile/out/src/sdk/WalletErrorFromJson.d.ts.map +1 -0
- package/mobile/out/src/sdk/WalletErrorFromJson.js +69 -0
- package/mobile/out/src/sdk/WalletErrorFromJson.js.map +1 -0
- package/mobile/out/src/sdk/WalletStorage.interfaces.d.ts +49 -0
- package/mobile/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
- package/mobile/out/src/sdk/index.d.ts +1 -0
- package/mobile/out/src/sdk/index.d.ts.map +1 -1
- package/mobile/out/src/sdk/index.js +1 -0
- package/mobile/out/src/sdk/index.js.map +1 -1
- package/mobile/out/src/services/chaintracker/ChaintracksChainTracker.js +1 -1
- package/mobile/out/src/services/chaintracker/ChaintracksChainTracker.js.map +1 -1
- package/mobile/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.d.ts.map +1 -1
- package/mobile/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.js +16 -9
- package/mobile/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.js.map +1 -1
- package/mobile/out/src/storage/StorageProvider.d.ts.map +1 -1
- package/mobile/out/src/storage/StorageProvider.js +4 -0
- package/mobile/out/src/storage/StorageProvider.js.map +1 -1
- package/mobile/out/src/storage/WalletStorageManager.d.ts +34 -2
- package/mobile/out/src/storage/WalletStorageManager.d.ts.map +1 -1
- package/mobile/out/src/storage/WalletStorageManager.js +146 -0
- package/mobile/out/src/storage/WalletStorageManager.js.map +1 -1
- package/mobile/out/src/storage/remoting/StorageClient.d.ts.map +1 -1
- package/mobile/out/src/storage/remoting/StorageClient.js +3 -5
- package/mobile/out/src/storage/remoting/StorageClient.js.map +1 -1
- package/mobile/package-lock.json +2 -2
- package/mobile/package.json +1 -1
- package/out/src/monitor/Monitor.d.ts +8 -0
- package/out/src/monitor/Monitor.d.ts.map +1 -1
- package/out/src/monitor/Monitor.js +8 -0
- package/out/src/monitor/Monitor.js.map +1 -1
- package/out/src/monitor/tasks/TaskReorg.d.ts +8 -12
- package/out/src/monitor/tasks/TaskReorg.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskReorg.js +20 -73
- package/out/src/monitor/tasks/TaskReorg.js.map +1 -1
- package/out/src/sdk/WERR_errors.d.ts +8 -0
- package/out/src/sdk/WERR_errors.d.ts.map +1 -1
- package/out/src/sdk/WERR_errors.js +33 -0
- package/out/src/sdk/WERR_errors.js.map +1 -1
- package/out/src/sdk/WalletError.d.ts +19 -0
- package/out/src/sdk/WalletError.d.ts.map +1 -1
- package/out/src/sdk/WalletError.js +42 -1
- package/out/src/sdk/WalletError.js.map +1 -1
- package/out/src/sdk/WalletErrorFromJson.d.ts +12 -0
- package/out/src/sdk/WalletErrorFromJson.d.ts.map +1 -0
- package/out/src/sdk/WalletErrorFromJson.js +69 -0
- package/out/src/sdk/WalletErrorFromJson.js.map +1 -0
- package/out/src/sdk/WalletStorage.interfaces.d.ts +49 -0
- package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
- package/out/src/sdk/__test/WalletError.test.d.ts +2 -0
- package/out/src/sdk/__test/WalletError.test.d.ts.map +1 -0
- package/out/src/sdk/__test/WalletError.test.js +255 -0
- package/out/src/sdk/__test/WalletError.test.js.map +1 -0
- package/out/src/sdk/index.d.ts +1 -0
- package/out/src/sdk/index.d.ts.map +1 -1
- package/out/src/sdk/index.js +1 -0
- package/out/src/sdk/index.js.map +1 -1
- package/out/src/services/__tests/verifyBeef.test.js +7 -0
- package/out/src/services/__tests/verifyBeef.test.js.map +1 -1
- package/out/src/services/chaintracker/ChaintracksChainTracker.js +1 -1
- package/out/src/services/chaintracker/ChaintracksChainTracker.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.js +16 -9
- package/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.js.map +1 -1
- package/out/src/storage/StorageProvider.d.ts.map +1 -1
- package/out/src/storage/StorageProvider.js +4 -0
- package/out/src/storage/StorageProvider.js.map +1 -1
- package/out/src/storage/WalletStorageManager.d.ts +34 -2
- package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
- package/out/src/storage/WalletStorageManager.js +146 -0
- package/out/src/storage/WalletStorageManager.js.map +1 -1
- package/out/src/storage/__test/getBeefForTransaction.test.js +10 -0
- package/out/src/storage/__test/getBeefForTransaction.test.js.map +1 -1
- package/out/src/storage/remoting/StorageClient.d.ts.map +1 -1
- package/out/src/storage/remoting/StorageClient.js +3 -5
- package/out/src/storage/remoting/StorageClient.js.map +1 -1
- package/out/src/storage/remoting/StorageServer.d.ts.map +1 -1
- package/out/src/storage/remoting/StorageServer.js +12 -10
- package/out/src/storage/remoting/StorageServer.js.map +1 -1
- package/out/src/storage/schema/KnexMigrations.d.ts.map +1 -1
- package/out/src/storage/schema/KnexMigrations.js +12 -0
- package/out/src/storage/schema/KnexMigrations.js.map +1 -1
- package/out/test/Wallet/specOps/specOps.man.test.js +8 -6
- package/out/test/Wallet/specOps/specOps.man.test.js.map +1 -1
- package/out/tsconfig.all.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/monitor/Monitor.ts +8 -0
- package/src/monitor/tasks/TaskReorg.ts +20 -70
- package/src/sdk/WERR_errors.ts +34 -0
- package/src/sdk/WalletError.ts +42 -1
- package/src/sdk/WalletErrorFromJson.ts +80 -0
- package/src/sdk/WalletStorage.interfaces.ts +44 -0
- package/src/sdk/__test/WalletError.test.ts +318 -0
- package/src/sdk/index.ts +1 -0
- package/src/services/__tests/verifyBeef.test.ts +10 -1
- package/src/services/chaintracker/ChaintracksChainTracker.ts +1 -1
- package/src/services/chaintracker/chaintracks/util/ChaintracksFetch.ts +18 -11
- package/src/storage/StorageProvider.ts +4 -0
- package/src/storage/WalletStorageManager.ts +158 -0
- package/src/storage/__test/getBeefForTransaction.test.ts +11 -2
- package/src/storage/methods/internalizeAction.ts +1 -1
- package/src/storage/remoting/StorageClient.ts +4 -6
- package/src/storage/remoting/StorageServer.ts +13 -11
- package/src/storage/schema/KnexMigrations.ts +13 -0
- package/test/Wallet/specOps/specOps.man.test.ts +6 -4
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { WalletError } from '../WalletError'
|
|
2
|
+
import { WalletErrorFromJson } from '../WalletErrorFromJson'
|
|
3
|
+
import {
|
|
4
|
+
WERR_NOT_IMPLEMENTED,
|
|
5
|
+
WERR_INTERNAL,
|
|
6
|
+
WERR_INVALID_PARAMETER,
|
|
7
|
+
WERR_REVIEW_ACTIONS,
|
|
8
|
+
WERR_INSUFFICIENT_FUNDS,
|
|
9
|
+
WERR_BROADCAST_UNAVAILABLE,
|
|
10
|
+
WERR_NETWORK_CHAIN,
|
|
11
|
+
WERR_INVALID_OPERATION,
|
|
12
|
+
WERR_MISSING_PARAMETER,
|
|
13
|
+
WERR_BAD_REQUEST,
|
|
14
|
+
WERR_UNAUTHORIZED,
|
|
15
|
+
WERR_NOT_ACTIVE,
|
|
16
|
+
WERR_INVALID_PUBLIC_KEY
|
|
17
|
+
} from '../WERR_errors'
|
|
18
|
+
|
|
19
|
+
// Mock WalletStorage interface
|
|
20
|
+
const mockWalletStorage = {
|
|
21
|
+
createAction: jest.fn().mockImplementation((args: any) => {
|
|
22
|
+
throw new WERR_REVIEW_ACTIONS(
|
|
23
|
+
[{ txid: 'txid123', status: 'doubleSpend', competingTxs: ['txid456'], competingBeef: [0, 1, 2, 3] }],
|
|
24
|
+
[{ txid: 'txid123', status: 'failed' }],
|
|
25
|
+
'txid123',
|
|
26
|
+
[5, 6, 7, 8],
|
|
27
|
+
['00'.repeat(32) + '.0']
|
|
28
|
+
)
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe('WalletError tests', () => {
|
|
33
|
+
jest.setTimeout(99999999)
|
|
34
|
+
|
|
35
|
+
test('0 - WERR_REVIEW_ACTIONS from createAction failure', async () => {
|
|
36
|
+
try {
|
|
37
|
+
await mockWalletStorage.createAction({ someArgs: 'test' })
|
|
38
|
+
} catch (err) {
|
|
39
|
+
const werr = WalletError.fromUnknown(err)
|
|
40
|
+
expect(werr.name).toBe('WERR_REVIEW_ACTIONS')
|
|
41
|
+
expect(werr.message).toBe('Undelayed createAction or signAction results require review.')
|
|
42
|
+
|
|
43
|
+
const json = WalletError.unknownToJson(werr)
|
|
44
|
+
const werr2 = WalletErrorFromJson(JSON.parse(json))
|
|
45
|
+
expect(werr2 instanceof WERR_REVIEW_ACTIONS).toBe(true)
|
|
46
|
+
const werr3 = werr2 as WERR_REVIEW_ACTIONS
|
|
47
|
+
expect(werr3.txid).toBe('txid123')
|
|
48
|
+
expect(werr3.reviewActionResults).toEqual([
|
|
49
|
+
{ txid: 'txid123', status: 'doubleSpend', competingTxs: ['txid456'], competingBeef: [0, 1, 2, 3] }
|
|
50
|
+
])
|
|
51
|
+
expect(werr3.sendWithResults).toEqual([{ txid: 'txid123', status: 'failed' }])
|
|
52
|
+
expect(werr3.noSendChange).toEqual(['00'.repeat(32) + '.0'])
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('1 - WERR_NOT_IMPLEMENTED basic test', async () => {
|
|
57
|
+
const werr = new WERR_NOT_IMPLEMENTED('Custom not implemented message')
|
|
58
|
+
expect(werr.name).toBe('WERR_NOT_IMPLEMENTED')
|
|
59
|
+
expect(werr.message).toBe('Custom not implemented message')
|
|
60
|
+
|
|
61
|
+
const json = WalletError.unknownToJson(werr)
|
|
62
|
+
const werr2 = WalletErrorFromJson(JSON.parse(json))
|
|
63
|
+
expect(werr2.name).toBe('WERR_NOT_IMPLEMENTED')
|
|
64
|
+
expect(werr2.message).toBe('Custom not implemented message')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('2 - WERR_INTERNAL with default message', async () => {
|
|
68
|
+
const werr = new WERR_INTERNAL()
|
|
69
|
+
expect(werr.name).toBe('WERR_INTERNAL')
|
|
70
|
+
expect(werr.message).toBe('An internal error has occurred.')
|
|
71
|
+
|
|
72
|
+
const json = WalletError.unknownToJson(werr)
|
|
73
|
+
const werr2 = WalletErrorFromJson(JSON.parse(json))
|
|
74
|
+
expect(werr2.name).toBe('WERR_INTERNAL')
|
|
75
|
+
expect(werr2.message).toBe('An internal error has occurred.')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('3 - WERR_INVALID_PARAMETER with custom parameter', async () => {
|
|
79
|
+
const werr = new WERR_INVALID_PARAMETER('amount', 'positive')
|
|
80
|
+
expect(werr.name).toBe('WERR_INVALID_PARAMETER')
|
|
81
|
+
expect(werr.message).toBe('The amount parameter must be positive')
|
|
82
|
+
expect(werr.parameter).toBe('amount')
|
|
83
|
+
|
|
84
|
+
const json = werr.toJson()
|
|
85
|
+
const werr2 = WalletErrorFromJson(JSON.parse(json))
|
|
86
|
+
expect(werr2.name).toBe('WERR_INVALID_PARAMETER')
|
|
87
|
+
expect(werr2.message).toBe('The amount parameter must be positive')
|
|
88
|
+
expect((werr2 as WERR_INVALID_PARAMETER).parameter).toBe('amount')
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test('4 - WERR_INSUFFICIENT_FUNDS with numeric values', async () => {
|
|
92
|
+
const werr = new WERR_INSUFFICIENT_FUNDS(1000, 500)
|
|
93
|
+
expect(werr.name).toBe('WERR_INSUFFICIENT_FUNDS')
|
|
94
|
+
expect(werr.message).toContain('500 more satoshis are needed')
|
|
95
|
+
expect(werr.message).toContain('for a total of 1000')
|
|
96
|
+
expect(werr.totalSatoshisNeeded).toBe(1000)
|
|
97
|
+
expect(werr.moreSatoshisNeeded).toBe(500)
|
|
98
|
+
|
|
99
|
+
const json = werr.toJson()
|
|
100
|
+
const werr2 = WalletErrorFromJson(JSON.parse(json))
|
|
101
|
+
expect(werr2.name).toBe('WERR_INSUFFICIENT_FUNDS')
|
|
102
|
+
expect((werr2 as WERR_INSUFFICIENT_FUNDS).totalSatoshisNeeded).toBe(1000)
|
|
103
|
+
expect((werr2 as WERR_INSUFFICIENT_FUNDS).moreSatoshisNeeded).toBe(500)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('5 - WERR_BROADCAST_UNAVAILABLE test', async () => {
|
|
107
|
+
const werr = new WERR_BROADCAST_UNAVAILABLE('Network issue')
|
|
108
|
+
expect(werr.name).toBe('WERR_BROADCAST_UNAVAILABLE')
|
|
109
|
+
expect(werr.message).toBe('Unable to broadcast transaction at this time.')
|
|
110
|
+
|
|
111
|
+
const json = WalletError.unknownToJson(werr)
|
|
112
|
+
const werr2 = WalletErrorFromJson(JSON.parse(json))
|
|
113
|
+
expect(werr2.name).toBe('WERR_BROADCAST_UNAVAILABLE')
|
|
114
|
+
expect(werr2.message).toBe('Unable to broadcast transaction at this time.')
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
test('6 - WERR_NETWORK_CHAIN test', async () => {
|
|
118
|
+
const werr = new WERR_NETWORK_CHAIN('Chain mismatch')
|
|
119
|
+
expect(werr.name).toBe('WERR_NETWORK_CHAIN')
|
|
120
|
+
expect(werr.message).toBe('Chain mismatch')
|
|
121
|
+
|
|
122
|
+
const json = WalletError.unknownToJson(werr)
|
|
123
|
+
const werr2 = WalletErrorFromJson(JSON.parse(json))
|
|
124
|
+
expect(werr2.name).toBe('WERR_NETWORK_CHAIN')
|
|
125
|
+
expect(werr2.message).toBe('Chain mismatch')
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
test('7 - WalletError.fromUnknown with plain Error', async () => {
|
|
129
|
+
const err = new Error('Test error')
|
|
130
|
+
const werr = WalletError.fromUnknown(err)
|
|
131
|
+
expect(werr.name).toBe('WERR_UNKNOWN')
|
|
132
|
+
expect(werr.message).toBe('Test error')
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
test('8 - WalletError.unknownToJson with unknown object', async () => {
|
|
136
|
+
const obj = { custom: 'data', code: 404 }
|
|
137
|
+
const json = WalletError.unknownToJson(obj)
|
|
138
|
+
const werr = WalletErrorFromJson(JSON.parse(json))
|
|
139
|
+
expect(werr.name).toBe('WERR_UNKNOWN')
|
|
140
|
+
expect(werr.message).toBe('[object Object]')
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
test('9 - WERR_INVALID_OPERATION basic test', async () => {
|
|
144
|
+
const werr = new WERR_INVALID_OPERATION('Custom invalid operation message')
|
|
145
|
+
expect(werr.name).toBe('WERR_INVALID_OPERATION')
|
|
146
|
+
expect(werr.message).toBe('Custom invalid operation message')
|
|
147
|
+
|
|
148
|
+
const json = WalletError.unknownToJson(werr)
|
|
149
|
+
const werr2 = WalletErrorFromJson(JSON.parse(json))
|
|
150
|
+
expect(werr2.name).toBe('WERR_INVALID_OPERATION')
|
|
151
|
+
expect(werr2.message).toBe('Custom invalid operation message')
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
test('10 - WERR_MISSING_PARAMETER with parameter', async () => {
|
|
155
|
+
const werr = new WERR_MISSING_PARAMETER('requiredField')
|
|
156
|
+
expect(werr.name).toBe('WERR_MISSING_PARAMETER')
|
|
157
|
+
expect(werr.message).toBe('The required requiredField parameter is missing.')
|
|
158
|
+
expect(werr.parameter).toBe('requiredField')
|
|
159
|
+
|
|
160
|
+
const json = werr.toJson()
|
|
161
|
+
const werr2 = WalletErrorFromJson(JSON.parse(json))
|
|
162
|
+
expect(werr2.name).toBe('WERR_MISSING_PARAMETER')
|
|
163
|
+
expect(werr2.message).toBe('The required requiredField parameter is missing.')
|
|
164
|
+
expect((werr2 as WERR_MISSING_PARAMETER).parameter).toBe('requiredField')
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
test('11 - WERR_BAD_REQUEST with custom message', async () => {
|
|
168
|
+
const werr = new WERR_BAD_REQUEST('Invalid request data')
|
|
169
|
+
expect(werr.name).toBe('WERR_BAD_REQUEST')
|
|
170
|
+
expect(werr.message).toBe('Invalid request data')
|
|
171
|
+
|
|
172
|
+
const json = WalletError.unknownToJson(werr)
|
|
173
|
+
const werr2 = WalletErrorFromJson(JSON.parse(json))
|
|
174
|
+
expect(werr2.name).toBe('WERR_BAD_REQUEST')
|
|
175
|
+
expect(werr2.message).toBe('Invalid request data')
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
test('12 - WERR_UNAUTHORIZED with default message', async () => {
|
|
179
|
+
const werr = new WERR_UNAUTHORIZED()
|
|
180
|
+
expect(werr.name).toBe('WERR_UNAUTHORIZED')
|
|
181
|
+
expect(werr.message).toBe('Access is denied due to an authorization error.')
|
|
182
|
+
|
|
183
|
+
const json = WalletError.unknownToJson(werr)
|
|
184
|
+
const werr2 = WalletErrorFromJson(JSON.parse(json))
|
|
185
|
+
expect(werr2.name).toBe('WERR_UNAUTHORIZED')
|
|
186
|
+
expect(werr2.message).toBe('Access is denied due to an authorization error.')
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
test('13 - WERR_NOT_ACTIVE with default message', async () => {
|
|
190
|
+
const werr = new WERR_NOT_ACTIVE()
|
|
191
|
+
expect(werr.name).toBe('WERR_NOT_ACTIVE')
|
|
192
|
+
expect(werr.message).toBe(
|
|
193
|
+
`WalletStorageManager is not accessing user's active storage or there are conflicting active stores configured.`
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
const json = WalletError.unknownToJson(werr)
|
|
197
|
+
const werr2 = WalletErrorFromJson(JSON.parse(json))
|
|
198
|
+
expect(werr2.name).toBe('WERR_NOT_ACTIVE')
|
|
199
|
+
expect(werr2.message).toBe(
|
|
200
|
+
`WalletStorageManager is not accessing user's active storage or there are conflicting active stores configured.`
|
|
201
|
+
)
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
test('14 - WERR_INVALID_PUBLIC_KEY with key and mainnet network', async () => {
|
|
205
|
+
const werr = new WERR_INVALID_PUBLIC_KEY('invalidkey123', 'mainnet')
|
|
206
|
+
expect(werr.name).toBe('WERR_INVALID_PUBLIC_KEY')
|
|
207
|
+
expect(werr.message).toBe('The provided public key "invalidkey123" is invalid or malformed.')
|
|
208
|
+
expect((werr as WERR_INVALID_PUBLIC_KEY).key).toBe('invalidkey123')
|
|
209
|
+
|
|
210
|
+
const json = WalletError.unknownToJson(werr)
|
|
211
|
+
const parsedJson = JSON.parse(json)
|
|
212
|
+
const werr2 = WalletErrorFromJson(parsedJson)
|
|
213
|
+
expect(werr2.name).toBe('WERR_INVALID_PUBLIC_KEY')
|
|
214
|
+
expect(werr2.message).toBe('The provided public key "invalidkey123" is invalid or malformed.')
|
|
215
|
+
expect((werr2 as WERR_INVALID_PUBLIC_KEY).key).toBe('invalidkey123')
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
test('15 - WERR_INVALID_PUBLIC_KEY with key and testnet network', async () => {
|
|
219
|
+
const werr = new WERR_INVALID_PUBLIC_KEY('invalidkey123', 'testnet')
|
|
220
|
+
expect(werr.name).toBe('WERR_INVALID_PUBLIC_KEY')
|
|
221
|
+
expect(werr.message).toBe('The provided public key is invalid or malformed.')
|
|
222
|
+
expect((werr as WERR_INVALID_PUBLIC_KEY).key).toBe('invalidkey123')
|
|
223
|
+
|
|
224
|
+
const json = WalletError.unknownToJson(werr)
|
|
225
|
+
const parsedJson = JSON.parse(json)
|
|
226
|
+
const werr2 = WalletErrorFromJson(parsedJson)
|
|
227
|
+
expect(werr2.name).toBe('WERR_INVALID_PUBLIC_KEY')
|
|
228
|
+
expect(werr2.message).toBe('The provided public key is invalid or malformed.')
|
|
229
|
+
expect((werr2 as WERR_INVALID_PUBLIC_KEY).key).toBe('invalidkey123')
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
test('16 - WalletError basic constructor with details and stack', async () => {
|
|
233
|
+
const customStack = 'custom stack trace'
|
|
234
|
+
const werr = new WalletError('WERR_TEST', 'Test message', customStack, { detail1: 'value1', detail2: 'value2' })
|
|
235
|
+
expect(werr.isError).toBe(true)
|
|
236
|
+
expect(werr.name).toBe('WERR_TEST')
|
|
237
|
+
expect(werr.message).toBe('Test message')
|
|
238
|
+
expect(werr.stack).toBe(customStack)
|
|
239
|
+
expect(werr.details).toEqual({ detail1: 'value1', detail2: 'value2' })
|
|
240
|
+
expect(werr.code).toBe('WERR_TEST')
|
|
241
|
+
expect(werr.description).toBe('Test message')
|
|
242
|
+
|
|
243
|
+
werr.code = 'WERR_NEW_CODE'
|
|
244
|
+
werr.description = 'New description'
|
|
245
|
+
expect(werr.name).toBe('WERR_NEW_CODE')
|
|
246
|
+
expect(werr.message).toBe('New description')
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
test('17 - WalletError.fromUnknown with string', async () => {
|
|
250
|
+
const werr = WalletError.fromUnknown('String error message')
|
|
251
|
+
expect(werr.name).toBe('WERR_UNKNOWN')
|
|
252
|
+
expect(werr.message).toBe('String error message')
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
test('18 - WalletError.fromUnknown with number', async () => {
|
|
256
|
+
const werr = WalletError.fromUnknown(404)
|
|
257
|
+
expect(werr.name).toBe('WERR_UNKNOWN')
|
|
258
|
+
expect(werr.message).toBe('404')
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
test('19 - WalletError.fromUnknown with custom object', async () => {
|
|
262
|
+
const obj = { code: 'ERR_404', message: 'Not found', status: 404 }
|
|
263
|
+
const werr = WalletError.fromUnknown(obj)
|
|
264
|
+
expect(werr.name).toBe('ERR_404')
|
|
265
|
+
expect(werr.message).toBe('Not found')
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
test('20 - WalletError.fromUnknown with nested walletError', async () => {
|
|
269
|
+
const innerErr = new WERR_INTERNAL('Inner error')
|
|
270
|
+
const outerObj = { message: 'Outer error', walletError: innerErr }
|
|
271
|
+
const werr = WalletError.fromUnknown(outerObj)
|
|
272
|
+
expect(werr.name).toBe('WERR_UNKNOWN')
|
|
273
|
+
expect(werr.message).toBe('Outer error')
|
|
274
|
+
expect((werr as any).walletError).toBeInstanceOf(WERR_INTERNAL)
|
|
275
|
+
expect((werr as any).walletError.message).toBe('Inner error')
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
test('21 - WalletError.fromUnknown with SQL details', async () => {
|
|
279
|
+
const err = { name: 'DBError', message: 'Query failed', sql: 'SELECT * FROM table', sqlMessage: 'Syntax error' }
|
|
280
|
+
const werr = WalletError.fromUnknown(err)
|
|
281
|
+
expect(werr.name).toBe('DBError')
|
|
282
|
+
expect(werr.message).toBe('Query failed')
|
|
283
|
+
expect(werr.details).toEqual({ sql: 'SELECT * FROM table', sqlMessage: 'Syntax error' })
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
test('22 - WalletError.unknownToJson with WalletError', async () => {
|
|
287
|
+
const werr = new WalletError('WERR_TEST', 'Test message')
|
|
288
|
+
const json = WalletError.unknownToJson(werr)
|
|
289
|
+
const parsed = JSON.parse(json)
|
|
290
|
+
expect(parsed.name).toBe('WERR_TEST')
|
|
291
|
+
expect(parsed.message).toBe('Test message')
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
test('23 - WalletError.unknownToJson with standard Error', async () => {
|
|
295
|
+
const err = new Error('Standard error')
|
|
296
|
+
const json = WalletError.unknownToJson(err)
|
|
297
|
+
const werr = WalletErrorFromJson(JSON.parse(json))
|
|
298
|
+
expect(werr.name).toBe('Error')
|
|
299
|
+
expect(werr.message).toBe('Standard error')
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
test('24 - WalletError.unknownToJson with string', async () => {
|
|
303
|
+
const json = WalletError.unknownToJson('String error')
|
|
304
|
+
const werr = WalletErrorFromJson(JSON.parse(json))
|
|
305
|
+
expect(werr.name).toBe('WERR_UNKNOWN')
|
|
306
|
+
expect(werr.message).toBe('String error')
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
test('25 - WalletError asStatus method', async () => {
|
|
310
|
+
const werr = new WalletError('WERR_TEST', 'Test description')
|
|
311
|
+
const status = werr.asStatus()
|
|
312
|
+
expect(status).toEqual({
|
|
313
|
+
status: 'error',
|
|
314
|
+
code: 'WERR_TEST',
|
|
315
|
+
description: 'Test description'
|
|
316
|
+
})
|
|
317
|
+
})
|
|
318
|
+
})
|
package/src/sdk/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Beef } from '@bsv/sdk'
|
|
1
|
+
import { Beef, Utils } from '@bsv/sdk'
|
|
2
2
|
import { Services } from '../Services'
|
|
3
3
|
import { _tu, logger } from '../../../test/utils/TestUtilsWalletStorage'
|
|
4
4
|
import { verifyTruthy } from '../../utility/utilityHelpers'
|
|
@@ -38,4 +38,13 @@ describe('verifyBeef tests', () => {
|
|
|
38
38
|
expect(ok).toBe(true)
|
|
39
39
|
}
|
|
40
40
|
})
|
|
41
|
+
|
|
42
|
+
test.skip('2_ review beef verify root', async () => {
|
|
43
|
+
const bhex =
|
|
44
|
+
'0200beef01fe7c830d000a02a0021d4ca6c031db7f6334c08ddfda43cbde3800c7fa27892f8e80a5218ca8493918a10081788ac8d8267d409b6258a6a6f5d28317ee65b5b25892def4f6cbf44f92571d01510027c2382032711033d0a1e2724b9eefcf257e27bce28e37b7472877860570ee6e0129008e15879954392f322efdd32376077a3323db02501926a697f5db6b68862f67ce01150061dcb195186d564d754a056d9ad90d65ece5bfa5ddccebd24b64d25df3780b15010b00bcd8f2c9c62b4fbbefad9640f9f6dccf21246fa08a6e1cab2c052666dee4182001040018ad6a5739749e27c191a5ef7442d861e5b8d204d36c91e08bf8015811851dbe010300f47047d1c4582eb02349eabcdafc7f4573e93ed687718275475d6f528783d16201000039a5fa5dbbbcd4a1754c250a7879ae1ad2eeb189d87d3614c2a2d9519a7a47af0101001670fc6a8d40adbd3f8a84ae35f0a702695f19f19a8feddcfd1de6249cc164e901010092a689a4cda27aea3552a98a7441ffbaed8566ae31e0a1a67e67647e2f3b8fda05025a8b77e1c82cfcfda197fec3f805a6b7000737a583e45833df6721975fe8bad102448f38860c45d33c87041c0fda51befb1c90853d3141a0df3ac737ccb9b5e61b01000100000001f7ddf439a165bf63a7d6c144b4bd8882ff45dc35a3ca3e75517fa56482fed6bd000000006b4830450221008106bc7164333415bc485ae1d12acd72bbc536f1f03b25aa42d92971565b329902202d484d09935be7fa49bbd5806148dbfdb90cc86516537351acf20655c03fa656412102b53b5339d6241c4271a07e7b09035966defe37c1a3edd60b8a427d5a5b488cb5ffffffff021d00000000000000c421029664d9baa433b4ded47ce151d348fda7ed30df597b93bf5f321ec2fe742b0faaac2131546f446f44744b7265457a6248594b466a6d6f42756475466d53585855475a4734aba7171082ff009628f6d1abea57bc1ffcdb6c2b45a5e17219eaf6bc6b6e093b5243036565505084548f9715a440b6c03e73427d4730450221008e4964dc5e8f3cc6f41da7508cba05babb2ce211fa47fe91ae9c06903d95fde902206cb21d6c188f302fccedbbcd80459561dbabcabe3da16853371fede9f5d027d06d75c8030000000000001976a914f8a84c2bef6eed4eb3270c8605a8063202ed25cb88ac000000000001000000015a8b77e1c82cfcfda197fec3f805a6b7000737a583e45833df6721975fe8bad1010000006b483045022100fb62de36ac2930029b1397931c3f30bf6df5166f2e82bed6b2ef1d23491f8e450220730105461dc12236439ee568709ee72c345bb6748efe8656a0e96e4cc5eaecfb412102c6b33e96f3b635ebd71bcedd9bcb90b4c098b9b38730f58984e23615e0864833ffffffff042800000000000000c521029664d9baa433b4ded47ce151d348fda7ed30df597b93bf5f321ec2fe742b0faaac2131546f446f44744b7265457a6248594b466a6d6f42756475466d53585855475a47361c08d47822cb0806cd17af298948641db6bd36440da9a988af0f6600cba6dabfcfe5c7fe086b7a08e8feef3a9d21d8b0126c2f4a260b46304402204f418ece238fb0587f887c1e0ea6beb4ebcefa6749d1b523195bd65dc9971374022009d0b21c669a72a8a01808d394c55de730a3a4d287b3bb209697b2e79a9787ce6d7516050000000000001976a914803a2e1d2ca2373c21129a7075f1a42587f16c8188acec030000000000001976a91441cb6381a584c464df4b6dd75b91fb0ab6c4b7a688acd0040000000000001976a914e08fbd92ba37c1d84bba8439c55793ea60c0dd6b88ac00000000000100000001448f38860c45d33c87041c0fda51befb1c90853d3141a0df3ac737ccb9b5e61b020000006a4730440220411ab1f23f747899bf71185fbb4ab03defc6e215fb1ee3d24060b14256d2dc40022035669cd13b5c5fd399a402862b4e6bc001d0cbf56660bac37b1563eeaf49a700412103b20f91159733fd69817cc4d4f9ed0cf4340f63b482e0a0a7f233885c61d1b044ffffffff020a00000000000000c421029664d9baa433b4ded47ce151d348fda7ed30df597b93bf5f321ec2fe742b0faaac2131546f446f44744b7265457a6248594b466a6d6f42756475466d53585855475a47343c32fe905bb02e70c0a9779048c921b1e26a2684c498ab44759ac25bcdfafa95309c59d1c3ac12f056ad8d10dabe777d1d57dd934730450221009a64cdc81a0ada12d329463db24260a15ad56bdc3523613c0fae2fb64762d20e022021b942e859749fc23585fdb0395585d6ea52dcf0a310cc989a38ff0483c8717e6d75b7150000000000001976a91468cce1214ccbd14d9dfd813d8490daadaa96b39288ac00000000'
|
|
45
|
+
const beef = Beef.fromString(bhex)
|
|
46
|
+
logger(beef.toLogString())
|
|
47
|
+
logger(Utils.toHex(beef.txs[1].rawTx!))
|
|
48
|
+
logger(beef.bumps[0].computeRoot('e47df21819ed320a78392e62e963ddd77143c3c52ad5255a07ff55ba507df71d'))
|
|
49
|
+
})
|
|
41
50
|
})
|
|
@@ -20,7 +20,7 @@ export class ChaintracksChainTracker implements ChainTracker {
|
|
|
20
20
|
chain ||= 'main'
|
|
21
21
|
this.chaintracks =
|
|
22
22
|
chaintracks ??
|
|
23
|
-
new ChaintracksServiceClient(chain, `https
|
|
23
|
+
new ChaintracksServiceClient(chain, `https://${chain}net-chaintracks.babbage.systems`)
|
|
24
24
|
this.cache = {}
|
|
25
25
|
this.options = options || {}
|
|
26
26
|
}
|
|
@@ -12,20 +12,27 @@ export class ChaintracksFetch implements ChaintracksFetchApi {
|
|
|
12
12
|
constructor() {}
|
|
13
13
|
|
|
14
14
|
async download(url: string): Promise<Uint8Array> {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
for (let retry = 0; ; retry++) {
|
|
16
|
+
const response = await fetch(url, {
|
|
17
|
+
method: 'GET',
|
|
18
|
+
headers: {
|
|
19
|
+
'Content-Type': 'application/octet-stream'
|
|
20
|
+
}
|
|
21
|
+
})
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
if (response.statusText === 'Too Many Requests' && retry < 3) {
|
|
25
|
+
// WhatsOnChain rate limits requests, so backoff and retry
|
|
26
|
+
await wait(1000 * (retry + 1))
|
|
27
|
+
continue
|
|
28
|
+
}
|
|
29
|
+
throw new Error(`Failed to download from ${url}: ${response.statusText}`)
|
|
30
|
+
}
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
const data = await response.arrayBuffer()
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
return new Uint8Array(data)
|
|
35
|
+
}
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
async fetchJson<R>(url: string): Promise<R> {
|
|
@@ -230,7 +230,11 @@ export abstract class StorageProvider extends StorageReaderWriter implements Wal
|
|
|
230
230
|
for (const txid of txids) {
|
|
231
231
|
const d: GetReqsAndBeefDetail = {
|
|
232
232
|
txid,
|
|
233
|
+
// status: 'readyToSend' | 'alreadySent' | 'error' | 'unknown'
|
|
233
234
|
status: 'unknown'
|
|
235
|
+
// req?: TableProvenTxReq
|
|
236
|
+
// proven?: TableProvenTx
|
|
237
|
+
// error?: string
|
|
234
238
|
}
|
|
235
239
|
r.details.push(d)
|
|
236
240
|
try {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AbortActionArgs,
|
|
3
3
|
AbortActionResult,
|
|
4
|
+
Beef,
|
|
4
5
|
InternalizeActionArgs,
|
|
5
6
|
InternalizeActionResult,
|
|
6
7
|
ListActionsResult,
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
TableCertificateX,
|
|
17
18
|
TableOutput,
|
|
18
19
|
TableOutputBasket,
|
|
20
|
+
TableProvenTx,
|
|
19
21
|
TableProvenTxReq,
|
|
20
22
|
TableSettings,
|
|
21
23
|
TableUser
|
|
@@ -519,6 +521,162 @@ export class WalletStorageManager implements sdk.WalletStorage {
|
|
|
519
521
|
})
|
|
520
522
|
}
|
|
521
523
|
|
|
524
|
+
/**
|
|
525
|
+
* For each proven_txs record currently sourcing its transaction merkle proof from the given deactivated header,
|
|
526
|
+
* attempt to reprove the transaction against the current chain,
|
|
527
|
+
* updating the proven_txs record if a new valid proof is found.
|
|
528
|
+
*
|
|
529
|
+
* @param deactivatedHash An orphaned header than may have served as a proof source for proven_txs records.
|
|
530
|
+
* @returns
|
|
531
|
+
*/
|
|
532
|
+
async reproveHeader(deactivatedHash: string): Promise<sdk.ReproveHeaderResult> {
|
|
533
|
+
const r: sdk.ReproveHeaderResult = { log: '', updated: [], unchanged: [], unavailable: [] }
|
|
534
|
+
const services = this.getServices()
|
|
535
|
+
const chaintracker = await services.getChainTracker()
|
|
536
|
+
|
|
537
|
+
// Lookup all the proven_txs records matching the deactivated headers
|
|
538
|
+
let ptxs: TableProvenTx[] = []
|
|
539
|
+
await this.runAsStorageProvider(async sp => {
|
|
540
|
+
ptxs = await sp.findProvenTxs({ partial: { blockHash: deactivatedHash } })
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
r.log += ` block ${deactivatedHash} orphaned with ${ptxs.length} impacted transactions\n`
|
|
544
|
+
|
|
545
|
+
for (const ptx of ptxs) {
|
|
546
|
+
// Loop over proven_txs records matching the deactivated header
|
|
547
|
+
const rp = await this.reproveProven(ptx, true)
|
|
548
|
+
|
|
549
|
+
r.log += rp.log
|
|
550
|
+
if (rp.unavailable) r.unavailable.push(ptx)
|
|
551
|
+
if (rp.unchanged) r.unchanged.push(ptx)
|
|
552
|
+
if (rp.updated) r.updated.push({ was: ptx, update: rp.updated.update, logUpdate: rp.updated.logUpdate })
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if (r.updated.length > 0) {
|
|
556
|
+
await this.runAsStorageProvider(async sp => {
|
|
557
|
+
for (const u of r.updated) {
|
|
558
|
+
await sp.updateProvenTx(u.was.provenTxId, u.update)
|
|
559
|
+
r.log += ` txid ${u.was.txid} proof data updated\n` + u.logUpdate
|
|
560
|
+
}
|
|
561
|
+
})
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
return r
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Extends the Beef `verify` function to handle BUMPs that have become invalid due to a chain reorg.
|
|
569
|
+
*
|
|
570
|
+
* Any merkle root that fails `isValidRootForHeight` triggers a reprove attempt for that block header.
|
|
571
|
+
* This results in proven_txs with invalid proofs being updated with new valid proofs where possible.
|
|
572
|
+
* Finally, a new beef is generated and verified against the chaintracker.
|
|
573
|
+
*
|
|
574
|
+
* @param beef
|
|
575
|
+
* @param allowTxidOnly
|
|
576
|
+
* @returns
|
|
577
|
+
*/
|
|
578
|
+
async verifyAndRepairBeef(beef: Beef, allowTxidOnly?: boolean): Promise<boolean> {
|
|
579
|
+
throw new sdk.WERR_NOT_IMPLEMENTED()
|
|
580
|
+
|
|
581
|
+
const services = this.getServices()
|
|
582
|
+
const chaintracker = await services.getChainTracker()
|
|
583
|
+
const verified = await beef.verify(chaintracker)
|
|
584
|
+
|
|
585
|
+
const r = beef.verifyValid(allowTxidOnly)
|
|
586
|
+
if (!r.valid) return false
|
|
587
|
+
|
|
588
|
+
const invalidRoots: Record<number, string> = {}
|
|
589
|
+
for (const height of Object.keys(r.roots)) {
|
|
590
|
+
const isValid = await chaintracker.isValidRootForHeight(r.roots[height], Number(height))
|
|
591
|
+
if (!isValid) {
|
|
592
|
+
invalidRoots[height] = r.roots[height]
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
if (Object.keys(invalidRoots).length === 0) {
|
|
597
|
+
// There are no invalid merkle roots and the beef is structurally valid,
|
|
598
|
+
// the beef is fully verified.
|
|
599
|
+
return true
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
for (const heightStr of Object.keys(invalidRoots)) {
|
|
603
|
+
const hash = invalidRoots[Number(heightStr)]
|
|
604
|
+
const r = await this.reproveHeader(hash)
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// All invalid BUMPs must be removed from the beef
|
|
608
|
+
// and all txid's that were proven by those BUMPs need
|
|
609
|
+
// new beefs merged into the beef.
|
|
610
|
+
// In most cases, this will be a replacement BUMP,
|
|
611
|
+
// but it may also require a deeper proof.
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Attempt to reprove the transaction against the current chain,
|
|
616
|
+
* If a new valid proof is found and noUpdate is not true,
|
|
617
|
+
* update the proven_txs record with new block and merkle proof data.
|
|
618
|
+
* If noUpdate is true, the update to be applied is available in the returned result.
|
|
619
|
+
*
|
|
620
|
+
* @param ptx proven_txs record to reprove
|
|
621
|
+
* @param noUpdate
|
|
622
|
+
* @returns
|
|
623
|
+
*/
|
|
624
|
+
async reproveProven(ptx: TableProvenTx, noUpdate?: boolean): Promise<sdk.ReproveProvenResult> {
|
|
625
|
+
const r: sdk.ReproveProvenResult = { log: '', updated: undefined, unchanged: false, unavailable: false }
|
|
626
|
+
const services = this.getServices()
|
|
627
|
+
const chaintracker = await services.getChainTracker()
|
|
628
|
+
|
|
629
|
+
const mpr = await services.getMerklePath(ptx.txid)
|
|
630
|
+
if (mpr.merklePath && mpr.header) {
|
|
631
|
+
const mp = mpr.merklePath
|
|
632
|
+
const h = mpr.header
|
|
633
|
+
const leaf = mp.path[0].find(leaf => leaf.txid === true && leaf.hash === ptx.txid)
|
|
634
|
+
if (leaf) {
|
|
635
|
+
const update: Partial<TableProvenTx> = {
|
|
636
|
+
height: mp.blockHeight,
|
|
637
|
+
index: leaf.offset,
|
|
638
|
+
merklePath: mp.toBinary(),
|
|
639
|
+
merkleRoot: h.merkleRoot,
|
|
640
|
+
blockHash: h.hash
|
|
641
|
+
}
|
|
642
|
+
if (update.blockHash === ptx.blockHash) {
|
|
643
|
+
r.log += ` txid ${ptx.txid} merkle path update still based on deactivated header ${ptx.blockHash}\n`
|
|
644
|
+
r.unchanged = true
|
|
645
|
+
} else {
|
|
646
|
+
// Verify the new proof's validity.
|
|
647
|
+
const merkleRoot = mp.computeRoot(ptx.txid)
|
|
648
|
+
const isValid = await chaintracker.isValidRootForHeight(merkleRoot, update.height!)
|
|
649
|
+
const logUpdate = ` height ${ptx.height} ${ptx.height === update.height ? 'unchanged' : `-> ${update.height}`}\n`
|
|
650
|
+
r.log += ` blockHash ${ptx.blockHash} -> ${update.blockHash}\n`
|
|
651
|
+
r.log += ` merkleRoot ${ptx.merkleRoot} -> ${update.merkleRoot}\n`
|
|
652
|
+
r.log += ` index ${ptx.index} -> ${update.index}\n`
|
|
653
|
+
if (isValid) {
|
|
654
|
+
r.updated = { update, logUpdate }
|
|
655
|
+
} else {
|
|
656
|
+
r.log +=
|
|
657
|
+
` txid ${ptx.txid} chaintracker fails to confirm updated merkle path update invalid\n` + logUpdate
|
|
658
|
+
r.unavailable = true
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
} else {
|
|
662
|
+
r.log += ` txid ${ptx.txid} merkle path update doesn't include txid\n`
|
|
663
|
+
r.unavailable = true
|
|
664
|
+
}
|
|
665
|
+
} else {
|
|
666
|
+
r.log += ` txid ${ptx.txid} merkle path update unavailable\n`
|
|
667
|
+
r.unavailable = true
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
if (r.updated && !noUpdate) {
|
|
671
|
+
await this.runAsStorageProvider(async sp => {
|
|
672
|
+
await sp.updateProvenTx(ptx.provenTxId, r.updated!.update)
|
|
673
|
+
r.log += ` txid ${ptx.txid} proof data updated\n` + r.updated!.logUpdate
|
|
674
|
+
})
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
return r
|
|
678
|
+
}
|
|
679
|
+
|
|
522
680
|
async syncFromReader(
|
|
523
681
|
identityKey: string,
|
|
524
682
|
reader: sdk.WalletStorageSyncReader,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { Beef, ListActionsResult, ListOutputsResult } from '@bsv/sdk'
|
|
2
|
-
import { WalletError } from '../../sdk/WalletError'
|
|
1
|
+
import { Beef, ListActionsResult, ListOutputsResult, Utils } from '@bsv/sdk'
|
|
3
2
|
import { StorageAdminStats, StorageProvider } from '../StorageProvider'
|
|
4
3
|
import { Chain } from '../../sdk/types'
|
|
5
4
|
import { Services } from '../../services/Services'
|
|
@@ -60,6 +59,16 @@ describe('getBeefForTransaction tests', () => {
|
|
|
60
59
|
expect(beef.bumps.length > 0)
|
|
61
60
|
}
|
|
62
61
|
})
|
|
62
|
+
|
|
63
|
+
test.skip('1 obtain atomic beef hex for txid', async () => {
|
|
64
|
+
const ps = new ProtoStorage('main')
|
|
65
|
+
const txid = '4cefbe79926d6ef2cc727d8faccac186d9bb141f170411dd75bc6329f428f5a4'
|
|
66
|
+
const beef = await ps.getBeefForTxid(txid)
|
|
67
|
+
expect(beef.bumps.length > 0)
|
|
68
|
+
console.log(beef.toLogString())
|
|
69
|
+
const hex = Utils.toHex(beef.toBinaryAtomic(txid))
|
|
70
|
+
console.log(hex)
|
|
71
|
+
})
|
|
63
72
|
})
|
|
64
73
|
|
|
65
74
|
class ProtoStorage extends StorageProvider {
|
|
@@ -18,7 +18,7 @@ import { randomBytesBase64, verifyId, verifyOne, verifyOneOrNone } from '../../u
|
|
|
18
18
|
import { TransactionStatus } from '../../sdk/types'
|
|
19
19
|
import { EntityProvenTxReq } from '../schema/entities/EntityProvenTxReq'
|
|
20
20
|
import { blockHash } from '../../services/chaintracker/chaintracks/util/blockHeaderUtilities'
|
|
21
|
-
import { TableProvenTx } from '../
|
|
21
|
+
import { TableProvenTx } from '../schema/tables/TableProvenTx'
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Internalize Action allows a wallet to take ownership of outputs in a pre-existing transaction.
|
|
@@ -44,6 +44,8 @@ import { TableOutputBasket } from '../schema/tables/TableOutputBasket'
|
|
|
44
44
|
import { TableOutput } from '../schema/tables/TableOutput'
|
|
45
45
|
import { TableProvenTxReq } from '../schema/tables/TableProvenTxReq'
|
|
46
46
|
import { EntityTimeStamp } from '../../sdk/types'
|
|
47
|
+
import { WalletError } from '../../sdk/WalletError'
|
|
48
|
+
import { WalletErrorFromJson } from '../../sdk/WalletErrorFromJson'
|
|
47
49
|
|
|
48
50
|
/**
|
|
49
51
|
* `StorageClient` implements the `WalletStorageProvider` interface which allows it to
|
|
@@ -118,12 +120,8 @@ export class StorageClient implements WalletStorageProvider {
|
|
|
118
120
|
|
|
119
121
|
const json = await response.json()
|
|
120
122
|
if (json.error) {
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
// You could attach more info here if you like:
|
|
124
|
-
;(err as any).code = code
|
|
125
|
-
;(err as any).data = data
|
|
126
|
-
throw err
|
|
123
|
+
const werr = WalletErrorFromJson(json.error)
|
|
124
|
+
throw werr
|
|
127
125
|
}
|
|
128
126
|
|
|
129
127
|
return json.result
|