@bopen-io/wallet-toolbox 1.7.18

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 (390) hide show
  1. package/.claude/settings.local.json +10 -0
  2. package/.env.template +22 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  4. package/.github/ISSUE_TEMPLATE/discussion.md +24 -0
  5. package/.github/pull_request_template.md +22 -0
  6. package/.github/workflows/push.yaml +145 -0
  7. package/.prettierrc +10 -0
  8. package/CHANGELOG.md +280 -0
  9. package/CONTRIBUTING.md +89 -0
  10. package/README.md +43 -0
  11. package/docs/README.md +85 -0
  12. package/docs/client.md +19627 -0
  13. package/docs/monitor.md +953 -0
  14. package/docs/open-rpc/index.html +46 -0
  15. package/docs/services.md +6377 -0
  16. package/docs/setup.md +1268 -0
  17. package/docs/storage.md +5367 -0
  18. package/docs/wallet.md +19626 -0
  19. package/jest.config.ts +25 -0
  20. package/license.md +28 -0
  21. package/out/tsconfig.all.tsbuildinfo +1 -0
  22. package/package.json +63 -0
  23. package/src/CWIStyleWalletManager.ts +1999 -0
  24. package/src/Setup.ts +579 -0
  25. package/src/SetupClient.ts +322 -0
  26. package/src/SetupWallet.ts +108 -0
  27. package/src/SimpleWalletManager.ts +526 -0
  28. package/src/Wallet.ts +1169 -0
  29. package/src/WalletAuthenticationManager.ts +153 -0
  30. package/src/WalletLogger.ts +213 -0
  31. package/src/WalletPermissionsManager.ts +3660 -0
  32. package/src/WalletSettingsManager.ts +114 -0
  33. package/src/__tests/CWIStyleWalletManager.test.d.ts.map +1 -0
  34. package/src/__tests/CWIStyleWalletManager.test.js.map +1 -0
  35. package/src/__tests/CWIStyleWalletManager.test.ts +675 -0
  36. package/src/__tests/WalletPermissionsManager.callbacks.test.ts +323 -0
  37. package/src/__tests/WalletPermissionsManager.checks.test.ts +844 -0
  38. package/src/__tests/WalletPermissionsManager.encryption.test.ts +412 -0
  39. package/src/__tests/WalletPermissionsManager.fixtures.ts +307 -0
  40. package/src/__tests/WalletPermissionsManager.flows.test.ts +462 -0
  41. package/src/__tests/WalletPermissionsManager.initialization.test.ts +300 -0
  42. package/src/__tests/WalletPermissionsManager.pmodules.test.ts +798 -0
  43. package/src/__tests/WalletPermissionsManager.proxying.test.ts +724 -0
  44. package/src/__tests/WalletPermissionsManager.tokens.test.ts +503 -0
  45. package/src/index.all.ts +27 -0
  46. package/src/index.client.ts +25 -0
  47. package/src/index.mobile.ts +21 -0
  48. package/src/index.ts +1 -0
  49. package/src/monitor/Monitor.ts +412 -0
  50. package/src/monitor/MonitorDaemon.ts +188 -0
  51. package/src/monitor/README.md +3 -0
  52. package/src/monitor/__test/MonitorDaemon.man.test.ts +45 -0
  53. package/src/monitor/tasks/TaskCheckForProofs.ts +243 -0
  54. package/src/monitor/tasks/TaskCheckNoSends.ts +73 -0
  55. package/src/monitor/tasks/TaskClock.ts +33 -0
  56. package/src/monitor/tasks/TaskFailAbandoned.ts +54 -0
  57. package/src/monitor/tasks/TaskMonitorCallHistory.ts +26 -0
  58. package/src/monitor/tasks/TaskNewHeader.ts +93 -0
  59. package/src/monitor/tasks/TaskPurge.ts +68 -0
  60. package/src/monitor/tasks/TaskReorg.ts +89 -0
  61. package/src/monitor/tasks/TaskReviewStatus.ts +48 -0
  62. package/src/monitor/tasks/TaskSendWaiting.ts +122 -0
  63. package/src/monitor/tasks/TaskSyncWhenIdle.ts +26 -0
  64. package/src/monitor/tasks/TaskUnFail.ts +151 -0
  65. package/src/monitor/tasks/WalletMonitorTask.ts +47 -0
  66. package/src/sdk/CertOpsWallet.ts +18 -0
  67. package/src/sdk/PrivilegedKeyManager.ts +372 -0
  68. package/src/sdk/README.md +13 -0
  69. package/src/sdk/WERR_errors.ts +234 -0
  70. package/src/sdk/WalletError.ts +170 -0
  71. package/src/sdk/WalletErrorFromJson.ts +80 -0
  72. package/src/sdk/WalletServices.interfaces.ts +700 -0
  73. package/src/sdk/WalletSigner.interfaces.ts +11 -0
  74. package/src/sdk/WalletStorage.interfaces.ts +606 -0
  75. package/src/sdk/__test/CertificateLifeCycle.test.ts +131 -0
  76. package/src/sdk/__test/PrivilegedKeyManager.test.ts +738 -0
  77. package/src/sdk/__test/WalletError.test.ts +318 -0
  78. package/src/sdk/__test/validationHelpers.test.ts +21 -0
  79. package/src/sdk/index.ts +10 -0
  80. package/src/sdk/types.ts +226 -0
  81. package/src/services/README.md +11 -0
  82. package/src/services/ServiceCollection.ts +248 -0
  83. package/src/services/Services.ts +603 -0
  84. package/src/services/__tests/ARC.man.test.ts +123 -0
  85. package/src/services/__tests/ARC.timeout.man.test.ts +79 -0
  86. package/src/services/__tests/ArcGorillaPool.man.test.ts +108 -0
  87. package/src/services/__tests/arcServices.test.ts +8 -0
  88. package/src/services/__tests/bitrails.test.ts +56 -0
  89. package/src/services/__tests/getMerklePath.test.ts +15 -0
  90. package/src/services/__tests/getRawTx.test.ts +13 -0
  91. package/src/services/__tests/postBeef.test.ts +104 -0
  92. package/src/services/__tests/verifyBeef.test.ts +50 -0
  93. package/src/services/chaintracker/BHServiceClient.ts +212 -0
  94. package/src/services/chaintracker/ChaintracksChainTracker.ts +71 -0
  95. package/src/services/chaintracker/__tests/ChaintracksChainTracker.test.ts +33 -0
  96. package/src/services/chaintracker/__tests/ChaintracksServiceClient.test.ts +29 -0
  97. package/src/services/chaintracker/chaintracks/Api/BlockHeaderApi.ts +72 -0
  98. package/src/services/chaintracker/chaintracks/Api/BulkIngestorApi.ts +83 -0
  99. package/src/services/chaintracker/chaintracks/Api/BulkStorageApi.ts +92 -0
  100. package/src/services/chaintracker/chaintracks/Api/ChaintracksApi.ts +64 -0
  101. package/src/services/chaintracker/chaintracks/Api/ChaintracksClientApi.ts +189 -0
  102. package/src/services/chaintracker/chaintracks/Api/ChaintracksFetchApi.ts +18 -0
  103. package/src/services/chaintracker/chaintracks/Api/ChaintracksFsApi.ts +58 -0
  104. package/src/services/chaintracker/chaintracks/Api/ChaintracksStorageApi.ts +386 -0
  105. package/src/services/chaintracker/chaintracks/Api/LiveIngestorApi.ts +25 -0
  106. package/src/services/chaintracker/chaintracks/Chaintracks.ts +609 -0
  107. package/src/services/chaintracker/chaintracks/ChaintracksService.ts +199 -0
  108. package/src/services/chaintracker/chaintracks/ChaintracksServiceClient.ts +154 -0
  109. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.ts +176 -0
  110. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDN.ts +174 -0
  111. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDNBabbage.ts +18 -0
  112. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.ts +113 -0
  113. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.ts +81 -0
  114. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.ts +86 -0
  115. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorTeranodeP2P.ts +59 -0
  116. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.ts +104 -0
  117. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.ts +66 -0
  118. package/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.ts +566 -0
  119. package/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.ts +219 -0
  120. package/src/services/chaintracker/chaintracks/Ingest/__tests/BulkIngestorCDNBabbage.test.ts +54 -0
  121. package/src/services/chaintracker/chaintracks/Ingest/__tests/LiveIngestorWhatsOnChainPoll.test.ts +33 -0
  122. package/src/services/chaintracker/chaintracks/Ingest/__tests/WhatsOnChainServices.test.ts +124 -0
  123. package/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.ts +92 -0
  124. package/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.ts +104 -0
  125. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.ts +382 -0
  126. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.ts +574 -0
  127. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.ts +438 -0
  128. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageMemory.ts +29 -0
  129. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.ts +304 -0
  130. package/src/services/chaintracker/chaintracks/Storage/__tests/ChaintracksStorageIdb.test.ts +102 -0
  131. package/src/services/chaintracker/chaintracks/Storage/__tests/ChaintracksStorageKnex.test.ts +45 -0
  132. package/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.ts +77 -0
  133. package/src/services/chaintracker/chaintracks/__tests/ChaintracksClientApi.test.ts +192 -0
  134. package/src/services/chaintracker/chaintracks/__tests/LocalCdnServer.ts +75 -0
  135. package/src/services/chaintracker/chaintracks/__tests/createIdbChaintracks.test.ts +62 -0
  136. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNetBlockHeaders.json +1 -0
  137. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_0.headers +0 -0
  138. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_1.headers +0 -0
  139. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_2.headers +0 -0
  140. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_3.headers +0 -0
  141. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNetBlockHeaders.json +1 -0
  142. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_0.headers +0 -0
  143. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_1.headers +0 -0
  144. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_2.headers +0 -0
  145. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_3.headers +0 -0
  146. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNetBlockHeaders.json +1 -0
  147. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_0.headers +0 -0
  148. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_1.headers +0 -0
  149. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_2.headers +0 -0
  150. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_3.headers +0 -0
  151. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNetBlockHeaders.json +1 -0
  152. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_0.headers +0 -0
  153. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_1.headers +0 -0
  154. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_2.headers +0 -0
  155. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_3.headers +0 -0
  156. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_4.headers +0 -0
  157. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNetBlockHeaders.json +1 -0
  158. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_0.headers +0 -0
  159. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_1.headers +0 -0
  160. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_2.headers +0 -0
  161. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_3.headers +0 -0
  162. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_4.headers +0 -0
  163. package/src/services/chaintracker/chaintracks/createDefaultIdbChaintracksOptions.ts +92 -0
  164. package/src/services/chaintracker/chaintracks/createDefaultKnexChaintracksOptions.ts +111 -0
  165. package/src/services/chaintracker/chaintracks/createDefaultNoDbChaintracksOptions.ts +91 -0
  166. package/src/services/chaintracker/chaintracks/createIdbChaintracks.ts +60 -0
  167. package/src/services/chaintracker/chaintracks/createKnexChaintracks.ts +65 -0
  168. package/src/services/chaintracker/chaintracks/createNoDbChaintracks.ts +60 -0
  169. package/src/services/chaintracker/chaintracks/index.all.ts +12 -0
  170. package/src/services/chaintracker/chaintracks/index.client.ts +4 -0
  171. package/src/services/chaintracker/chaintracks/index.mobile.ts +37 -0
  172. package/src/services/chaintracker/chaintracks/util/BulkFileDataManager.ts +975 -0
  173. package/src/services/chaintracker/chaintracks/util/BulkFileDataReader.ts +60 -0
  174. package/src/services/chaintracker/chaintracks/util/BulkFilesReader.ts +336 -0
  175. package/src/services/chaintracker/chaintracks/util/BulkHeaderFile.ts +247 -0
  176. package/src/services/chaintracker/chaintracks/util/ChaintracksFetch.ts +69 -0
  177. package/src/services/chaintracker/chaintracks/util/ChaintracksFs.ts +141 -0
  178. package/src/services/chaintracker/chaintracks/util/HeightRange.ts +153 -0
  179. package/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.ts +76 -0
  180. package/src/services/chaintracker/chaintracks/util/__tests/BulkFileDataManager.test.ts +304 -0
  181. package/src/services/chaintracker/chaintracks/util/__tests/ChaintracksFetch.test.ts +60 -0
  182. package/src/services/chaintracker/chaintracks/util/__tests/HeightRange.test.ts +67 -0
  183. package/src/services/chaintracker/chaintracks/util/__tests/SingleWriterMultiReaderLock.test.ts +49 -0
  184. package/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.ts +573 -0
  185. package/src/services/chaintracker/chaintracks/util/dirtyHashes.ts +29 -0
  186. package/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.ts +432 -0
  187. package/src/services/chaintracker/index.all.ts +4 -0
  188. package/src/services/chaintracker/index.client.ts +4 -0
  189. package/src/services/chaintracker/index.mobile.ts +4 -0
  190. package/src/services/createDefaultWalletServicesOptions.ts +77 -0
  191. package/src/services/index.ts +1 -0
  192. package/src/services/processingErrors/arcSuccessError.json +76 -0
  193. package/src/services/providers/ARC.ts +350 -0
  194. package/src/services/providers/Bitails.ts +256 -0
  195. package/src/services/providers/SdkWhatsOnChain.ts +83 -0
  196. package/src/services/providers/WhatsOnChain.ts +883 -0
  197. package/src/services/providers/__tests/WhatsOnChain.test.ts +242 -0
  198. package/src/services/providers/__tests/exchangeRates.test.ts +18 -0
  199. package/src/services/providers/exchangeRates.ts +265 -0
  200. package/src/services/providers/getBeefForTxid.ts +369 -0
  201. package/src/signer/README.md +5 -0
  202. package/src/signer/WalletSigner.ts +17 -0
  203. package/src/signer/methods/acquireDirectCertificate.ts +52 -0
  204. package/src/signer/methods/buildSignableTransaction.ts +183 -0
  205. package/src/signer/methods/completeSignedTransaction.ts +117 -0
  206. package/src/signer/methods/createAction.ts +172 -0
  207. package/src/signer/methods/internalizeAction.ts +106 -0
  208. package/src/signer/methods/proveCertificate.ts +43 -0
  209. package/src/signer/methods/signAction.ts +54 -0
  210. package/src/storage/README.md +14 -0
  211. package/src/storage/StorageIdb.ts +2304 -0
  212. package/src/storage/StorageKnex.ts +1425 -0
  213. package/src/storage/StorageProvider.ts +810 -0
  214. package/src/storage/StorageReader.ts +194 -0
  215. package/src/storage/StorageReaderWriter.ts +432 -0
  216. package/src/storage/StorageSyncReader.ts +34 -0
  217. package/src/storage/WalletStorageManager.ts +943 -0
  218. package/src/storage/__test/StorageIdb.test.ts +43 -0
  219. package/src/storage/__test/WalletStorageManager.test.ts +275 -0
  220. package/src/storage/__test/adminStats.man.test.ts +89 -0
  221. package/src/storage/__test/getBeefForTransaction.test.ts +385 -0
  222. package/src/storage/index.all.ts +11 -0
  223. package/src/storage/index.client.ts +7 -0
  224. package/src/storage/index.mobile.ts +6 -0
  225. package/src/storage/methods/ListActionsSpecOp.ts +70 -0
  226. package/src/storage/methods/ListOutputsSpecOp.ts +129 -0
  227. package/src/storage/methods/__test/GenerateChange/generateChangeSdk.test.ts +1057 -0
  228. package/src/storage/methods/__test/GenerateChange/randomValsUsed1.ts +20 -0
  229. package/src/storage/methods/__test/offsetKey.test.ts +274 -0
  230. package/src/storage/methods/attemptToPostReqsToNetwork.ts +389 -0
  231. package/src/storage/methods/createAction.ts +947 -0
  232. package/src/storage/methods/generateChange.ts +556 -0
  233. package/src/storage/methods/getBeefForTransaction.ts +139 -0
  234. package/src/storage/methods/getSyncChunk.ts +293 -0
  235. package/src/storage/methods/internalizeAction.ts +562 -0
  236. package/src/storage/methods/listActionsIdb.ts +183 -0
  237. package/src/storage/methods/listActionsKnex.ts +226 -0
  238. package/src/storage/methods/listCertificates.ts +73 -0
  239. package/src/storage/methods/listOutputsIdb.ts +203 -0
  240. package/src/storage/methods/listOutputsKnex.ts +263 -0
  241. package/src/storage/methods/offsetKey.ts +89 -0
  242. package/src/storage/methods/processAction.ts +420 -0
  243. package/src/storage/methods/purgeData.ts +251 -0
  244. package/src/storage/methods/purgeDataIdb.ts +10 -0
  245. package/src/storage/methods/reviewStatus.ts +101 -0
  246. package/src/storage/methods/reviewStatusIdb.ts +43 -0
  247. package/src/storage/methods/utils.Buffer.ts +33 -0
  248. package/src/storage/methods/utils.ts +56 -0
  249. package/src/storage/remoting/StorageClient.ts +567 -0
  250. package/src/storage/remoting/StorageMobile.ts +544 -0
  251. package/src/storage/remoting/StorageServer.ts +291 -0
  252. package/src/storage/remoting/__test/StorageClient.test.ts +113 -0
  253. package/src/storage/schema/KnexMigrations.ts +489 -0
  254. package/src/storage/schema/StorageIdbSchema.ts +150 -0
  255. package/src/storage/schema/entities/EntityBase.ts +210 -0
  256. package/src/storage/schema/entities/EntityCertificate.ts +188 -0
  257. package/src/storage/schema/entities/EntityCertificateField.ts +136 -0
  258. package/src/storage/schema/entities/EntityCommission.ts +148 -0
  259. package/src/storage/schema/entities/EntityOutput.ts +290 -0
  260. package/src/storage/schema/entities/EntityOutputBasket.ts +153 -0
  261. package/src/storage/schema/entities/EntityOutputTag.ts +121 -0
  262. package/src/storage/schema/entities/EntityOutputTagMap.ts +123 -0
  263. package/src/storage/schema/entities/EntityProvenTx.ts +319 -0
  264. package/src/storage/schema/entities/EntityProvenTxReq.ts +580 -0
  265. package/src/storage/schema/entities/EntitySyncState.ts +389 -0
  266. package/src/storage/schema/entities/EntityTransaction.ts +306 -0
  267. package/src/storage/schema/entities/EntityTxLabel.ts +121 -0
  268. package/src/storage/schema/entities/EntityTxLabelMap.ts +123 -0
  269. package/src/storage/schema/entities/EntityUser.ts +112 -0
  270. package/src/storage/schema/entities/MergeEntity.ts +73 -0
  271. package/src/storage/schema/entities/__tests/CertificateFieldTests.test.ts +353 -0
  272. package/src/storage/schema/entities/__tests/CertificateTests.test.ts +354 -0
  273. package/src/storage/schema/entities/__tests/CommissionTests.test.ts +371 -0
  274. package/src/storage/schema/entities/__tests/OutputBasketTests.test.ts +278 -0
  275. package/src/storage/schema/entities/__tests/OutputTagMapTests.test.ts +242 -0
  276. package/src/storage/schema/entities/__tests/OutputTagTests.test.ts +288 -0
  277. package/src/storage/schema/entities/__tests/OutputTests.test.ts +464 -0
  278. package/src/storage/schema/entities/__tests/ProvenTxReqTests.test.ts +340 -0
  279. package/src/storage/schema/entities/__tests/ProvenTxTests.test.ts +504 -0
  280. package/src/storage/schema/entities/__tests/SyncStateTests.test.ts +288 -0
  281. package/src/storage/schema/entities/__tests/TransactionTests.test.ts +604 -0
  282. package/src/storage/schema/entities/__tests/TxLabelMapTests.test.ts +361 -0
  283. package/src/storage/schema/entities/__tests/TxLabelTests.test.ts +198 -0
  284. package/src/storage/schema/entities/__tests/stampLogTests.test.ts +90 -0
  285. package/src/storage/schema/entities/__tests/usersTests.test.ts +340 -0
  286. package/src/storage/schema/entities/index.ts +16 -0
  287. package/src/storage/schema/tables/TableCertificate.ts +21 -0
  288. package/src/storage/schema/tables/TableCertificateField.ts +12 -0
  289. package/src/storage/schema/tables/TableCommission.ts +13 -0
  290. package/src/storage/schema/tables/TableMonitorEvent.ts +9 -0
  291. package/src/storage/schema/tables/TableOutput.ts +64 -0
  292. package/src/storage/schema/tables/TableOutputBasket.ts +12 -0
  293. package/src/storage/schema/tables/TableOutputTag.ts +10 -0
  294. package/src/storage/schema/tables/TableOutputTagMap.ts +9 -0
  295. package/src/storage/schema/tables/TableProvenTx.ts +14 -0
  296. package/src/storage/schema/tables/TableProvenTxReq.ts +65 -0
  297. package/src/storage/schema/tables/TableSettings.ts +17 -0
  298. package/src/storage/schema/tables/TableSyncState.ts +18 -0
  299. package/src/storage/schema/tables/TableTransaction.ts +54 -0
  300. package/src/storage/schema/tables/TableTxLabel.ts +10 -0
  301. package/src/storage/schema/tables/TableTxLabelMap.ts +9 -0
  302. package/src/storage/schema/tables/TableUser.ts +16 -0
  303. package/src/storage/schema/tables/index.ts +16 -0
  304. package/src/storage/sync/StorageMySQLDojoReader.ts +696 -0
  305. package/src/storage/sync/index.ts +1 -0
  306. package/src/utility/Format.ts +133 -0
  307. package/src/utility/README.md +3 -0
  308. package/src/utility/ReaderUint8Array.ts +187 -0
  309. package/src/utility/ScriptTemplateBRC29.ts +73 -0
  310. package/src/utility/__tests/utilityHelpers.noBuffer.test.ts +109 -0
  311. package/src/utility/aggregateResults.ts +68 -0
  312. package/src/utility/identityUtils.ts +159 -0
  313. package/src/utility/index.all.ts +7 -0
  314. package/src/utility/index.client.ts +7 -0
  315. package/src/utility/parseTxScriptOffsets.ts +29 -0
  316. package/src/utility/stampLog.ts +69 -0
  317. package/src/utility/tscProofToMerklePath.ts +48 -0
  318. package/src/utility/utilityHelpers.buffer.ts +34 -0
  319. package/src/utility/utilityHelpers.noBuffer.ts +60 -0
  320. package/src/utility/utilityHelpers.ts +275 -0
  321. package/src/wab-client/WABClient.ts +94 -0
  322. package/src/wab-client/__tests/WABClient.man.test.ts +59 -0
  323. package/src/wab-client/auth-method-interactors/AuthMethodInteractor.ts +47 -0
  324. package/src/wab-client/auth-method-interactors/DevConsoleInteractor.ts +73 -0
  325. package/src/wab-client/auth-method-interactors/PersonaIDInteractor.ts +35 -0
  326. package/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.ts +72 -0
  327. package/syncVersions.js +71 -0
  328. package/test/Wallet/StorageClient/storageClient.man.test.ts +75 -0
  329. package/test/Wallet/action/abortAction.test.ts +47 -0
  330. package/test/Wallet/action/createAction.test.ts +299 -0
  331. package/test/Wallet/action/createAction2.test.ts +1273 -0
  332. package/test/Wallet/action/createActionToGenerateBeefs.man.test.ts +293 -0
  333. package/test/Wallet/action/internalizeAction.a.test.ts +286 -0
  334. package/test/Wallet/action/internalizeAction.test.ts +682 -0
  335. package/test/Wallet/action/relinquishOutput.test.ts +37 -0
  336. package/test/Wallet/certificate/acquireCertificate.test.ts +298 -0
  337. package/test/Wallet/certificate/listCertificates.test.ts +346 -0
  338. package/test/Wallet/construct/Wallet.constructor.test.ts +57 -0
  339. package/test/Wallet/get/getHeaderForHeight.test.ts +82 -0
  340. package/test/Wallet/get/getHeight.test.ts +52 -0
  341. package/test/Wallet/get/getKnownTxids.test.ts +86 -0
  342. package/test/Wallet/get/getNetwork.test.ts +27 -0
  343. package/test/Wallet/get/getVersion.test.ts +27 -0
  344. package/test/Wallet/list/listActions.test.ts +279 -0
  345. package/test/Wallet/list/listActions2.test.ts +1381 -0
  346. package/test/Wallet/list/listCertificates.test.ts +118 -0
  347. package/test/Wallet/list/listOutputs.test.ts +447 -0
  348. package/test/Wallet/live/walletLive.man.test.ts +521 -0
  349. package/test/Wallet/local/localWallet.man.test.ts +93 -0
  350. package/test/Wallet/local/localWallet2.man.test.ts +277 -0
  351. package/test/Wallet/signAction/mountaintop.man.test.ts +130 -0
  352. package/test/Wallet/specOps/specOps.man.test.ts +220 -0
  353. package/test/Wallet/support/janitor.man.test.ts +40 -0
  354. package/test/Wallet/support/operations.man.test.ts +407 -0
  355. package/test/Wallet/support/reqErrorReview.2025.05.06.man.test.ts +347 -0
  356. package/test/Wallet/sync/Wallet.sync.test.ts +215 -0
  357. package/test/Wallet/sync/Wallet.updateWalletLegacyTestData.man.test.ts +203 -0
  358. package/test/Wallet/sync/setActive.test.ts +170 -0
  359. package/test/WalletClient/LocalKVStore.man.test.ts +114 -0
  360. package/test/WalletClient/WERR.man.test.ts +35 -0
  361. package/test/bsv-ts-sdk/LocalKVStore.test.ts +102 -0
  362. package/test/checkDB.ts +57 -0
  363. package/test/checkdb +0 -0
  364. package/test/examples/backup.man.test.ts +59 -0
  365. package/test/examples/pushdrop.test.ts +282 -0
  366. package/test/monitor/Monitor.test.ts +620 -0
  367. package/test/services/Services.test.ts +263 -0
  368. package/test/storage/KnexMigrations.test.ts +86 -0
  369. package/test/storage/StorageMySQLDojoReader.man.test.ts +60 -0
  370. package/test/storage/count.test.ts +177 -0
  371. package/test/storage/find.test.ts +195 -0
  372. package/test/storage/findLegacy.test.ts +67 -0
  373. package/test/storage/idb/allocateChange.test.ts +251 -0
  374. package/test/storage/idb/count.test.ts +158 -0
  375. package/test/storage/idb/find.test.ts +177 -0
  376. package/test/storage/idb/idbSpeed.test.ts +36 -0
  377. package/test/storage/idb/insert.test.ts +268 -0
  378. package/test/storage/idb/transactionAbort.test.ts +108 -0
  379. package/test/storage/idb/update.test.ts +999 -0
  380. package/test/storage/insert.test.ts +278 -0
  381. package/test/storage/update.test.ts +1021 -0
  382. package/test/storage/update2.test.ts +897 -0
  383. package/test/utils/TestUtilsWalletStorage.ts +2526 -0
  384. package/test/utils/localWalletMethods.ts +363 -0
  385. package/test/utils/removeFailedFromDatabase.sql +17 -0
  386. package/ts2md.json +44 -0
  387. package/tsconfig.all.json +31 -0
  388. package/tsconfig.client.json +29 -0
  389. package/tsconfig.json +17 -0
  390. package/tsconfig.mobile.json +28 -0
