@bsv/wallet-toolbox 1.3.24 → 1.3.25
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/mobile/out/src/monitor/Monitor.d.ts.map +1 -1
- package/mobile/out/src/monitor/Monitor.js +4 -0
- package/mobile/out/src/monitor/Monitor.js.map +1 -1
- package/mobile/out/src/monitor/tasks/TaskServiceCallHistory.d.ts +12 -0
- package/mobile/out/src/monitor/tasks/TaskServiceCallHistory.d.ts.map +1 -0
- package/mobile/out/src/monitor/tasks/TaskServiceCallHistory.js +23 -0
- package/mobile/out/src/monitor/tasks/TaskServiceCallHistory.js.map +1 -0
- package/mobile/out/src/sdk/WalletServices.interfaces.d.ts +2 -0
- package/mobile/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
- package/mobile/out/src/sdk/WalletStorage.interfaces.d.ts +5 -0
- package/mobile/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
- package/mobile/out/src/services/ServiceCollection.d.ts +38 -0
- package/mobile/out/src/services/ServiceCollection.d.ts.map +1 -1
- package/mobile/out/src/services/ServiceCollection.js +85 -0
- package/mobile/out/src/services/ServiceCollection.js.map +1 -1
- package/mobile/out/src/services/Services.d.ts +11 -2
- package/mobile/out/src/services/Services.d.ts.map +1 -1
- package/mobile/out/src/services/Services.js +159 -68
- package/mobile/out/src/services/Services.js.map +1 -1
- package/mobile/out/src/services/createDefaultWalletServicesOptions.d.ts +1 -0
- package/mobile/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
- package/mobile/out/src/services/createDefaultWalletServicesOptions.js +15 -1
- package/mobile/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
- package/mobile/out/src/services/providers/ARC.d.ts +3 -2
- package/mobile/out/src/services/providers/ARC.d.ts.map +1 -1
- package/mobile/out/src/services/providers/ARC.js +5 -4
- package/mobile/out/src/services/providers/ARC.js.map +1 -1
- package/mobile/out/src/signer/methods/internalizeAction.d.ts.map +1 -1
- package/mobile/out/src/signer/methods/internalizeAction.js +3 -13
- package/mobile/out/src/signer/methods/internalizeAction.js.map +1 -1
- package/mobile/out/src/storage/StorageProvider.js +1 -1
- package/mobile/out/src/storage/StorageProvider.js.map +1 -1
- package/mobile/out/src/storage/methods/createAction.d.ts.map +1 -1
- package/mobile/out/src/storage/methods/createAction.js +5 -1
- package/mobile/out/src/storage/methods/createAction.js.map +1 -1
- package/mobile/out/src/storage/methods/internalizeAction.js +2 -1
- package/mobile/out/src/storage/methods/internalizeAction.js.map +1 -1
- package/mobile/package-lock.json +7 -6
- package/mobile/package.json +2 -2
- package/out/src/monitor/Monitor.d.ts.map +1 -1
- package/out/src/monitor/Monitor.js +4 -0
- package/out/src/monitor/Monitor.js.map +1 -1
- package/out/src/monitor/tasks/TaskServiceCallHistory.d.ts +12 -0
- package/out/src/monitor/tasks/TaskServiceCallHistory.d.ts.map +1 -0
- package/out/src/monitor/tasks/TaskServiceCallHistory.js +23 -0
- package/out/src/monitor/tasks/TaskServiceCallHistory.js.map +1 -0
- package/out/src/sdk/WalletServices.interfaces.d.ts +2 -0
- package/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
- package/out/src/sdk/WalletStorage.interfaces.d.ts +5 -0
- package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
- package/out/src/services/ServiceCollection.d.ts +38 -0
- package/out/src/services/ServiceCollection.d.ts.map +1 -1
- package/out/src/services/ServiceCollection.js +85 -0
- package/out/src/services/ServiceCollection.js.map +1 -1
- package/out/src/services/Services.d.ts +11 -2
- package/out/src/services/Services.d.ts.map +1 -1
- package/out/src/services/Services.js +159 -68
- package/out/src/services/Services.js.map +1 -1
- package/out/src/services/__tests/ArcGorillaPool.man.test.d.ts +2 -0
- package/out/src/services/__tests/ArcGorillaPool.man.test.d.ts.map +1 -0
- package/out/src/services/__tests/ArcGorillaPool.man.test.js +93 -0
- package/out/src/services/__tests/ArcGorillaPool.man.test.js.map +1 -0
- package/out/src/services/createDefaultWalletServicesOptions.d.ts +1 -0
- package/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
- package/out/src/services/createDefaultWalletServicesOptions.js +15 -1
- package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
- package/out/src/services/providers/ARC.d.ts +3 -2
- package/out/src/services/providers/ARC.d.ts.map +1 -1
- package/out/src/services/providers/ARC.js +5 -4
- package/out/src/services/providers/ARC.js.map +1 -1
- package/out/src/signer/methods/internalizeAction.d.ts.map +1 -1
- package/out/src/signer/methods/internalizeAction.js +3 -13
- package/out/src/signer/methods/internalizeAction.js.map +1 -1
- package/out/src/storage/StorageKnex.d.ts.map +1 -1
- package/out/src/storage/StorageKnex.js +50 -2
- package/out/src/storage/StorageKnex.js.map +1 -1
- package/out/src/storage/StorageProvider.js +1 -1
- package/out/src/storage/StorageProvider.js.map +1 -1
- package/out/src/storage/methods/createAction.d.ts.map +1 -1
- package/out/src/storage/methods/createAction.js +5 -1
- package/out/src/storage/methods/createAction.js.map +1 -1
- package/out/src/storage/methods/internalizeAction.js +2 -1
- package/out/src/storage/methods/internalizeAction.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/local/localWallet.man.test.js +12 -16
- package/out/test/Wallet/local/localWallet.man.test.js.map +1 -1
- package/out/test/Wallet/support/operations.man.test.js +96 -6
- package/out/test/Wallet/support/operations.man.test.js.map +1 -1
- package/out/test/storage/KnexMigrations.test.js +1 -1
- package/out/test/storage/KnexMigrations.test.js.map +1 -1
- package/out/tsconfig.all.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/monitor/Monitor.ts +4 -0
- package/src/monitor/tasks/TaskServiceCallHistory.ts +26 -0
- package/src/sdk/WalletServices.interfaces.ts +2 -0
- package/src/sdk/WalletStorage.interfaces.ts +5 -0
- package/src/services/ServiceCollection.ts +121 -0
- package/src/services/Services.ts +157 -71
- package/src/services/__tests/ArcGorillaPool.man.test.ts +108 -0
- package/src/services/createDefaultWalletServicesOptions.ts +16 -1
- package/src/services/providers/ARC.ts +8 -6
- package/src/signer/methods/internalizeAction.ts +4 -14
- package/src/storage/StorageKnex.ts +25 -1
- package/src/storage/StorageProvider.ts +1 -1
- package/src/storage/methods/createAction.ts +5 -3
- package/src/storage/methods/internalizeAction.ts +2 -1
- package/src/storage/schema/KnexMigrations.ts +13 -0
- package/test/Wallet/local/localWallet.man.test.ts +13 -16
- package/test/Wallet/support/operations.man.test.ts +107 -7
- package/test/storage/KnexMigrations.test.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bsv/wallet-toolbox",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.25",
|
|
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",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@bsv/auth-express-middleware": "^1.1.2",
|
|
34
34
|
"@bsv/payment-express-middleware": "^1.0.6",
|
|
35
|
-
"@bsv/sdk": "^1.
|
|
35
|
+
"@bsv/sdk": "^1.5.1",
|
|
36
36
|
"express": "^4.21.2",
|
|
37
37
|
"idb": "^8.0.2",
|
|
38
38
|
"knex": "^3.1.0",
|
package/src/monitor/Monitor.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { TaskFailAbandoned } from './tasks/TaskFailAbandoned'
|
|
|
13
13
|
import { TaskCheckForProofs } from './tasks/TaskCheckForProofs'
|
|
14
14
|
import { TaskClock } from './tasks/TaskClock'
|
|
15
15
|
import { TaskNewHeader } from './tasks/TaskNewHeader'
|
|
16
|
+
import { TaskServiceCallHistory } from './tasks/TaskServiceCallHistory'
|
|
16
17
|
|
|
17
18
|
import { TaskSendWaiting } from './tasks/TaskSendWaiting'
|
|
18
19
|
import { TaskCheckNoSends } from './tasks/TaskCheckNoSends'
|
|
@@ -110,6 +111,7 @@ export class Monitor {
|
|
|
110
111
|
addAllTasksToOther(): void {
|
|
111
112
|
this._otherTasks.push(new TaskClock(this))
|
|
112
113
|
this._otherTasks.push(new TaskNewHeader(this))
|
|
114
|
+
this._otherTasks.push(new TaskServiceCallHistory(this))
|
|
113
115
|
this._otherTasks.push(new TaskPurge(this, this.defaultPurgeParams))
|
|
114
116
|
this._otherTasks.push(new TaskReviewStatus(this))
|
|
115
117
|
this._otherTasks.push(new TaskSendWaiting(this))
|
|
@@ -128,6 +130,7 @@ export class Monitor {
|
|
|
128
130
|
addDefaultTasks(): void {
|
|
129
131
|
this._tasks.push(new TaskClock(this))
|
|
130
132
|
this._tasks.push(new TaskNewHeader(this))
|
|
133
|
+
this._tasks.push(new TaskServiceCallHistory(this))
|
|
131
134
|
this._tasks.push(new TaskSendWaiting(this, 8 * this.oneSecond, 7 * this.oneSecond)) // Check every 8 seconds but must be 7 seconds old
|
|
132
135
|
this._tasks.push(new TaskCheckForProofs(this, 2 * this.oneHour)) // Every two hours if no block found
|
|
133
136
|
this._tasks.push(new TaskCheckNoSends(this))
|
|
@@ -144,6 +147,7 @@ export class Monitor {
|
|
|
144
147
|
addMultiUserTasks(): void {
|
|
145
148
|
this._tasks.push(new TaskClock(this))
|
|
146
149
|
this._tasks.push(new TaskNewHeader(this))
|
|
150
|
+
this._tasks.push(new TaskServiceCallHistory(this))
|
|
147
151
|
this._tasks.push(new TaskSendWaiting(this, 8 * this.oneSecond, 7 * this.oneSecond)) // Check every 8 seconds but must be 7 seconds old
|
|
148
152
|
this._tasks.push(new TaskCheckForProofs(this, 2 * this.oneHour)) // Every two hours if no block found
|
|
149
153
|
this._tasks.push(new TaskCheckNoSends(this))
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { TableMonitorEvent } from '../../storage/index.client'
|
|
2
|
+
import { Monitor } from '../Monitor'
|
|
3
|
+
import { WalletMonitorTask } from './WalletMonitorTask'
|
|
4
|
+
|
|
5
|
+
export class TaskServiceCallHistory extends WalletMonitorTask {
|
|
6
|
+
static taskName = 'ServiceCallHistory'
|
|
7
|
+
|
|
8
|
+
constructor(
|
|
9
|
+
monitor: Monitor,
|
|
10
|
+
public triggerMsecs = monitor.oneMinute * 12
|
|
11
|
+
) {
|
|
12
|
+
super(monitor, TaskServiceCallHistory.taskName)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
trigger(nowMsecsSinceEpoch: number): { run: boolean } {
|
|
16
|
+
return {
|
|
17
|
+
run: nowMsecsSinceEpoch > this.lastRunMsecsSinceEpoch + this.triggerMsecs
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async runTask(): Promise<string> {
|
|
22
|
+
const r = await this.monitor.services.getServicesCallHistory(true)
|
|
23
|
+
const log = JSON.stringify(r)
|
|
24
|
+
return log
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -200,6 +200,8 @@ export interface WalletServicesOptions {
|
|
|
200
200
|
chaintracks?: ChaintracksServiceClient
|
|
201
201
|
arcUrl: string
|
|
202
202
|
arcConfig: ArcConfig
|
|
203
|
+
arcGorillaPoolUrl?: string
|
|
204
|
+
arcGorillaPoolConfig?: ArcConfig
|
|
203
205
|
}
|
|
204
206
|
|
|
205
207
|
export interface GetStatusForTxidsResult {
|
|
@@ -189,6 +189,11 @@ export interface FindSincePagedArgs {
|
|
|
189
189
|
since?: Date
|
|
190
190
|
paged?: Paged
|
|
191
191
|
trx?: TrxToken
|
|
192
|
+
/**
|
|
193
|
+
* Support for orderDescending is implemented in StorageKnex for basic table find methods,
|
|
194
|
+
* excluding certificate_fields table, map tables, and settings (singleton row table).
|
|
195
|
+
*/
|
|
196
|
+
orderDescending?: boolean
|
|
192
197
|
}
|
|
193
198
|
|
|
194
199
|
export interface FindForUserSincePagedArgs extends FindSincePagedArgs {
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
import { WalletError } from "../sdk/WalletError";
|
|
2
|
+
|
|
1
3
|
export class ServiceCollection<T> {
|
|
4
|
+
since: Date
|
|
2
5
|
services: { name: string; service: T }[]
|
|
3
6
|
_index: number
|
|
4
7
|
|
|
8
|
+
_callHistory: Record<string, ServiceCallHistory> = {}
|
|
9
|
+
|
|
5
10
|
constructor(services?: { name: string; service: T }[]) {
|
|
6
11
|
this.services = services || []
|
|
7
12
|
this._index = 0
|
|
13
|
+
this.since = new Date()
|
|
8
14
|
}
|
|
9
15
|
|
|
10
16
|
add(s: { name: string; service: T }): ServiceCollection<T> {
|
|
@@ -24,6 +30,23 @@ export class ServiceCollection<T> {
|
|
|
24
30
|
return this.services[this._index].service
|
|
25
31
|
}
|
|
26
32
|
|
|
33
|
+
get serviceToCall(): ServiceToCall<T> {
|
|
34
|
+
const i = this._index
|
|
35
|
+
const name = this.services[i].name
|
|
36
|
+
const service = this.services[i].service
|
|
37
|
+
const call = { name, when: new Date(), durationMsecs: 0, success: false, result: undefined, error: undefined }
|
|
38
|
+
return { name, service, call }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get allServicesToCall(): ServiceToCall<T>[] {
|
|
42
|
+
const all: ServiceToCall<T>[] = []
|
|
43
|
+
for (let i = 0; i < this.services.length; i++) {
|
|
44
|
+
all.push(this.serviceToCall)
|
|
45
|
+
this.next()
|
|
46
|
+
}
|
|
47
|
+
return all
|
|
48
|
+
}
|
|
49
|
+
|
|
27
50
|
get allServices() {
|
|
28
51
|
return this.services.map(x => x.service)
|
|
29
52
|
}
|
|
@@ -47,4 +70,102 @@ export class ServiceCollection<T> {
|
|
|
47
70
|
clone(): ServiceCollection<T> {
|
|
48
71
|
return new ServiceCollection([...this.services])
|
|
49
72
|
}
|
|
73
|
+
|
|
74
|
+
_addServiceCall(name: string, call: ServiceCall): ServiceCallHistory {
|
|
75
|
+
let h = this._callHistory[name]
|
|
76
|
+
if (!h) {
|
|
77
|
+
h = { name, calls: [], count: 0, countError: 0, countFailure: 0, countSuccess: 0, since: this.since }
|
|
78
|
+
this._callHistory[name] = h
|
|
79
|
+
}
|
|
80
|
+
h.calls.push(call)
|
|
81
|
+
h.count++
|
|
82
|
+
h.calls = h.calls.slice(-32)
|
|
83
|
+
return h
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
addServiceCallSuccess(stc: ServiceToCall<T>, result?: string): void {
|
|
87
|
+
const call = stc.call
|
|
88
|
+
call.success = true
|
|
89
|
+
call.result = result
|
|
90
|
+
call.error = undefined
|
|
91
|
+
call.durationMsecs = new Date().getTime() - call.when.getTime()
|
|
92
|
+
this._addServiceCall(this.name, call).countSuccess++
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
addServiceCallFailure(stc: ServiceToCall<T>, result?: string): void {
|
|
96
|
+
const call = stc.call
|
|
97
|
+
call.success = false
|
|
98
|
+
call.result = result
|
|
99
|
+
call.error = undefined
|
|
100
|
+
call.durationMsecs = new Date().getTime() - call.when.getTime()
|
|
101
|
+
this._addServiceCall(this.name, call).countFailure++
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
addServiceCallError(stc: ServiceToCall<T>, error: WalletError): void {
|
|
105
|
+
const call = stc.call
|
|
106
|
+
call.success = false
|
|
107
|
+
call.result = undefined
|
|
108
|
+
call.error = error
|
|
109
|
+
call.durationMsecs = new Date().getTime() - call.when.getTime()
|
|
110
|
+
this._addServiceCall(this.name, call).countError++
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @returns A copy of current service call history
|
|
115
|
+
*/
|
|
116
|
+
getServiceCallHistory(reset?: boolean): Record<string, ServiceCallHistory> {
|
|
117
|
+
const histories: Record<string, ServiceCallHistory> = {}
|
|
118
|
+
for (const name of Object.keys(this._callHistory)) {
|
|
119
|
+
const h = this._callHistory[name]
|
|
120
|
+
histories[name] = {
|
|
121
|
+
name: h.name,
|
|
122
|
+
count: h.count,
|
|
123
|
+
countError: h.countError,
|
|
124
|
+
countFailure: h.countFailure,
|
|
125
|
+
countSuccess: h.countSuccess,
|
|
126
|
+
since: h.since,
|
|
127
|
+
calls: h.calls.map(c => ({
|
|
128
|
+
name: c.name,
|
|
129
|
+
when: c.when,
|
|
130
|
+
durationMsecs: c.durationMsecs,
|
|
131
|
+
success: c.success,
|
|
132
|
+
result: c.result,
|
|
133
|
+
error: c.error ? { message: c.error.message, code: c.error.code } : undefined
|
|
134
|
+
}))
|
|
135
|
+
}
|
|
136
|
+
if (reset) {
|
|
137
|
+
h.count = 0
|
|
138
|
+
h.countError = 0
|
|
139
|
+
h.countFailure = 0
|
|
140
|
+
h.countSuccess = 0
|
|
141
|
+
h.since = new Date()
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return histories
|
|
145
|
+
}
|
|
50
146
|
}
|
|
147
|
+
|
|
148
|
+
export interface ServiceCall {
|
|
149
|
+
name: string
|
|
150
|
+
when: Date
|
|
151
|
+
durationMsecs: number
|
|
152
|
+
success: boolean
|
|
153
|
+
result?: string
|
|
154
|
+
error?: { message: string, code: string }
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface ServiceCallHistory {
|
|
158
|
+
name: string
|
|
159
|
+
calls: ServiceCall[]
|
|
160
|
+
count: number
|
|
161
|
+
countSuccess: number
|
|
162
|
+
countFailure: number
|
|
163
|
+
countError: number
|
|
164
|
+
since: Date
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface ServiceToCall<T> {
|
|
168
|
+
name: string
|
|
169
|
+
service: T
|
|
170
|
+
call: ServiceCall
|
|
171
|
+
}
|
package/src/services/Services.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Transaction as BsvTransaction, Beef, ChainTracker, Utils } from '@bsv/sdk'
|
|
2
2
|
import { asArray, asString, doubleSha256BE, sdk, sha256Hash, TableOutput, wait } from '../index.client'
|
|
3
|
-
import { ServiceCollection } from './ServiceCollection'
|
|
3
|
+
import { ServiceCall, ServiceCollection } from './ServiceCollection'
|
|
4
4
|
import { createDefaultWalletServicesOptions } from './createDefaultWalletServicesOptions'
|
|
5
5
|
import { ChaintracksChainTracker } from './chaintracker'
|
|
6
6
|
import { WhatsOnChain } from './providers/WhatsOnChain'
|
|
@@ -16,7 +16,8 @@ export class Services implements sdk.WalletServices {
|
|
|
16
16
|
|
|
17
17
|
options: sdk.WalletServicesOptions
|
|
18
18
|
whatsonchain: WhatsOnChain
|
|
19
|
-
|
|
19
|
+
arcTaal: ARC
|
|
20
|
+
arcGorillaPool?: ARC
|
|
20
21
|
bitails: Bitails
|
|
21
22
|
|
|
22
23
|
getMerklePathServices: ServiceCollection<sdk.GetMerklePathService>
|
|
@@ -36,7 +37,10 @@ export class Services implements sdk.WalletServices {
|
|
|
36
37
|
|
|
37
38
|
this.whatsonchain = new WhatsOnChain(this.chain, { apiKey: this.options.whatsOnChainApiKey }, this)
|
|
38
39
|
|
|
39
|
-
this.
|
|
40
|
+
this.arcTaal = new ARC(this.options.arcUrl, this.options.arcConfig, 'arcTaal')
|
|
41
|
+
if (this.options.arcGorillaPoolUrl) {
|
|
42
|
+
//this.arcGorillaPool = new ARC(this.options.arcGorillaPoolUrl, this.options.arcGorillaPoolConfig, 'arcGorillaPool')
|
|
43
|
+
}
|
|
40
44
|
|
|
41
45
|
this.bitails = new Bitails(this.chain)
|
|
42
46
|
|
|
@@ -49,11 +53,17 @@ export class Services implements sdk.WalletServices {
|
|
|
49
53
|
this.getRawTxServices = new ServiceCollection<sdk.GetRawTxService>()
|
|
50
54
|
.add({ name: 'WhatsOnChain', service: this.whatsonchain.getRawTxResult.bind(this.whatsonchain) })
|
|
51
55
|
|
|
52
|
-
//prettier-ignore
|
|
53
56
|
this.postBeefServices = new ServiceCollection<sdk.PostBeefService>()
|
|
54
|
-
|
|
57
|
+
if (this.arcGorillaPool) {
|
|
58
|
+
//prettier-ignore
|
|
59
|
+
this.postBeefServices.add({ name: 'GorillaPool', service: this.arcGorillaPool.postBeef.bind(this.arcGorillaPool) })
|
|
60
|
+
}
|
|
61
|
+
//prettier-ignore
|
|
62
|
+
this.postBeefServices
|
|
63
|
+
.add({ name: 'TaalArcBeef', service: this.arcTaal.postBeef.bind(this.arcTaal) })
|
|
55
64
|
.add({ name: 'WhatsOnChain', service: this.whatsonchain.postBeef.bind(this.whatsonchain) })
|
|
56
65
|
.add({ name: 'Bitails', service: this.bitails.postBeef.bind(this.bitails) })
|
|
66
|
+
;
|
|
57
67
|
|
|
58
68
|
//prettier-ignore
|
|
59
69
|
this.getUtxoStatusServices = new ServiceCollection<sdk.GetUtxoStatusService>()
|
|
@@ -73,6 +83,18 @@ export class Services implements sdk.WalletServices {
|
|
|
73
83
|
.add({ name: 'exchangeratesapi', service: updateExchangeratesapi })
|
|
74
84
|
}
|
|
75
85
|
|
|
86
|
+
getServicesCallHistory(reset?: boolean) {
|
|
87
|
+
return {
|
|
88
|
+
version: 1,
|
|
89
|
+
getMerklePath: this.getMerklePathServices.getServiceCallHistory(reset),
|
|
90
|
+
getRawTx: this.getRawTxServices.getServiceCallHistory(reset),
|
|
91
|
+
postBeef: this.postBeefServices.getServiceCallHistory(reset),
|
|
92
|
+
getUtxoStatus: this.getUtxoStatusServices.getServiceCallHistory(reset),
|
|
93
|
+
getStatusForTxids: this.getStatusForTxidsServices.getServiceCallHistory(reset),
|
|
94
|
+
getScriptHashHistory: this.getScriptHashHistoryServices.getServiceCallHistory(reset)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
76
98
|
async getChainTracker(): Promise<ChainTracker> {
|
|
77
99
|
if (!this.options.chaintracks)
|
|
78
100
|
throw new sdk.WERR_INVALID_PARAMETER('options.chaintracks', `valid to enable 'getChainTracker' service.`)
|
|
@@ -123,11 +145,22 @@ export class Services implements sdk.WalletServices {
|
|
|
123
145
|
}
|
|
124
146
|
|
|
125
147
|
for (let tries = 0; tries < services.count; tries++) {
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
148
|
+
const stc = services.serviceToCall
|
|
149
|
+
try {
|
|
150
|
+
const r = await stc.service(txids)
|
|
151
|
+
if (r.status === 'success') {
|
|
152
|
+
services.addServiceCallSuccess(stc)
|
|
153
|
+
r0 = r
|
|
154
|
+
break
|
|
155
|
+
} else {
|
|
156
|
+
if (r.error)
|
|
157
|
+
services.addServiceCallError(stc, r.error)
|
|
158
|
+
else
|
|
159
|
+
services.addServiceCallFailure(stc)
|
|
160
|
+
}
|
|
161
|
+
} catch (eu: unknown) {
|
|
162
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
163
|
+
services.addServiceCallError(stc, e)
|
|
131
164
|
}
|
|
132
165
|
services.next()
|
|
133
166
|
}
|
|
@@ -174,11 +207,22 @@ export class Services implements sdk.WalletServices {
|
|
|
174
207
|
|
|
175
208
|
for (let retry = 0; retry < 2; retry++) {
|
|
176
209
|
for (let tries = 0; tries < services.count; tries++) {
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
210
|
+
const stc = services.serviceToCall
|
|
211
|
+
try {
|
|
212
|
+
const r = await stc.service(output, outputFormat, outpoint)
|
|
213
|
+
if (r.status === 'success') {
|
|
214
|
+
services.addServiceCallSuccess(stc)
|
|
215
|
+
r0 = r
|
|
216
|
+
break
|
|
217
|
+
} else {
|
|
218
|
+
if (r.error)
|
|
219
|
+
services.addServiceCallError(stc, r.error)
|
|
220
|
+
else
|
|
221
|
+
services.addServiceCallFailure(stc)
|
|
222
|
+
}
|
|
223
|
+
} catch (eu: unknown) {
|
|
224
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
225
|
+
services.addServiceCallError(stc, e)
|
|
182
226
|
}
|
|
183
227
|
services.next()
|
|
184
228
|
}
|
|
@@ -200,19 +244,27 @@ export class Services implements sdk.WalletServices {
|
|
|
200
244
|
}
|
|
201
245
|
|
|
202
246
|
for (let tries = 0; tries < services.count; tries++) {
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
247
|
+
const stc = services.serviceToCall
|
|
248
|
+
try {
|
|
249
|
+
const r = await stc.service(hash)
|
|
250
|
+
if (r.status === 'success') {
|
|
251
|
+
r0 = r
|
|
252
|
+
break
|
|
253
|
+
} else {
|
|
254
|
+
if (r.error)
|
|
255
|
+
services.addServiceCallError(stc, r.error)
|
|
256
|
+
else
|
|
257
|
+
services.addServiceCallFailure(stc)
|
|
258
|
+
}
|
|
259
|
+
} catch (eu: unknown) {
|
|
260
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
261
|
+
services.addServiceCallError(stc, e)
|
|
208
262
|
}
|
|
209
263
|
services.next()
|
|
210
264
|
}
|
|
211
265
|
return r0
|
|
212
266
|
}
|
|
213
267
|
|
|
214
|
-
postBeefCount = 0
|
|
215
|
-
|
|
216
268
|
/**
|
|
217
269
|
*
|
|
218
270
|
* @param beef
|
|
@@ -220,15 +272,20 @@ export class Services implements sdk.WalletServices {
|
|
|
220
272
|
* @returns
|
|
221
273
|
*/
|
|
222
274
|
async postBeef(beef: Beef, txids: string[]): Promise<sdk.PostBeefResult[]> {
|
|
223
|
-
this.
|
|
224
|
-
const
|
|
225
|
-
for (let i = this.postBeefCount % services.length; i > 0; i--) {
|
|
226
|
-
// roll the array of services so the providers aren't always called in the same order.
|
|
227
|
-
services.unshift(services.pop()!)
|
|
228
|
-
}
|
|
275
|
+
const services = this.postBeefServices
|
|
276
|
+
const stcs = services.allServicesToCall
|
|
229
277
|
let rs = await Promise.all(
|
|
230
|
-
|
|
231
|
-
const r = await service(beef, txids)
|
|
278
|
+
stcs.map(async stc => {
|
|
279
|
+
const r = await stc.service(beef, txids)
|
|
280
|
+
if (r.status === 'success') {
|
|
281
|
+
services.addServiceCallSuccess(stc)
|
|
282
|
+
} else {
|
|
283
|
+
if (r.error) {
|
|
284
|
+
services.addServiceCallError(stc, r.error)
|
|
285
|
+
} else {
|
|
286
|
+
services.addServiceCallFailure(stc)
|
|
287
|
+
}
|
|
288
|
+
}
|
|
232
289
|
return r
|
|
233
290
|
})
|
|
234
291
|
)
|
|
@@ -236,31 +293,44 @@ export class Services implements sdk.WalletServices {
|
|
|
236
293
|
}
|
|
237
294
|
|
|
238
295
|
async getRawTx(txid: string, useNext?: boolean): Promise<sdk.GetRawTxResult> {
|
|
239
|
-
|
|
296
|
+
const services = this.getRawTxServices
|
|
297
|
+
if (useNext) services.next()
|
|
240
298
|
|
|
241
299
|
const r0: sdk.GetRawTxResult = { txid }
|
|
242
300
|
|
|
243
|
-
for (let tries = 0; tries <
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
301
|
+
for (let tries = 0; tries < services.count; tries++) {
|
|
302
|
+
const stc = services.serviceToCall
|
|
303
|
+
try {
|
|
304
|
+
const r = await stc.service(txid, this.chain)
|
|
305
|
+
if (r.rawTx) {
|
|
306
|
+
const hash = asString(doubleSha256BE(r.rawTx!))
|
|
307
|
+
// Confirm transaction hash matches txid
|
|
308
|
+
if (hash === asString(txid)) {
|
|
309
|
+
// If we have a match, call it done.
|
|
310
|
+
r0.rawTx = r.rawTx
|
|
311
|
+
r0.name = r.name
|
|
312
|
+
r0.error = undefined
|
|
313
|
+
services.addServiceCallSuccess(stc)
|
|
314
|
+
break
|
|
315
|
+
}
|
|
316
|
+
r.error = new sdk.WERR_INTERNAL(`computed txid ${hash} doesn't match requested value ${txid}`)
|
|
317
|
+
r.rawTx = undefined
|
|
255
318
|
}
|
|
256
|
-
r.error = new sdk.WERR_INTERNAL(`computed txid ${hash} doesn't match requested value ${txid}`)
|
|
257
|
-
r.rawTx = undefined
|
|
258
|
-
}
|
|
259
|
-
if (r.error && !r0.error && !r0.rawTx)
|
|
260
|
-
// If we have an error and didn't before...
|
|
261
|
-
r0.error = r.error
|
|
262
319
|
|
|
263
|
-
|
|
320
|
+
if (r.error)
|
|
321
|
+
services.addServiceCallError(stc, r.error)
|
|
322
|
+
else
|
|
323
|
+
services.addServiceCallFailure(stc)
|
|
324
|
+
|
|
325
|
+
if (r.error && !r0.error && !r0.rawTx)
|
|
326
|
+
// If we have an error and didn't before...
|
|
327
|
+
r0.error = r.error
|
|
328
|
+
|
|
329
|
+
} catch (eu: unknown) {
|
|
330
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
331
|
+
services.addServiceCallError(stc, e)
|
|
332
|
+
}
|
|
333
|
+
services.next()
|
|
264
334
|
}
|
|
265
335
|
return r0
|
|
266
336
|
}
|
|
@@ -307,28 +377,41 @@ export class Services implements sdk.WalletServices {
|
|
|
307
377
|
}
|
|
308
378
|
|
|
309
379
|
async getMerklePath(txid: string, useNext?: boolean): Promise<sdk.GetMerklePathResult> {
|
|
310
|
-
|
|
380
|
+
const services = this.getMerklePathServices
|
|
381
|
+
if (useNext) services.next()
|
|
311
382
|
|
|
312
383
|
const r0: sdk.GetMerklePathResult = { notes: [] }
|
|
313
384
|
|
|
314
|
-
for (let tries = 0; tries <
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
385
|
+
for (let tries = 0; tries < services.count; tries++) {
|
|
386
|
+
const stc = services.serviceToCall
|
|
387
|
+
try {
|
|
388
|
+
const r = await stc.service(txid, this)
|
|
389
|
+
if (r.notes) r0.notes!.push(...r.notes)
|
|
390
|
+
if (!r0.name) r0.name = r.name
|
|
391
|
+
if (r.merklePath) {
|
|
392
|
+
// If we have a proof, call it done.
|
|
393
|
+
r0.merklePath = r.merklePath
|
|
394
|
+
r0.header = r.header
|
|
395
|
+
r0.name = r.name
|
|
396
|
+
r0.error = undefined
|
|
397
|
+
services.addServiceCallSuccess(stc)
|
|
398
|
+
break
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (r.error)
|
|
402
|
+
services.addServiceCallError(stc, r.error)
|
|
403
|
+
else
|
|
404
|
+
services.addServiceCallFailure(stc)
|
|
405
|
+
|
|
406
|
+
if (r.error && !r0.error) {
|
|
407
|
+
// If we have an error and didn't before...
|
|
408
|
+
r0.error = r.error
|
|
409
|
+
}
|
|
410
|
+
} catch (eu: unknown) {
|
|
411
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
412
|
+
services.addServiceCallError(stc, e)
|
|
329
413
|
}
|
|
330
|
-
|
|
331
|
-
this.getMerklePathServices.next()
|
|
414
|
+
services.next()
|
|
332
415
|
}
|
|
333
416
|
return r0
|
|
334
417
|
}
|
|
@@ -350,16 +433,19 @@ export class Services implements sdk.WalletServices {
|
|
|
350
433
|
let r0: sdk.FiatExchangeRates | undefined
|
|
351
434
|
|
|
352
435
|
for (let tries = 0; tries < services.count; tries++) {
|
|
353
|
-
const
|
|
436
|
+
const stc = services.serviceToCall
|
|
354
437
|
try {
|
|
355
|
-
const r = await service(this.targetCurrencies, this.options)
|
|
438
|
+
const r = await stc.service(this.targetCurrencies, this.options)
|
|
356
439
|
if (this.targetCurrencies.every(c => typeof r.rates[c] === 'number')) {
|
|
440
|
+
services.addServiceCallSuccess(stc)
|
|
357
441
|
r0 = r
|
|
358
442
|
break
|
|
443
|
+
} else {
|
|
444
|
+
services.addServiceCallFailure(stc)
|
|
359
445
|
}
|
|
360
446
|
} catch (eu: unknown) {
|
|
361
447
|
const e = sdk.WalletError.fromUnknown(eu)
|
|
362
|
-
|
|
448
|
+
services.addServiceCallError(stc, e)
|
|
363
449
|
}
|
|
364
450
|
services.next()
|
|
365
451
|
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { _tu, logger } from '../../../test/utils/TestUtilsWalletStorage'
|
|
2
|
+
import { sdk, wait } from '../../index.client'
|
|
3
|
+
import { ARC } from '../providers/ARC'
|
|
4
|
+
import { Beef, BeefTx } from '@bsv/sdk'
|
|
5
|
+
import { arcDefaultUrl, arcGorillaPoolUrl } from '../createDefaultWalletServicesOptions'
|
|
6
|
+
import { Setup } from '../../index.all'
|
|
7
|
+
|
|
8
|
+
describe('ArcGorillaPool tests', () => {
|
|
9
|
+
jest.setTimeout(99999999)
|
|
10
|
+
|
|
11
|
+
const env = _tu.getEnv('main')
|
|
12
|
+
const arc = new ARC(arcGorillaPoolUrl(env.chain)!, {
|
|
13
|
+
apiKey: ''
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test.skip('0 double spend', async () => {
|
|
17
|
+
const beef = Beef.fromString(testnetDoubleSpendBeef)
|
|
18
|
+
const txids = [beef.txs.slice(-1)[0].txid]
|
|
19
|
+
const r = await arc.postBeef(beef, txids)
|
|
20
|
+
expect(r.status === 'error').toBe(true)
|
|
21
|
+
expect(r.txidResults[0].doubleSpend).toBe(true)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test.skip('1 postRawTx', async () => {
|
|
25
|
+
const r = await postRawTxTest('main', arc)
|
|
26
|
+
logger(`2 postBeef mainnet done ${r}`)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('2 postBeef', async () => {
|
|
30
|
+
const r = await postBeefTest('main', arc)
|
|
31
|
+
logger(`2 postBeef mainnet done ${r}`)
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
async function postBeefTest(chain: sdk.Chain, arc: ARC): Promise<string> {
|
|
36
|
+
if (Setup.noEnv(chain)) return 'skipped'
|
|
37
|
+
const c = await _tu.createNoSendTxPair(chain)
|
|
38
|
+
|
|
39
|
+
const txids = [c.txidDo, c.txidUndo]
|
|
40
|
+
|
|
41
|
+
const r = await arc.postBeef(c.beef, txids)
|
|
42
|
+
expect(r.status).toBe('success')
|
|
43
|
+
for (const txid of txids) {
|
|
44
|
+
const tr = r.txidResults.find(tx => tx.txid === txid)
|
|
45
|
+
expect(tr).not.toBeUndefined()
|
|
46
|
+
expect(tr!.status).toBe('success')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// replace Undo transaction with double spend transaction and send again.
|
|
50
|
+
const beef2 = c.beef.clone()
|
|
51
|
+
beef2.txs[beef2.txs.length - 1] = BeefTx.fromTx(c.doubleSpendTx)
|
|
52
|
+
const txids2 = [c.txidDo, c.doubleSpendTx.id('hex')]
|
|
53
|
+
|
|
54
|
+
const r2 = await arc.postBeef(beef2, txids2)
|
|
55
|
+
expect(r2.status).toBe('error')
|
|
56
|
+
for (const txid of txids2) {
|
|
57
|
+
const tr = r2.txidResults.find(tx => tx.txid === txid)
|
|
58
|
+
expect(tr).not.toBeUndefined()
|
|
59
|
+
if (txid === c.txidDo) {
|
|
60
|
+
expect(tr!.status).toBe('success')
|
|
61
|
+
} else {
|
|
62
|
+
expect(tr!.status).toBe('error')
|
|
63
|
+
expect(tr!.doubleSpend).toBe(true)
|
|
64
|
+
expect(tr!.competingTxs).toEqual([c.txidUndo])
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return 'passed'
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function postRawTxTest(chain: sdk.Chain, arc: ARC): Promise<void> {
|
|
71
|
+
if (Setup.noEnv(chain)) return
|
|
72
|
+
const c = await _tu.createNoSendTxPair(chain)
|
|
73
|
+
|
|
74
|
+
const rawTxDo = c.beef.findTxid(c.txidDo)!.tx!.toHex()
|
|
75
|
+
const rawTxUndo = c.beef.findTxid(c.txidUndo)!.tx!.toHex()
|
|
76
|
+
|
|
77
|
+
const rDo = await arc.postRawTx(rawTxDo)
|
|
78
|
+
expect(rDo.status).toBe('success')
|
|
79
|
+
expect(rDo.txid).toBe(c.txidDo)
|
|
80
|
+
|
|
81
|
+
await wait(1000)
|
|
82
|
+
|
|
83
|
+
const rUndo = await arc.postRawTx(rawTxUndo)
|
|
84
|
+
expect(rUndo.status).toBe('success')
|
|
85
|
+
expect(rUndo.txid).toBe(c.txidUndo)
|
|
86
|
+
expect(rUndo.doubleSpend).not.toBe(true)
|
|
87
|
+
|
|
88
|
+
await wait(1000)
|
|
89
|
+
|
|
90
|
+
{
|
|
91
|
+
// Send same transaction again...
|
|
92
|
+
const rUndo = await arc.postRawTx(rawTxUndo)
|
|
93
|
+
expect(rUndo.status).toBe('success')
|
|
94
|
+
expect(rUndo.txid).toBe(c.txidUndo)
|
|
95
|
+
expect(rUndo.doubleSpend).not.toBe(true)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
await wait(1000)
|
|
99
|
+
|
|
100
|
+
// Confirm double spend detection.
|
|
101
|
+
const rDouble = await arc.postRawTx(c.doubleSpendTx.toHex())
|
|
102
|
+
expect(rDouble.status).toBe('error')
|
|
103
|
+
expect(rDouble.doubleSpend).toBe(true)
|
|
104
|
+
expect(rDouble.competingTxs![0]).toBe(c.txidUndo)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const testnetDoubleSpendBeef =
|
|
108
|
+
'0100beef01fe65631900020200009df812619ae232d2363d91516ab3e811211192933526bbc2aee71b54ccb236d10102462876eec65d9aa26d957421c5cc8dd9119b61177242b9dd814fb190fd0a361801010076a3297928f6841bcb656e91225540e87c65f67d8ec12bc768d7656eb7561b3d02010000000159617a9d17562f7c9765e5dfa6a9a393aa2809ca6166a3d7a31c09efcc5070141f0000006a47304402200a528145a67ba1879b88a093cb711f79f04413a81d5678f314302e36a7f59e43022010bc4bb3c2574052c50bbdc8a05c31fb39e69280656b34f5dc22e2ceadc3bb4a412102fd4200bf389d16479b3d06f97fee0752f2c3b9dc29fb3ddce2b327d851b8902bffffffff0204000000000000001976a9140df1a69c834bb7d9bb5b2b7d6a34e5a401db3e1688ac01000000000000001976a91423f2562a8092ed24eddc77c74387b44c561692a188ac0000000001000100000001462876eec65d9aa26d957421c5cc8dd9119b61177242b9dd814fb190fd0a3618000000006a47304402204183bbfdcf11d50907b91f5e70ea8f81228501ce84e24af75c8d984682d094dc022029caa8f7e5acb4990bbeafee523a3c4a99b78e98b9e5c41349147b099679d4ae412103b76389eea6494c2c30443cba9d59b9dba05fb04e467bc94272629615b87a429fffffffff0202000000000000001976a91476d851e59fcb4ee0ebe6947496db3a393b08e49c88ac01000000000000001976a91423f2562a8092ed24eddc77c74387b44c561692a188ac0000000000'
|