@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,219 @@
1
+ import { Chain } from '../../../../sdk/types'
2
+ import { BlockHeader } from '../../../../sdk/WalletServices.interfaces'
3
+ import { WhatsOnChain, WocChainInfo } from '../../../providers/WhatsOnChain'
4
+ import { ChaintracksFetchApi } from '../Api/ChaintracksFetchApi'
5
+ import { ChaintracksFetch } from '../util/ChaintracksFetch'
6
+ import { HeightRange } from '../util/HeightRange'
7
+
8
+ /**
9
+ * return true to ignore error, false to close service connection
10
+ */
11
+ export type ErrorHandler = (code: number, message: string) => boolean
12
+ export type EnqueueHandler = (header: BlockHeader) => void
13
+
14
+ export interface WhatsOnChainServicesOptions {
15
+ /**
16
+ * Which chain is being tracked: main, test, or stn.
17
+ */
18
+ chain: Chain
19
+ /**
20
+ * WhatsOnChain.com API Key
21
+ * https://docs.taal.com/introduction/get-an-api-key
22
+ * If unknown or empty, maximum request rate is limited.
23
+ * https://developers.whatsonchain.com/#rate-limits
24
+ */
25
+ apiKey?: string
26
+ /**
27
+ * Request timeout for GETs to https://api.whatsonchain.com/v1/bsv
28
+ */
29
+ timeout: number
30
+ /**
31
+ * User-Agent header value for requests to https://api.whatsonchain.com/v1/bsv
32
+ */
33
+ userAgent: string
34
+ /**
35
+ * Enable WhatsOnChain client cache option.
36
+ */
37
+ enableCache: boolean
38
+ /**
39
+ * How long chainInfo is considered still valid before updating (msecs).
40
+ */
41
+ chainInfoMsecs: number
42
+ }
43
+
44
+ export class WhatsOnChainServices {
45
+ static createWhatsOnChainServicesOptions(chain: Chain): WhatsOnChainServicesOptions {
46
+ const options: WhatsOnChainServicesOptions = {
47
+ chain,
48
+ apiKey: '',
49
+ timeout: 30000,
50
+ userAgent: 'BabbageWhatsOnChainServices',
51
+ enableCache: true,
52
+ chainInfoMsecs: 5000
53
+ }
54
+ return options
55
+ }
56
+
57
+ static chainInfo: (WocChainInfo | undefined)[] = []
58
+ static chainInfoTime: (Date | undefined)[] = []
59
+ static chainInfoMsecs: number[] = []
60
+
61
+ chain: Chain
62
+ woc: WhatsOnChain
63
+
64
+ constructor(public options: WhatsOnChainServicesOptions) {
65
+ const config = {
66
+ apiKey: this.options.apiKey,
67
+ timeout: this.options.timeout,
68
+ userAgent: this.options.userAgent,
69
+ enableCache: this.options.enableCache
70
+ }
71
+ this.chain = options.chain
72
+ WhatsOnChainServices.chainInfoMsecs[this.chain] = options.chainInfoMsecs
73
+ this.woc = new WhatsOnChain(this.chain, config)
74
+ }
75
+
76
+ async getHeaderByHash(hash: string): Promise<BlockHeader | undefined> {
77
+ const header = await this.woc.getBlockHeaderByHash(hash)
78
+ return header
79
+ }
80
+
81
+ async getChainInfo(): Promise<WocChainInfo> {
82
+ const now = new Date()
83
+ let update = WhatsOnChainServices.chainInfo[this.chain] === undefined
84
+ if (!update && WhatsOnChainServices.chainInfoTime[this.chain] !== undefined) {
85
+ const elapsed = now.getTime() - WhatsOnChainServices.chainInfoTime[this.chain].getTime()
86
+ update = elapsed > WhatsOnChainServices.chainInfoMsecs[this.chain]
87
+ }
88
+ if (update) {
89
+ WhatsOnChainServices.chainInfo[this.chain] = await this.woc.getChainInfo()
90
+ WhatsOnChainServices.chainInfoTime[this.chain] = now
91
+ }
92
+ if (!WhatsOnChainServices.chainInfo[this.chain]) throw new Error('Unexpected failure to update chainInfo.')
93
+ return WhatsOnChainServices.chainInfo[this.chain]
94
+ }
95
+
96
+ async getChainTipHeight(): Promise<number> {
97
+ return (await this.getChainInfo()).blocks
98
+ }
99
+
100
+ async getChainTipHash(): Promise<string> {
101
+ return (await this.getChainInfo()).bestblockhash
102
+ }
103
+
104
+ /**
105
+ * @param fetch
106
+ * @returns returns the last 10 block headers including height, size, chainwork...
107
+ */
108
+ async getHeaders(fetch?: ChaintracksFetchApi): Promise<WocGetHeadersHeader[]> {
109
+ fetch ||= new ChaintracksFetch()
110
+ const headers = await fetch.fetchJson<WocGetHeadersHeader[]>(
111
+ `https://api.whatsonchain.com/v1/bsv/${this.chain}/block/headers`
112
+ )
113
+ return headers
114
+ }
115
+
116
+ async getHeaderByteFileLinks(
117
+ neededRange: HeightRange,
118
+ fetch?: ChaintracksFetchApi
119
+ ): Promise<GetHeaderByteFileLinksResult[]> {
120
+ fetch ||= new ChaintracksFetch()
121
+ const files = await fetch.fetchJson<WocGetHeaderByteFileLinks>(
122
+ `https://api.whatsonchain.com/v1/bsv/${this.chain}/block/headers/resources`
123
+ )
124
+ const r: GetHeaderByteFileLinksResult[] = []
125
+ let range: HeightRange | undefined = undefined
126
+ for (const link of files.files) {
127
+ const parsed = parseFileLink(link)
128
+ if (parsed === undefined) continue // parse error, return empty result
129
+ if (parsed.range === 'latest') {
130
+ if (range === undefined) continue // should not happen on valid input
131
+ const fromHeight = range.maxHeight + 1
132
+ if (neededRange.maxHeight >= fromHeight) {
133
+ // We need this range but don't know maxHeight
134
+ const data = await fetch.download(link)
135
+ range = new HeightRange(fromHeight, fromHeight + data.length / 80 - 1)
136
+ if (!neededRange.intersect(range).isEmpty)
137
+ r.push({ sourceUrl: parsed.sourceUrl, fileName: parsed.fileName, range, data })
138
+ }
139
+ } else {
140
+ range = new HeightRange(parsed.range.fromHeight, parsed.range.toHeight)
141
+ if (!neededRange.intersect(range).isEmpty)
142
+ r.push({ sourceUrl: parsed.sourceUrl, fileName: parsed.fileName, range, data: undefined })
143
+ }
144
+ }
145
+ return r
146
+
147
+ function parseFileLink(
148
+ file: string
149
+ ): { range: { fromHeight: number; toHeight: number } | 'latest'; sourceUrl: string; fileName: string } | undefined {
150
+ const url = new URL(file)
151
+ const parts = url.pathname.split('/')
152
+ const fileName = parts.pop()
153
+ if (!fileName) return undefined // no file name, invalid link
154
+ const sourceUrl = `${url.protocol}//${url.hostname}${parts.join('/')}`
155
+ const bits = fileName.split('_')
156
+ if (bits.length === 1 && bits[0] === 'latest') {
157
+ return { range: 'latest', sourceUrl, fileName }
158
+ }
159
+ if (bits.length === 3) {
160
+ const fromHeight = parseInt(bits[0], 10)
161
+ const toHeight = parseInt(bits[1], 10)
162
+ if (Number.isInteger(fromHeight) && Number.isInteger(toHeight)) {
163
+ return { range: { fromHeight, toHeight }, sourceUrl, fileName }
164
+ }
165
+ }
166
+ return undefined
167
+ }
168
+ }
169
+ }
170
+
171
+ export interface WocGetHeaderByteFileLinks {
172
+ files: string[]
173
+ }
174
+
175
+ export interface WocGetHeadersHeader {
176
+ hash: string
177
+ confirmations: number
178
+ size: number
179
+ height: number
180
+ version: number
181
+ versionHex: string
182
+ merkleroot: string
183
+ time: number
184
+ mediantime: number
185
+ nonce: number
186
+ bits: string
187
+ difficulty: number
188
+ chainwork: string
189
+ previousblockhash: string
190
+ nextblockhash: string
191
+ nTx: number
192
+ num_tx: number
193
+ }
194
+
195
+ export function wocGetHeadersHeaderToBlockHeader(h: WocGetHeadersHeader): BlockHeader {
196
+ const bits: number = typeof h.bits === 'string' ? parseInt(h.bits, 16) : h.bits
197
+ if (!h.previousblockhash) {
198
+ h.previousblockhash = '0000000000000000000000000000000000000000000000000000000000000000' // genesis
199
+ }
200
+ const bh: BlockHeader = {
201
+ height: h.height,
202
+ hash: h.hash,
203
+ version: h.version,
204
+ previousHash: h.previousblockhash,
205
+ merkleRoot: h.merkleroot,
206
+ time: h.time,
207
+ bits,
208
+ nonce: h.nonce
209
+ }
210
+
211
+ return bh
212
+ }
213
+
214
+ export interface GetHeaderByteFileLinksResult {
215
+ sourceUrl: string
216
+ fileName: string
217
+ range: HeightRange
218
+ data: Uint8Array | undefined
219
+ }
@@ -0,0 +1,54 @@
1
+ import { Knex, knex as makeKnex } from 'knex'
2
+ import { Chain } from '../../../../../sdk'
3
+ import { BulkIngestorCDNBabbage } from '../BulkIngestorCDNBabbage'
4
+ import { ChaintracksFetch } from '../../util/ChaintracksFetch'
5
+ import { ChaintracksFs } from '../../util/ChaintracksFs'
6
+ import { HeightRange } from '../../util/HeightRange'
7
+ import { ChaintracksStorageKnex } from '../../Storage/ChaintracksStorageKnex'
8
+ import { BulkFilesReaderStorage } from '../../util/BulkFilesReader'
9
+
10
+ const rootFolder = './src/services/chaintracker/chaintracks/__tests/data'
11
+ const fs = ChaintracksFs
12
+ const fetch = new ChaintracksFetch()
13
+
14
+ describe('BulkIngestorCDNBabbage tests', () => {
15
+ jest.setTimeout(99999999)
16
+
17
+ test('0 mainNet', async () => {
18
+ const { cdn, r } = await testUpdateLocalCache('main', '0')
19
+ expect(cdn.availableBulkFiles?.files.length).toBeGreaterThan(8)
20
+ expect(r.liveHeaders.length).toBe(0)
21
+ expect(r.reader.range.minHeight).toBe(0)
22
+ expect(r.reader.range.maxHeight).toBeGreaterThan(800000)
23
+ })
24
+
25
+ test('1 testNet', async () => {
26
+ const { cdn, r } = await testUpdateLocalCache('test', '1')
27
+ expect(cdn.availableBulkFiles?.files.length).toBeGreaterThan(15)
28
+ expect(r.liveHeaders.length).toBe(0)
29
+ expect(r.reader.range.minHeight).toBe(0)
30
+ expect(r.reader.range.maxHeight).toBeGreaterThan(1500000)
31
+ })
32
+ })
33
+
34
+ async function testUpdateLocalCache(chain: Chain, test: string) {
35
+ const bulkCDNOptions = BulkIngestorCDNBabbage.createBulkIngestorCDNBabbageOptions(chain, fetch)
36
+
37
+ const cdn = new BulkIngestorCDNBabbage(bulkCDNOptions)
38
+
39
+ const localSqlite: Knex.Config = {
40
+ client: 'sqlite3',
41
+ connection: { filename: fs.pathJoin(rootFolder, `BulkIngestorCDNBabbage.test_${test}.sqlite`) },
42
+ useNullAsDefault: true
43
+ }
44
+ const knexOptions = ChaintracksStorageKnex.createStorageKnexOptions(chain, makeKnex(localSqlite))
45
+ const storage = new ChaintracksStorageKnex(knexOptions)
46
+ const before = await storage.getAvailableHeightRanges()
47
+ await cdn.setStorage(storage, console.log)
48
+
49
+ const range = new HeightRange(0, 9900000)
50
+ const liveHeaders = await cdn.fetchHeaders(before, range, range, [])
51
+ const reader = await BulkFilesReaderStorage.fromStorage(storage, fetch, range)
52
+ await storage.knex.destroy()
53
+ return { cdn, r: { reader, liveHeaders } }
54
+ }
@@ -0,0 +1,33 @@
1
+ import { wait } from '../../../../../utility/utilityHelpers'
2
+ import { BlockHeader } from '../../Api/BlockHeaderApi'
3
+ import { LiveIngestorWhatsOnChainPoll } from '../LiveIngestorWhatsOnChainPoll'
4
+
5
+ describe('LiveIngestorWhatsOnChainPoll tests', () => {
6
+ jest.setTimeout(99999999)
7
+
8
+ test('0 listen for first new header', async () => {
9
+ const liveHeaders: BlockHeader[] = []
10
+ const options = LiveIngestorWhatsOnChainPoll.createLiveIngestorWhatsOnChainOptions('main')
11
+ const ingestor = new LiveIngestorWhatsOnChainPoll(options)
12
+ const p = ingestor.startListening(liveHeaders)
13
+ let log = ''
14
+ let count = 0
15
+ for (;;) {
16
+ const h = liveHeaders.shift()
17
+ if (h) {
18
+ log += `${h.height} ${h.hash}\n`
19
+ count++
20
+ } else {
21
+ if (log) {
22
+ console.log(`LiveIngestorWhatsOnChain received ${count} headers:\n${log}`)
23
+ log = ''
24
+ break
25
+ }
26
+ //if (count >= 11) break
27
+ await wait(100)
28
+ }
29
+ }
30
+ ingestor.stopListening()
31
+ await p
32
+ })
33
+ })
@@ -0,0 +1,124 @@
1
+ import { wait } from '../../../../../utility/utilityHelpers'
2
+ import { BlockHeader } from '../../Api/BlockHeaderApi'
3
+ import { deserializeBaseBlockHeader, deserializeBlockHeader } from '../../util/blockHeaderUtilities'
4
+ import { ChaintracksFetch } from '../../util/ChaintracksFetch'
5
+ import { ChaintracksFs } from '../../util/ChaintracksFs'
6
+ import { EnqueueHandler, ErrorHandler, WhatsOnChainServices, WocGetHeadersHeader } from '../WhatsOnChainServices'
7
+ import { StopListenerToken, WocHeadersBulkListener, WocHeadersLiveListener } from '../WhatsOnChainIngestorWs'
8
+ import { Chain } from '../../../../../sdk'
9
+ import { URL } from 'url'
10
+ import { HeightRange } from '../../util/HeightRange'
11
+
12
+ describe('WhatsOnChainServices tests', () => {
13
+ jest.setTimeout(999999999)
14
+
15
+ const chain: Chain = 'main'
16
+ const options = WhatsOnChainServices.createWhatsOnChainServicesOptions(chain)
17
+ const woc = new WhatsOnChainServices(options)
18
+
19
+ test('getHeaderByHash', async () => {
20
+ const header = await woc.getHeaderByHash('000000000000000001b3e99847d57ff3e0bfc4222cea5c29f10bf24387a250a2')
21
+ expect(header?.height === 781348).toBe(true)
22
+ })
23
+
24
+ test('getChainTipHeight', async () => {
25
+ const height = await woc.getChainTipHeight()
26
+ expect(height > 600000).toBe(true)
27
+ })
28
+
29
+ const stopOldListenersToken: StopListenerToken = { stop: undefined }
30
+ function stopOldListener() {
31
+ stopOldListenersToken.stop?.()
32
+ }
33
+
34
+ test.skip('0 listenForOldBlockHeaders', async () => {
35
+ // The service this depends on appears to be deprecated...
36
+ const height = await woc.getChainTipHeight()
37
+ expect(height > 600000).toBe(true)
38
+
39
+ const headersOld: BlockHeader[] = []
40
+ const errorsOld: { code: number; message: string }[] = []
41
+ const okOld = await WocHeadersBulkListener(
42
+ height - 4,
43
+ height,
44
+ h => headersOld.push(h),
45
+ (code, message) => {
46
+ errorsOld.push({ code, message })
47
+ return true
48
+ },
49
+ stopOldListenersToken,
50
+ chain
51
+ )
52
+ expect(okOld).toBe(true)
53
+ expect(errorsOld.length).toBe(0)
54
+ expect(headersOld.length >= 4).toBe(true)
55
+ })
56
+
57
+ const stopNewListenersToken: StopListenerToken = { stop: undefined }
58
+
59
+ test.skip('1 listenForNewBlockHeaders', async () => {
60
+ // The service this depends on appears to be deprecated...
61
+ const height = await woc.getChainTipHeight()
62
+ expect(height > 600000).toBe(true)
63
+
64
+ // Comment out this line to just wait for next new header...
65
+ //setTimeout(() => woc.stopNewListener(), 5000)
66
+ const headersNew: BlockHeader[] = []
67
+ const errorsNew: { code: number; message: string }[] = []
68
+ const eh: EnqueueHandler = h => {
69
+ headersNew.push(h)
70
+ if (headersNew.length >= 1) stopNewListenersToken.stop?.()
71
+ }
72
+ const errh: ErrorHandler = (code, message) => {
73
+ errorsNew.push({ code, message })
74
+ return true
75
+ }
76
+ const okNew = await WocHeadersLiveListener(eh, errh, stopNewListenersToken, chain, console.log.bind(console))
77
+ if (errorsNew.length > 0) console.log(JSON.stringify(errorsNew))
78
+ expect(errorsNew.length).toBe(0)
79
+ expect(okNew).toBe(true)
80
+ expect(headersNew.length >= 0).toBe(true)
81
+ })
82
+
83
+ test('2 get latest header bytes', async () => {
84
+ const fetch = new ChaintracksFetch()
85
+
86
+ //for (;;) {
87
+ const bytes = await fetch.download(`https://api.whatsonchain.com/v1/bsv/main/block/headers/latest`)
88
+ console.log(`headers: ${bytes.length / 80}`)
89
+ const latest = await fetch.download(`https://api.whatsonchain.com/v1/bsv/main/block/headers/latest?count=1`)
90
+ const bh = deserializeBlockHeader(latest, 0, 0)
91
+ console.log(`latest hash: ${bh.hash} at ${new Date().toISOString()}`)
92
+ // await wait(60 * 1000)
93
+ //}
94
+ })
95
+
96
+ test('3 get headers', async () => {
97
+ const fetch = new ChaintracksFetch()
98
+
99
+ //for (;;) {
100
+ const headers = await fetch.fetchJson<WocGetHeadersHeader[]>(
101
+ `https://api.whatsonchain.com/v1/bsv/main/block/headers`
102
+ )
103
+ let log = ''
104
+ for (const h of headers) {
105
+ log += `${h.height} ${h.hash} ${h.confirmations} ${h.nTx}\n`
106
+ }
107
+ console.log(`${new Date().toISOString()}\n${log}`)
108
+ //await wait(60 * 1000)
109
+ //}
110
+ })
111
+
112
+ test('4 get header byte file links', async () => {
113
+ const fetch = new ChaintracksFetch()
114
+ const woc = new WhatsOnChainServices(WhatsOnChainServices.createWhatsOnChainServicesOptions('main'))
115
+ const files = await woc.getHeaderByteFileLinks(new HeightRange(907123, 911000))
116
+ expect(files.length).toBe(3)
117
+ expect(files[0].range.minHeight).toBe(906001)
118
+ expect(files[0].range.maxHeight).toBe(908000)
119
+ expect(files[1].range.minHeight).toBe(908001)
120
+ expect(files[1].range.maxHeight).toBe(910000)
121
+ expect(files[2].range.minHeight).toBe(910001)
122
+ expect(files[2].range.maxHeight).toBeGreaterThan(910001)
123
+ })
124
+ })
@@ -0,0 +1,92 @@
1
+ // /* eslint-disable @typescript-eslint/no-empty-function */
2
+ /* eslint-disable @typescript-eslint/no-unused-vars */
3
+ import { BulkStorageApi, BulkStorageBaseOptions } from '../Api/BulkStorageApi'
4
+
5
+ import { ChaintracksStorageBase } from './ChaintracksStorageBase'
6
+
7
+ import { HeightRange } from '../util/HeightRange'
8
+ import { BulkFilesReader } from '../util/BulkFilesReader'
9
+ import { BulkHeaderFileInfo } from '../util/BulkHeaderFile'
10
+ import { BulkHeaderFilesInfo } from '../util/BulkHeaderFile'
11
+
12
+ import { addWork, convertBitsToWork, deserializeBlockHeaders, genesisBuffer } from '../util/blockHeaderUtilities'
13
+ import { Chain } from '../../../../sdk/types'
14
+ import { BlockHeader, LiveBlockHeader } from '../Api/BlockHeaderApi'
15
+ import { ChaintracksFsApi } from '../Api/ChaintracksFsApi'
16
+ import { Utils } from '@bsv/sdk'
17
+ import { asUint8Array } from '../../../../utility/utilityHelpers.noBuffer'
18
+
19
+ export abstract class BulkStorageBase implements BulkStorageApi {
20
+ static createBulkStorageBaseOptions(chain: Chain, fs: ChaintracksFsApi): BulkStorageBaseOptions {
21
+ const options: BulkStorageBaseOptions = {
22
+ chain,
23
+ fs
24
+ }
25
+ return options
26
+ }
27
+
28
+ chain: Chain
29
+ fs: ChaintracksFsApi
30
+ log: (...args: any[]) => void = () => {}
31
+
32
+ constructor(options: BulkStorageBaseOptions) {
33
+ this.chain = options.chain
34
+ this.fs = options.fs
35
+ }
36
+
37
+ async shutdown(): Promise<void> {}
38
+
39
+ abstract appendHeaders(minHeight: number, count: number, newBulkHeaders: Uint8Array): Promise<void>
40
+ abstract getMaxHeight(): Promise<number>
41
+ abstract headersToBuffer(height: number, count: number): Promise<Uint8Array>
42
+ abstract findHeaderForHeightOrUndefined(height: number): Promise<BlockHeader | undefined>
43
+
44
+ async findHeaderForHeight(height: number): Promise<BlockHeader> {
45
+ const header = await this.findHeaderForHeightOrUndefined(height)
46
+ if (!header) throw new Error(`No header found for height ${height}`)
47
+ return header
48
+ }
49
+
50
+ async getHeightRange(): Promise<HeightRange> {
51
+ return new HeightRange(0, await this.getMaxHeight())
52
+ }
53
+
54
+ async setStorage(storage: ChaintracksStorageBase, log: (...args: any[]) => void): Promise<void> {}
55
+
56
+ async exportBulkHeaders(rootFolder: string, jsonFilename: string, maxPerFile: number): Promise<void> {
57
+ const info: BulkHeaderFilesInfo = {
58
+ rootFolder: rootFolder,
59
+ jsonFilename: jsonFilename,
60
+ files: [],
61
+ headersPerFile: maxPerFile
62
+ }
63
+ const maxHeight = await this.getMaxHeight()
64
+ const baseFilename = jsonFilename.slice(0, -5) // remove ".json"
65
+ let prevHash = '00'.repeat(32)
66
+ let prevChainWork = '00'.repeat(32)
67
+ for (let height = 0; height <= maxHeight; height += maxPerFile) {
68
+ const count = Math.min(maxPerFile, maxHeight - height + 1)
69
+ let file: BulkHeaderFileInfo = {
70
+ fileName: `${baseFilename}_${info.files.length}.headers`,
71
+ firstHeight: height,
72
+ prevHash: prevHash,
73
+ prevChainWork: prevChainWork,
74
+ count: count,
75
+ lastHash: null,
76
+ fileHash: null,
77
+ lastChainWork: ''
78
+ }
79
+ const buffer = await this.headersToBuffer(height, count)
80
+ await this.fs.writeFile(this.fs.pathJoin(rootFolder, file.fileName), buffer)
81
+ /*
82
+ file = await BulkFilesReader.validateHeaderFile(this.fs, rootFolder, file)
83
+ if (!file.lastHash) throw new Error('Unexpected result.')
84
+ prevHash = file.lastHash
85
+ prevChainWork = file.lastChainWork
86
+ info.files.push(file)
87
+ */
88
+ }
89
+ const bytes = asUint8Array(JSON.stringify(info), 'utf8')
90
+ await this.fs.writeFile(this.fs.pathJoin(rootFolder, jsonFilename), bytes)
91
+ }
92
+ }
@@ -0,0 +1,104 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { Knex } from 'knex'
3
+ import { Chain } from '../../../../sdk'
4
+
5
+ interface Migration {
6
+ up: (knex: Knex) => PromiseLike<any>
7
+ down?: (knex: Knex) => PromiseLike<any>
8
+ }
9
+
10
+ interface MigrationSource<TMigrationSpec> {
11
+ getMigrations(loadExtensions: readonly string[]): Promise<TMigrationSpec[]>
12
+ getMigrationName(migration: TMigrationSpec): string
13
+ getMigration(migration: TMigrationSpec): Promise<Migration>
14
+ }
15
+
16
+ export class ChaintracksKnexMigrations implements MigrationSource<string> {
17
+ migrations: Record<string, Migration> = {}
18
+
19
+ constructor(public chain: Chain) {
20
+ this.migrations = this.setupMigrations()
21
+ }
22
+
23
+ async getMigrations(): Promise<string[]> {
24
+ return Object.keys(this.migrations).sort()
25
+ }
26
+
27
+ getMigrationName(migration: string) {
28
+ return migration
29
+ }
30
+
31
+ async getMigration(migration: string): Promise<Migration> {
32
+ return this.migrations[migration]
33
+ }
34
+
35
+ async getLatestMigration(): Promise<string> {
36
+ const ms = await this.getMigrations()
37
+ return ms[ms.length - 1]
38
+ }
39
+
40
+ static async latestMigration(): Promise<string> {
41
+ const km = new ChaintracksKnexMigrations('test')
42
+ return await km.getLatestMigration()
43
+ }
44
+
45
+ setupMigrations(): Record<string, Migration> {
46
+ const migrations: Record<string, Migration> = {}
47
+
48
+ const liveHeadersTableName = `live_headers`
49
+ const bulkFilesTableName = `bulk_files`
50
+
51
+ migrations['2025-06-28-001 initial migration'] = {
52
+ async up(knex) {
53
+ await knex.schema.createTable(liveHeadersTableName, table => {
54
+ table.increments('headerId')
55
+ table.integer('previousHeaderId').unsigned().references('headerId').inTable(liveHeadersTableName)
56
+ table.binary('previousHash', 32)
57
+ table.integer('height').unsigned().notNullable
58
+ table.boolean('isActive').notNullable
59
+ table.boolean('isChainTip').notNullable
60
+ table.binary('hash', 32).notNullable
61
+ table.binary('chainWork', 32).notNullable
62
+ table.integer('version').unsigned().notNullable
63
+ table.binary('merkleRoot', 32).notNullable
64
+ table.integer('time').unsigned().notNullable
65
+ table.integer('bits').unsigned().notNullable
66
+ table.integer('nonce').unsigned().notNullable
67
+
68
+ table.unique(['hash'])
69
+ table.index(['previousHeaderId'])
70
+ table.index(['height'])
71
+ table.index(['previousHash'])
72
+ table.index(['merkleRoot'])
73
+ table.index(['isChainTip'])
74
+ table.index(['isActive'])
75
+ table.index(['isActive', 'isChainTip'])
76
+ })
77
+
78
+ await knex.schema.createTable(bulkFilesTableName, table => {
79
+ table.increments('fileId')
80
+ table.string('chain').notNullable()
81
+ table.string('fileName').notNullable()
82
+ table.integer('firstHeight').unsigned().notNullable()
83
+ table.integer('count').unsigned().notNullable()
84
+ table.string('prevHash', 64).notNullable() // hex encoded
85
+ table.string('lastHash', 64).notNullable() // hex encoded
86
+ table.string('prevChainWork', 64).notNullable() // hex encoded
87
+ table.string('lastChainWork', 64).notNullable() // hex encoded
88
+ table.string('fileHash').notNullable() // base64 encoded
89
+ table.boolean('validated').defaultTo(false).notNullable()
90
+ table.string('sourceUrl').nullable()
91
+ table.binary('data', 32000000).nullable() // 32MB max size
92
+
93
+ table.index(['firstHeight', 'chain'])
94
+ })
95
+ },
96
+ async down(knex) {
97
+ await knex.schema.dropTable(liveHeadersTableName)
98
+ await knex.schema.dropTable(bulkFilesTableName)
99
+ }
100
+ }
101
+
102
+ return migrations
103
+ }
104
+ }