@@ -0,0 +1,60 @@
1
+ import { WERR_INTERNAL } from '../../../../sdk'
2
+ import { BulkFileDataManager } from './BulkFileDataManager'
3
+ import { BulkHeaderFileInfo } from './BulkHeaderFile'
4
+ import { HeightRange } from './HeightRange'
5
+
6
+ export class BulkFileDataReader {
7
+ readonly manager: BulkFileDataManager
8
+ readonly range: HeightRange
9
+ readonly maxBufferSize: number
10
+ nextHeight: number
11
+
12
+ constructor(manager: BulkFileDataManager, range: HeightRange, maxBufferSize: number) {
13
+ this.manager = manager
14
+ this.range = range
15
+ this.maxBufferSize = maxBufferSize
16
+ this.nextHeight = range.minHeight
17
+ }
18
+
19
+ /**
20
+ * Returns the Buffer of block headers from the given `file` for the given `range`.
21
+ * If `range` is undefined, the file's full height range is read.
22
+ * The returned Buffer will only contain headers in `file` and in `range`
23
+ * @param file
24
+ * @param range
25
+ */
26
+ private async readBufferFromFile(file: BulkHeaderFileInfo, range?: HeightRange): Promise<Uint8Array | undefined> {
27
+ // Constrain the range to the file's contents...
28
+ let fileRange = new HeightRange(file.firstHeight, file.firstHeight + file.count - 1)
29
+ if (range) fileRange = fileRange.intersect(range)
30
+ if (fileRange.isEmpty) return undefined
31
+ const offset = (fileRange.minHeight - file.firstHeight) * 80
32
+ const length = fileRange.length * 80
33
+ return await this.manager.getDataFromFile(file, offset, length)
34
+ }
35
+
36
+ /**
37
+ * @returns an array containing the next `maxBufferSize` bytes of headers from the files.
38
+ */
39
+ async read(): Promise<Uint8Array | undefined> {
40
+ if (this.nextHeight === undefined || !this.range || this.range.isEmpty || this.nextHeight > this.range.maxHeight)
41
+ return undefined
42
+ let lastHeight = this.nextHeight + this.maxBufferSize / 80 - 1
43
+ lastHeight = Math.min(lastHeight, this.range.maxHeight)
44
+ let file = await this.manager.getFileForHeight(this.nextHeight)
45
+ if (!file) throw new WERR_INTERNAL(`logic error`)
46
+ const readRange = new HeightRange(this.nextHeight, lastHeight)
47
+ let buffers = new Uint8Array(readRange.length * 80)
48
+ let offset = 0
49
+ while (file) {
50
+ const buffer = await this.readBufferFromFile(file, readRange)
51
+ if (!buffer) break
52
+ buffers.set(buffer, offset)
53
+ offset += buffer.length
54
+ file = await this.manager.getFileForHeight(file.firstHeight + file.count)
55
+ }
56
+ if (!buffers.length || offset !== readRange.length * 80) return undefined
57
+ this.nextHeight = lastHeight + 1
58
+ return buffers
59
+ }
60
+ }
@@ -0,0 +1,336 @@
1
+ import { HeightRange } from './HeightRange'
2
+ import { deserializeBaseBlockHeader, validateBufferOfHeaders } from './blockHeaderUtilities'
3
+ import { BaseBlockHeader } from '../../../../sdk/WalletServices.interfaces'
4
+ import { asArray, asString, asUint8Array } from '../../../../utility/utilityHelpers.noBuffer'
5
+ import { ChaintracksFsApi } from '../Api/ChaintracksFsApi'
6
+ import { Hash } from '@bsv/sdk'
7
+ import { WERR_INTERNAL, WERR_INVALID_OPERATION, WERR_INVALID_PARAMETER } from '../../../../sdk'
8
+ import { ChaintracksStorageBase } from '../Storage/ChaintracksStorageBase'
9
+ import { ChaintracksFetchApi } from '../Api/ChaintracksFetchApi'
10
+ import {
11
+ BulkHeaderFile,
12
+ BulkHeaderFileFs,
13
+ BulkHeaderFileInfo,
14
+ BulkHeaderFilesInfo,
15
+ BulkHeaderFileStorage
16
+ } from './BulkHeaderFile'
17
+
18
+ /**
19
+ * Breaks available bulk headers stored in multiple files into a sequence of buffers with
20
+ * limited maximum size.
21
+ */
22
+ export class BulkFilesReader {
23
+ /**
24
+ * Previously validated bulk header files which may pull data from backing storage on demand.
25
+ */
26
+ files: BulkHeaderFile[]
27
+ /**
28
+ * Subset of headers currently being "read".
29
+ */
30
+ range: HeightRange
31
+ /**
32
+ * Maximum buffer size returned from `read()` in bytes.
33
+ */
34
+ maxBufferSize = 400 * 80
35
+ /**
36
+ * "Read pointer", the next height to be "read".
37
+ */
38
+ nextHeight: number | undefined
39
+
40
+ constructor(files: BulkHeaderFile[], range?: HeightRange, maxBufferSize?: number) {
41
+ this.files = files
42
+ this.range = HeightRange.empty
43
+ this.setRange(range)
44
+ this.setMaxBufferSize(maxBufferSize || 400 * 80)
45
+ }
46
+
47
+ protected setRange(range?: HeightRange) {
48
+ this.range = this.heightRange
49
+ if (range) {
50
+ this.range = this.range.intersect(range)
51
+ }
52
+ this.nextHeight = this.range.isEmpty ? undefined : this.range.minHeight
53
+ }
54
+
55
+ setMaxBufferSize(maxBufferSize: number | undefined) {
56
+ this.maxBufferSize = maxBufferSize || 400 * 80
57
+ if (this.maxBufferSize % 80 !== 0) throw new Error('maxBufferSize must be a multiple of 80 bytes.')
58
+ }
59
+
60
+ private getLastFile(): BulkHeaderFileInfo | undefined {
61
+ return this.files[this.files.length - 1]
62
+ }
63
+
64
+ get heightRange(): HeightRange {
65
+ const last = this.getLastFile()
66
+ if (!last || !this.files) return HeightRange.empty
67
+ const first = this.files[0]
68
+ return new HeightRange(first.firstHeight, last.firstHeight + last.count - 1)
69
+ }
70
+
71
+ private getFileForHeight(height: number): BulkHeaderFile | undefined {
72
+ if (!this.files) return undefined
73
+ return this.files.find(file => file.firstHeight <= height && file.firstHeight + file.count > height)
74
+ }
75
+
76
+ async readBufferForHeightOrUndefined(height: number): Promise<Uint8Array | undefined> {
77
+ const file = this.getFileForHeight(height)
78
+ if (!file) return undefined
79
+ const buffer = await file.readDataFromFile(80, (height - file.firstHeight) * 80)
80
+ return buffer
81
+ }
82
+
83
+ async readBufferForHeight(height: number): Promise<Uint8Array> {
84
+ const header = await this.readBufferForHeightOrUndefined(height)
85
+ if (!header) throw new Error(`Failed to read bulk header buffer at height=${height}`)
86
+ return header
87
+ }
88
+
89
+ async readHeaderForHeight(height: number): Promise<BaseBlockHeader> {
90
+ const buffer = await this.readBufferForHeight(height)
91
+ return deserializeBaseBlockHeader(buffer, 0)
92
+ }
93
+
94
+ async readHeaderForHeightOrUndefined(height: number): Promise<BaseBlockHeader | undefined> {
95
+ const buffer = await this.readBufferForHeightOrUndefined(height)
96
+ return buffer ? deserializeBaseBlockHeader(buffer, 0) : undefined
97
+ }
98
+
99
+ /**
100
+ * Returns the Buffer of block headers from the given `file` for the given `range`.
101
+ * If `range` is undefined, the file's full height range is read.
102
+ * The returned Buffer will only contain headers in `file` and in `range`
103
+ * @param file
104
+ * @param range
105
+ */
106
+ private async readBufferFromFile(file: BulkHeaderFile, range?: HeightRange): Promise<Uint8Array | undefined> {
107
+ // Constrain the range to the file's contents...
108
+ let fileRange = file.heightRange
109
+ if (range) fileRange = fileRange.intersect(range)
110
+ if (fileRange.isEmpty) return undefined
111
+ const position = (fileRange.minHeight - file.firstHeight) * 80
112
+ const length = fileRange.length * 80
113
+ return await file.readDataFromFile(length, position)
114
+ }
115
+
116
+ private nextFile(file: BulkHeaderFile | undefined): BulkHeaderFile | undefined {
117
+ if (!file) return this.files[0]
118
+ const i = this.files.indexOf(file)
119
+ if (i < 0) throw new WERR_INVALID_PARAMETER(`file`, `a valid file from this.files`)
120
+ return this.files[i + 1]
121
+ }
122
+
123
+ /**
124
+ * @returns an array containing the next `maxBufferSize` bytes of headers from the files.
125
+ */
126
+ async read(): Promise<Uint8Array | undefined> {
127
+ if (this.nextHeight === undefined || !this.range || this.nextHeight > this.range.maxHeight) return undefined
128
+ let lastHeight = this.nextHeight + this.maxBufferSize / 80 - 1
129
+ lastHeight = Math.min(lastHeight, this.range.maxHeight)
130
+ let file = this.getFileForHeight(this.nextHeight)
131
+ if (!file) throw new WERR_INTERNAL(`logic error`)
132
+ const readRange = new HeightRange(this.nextHeight, lastHeight)
133
+ let buffers = new Uint8Array(readRange.length * 80)
134
+ let offset = 0
135
+ while (file) {
136
+ const buffer = await this.readBufferFromFile(file, readRange)
137
+ if (!buffer) break
138
+ buffers.set(buffer, offset)
139
+ offset += buffer.length
140
+ file = this.nextFile(file)
141
+ }
142
+ if (!buffers.length || offset !== readRange.length * 80) return undefined
143
+ this.nextHeight = lastHeight + 1
144
+ return buffers
145
+ }
146
+
147
+ /**
148
+ * Reset the reading process and adjust the range to be read to a new subset of what's available...
149
+ * @param range new range for subsequent `read` calls to return.
150
+ * @param maxBufferSize optionally update largest buffer size for `read` to return
151
+ */
152
+ resetRange(range: HeightRange, maxBufferSize?: number) {
153
+ this.setRange(range)
154
+ this.setMaxBufferSize(maxBufferSize || 400 * 80)
155
+ }
156
+
157
+ async validateFiles(): Promise<void> {
158
+ let lastChainWork: string | undefined = '00'.repeat(32)
159
+ let lastHeaderHash = '00'.repeat(32)
160
+ for (const file of this.files) {
161
+ if (file.prevChainWork !== lastChainWork)
162
+ throw new WERR_INVALID_OPERATION(
163
+ `prevChainWork mismatch for file ${file.fileName}: expected ${file.prevChainWork}, got ${lastChainWork}`
164
+ )
165
+ if (file.prevHash !== lastHeaderHash)
166
+ throw new WERR_INVALID_OPERATION(
167
+ `prevHash mismatch for file ${file.fileName}: expected ${file.prevHash}, got ${lastHeaderHash}`
168
+ )
169
+ const data = await file.ensureData()
170
+ if (data.length !== file.count * 80)
171
+ throw new WERR_INVALID_OPERATION(
172
+ `data length mismatch for file ${file.fileName}: expected ${file.count * 80} bytes, got ${data.length} bytes`
173
+ )
174
+ const fileHash = await file.computeFileHash()
175
+ if (!file.fileHash) throw new WERR_INVALID_OPERATION(`fileHash missing for file ${file.fileName}`)
176
+ if (file.fileHash !== fileHash)
177
+ throw new WERR_INVALID_OPERATION(
178
+ `fileHash mismatch for file ${file.fileName}: expected ${file.fileHash}, got ${fileHash}`
179
+ )
180
+ ;({ lastHeaderHash, lastChainWork } = validateBufferOfHeaders(data, lastHeaderHash, 0, file.count, lastChainWork))
181
+
182
+ if (file.lastHash !== lastHeaderHash)
183
+ throw new WERR_INVALID_OPERATION(
184
+ `lastHash mismatch for file ${file.fileName}: expected ${file.lastHash}, got ${lastHeaderHash}`
185
+ )
186
+ if (file.lastChainWork !== lastChainWork)
187
+ throw new WERR_INVALID_OPERATION(
188
+ `lastChainWork mismatch for file ${file.fileName}: expected ${file.lastChainWork}, got ${lastChainWork}`
189
+ )
190
+
191
+ file.validated = true
192
+ }
193
+ }
194
+
195
+ async exportHeadersToFs(toFs: ChaintracksFsApi, toHeadersPerFile: number, toFolder: string): Promise<void> {
196
+ if (!this.files || this.files.length === 0 || this.files[0].count === 0)
197
+ throw new WERR_INVALID_OPERATION('no headers currently available to export')
198
+ if (!this.files[0].chain) throw new WERR_INVALID_OPERATION('chain is not defined for the first file')
199
+
200
+ const chain = this.files[0].chain
201
+ const toFileName = (i: number) => `${chain}Net_${i}.headers`
202
+ const toPath = (i: number) => toFs.pathJoin(toFolder, toFileName(i))
203
+ const toJsonPath = () => toFs.pathJoin(toFolder, `${chain}NetBlockHeaders.json`)
204
+
205
+ const toBulkFiles: BulkHeaderFilesInfo = {
206
+ rootFolder: toFolder,
207
+ jsonFilename: `${chain}NetBlockHeaders.json`,
208
+ headersPerFile: toHeadersPerFile,
209
+ files: []
210
+ }
211
+
212
+ const bf0 = this.files[0]
213
+
214
+ let firstHeight = bf0.firstHeight
215
+ let lastHeaderHash = bf0.prevHash
216
+ let lastChainWork = bf0.prevChainWork!
217
+
218
+ const reader = new BulkFilesReader(this.files, this.heightRange, toHeadersPerFile * 80)
219
+
220
+ let i = -1
221
+ for (;;) {
222
+ i++
223
+ const data = await reader.read()
224
+ if (!data || data.length === 0) {
225
+ break
226
+ }
227
+
228
+ const last = validateBufferOfHeaders(data, lastHeaderHash, 0, undefined, lastChainWork)
229
+
230
+ await toFs.writeFile(toPath(i), data)
231
+
232
+ const fileHash = asString(Hash.sha256(asArray(data)), 'base64')
233
+ const file: BulkHeaderFileInfo = {
234
+ chain,
235
+ count: data.length / 80,
236
+ fileHash,
237
+ fileName: toFileName(i),
238
+ firstHeight,
239
+ lastChainWork: last.lastChainWork!,
240
+ lastHash: last.lastHeaderHash,
241
+ prevChainWork: lastChainWork,
242
+ prevHash: lastHeaderHash
243
+ }
244
+ toBulkFiles.files.push(file)
245
+ firstHeight += file.count
246
+ lastHeaderHash = file.lastHash!
247
+ lastChainWork = file.lastChainWork!
248
+ }
249
+
250
+ await toFs.writeFile(toJsonPath(), asUint8Array(JSON.stringify(toBulkFiles), 'utf8'))
251
+ }
252
+ }
253
+
254
+ export class BulkFilesReaderFs extends BulkFilesReader {
255
+ constructor(
256
+ public fs: ChaintracksFsApi,
257
+ files: BulkHeaderFileFs[],
258
+ range?: HeightRange,
259
+ maxBufferSize?: number
260
+ ) {
261
+ super(files, range, maxBufferSize)
262
+ }
263
+
264
+ /**
265
+ * Return a BulkFilesReader configured to access the intersection of `range` and available headers.
266
+ * @param rootFolder
267
+ * @param jsonFilename
268
+ * @param range
269
+ * @returns
270
+ */
271
+ static async fromFs(
272
+ fs: ChaintracksFsApi,
273
+ rootFolder: string,
274
+ jsonFilename: string,
275
+ range?: HeightRange,
276
+ maxBufferSize?: number
277
+ ): Promise<BulkFilesReaderFs> {
278
+ const filesInfo = await this.readJsonFile(fs, rootFolder, jsonFilename)
279
+ const readerFiles = filesInfo.files.map(file => new BulkHeaderFileFs(file, fs, rootFolder))
280
+ return new BulkFilesReaderFs(fs, readerFiles, range, maxBufferSize)
281
+ }
282
+
283
+ static async writeEmptyJsonFile(fs: ChaintracksFsApi, rootFolder: string, jsonFilename: string): Promise<string> {
284
+ const json = JSON.stringify({ files: [], rootFolder })
285
+ await fs.writeFile(fs.pathJoin(rootFolder, jsonFilename), asUint8Array(json, 'utf8'))
286
+ return json
287
+ }
288
+
289
+ static async readJsonFile(
290
+ fs: ChaintracksFsApi,
291
+ rootFolder: string,
292
+ jsonFilename: string,
293
+ failToEmptyRange: boolean = true
294
+ ): Promise<BulkHeaderFilesInfo> {
295
+ const filePath = (file: string) => fs.pathJoin(rootFolder, file)
296
+
297
+ const jsonPath = filePath(jsonFilename)
298
+
299
+ let json: string
300
+
301
+ try {
302
+ json = asString(await fs.readFile(jsonPath), 'utf8')
303
+ } catch (uerr: unknown) {
304
+ if (!failToEmptyRange)
305
+ throw new WERR_INVALID_PARAMETER(`${rootFolder}/${jsonFilename}`, `a valid, existing JSON file.`)
306
+ json = await this.writeEmptyJsonFile(fs, rootFolder, jsonFilename)
307
+ }
308
+
309
+ const readerFiles = <BulkHeaderFilesInfo>JSON.parse(json)
310
+ readerFiles.jsonFilename = jsonFilename
311
+ readerFiles.rootFolder = rootFolder
312
+ return readerFiles
313
+ }
314
+ }
315
+
316
+ export class BulkFilesReaderStorage extends BulkFilesReader {
317
+ constructor(
318
+ storage: ChaintracksStorageBase,
319
+ files: BulkHeaderFileStorage[],
320
+ range?: HeightRange,
321
+ maxBufferSize?: number
322
+ ) {
323
+ super(files, range, maxBufferSize)
324
+ }
325
+
326
+ static async fromStorage(
327
+ storage: ChaintracksStorageBase,
328
+ fetch?: ChaintracksFetchApi,
329
+ range?: HeightRange,
330
+ maxBufferSize?: number
331
+ ): Promise<BulkFilesReaderStorage> {
332
+ const files = await storage.bulkManager.getBulkFiles(true)
333
+ const readerFiles = files.map(file => new BulkHeaderFileStorage(file, storage, fetch))
334
+ return new BulkFilesReaderStorage(storage, readerFiles, range, maxBufferSize)
335
+ }
336
+ }
@@ -0,0 +1,247 @@
1
+ import { HeightRange } from './HeightRange'
2
+ import { ChaintracksFsApi } from '../Api/ChaintracksFsApi'
3
+ import { ChaintracksFetchApi } from '../Api/ChaintracksFetchApi'
4
+ import { ChaintracksStorageBase } from '../Storage/ChaintracksStorageBase'
5
+ import { Hash } from '@bsv/sdk'
6
+ import { Chain } from '../../../../sdk/types'
7
+ import { WERR_INVALID_OPERATION, WERR_INVALID_PARAMETER } from '../../../../sdk/WERR_errors'
8
+ import { asArray, asString } from '../../../../utility/utilityHelpers.noBuffer'
9
+
10
+ /**
11
+ * Descriptive information about a single bulk header file.
12
+ */
13
+ export interface BulkHeaderFileInfo {
14
+ /**
15
+ * filename and extension, no path
16
+ */
17
+ fileName: string
18
+ /**
19
+ * chain height of first header in file
20
+ */
21
+ firstHeight: number
22
+ /**
23
+ * count of how many headers the file contains. File size must be 80 * count.
24
+ */
25
+ count: number
26
+ /**
27
+ * prevChainWork is the cummulative chain work up to the first header in this file's data, as a hex string.
28
+ */
29
+ prevChainWork: string
30
+ /**
31
+ * lastChainWork is the cummulative chain work including the last header in this file's data, as a hex string.
32
+ */
33
+ lastChainWork: string
34
+ /**
35
+ * previousHash of first header in file in standard hex string block hash encoding
36
+ */
37
+ prevHash: string
38
+ /**
39
+ * block hash of last header in the file in standard hex string block hash encoding
40
+ */
41
+ lastHash: string | null
42
+ /**
43
+ * file contents single sha256 hash as base64 string
44
+ */
45
+ fileHash: string | null
46
+ /**
47
+ * Which chain: 'main' or 'test'
48
+ */
49
+ chain?: Chain
50
+
51
+ data?: Uint8Array // optional, used for validation
52
+
53
+ /**
54
+ * true iff these properties should be considered pre-validated, including a valid required fileHash of data (when not undefined).
55
+ */
56
+ validated?: boolean
57
+ /**
58
+ * optional, used for database storage
59
+ */
60
+ fileId?: number
61
+ /**
62
+ * optional, if valid `${sourceUrl}/${fileName}` is the source of this data.
63
+ */
64
+ sourceUrl?: string
65
+ }
66
+
67
+ export abstract class BulkHeaderFile implements BulkHeaderFileInfo {
68
+ chain?: Chain | undefined
69
+ count: number
70
+ data?: Uint8Array<ArrayBufferLike> | undefined
71
+ fileHash: string | null
72
+ fileId?: number | undefined
73
+ fileName: string
74
+ firstHeight: number
75
+ lastChainWork: string
76
+ lastHash: string | null
77
+ prevChainWork: string
78
+ prevHash: string
79
+ sourceUrl?: string | undefined
80
+ validated?: boolean | undefined
81
+
82
+ constructor(info: BulkHeaderFileInfo) {
83
+ this.chain = info.chain
84
+ this.count = info.count
85
+ this.data = info.data
86
+ this.fileHash = info.fileHash
87
+ this.fileId = info.fileId
88
+ this.fileName = info.fileName
89
+ this.firstHeight = info.firstHeight
90
+ this.lastChainWork = info.lastChainWork
91
+ this.lastHash = info.lastHash
92
+ this.prevChainWork = info.prevChainWork
93
+ this.prevHash = info.prevHash
94
+ this.sourceUrl = info.sourceUrl
95
+ this.validated = info.validated
96
+ }
97
+
98
+ abstract readDataFromFile(length: number, offset: number): Promise<Uint8Array | undefined>
99
+
100
+ get heightRange(): HeightRange {
101
+ return new HeightRange(this.firstHeight, this.firstHeight + this.count - 1)
102
+ }
103
+
104
+ async ensureData(): Promise<Uint8Array> {
105
+ if (!this.data) throw new WERR_INVALID_OPERATION(`data is undefined and no ensureData() override`)
106
+ return this.data
107
+ }
108
+
109
+ /**
110
+ * Whenever reloading data from a backing store, validated fileHash must be re-verified
111
+ * @returns the sha256 hash of the file's data as base64 string.
112
+ */
113
+ async computeFileHash(): Promise<string> {
114
+ if (!this.data) throw new WERR_INVALID_OPERATION(`requires defined data`)
115
+ return asString(Hash.sha256(asArray(this.data)), 'base64')
116
+ }
117
+
118
+ async releaseData(): Promise<void> {
119
+ this.data = undefined
120
+ }
121
+
122
+ toCdnInfo(): BulkHeaderFileInfo {
123
+ return {
124
+ count: this.count,
125
+ fileHash: this.fileHash,
126
+ fileName: this.fileName,
127
+ firstHeight: this.firstHeight,
128
+ lastChainWork: this.lastChainWork,
129
+ lastHash: this.lastHash,
130
+ prevChainWork: this.prevChainWork,
131
+ prevHash: this.prevHash
132
+ }
133
+ }
134
+
135
+ toStorageInfo(): BulkHeaderFileInfo {
136
+ return {
137
+ count: this.count,
138
+ fileHash: this.fileHash,
139
+ fileName: this.fileName,
140
+ firstHeight: this.firstHeight,
141
+ lastChainWork: this.lastChainWork,
142
+ lastHash: this.lastHash,
143
+ prevChainWork: this.prevChainWork,
144
+ prevHash: this.prevHash,
145
+ chain: this.chain,
146
+ validated: this.validated,
147
+ sourceUrl: this.sourceUrl,
148
+ fileId: this.fileId
149
+ }
150
+ }
151
+ }
152
+
153
+ export class BulkHeaderFileFs extends BulkHeaderFile {
154
+ constructor(
155
+ info: BulkHeaderFileInfo,
156
+ public fs: ChaintracksFsApi,
157
+ public rootFolder: string
158
+ ) {
159
+ super(info)
160
+ }
161
+
162
+ override async readDataFromFile(length: number, offset: number): Promise<Uint8Array | undefined> {
163
+ if (this.data) {
164
+ return this.data.slice(offset, offset + length)
165
+ }
166
+ const f = await this.fs.openReadableFile(this.fs.pathJoin(this.rootFolder, this.fileName))
167
+ try {
168
+ const buffer = await f.read(length, offset)
169
+ return buffer
170
+ } finally {
171
+ await f.close()
172
+ }
173
+ }
174
+
175
+ override async ensureData(): Promise<Uint8Array> {
176
+ if (this.data) return this.data
177
+ this.data = await this.readDataFromFile(this.count * 80, 0)
178
+ if (!this.data) throw new WERR_INVALID_OPERATION(`failed to read data for ${this.fileName}`)
179
+ if (this.validated) {
180
+ const hash = await this.computeFileHash()
181
+ if (hash !== this.fileHash)
182
+ throw new WERR_INVALID_OPERATION(`BACKING FILE DATA CORRUPTION: invalid fileHash for ${this.fileName}`)
183
+ }
184
+ return this.data
185
+ }
186
+ }
187
+
188
+ export class BulkHeaderFileStorage extends BulkHeaderFile {
189
+ constructor(
190
+ info: BulkHeaderFileInfo,
191
+ public storage: ChaintracksStorageBase,
192
+ public fetch?: ChaintracksFetchApi
193
+ ) {
194
+ super(info)
195
+ }
196
+
197
+ override async readDataFromFile(length: number, offset: number): Promise<Uint8Array | undefined> {
198
+ return (await this.ensureData()).slice(offset, offset + length)
199
+ }
200
+
201
+ override async ensureData(): Promise<Uint8Array> {
202
+ if (this.data) return this.data
203
+ if (!this.sourceUrl || !this.fetch) {
204
+ throw new WERR_INVALID_PARAMETER('sourceUrl and fetch', 'defined. Or data must be defined.')
205
+ }
206
+ const url = this.fetch.pathJoin(this.sourceUrl!, this.fileName)
207
+ this.data = await this.fetch.download(url)
208
+ if (!this.data) throw new WERR_INVALID_OPERATION(`failed to download data from ${url}`)
209
+ if (this.validated) {
210
+ const hash = await this.computeFileHash()
211
+ if (hash !== this.fileHash)
212
+ throw new WERR_INVALID_OPERATION(`BACKING DOWNLOAD DATA CORRUPTION: invalid fileHash for ${this.fileName}`)
213
+ }
214
+ return this.data
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Describes a collection of bulk block header files.
220
+ */
221
+ export interface BulkHeaderFilesInfo {
222
+ /**
223
+ * Where this file was fetched or read from.
224
+ */
225
+ rootFolder: string
226
+ /**
227
+ * Sub-path to this resource on rootFolder
228
+ */
229
+ jsonFilename: string
230
+ /**
231
+ * Array of information about each bulk block header file.
232
+ */
233
+ files: BulkHeaderFileInfo[]
234
+ /**
235
+ * Maximum number of headers in a single file in this collection of files.
236
+ */
237
+ headersPerFile: number
238
+ }
239
+
240
+ export abstract class BulkHeaderFiles implements BulkHeaderFilesInfo {
241
+ constructor(
242
+ public rootFolder: string,
243
+ public jsonFilename: string,
244
+ public files: BulkHeaderFileInfo[],
245
+ public headersPerFile: number
246
+ ) {}
247
+ }