@bsv/wallet-toolbox 1.4.1 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/mobile/out/src/monitor/tasks/TaskCheckForProofs.d.ts +1 -1
  3. package/mobile/out/src/monitor/tasks/TaskCheckForProofs.d.ts.map +1 -1
  4. package/mobile/out/src/monitor/tasks/TaskCheckForProofs.js +12 -2
  5. package/mobile/out/src/monitor/tasks/TaskCheckForProofs.js.map +1 -1
  6. package/mobile/out/src/monitor/tasks/TaskCheckNoSends.d.ts.map +1 -1
  7. package/mobile/out/src/monitor/tasks/TaskCheckNoSends.js +6 -1
  8. package/mobile/out/src/monitor/tasks/TaskCheckNoSends.js.map +1 -1
  9. package/mobile/out/src/monitor/tasks/TaskNewHeader.d.ts +20 -0
  10. package/mobile/out/src/monitor/tasks/TaskNewHeader.d.ts.map +1 -1
  11. package/mobile/out/src/monitor/tasks/TaskNewHeader.js +21 -2
  12. package/mobile/out/src/monitor/tasks/TaskNewHeader.js.map +1 -1
  13. package/mobile/package-lock.json +2 -2
  14. package/mobile/package.json +1 -1
  15. package/out/src/monitor/tasks/TaskCheckForProofs.d.ts +1 -1
  16. package/out/src/monitor/tasks/TaskCheckForProofs.d.ts.map +1 -1
  17. package/out/src/monitor/tasks/TaskCheckForProofs.js +12 -2
  18. package/out/src/monitor/tasks/TaskCheckForProofs.js.map +1 -1
  19. package/out/src/monitor/tasks/TaskCheckNoSends.d.ts.map +1 -1
  20. package/out/src/monitor/tasks/TaskCheckNoSends.js +6 -1
  21. package/out/src/monitor/tasks/TaskCheckNoSends.js.map +1 -1
  22. package/out/src/monitor/tasks/TaskNewHeader.d.ts +20 -0
  23. package/out/src/monitor/tasks/TaskNewHeader.d.ts.map +1 -1
  24. package/out/src/monitor/tasks/TaskNewHeader.js +21 -2
  25. package/out/src/monitor/tasks/TaskNewHeader.js.map +1 -1
  26. package/out/test/monitor/Monitor.test.js +10 -0
  27. package/out/test/monitor/Monitor.test.js.map +1 -1
  28. package/out/tsconfig.all.tsbuildinfo +1 -1
  29. package/package.json +1 -1
  30. package/src/monitor/tasks/TaskCheckForProofs.ts +13 -2
  31. package/src/monitor/tasks/TaskCheckNoSends.ts +7 -1
  32. package/src/monitor/tasks/TaskNewHeader.ts +28 -1
  33. package/test/monitor/Monitor.test.ts +11 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/wallet-toolbox",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
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",
@@ -50,6 +50,11 @@ export class TaskCheckForProofs extends WalletMonitorTask {
50
50
  const countsAsAttempt = TaskCheckForProofs.checkNow
51
51
  TaskCheckForProofs.checkNow = false
52
52
 
53
+ const maxAcceptableHeight = this.monitor.lastNewHeader?.height
54
+ if (maxAcceptableHeight === undefined) {
55
+ return log
56
+ }
57
+
53
58
  const limit = 100
54
59
  let offset = 0
55
60
  for (;;) {
@@ -60,7 +65,7 @@ export class TaskCheckForProofs extends WalletMonitorTask {
60
65
  })
61
66
  if (reqs.length === 0) break
62
67
  log += `${reqs.length} reqs with status 'callback', 'unmined', 'sending', 'unknown', or 'unconfirmed'\n`
63
- const r = await getProofs(this, reqs, 2, countsAsAttempt)
68
+ const r = await getProofs(this, reqs, 2, countsAsAttempt, false, maxAcceptableHeight)
64
69
  log += `${r.log}\n`
65
70
  //console.log(log);
66
71
  if (reqs.length < limit) break
@@ -90,7 +95,8 @@ export async function getProofs(
90
95
  reqs: TableProvenTxReq[],
91
96
  indent = 0,
92
97
  countsAsAttempt = false,
93
- ignoreStatus = false
98
+ ignoreStatus = false,
99
+ maxAcceptableHeight: number
94
100
  ): Promise<{
95
101
  proven: TableProvenTxReq[]
96
102
  invalid: TableProvenTxReq[]
@@ -179,6 +185,11 @@ export async function getProofs(
179
185
  // one more time.
180
186
  //
181
187
  r = await task.monitor.services.getMerklePath(req.txid)
188
+ if (r.header && r.header.height > maxAcceptableHeight) {
189
+ // Ignore proofs from bleeding edge of new blocks as these are the most often re-orged.
190
+ log += ` ignoring possible proof from very new block at height ${r.header.height} ${r.header.hash}\n`
191
+ continue
192
+ }
182
193
  ptx = await EntityProvenTx.fromReq(req, r, countsAsAttempt && req.status !== 'nosend')
183
194
 
184
195
  if (ptx) {
@@ -47,6 +47,12 @@ export class TaskCheckNoSends extends WalletMonitorTask {
47
47
  const countsAsAttempt = TaskCheckNoSends.checkNow
48
48
  TaskCheckNoSends.checkNow = false
49
49
 
50
+ const maxAcceptableHeight = this.monitor.lastNewHeader?.height
51
+ if (maxAcceptableHeight === undefined) {
52
+ return log
53
+ }
54
+
55
+
50
56
  const limit = 100
51
57
  let offset = 0
52
58
  for (;;) {
@@ -57,7 +63,7 @@ export class TaskCheckNoSends extends WalletMonitorTask {
57
63
  })
58
64
  if (reqs.length === 0) break
59
65
  log += `${reqs.length} reqs with status 'nosend'\n`
60
- const r = await getProofs(this, reqs, 2, countsAsAttempt)
66
+ const r = await getProofs(this, reqs, 2, countsAsAttempt, false, maxAcceptableHeight)
61
67
  log += `${r.log}\n`
62
68
  //console.log(log);
63
69
  if (reqs.length < limit) break
@@ -2,9 +2,29 @@ import { BlockHeader } from '../../services/chaintracker/chaintracks/Api/BlockHe
2
2
  import { Monitor } from '../Monitor'
3
3
  import { WalletMonitorTask } from './WalletMonitorTask'
4
4
 
5
+ /**
6
+ * This task polls for new block headers performing two essential functions:
7
+ * 1. The arrival of a new block is the right time to check for proofs for recently broadcast transactions.
8
+ * 2. The height of the block is used to limit which proofs are accepted with the aim of avoiding re-orged proofs.
9
+ *
10
+ * The most common new block orphan is one which is almost immediately orphaned.
11
+ * Waiting a minute before pursuing proof requests avoids almost all the re-org work that could be done.
12
+ * Thus this task queues new headers for one cycle.
13
+ * If a new header arrives during that cycle, it replaces the queued header and delays again.
14
+ * Only when there is an elapsed cycle without a new header does proof solicitation get triggered,
15
+ * with that header height as the limit for which proofs are accepted.
16
+ */
5
17
  export class TaskNewHeader extends WalletMonitorTask {
6
18
  static taskName = 'NewHeader'
19
+ /**
20
+ * This is always the most recent chain tip header returned from the chaintracker.
21
+ */
7
22
  header?: BlockHeader
23
+ /**
24
+ * Tracks the value of `header` except that it is set to undefined
25
+ * when a cycle without a new header occurs and `processNewBlockHeader` is called.
26
+ */
27
+ queuedHeader?: BlockHeader
8
28
 
9
29
  constructor(
10
30
  monitor: Monitor,
@@ -38,7 +58,14 @@ export class TaskNewHeader extends WalletMonitorTask {
38
58
  } else {
39
59
  isNew = false
40
60
  }
41
- if (isNew) this.monitor.processNewBlockHeader(this.header)
61
+ if (isNew) {
62
+ this.queuedHeader = this.header
63
+ } else if (this.queuedHeader) {
64
+ // Only process new block header if it has remained the chain tip for a full cycle
65
+ log = `process header: ${this.header.height} ${this.header.hash}`
66
+ this.monitor.processNewBlockHeader(this.queuedHeader)
67
+ this.queuedHeader = undefined
68
+ }
42
69
  return log
43
70
  }
44
71
  }
@@ -143,6 +143,17 @@ describe('Monitor tests', () => {
143
143
  for (const { activeStorage: storage, monitor } of ctxs) {
144
144
  if (!monitor) throw new sdk.WERR_INTERNAL('test requires setup with monitor')
145
145
 
146
+ monitor.lastNewHeader = {
147
+ height: 999999999,
148
+ hash: '',
149
+ time: 0,
150
+ version: 0,
151
+ previousHash: '',
152
+ merkleRoot: '',
153
+ bits: 0,
154
+ nonce: 0
155
+ }
156
+
146
157
  {
147
158
  for (const txid of expectedTxids) {
148
159
  // no matching ProvenTx exists.