@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,199 @@
1
+ import { Chaintracks } from './Chaintracks'
2
+
3
+ import { IncomingMessage, Server, ServerResponse } from 'http'
4
+ import express, { Request, Response } from 'express'
5
+ import bodyParser from 'body-parser'
6
+ import { Chain } from '../../../sdk/types'
7
+ import { createDefaultNoDbChaintracksOptions } from './createDefaultNoDbChaintracksOptions'
8
+ import { Services } from '../../Services'
9
+ import { FiatExchangeRates, WERR_INVALID_PARAMETER } from '../../../sdk'
10
+ import { ChaintracksInfoApi } from './Api/ChaintracksClientApi'
11
+ import { wait } from '../../../utility/utilityHelpers'
12
+ import { BaseBlockHeader, BlockHeader } from './Api/BlockHeaderApi'
13
+
14
+ export interface ChaintracksServiceOptions {
15
+ chain: Chain
16
+ /**
17
+ * prepended to the path of each registered service endpoint
18
+ */
19
+ routingPrefix: string
20
+ /**
21
+ * Defaults to default configured Chaintracks instance with NoDb storage.
22
+ */
23
+ chaintracks?: Chaintracks
24
+ services?: Services
25
+ port?: number
26
+ }
27
+
28
+ export class ChaintracksService {
29
+ static createChaintracksServiceOptions(chain: Chain): ChaintracksServiceOptions {
30
+ const options: ChaintracksServiceOptions = {
31
+ chain,
32
+ routingPrefix: ''
33
+ }
34
+ return options
35
+ }
36
+
37
+ chain: Chain
38
+ options: ChaintracksServiceOptions
39
+ port?: number
40
+ chaintracks: Chaintracks
41
+ services: Services
42
+ server?: Server<typeof IncomingMessage, typeof ServerResponse>
43
+
44
+ constructor(options: ChaintracksServiceOptions) {
45
+ this.options = { ...options }
46
+ this.port = options.port
47
+ this.chain = options.chain
48
+ this.chaintracks = options.chaintracks || new Chaintracks(createDefaultNoDbChaintracksOptions(this.chain))
49
+ this.services = options.services || new Services(this.chain)
50
+ // Prevent recursion...
51
+ this.services.updateFiatExchangeRateServices.remove('ChaintracksService')
52
+ if (this.chaintracks.chain !== this.chain || this.services.chain !== this.chain) {
53
+ throw new WERR_INVALID_PARAMETER(
54
+ 'chain',
55
+ `All components (chaintracks and services) must be on chain ${this.chain}`
56
+ )
57
+ }
58
+ }
59
+
60
+ async stopJsonRpcServer(): Promise<void> {
61
+ this.server?.close()
62
+ await this.chaintracks?.destroy()
63
+ }
64
+
65
+ async startJsonRpcServer(port?: number): Promise<void> {
66
+ await this.chaintracks.makeAvailable()
67
+
68
+ port ||= this.port || 3011
69
+ this.port = port
70
+
71
+ const app = express()
72
+ app.use(bodyParser.json())
73
+
74
+ // This allows the API to be used when CORS is enforced
75
+ app.use((req, res, next) => {
76
+ res.header('Access-Control-Allow-Origin', '*')
77
+ res.header('Access-Control-Allow-Headers', '*')
78
+ res.header('Access-Control-Allow-Methods', '*')
79
+ res.header('Access-Control-Expose-Headers', '*')
80
+ res.header('Access-Control-Allow-Private-Network', 'true')
81
+ if (req.method === 'OPTIONS') {
82
+ res.sendStatus(200)
83
+ } else {
84
+ next()
85
+ }
86
+ })
87
+
88
+ app.get(`/robots.txt`, (req: Request, res: Response) => {
89
+ res.type('text/plain')
90
+ res.send(`User-agent: *\nDisallow: /`)
91
+ })
92
+
93
+ app.get(`/`, (req: Request, res: Response) => {
94
+ res.type('text/plain')
95
+ res.send(`Chaintracks ${this.chain}Net Block Header Service`)
96
+ })
97
+
98
+ const handleErr = (err: any, res: any) => {
99
+ res.status(500).json({
100
+ status: 'error',
101
+ code: 'ERR_INTERNAL',
102
+ description: err?.message || 'An internal error has occurred.'
103
+ })
104
+ }
105
+
106
+ const appGetVoid = (path: string, action: (q: any) => Promise<void>, noCache = false) => {
107
+ app['get'](this.options.routingPrefix + path, async (req, res) => {
108
+ if (noCache) {
109
+ res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
110
+ res.setHeader('Pragma', 'no-cache')
111
+ res.setHeader('Expires', '0')
112
+ }
113
+ try {
114
+ console.log(`request ${path}`)
115
+ await action(req.query)
116
+ res.status(200).json({ status: 'success' })
117
+ } catch (err) {
118
+ handleErr(err, res)
119
+ }
120
+ })
121
+ }
122
+
123
+ const appGet = <T>(path: string, action: (q: any) => Promise<T>, noCache = false) => {
124
+ app['get'](this.options.routingPrefix + path, async (req, res) => {
125
+ if (noCache) {
126
+ res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
127
+ res.setHeader('Pragma', 'no-cache')
128
+ res.setHeader('Expires', '0')
129
+ }
130
+ try {
131
+ const r = await action(req.query)
132
+ console.log('request', path, JSON.stringify(req.query), '->', JSON.stringify(r))
133
+ res.status(200).json({ status: 'success', value: r })
134
+ } catch (err) {
135
+ console.log(`request ${path} -> error`)
136
+ handleErr(err, res)
137
+ }
138
+ })
139
+ }
140
+
141
+ const appPostVoid = <T>(path: string, action: (p: T) => Promise<void>) => {
142
+ app['post'](this.options.routingPrefix + path, async (req, res) => {
143
+ try {
144
+ console.log(`request POST ${path}`)
145
+ await action(<T>req.body)
146
+ res.status(200).json({ status: 'success' })
147
+ } catch (err) {
148
+ handleErr(err, res)
149
+ }
150
+ })
151
+ }
152
+
153
+ appGet<Chain>('/getChain', async () => await this.chaintracks.getChain())
154
+ appGet<ChaintracksInfoApi>(
155
+ '/getInfo',
156
+ async q => {
157
+ if (q.wait) await wait(Number(q.wait))
158
+ const r = await this.chaintracks.getInfo()
159
+ if (q.wait) r['wait'] = q.wait
160
+ return r
161
+ },
162
+ true
163
+ )
164
+
165
+ appGet<FiatExchangeRates>(
166
+ '/getFiatExchangeRates',
167
+ async () => {
168
+ // update if needed
169
+ await this.services.getFiatExchangeRate('GBP')
170
+ // return current values
171
+ return this.services.options.fiatExchangeRates
172
+ },
173
+ true
174
+ )
175
+
176
+ appPostVoid('/addHeaderHex', async (header: BaseBlockHeader) => {
177
+ await this.chaintracks.addHeader(header)
178
+ })
179
+
180
+ appGet<number>('/getPresentHeight', async () => await this.chaintracks.getPresentHeight(), true)
181
+ appGet<string>('/findChainTipHashHex', async () => (await this.chaintracks.findChainTipHash()) || '', true)
182
+ appGet<BlockHeader>('/findChainTipHeaderHex', async () => await this.chaintracks.findChainTipHeader(), true)
183
+
184
+ appGet<BlockHeader | undefined>('/findHeaderHexForHeight', async q => {
185
+ return await this.chaintracks.findHeaderForHeight(Number(q.height))
186
+ })
187
+ appGet<BlockHeader | undefined>('/findHeaderHexForBlockHash', async q => {
188
+ return await this.chaintracks.findLiveHeaderForBlockHash(q.hash)
189
+ })
190
+
191
+ appGet<string>('/getHeaders', async q => {
192
+ return await this.chaintracks.getHeaders(Number(q.height), Number(q.count))
193
+ })
194
+
195
+ this.server = app.listen(this.port, () => {
196
+ console.log(`ChaintracksService listening on port ${this.port}`)
197
+ })
198
+ }
199
+ }
@@ -0,0 +1,154 @@
1
+ import { Chain } from '../../../sdk/types'
2
+ import { asString } from '../../../utility/utilityHelpers.noBuffer'
3
+ import { BaseBlockHeader, BlockHeader } from './Api/BlockHeaderApi'
4
+ import { ChaintracksClientApi, ChaintracksInfoApi, HeaderListener, ReorgListener } from './Api/ChaintracksClientApi'
5
+
6
+ interface FetchStatus<T> {
7
+ status: 'success' | 'error'
8
+ code?: string
9
+ description?: string
10
+ value?: T
11
+ }
12
+
13
+ export interface ChaintracksServiceClientOptions {}
14
+
15
+ /**
16
+ * Connects to a ChaintracksService to implement 'ChaintracksClientApi'
17
+ *
18
+ */
19
+ export class ChaintracksServiceClient implements ChaintracksClientApi {
20
+ static createChaintracksServiceClientOptions(): ChaintracksServiceClientOptions {
21
+ const options: ChaintracksServiceClientOptions = {
22
+ useAuthrite: false
23
+ }
24
+ return options
25
+ }
26
+
27
+ options: ChaintracksServiceClientOptions
28
+
29
+ constructor(
30
+ public chain: Chain,
31
+ public serviceUrl: string,
32
+ options?: ChaintracksServiceClientOptions
33
+ ) {
34
+ this.options = options || ChaintracksServiceClient.createChaintracksServiceClientOptions()
35
+ }
36
+
37
+ subscribeHeaders(listener: HeaderListener): Promise<string> {
38
+ throw new Error('Method not implemented.')
39
+ }
40
+ subscribeReorgs(listener: ReorgListener): Promise<string> {
41
+ throw new Error('Method not implemented.')
42
+ }
43
+ unsubscribe(subscriptionId: string): Promise<boolean> {
44
+ throw new Error('Method not implemented.')
45
+ }
46
+
47
+ async currentHeight(): Promise<number> {
48
+ return await this.getPresentHeight()
49
+ }
50
+
51
+ async isValidRootForHeight(root: string, height: number): Promise<boolean> {
52
+ const r = await this.findHeaderForHeight(height)
53
+ if (!r) return false
54
+ const isValid = root === asString(r.merkleRoot)
55
+ return isValid
56
+ }
57
+
58
+ async getJsonOrUndefined<T>(path: string): Promise<T | undefined> {
59
+ let e: Error | undefined = undefined
60
+ for (let retry = 0; retry < 3; retry++) {
61
+ try {
62
+ const r = await fetch(`${this.serviceUrl}${path}`)
63
+ const v = <FetchStatus<T>>await r.json()
64
+ if (v.status === 'success') return v.value
65
+ else e = new Error(JSON.stringify(v))
66
+ } catch (eu: unknown) {
67
+ e = eu as Error
68
+ }
69
+ if (e && e.name !== 'ECONNRESET') break
70
+ }
71
+ if (e) throw e
72
+ }
73
+
74
+ async getJson<T>(path: string): Promise<T> {
75
+ const r = await this.getJsonOrUndefined<T>(path)
76
+ if (r === undefined) throw new Error('Value was undefined. Requested object may not exist.')
77
+ return r
78
+ }
79
+
80
+ async postJsonVoid<T>(path: string, params: T): Promise<void> {
81
+ const headers = {}
82
+ headers['Content-Type'] = 'application/json'
83
+ const r = await fetch(`${this.serviceUrl}${path}`, {
84
+ body: JSON.stringify(params),
85
+ method: 'POST',
86
+ headers
87
+ //cache: 'no-cache',
88
+ })
89
+ try {
90
+ const s = <FetchStatus<void>>await r.json()
91
+ if (s.status === 'success') return
92
+ throw new Error(JSON.stringify(s))
93
+ } catch (e) {
94
+ console.log(`Exception: ${JSON.stringify(e)}`)
95
+ throw new Error(JSON.stringify(e))
96
+ }
97
+ }
98
+
99
+ //
100
+ // HTTP API FUNCTIONS
101
+ //
102
+
103
+ async addHeader(header: BaseBlockHeader): Promise<void> {
104
+ const r = await this.postJsonVoid('/addHeaderHex', header)
105
+ if (typeof r === 'string') throw new Error(r)
106
+ }
107
+
108
+ async startListening(): Promise<void> {
109
+ await this.getPresentHeight()
110
+ }
111
+ async listening(): Promise<void> {
112
+ await this.getPresentHeight()
113
+ }
114
+ async getChain(): Promise<Chain> {
115
+ return this.chain
116
+ //return await this.getJson('/getChain')
117
+ }
118
+
119
+ async isListening(): Promise<boolean> {
120
+ try {
121
+ await this.getPresentHeight()
122
+ return true
123
+ } catch {
124
+ return false
125
+ }
126
+ }
127
+ async isSynchronized(): Promise<boolean> {
128
+ return await this.isListening()
129
+ }
130
+ async getPresentHeight(): Promise<number> {
131
+ return await this.getJson('/getPresentHeight')
132
+ }
133
+ async getInfo(): Promise<ChaintracksInfoApi> {
134
+ return await this.getJson('/getInfo')
135
+ }
136
+ async findChainTipHeader(): Promise<BlockHeader> {
137
+ return await this.getJson('/findChainTipHeaderHex')
138
+ }
139
+ async findChainTipHash(): Promise<string> {
140
+ return await this.getJson('/findChainTipHashHex')
141
+ }
142
+
143
+ async getHeaders(height: number, count: number): Promise<string> {
144
+ return await this.getJson<string>(`/getHeaders?height=${height}&count=${count}`)
145
+ }
146
+
147
+ async findHeaderForHeight(height: number): Promise<BlockHeader | undefined> {
148
+ return await this.getJsonOrUndefined(`/findHeaderHexForHeight?height=${height}`)
149
+ }
150
+
151
+ async findHeaderForBlockHash(hash: string): Promise<BlockHeader | undefined> {
152
+ return await this.getJsonOrUndefined(`/findHeaderHexForBlockHash?hash=${hash}`)
153
+ }
154
+ }
@@ -0,0 +1,176 @@
1
+ import { BulkIngestorApi, BulkIngestorBaseOptions, BulkSyncResult } from '../Api/BulkIngestorApi'
2
+ import { ChaintracksStorageApi } from '../Api/ChaintracksStorageApi'
3
+
4
+ import { BulkHeaderFilesInfo } from '../util/BulkHeaderFile'
5
+ import { HeightRange, HeightRanges } from '../util/HeightRange'
6
+ import { Chain } from '../../../../sdk/types'
7
+ import { BlockHeader } from '../Api/BlockHeaderApi'
8
+ import { ChaintracksStorageBase } from '../Storage/ChaintracksStorageBase'
9
+
10
+ export abstract class BulkIngestorBase implements BulkIngestorApi {
11
+ /**
12
+ *
13
+ * @param chain
14
+ * @param localCachePath defaults to './data/ingest_headers/'
15
+ * @returns
16
+ */
17
+ static createBulkIngestorBaseOptions(chain: Chain) {
18
+ const options: BulkIngestorBaseOptions = {
19
+ chain,
20
+ jsonResource: `${chain}NetBlockHeaders.json`
21
+ }
22
+ return options
23
+ }
24
+
25
+ chain: Chain
26
+ jsonFilename: string
27
+ log: (...args: any[]) => void = () => {}
28
+
29
+ constructor(options: BulkIngestorBaseOptions) {
30
+ if (!options.jsonResource) throw new Error('The jsonFilename options property is required.')
31
+ this.chain = options.chain
32
+ this.jsonFilename = options.jsonResource
33
+ }
34
+
35
+ private storageEngine: ChaintracksStorageBase | undefined
36
+
37
+ async setStorage(storage: ChaintracksStorageBase, log: (...args: any[]) => void): Promise<void> {
38
+ this.storageEngine = storage
39
+ this.log = log
40
+ }
41
+
42
+ async shutdown(): Promise<void> {}
43
+
44
+ storageOrUndefined(): ChaintracksStorageApi | undefined {
45
+ return this.storageEngine
46
+ }
47
+
48
+ storage(): ChaintracksStorageBase {
49
+ if (!this.storageEngine) throw new Error('storageEngine must be set.')
50
+ return this.storageEngine
51
+ }
52
+
53
+ /**
54
+ * information about locally cached bulk header files managed by this bulk ingestor
55
+ */
56
+ filesInfo: BulkHeaderFilesInfo | undefined
57
+
58
+ /**
59
+ * At least one derived BulkIngestor must override this method to provide the current height of the active chain tip.
60
+ * @returns undefined unless overridden
61
+ */
62
+ async getPresentHeight(): Promise<number | undefined> {
63
+ return undefined
64
+ }
65
+
66
+ /**
67
+ * A BulkIngestor fetches and updates storage with bulk headers in bulkRange.
68
+ *
69
+ * If it can, it must also fetch live headers in fetch range that are not in bulkRange and return them as an array.
70
+ *
71
+ * The storage methods `insertBulkFile`, `updateBulkFile`, and `addBulkHeaders` should be used to add bulk headers to storage.
72
+ *
73
+ * @param before bulk and live range of headers before ingesting any new headers.
74
+ * @param fetchRange range of headers still needed, includes both missing bulk and live headers.
75
+ * @param bulkRange range of bulk headers still needed
76
+ * @param priorLiveHeaders any headers accumulated by prior bulk ingestor(s) that are too recent for bulk storage.
77
+ * @returns new live headers: headers in fetchRange but not in bulkRange
78
+ */
79
+ abstract fetchHeaders(
80
+ before: HeightRanges,
81
+ fetchRange: HeightRange,
82
+ bulkRange: HeightRange,
83
+ priorLiveHeaders: BlockHeader[]
84
+ ): Promise<BlockHeader[]>
85
+
86
+ /**
87
+ * A BulkIngestor has two potential goals:
88
+ * 1. To source missing bulk headers and include them in bulk storage.
89
+ * 2. To source missing live headers to be forwarded to live storage.
90
+ *
91
+ * @param presentHeight current height of the active chain tip, may lag the true value.
92
+ * @param before current bulk and live storage height ranges, either may be empty.
93
+ * @param priorLiveHeaders any headers accumulated by prior bulk ingestor(s) that are too recent for bulk storage.
94
+ * @returns updated priorLiveHeaders including any accumulated by this ingestor
95
+ */
96
+ async synchronize(
97
+ presentHeight: number,
98
+ before: HeightRanges,
99
+ priorLiveHeaders: BlockHeader[]
100
+ ): Promise<BulkSyncResult> {
101
+ const storage = this.storage()
102
+
103
+ const r: BulkSyncResult = {
104
+ liveHeaders: priorLiveHeaders,
105
+ liveRange: HeightRange.from(priorLiveHeaders),
106
+ done: false,
107
+ log: ''
108
+ }
109
+
110
+ // Decisions to be made:
111
+ // Q1. Are we already done?
112
+ // Q2. Are there live headers that should be migrated to bulk?
113
+ // Q3. What range of headers do we still need to retrieve?
114
+
115
+ // Q1: We are done if we have enough live headers and they include presentHeight.
116
+ const currentFullRange = before.bulk.union(before.live)
117
+ if (currentFullRange.maxHeight >= presentHeight) {
118
+ r.done = true
119
+ return r
120
+ }
121
+
122
+ const targetBulkRange = new HeightRange(0, Math.max(0, presentHeight - storage.liveHeightThreshold))
123
+ let missingBulkRange = targetBulkRange.subtract(before.bulk)
124
+
125
+ const updateMissingBulkRange = async () => {
126
+ before = await storage.getAvailableHeightRanges()
127
+ missingBulkRange = targetBulkRange.subtract(before.bulk)
128
+ }
129
+
130
+ // Q2: If missingBulkRange isn't empty and there are live headers in storage,
131
+ // migrate from existing live headers in excess of reorgHeightThreshold.
132
+ if (!missingBulkRange.isEmpty && !before.live.isEmpty) {
133
+ const countToMigrate = Math.min(
134
+ missingBulkRange.length,
135
+ Math.max(0, before.live.length - storage.reorgHeightThreshold)
136
+ )
137
+ r.log += `Migrating ${countToMigrate} live headers to bulk storage.\n`
138
+ await storage.migrateLiveToBulk(countToMigrate)
139
+ await updateMissingBulkRange()
140
+ if (!missingBulkRange.isEmpty) {
141
+ // If there are still missing bulk headers, MUST flush live storage.
142
+ const countToFlush = before.live.length
143
+ r.log += `Flushing ${countToFlush} live headers from live storage.\n`
144
+ await storage.deleteLiveBlockHeaders()
145
+ await updateMissingBulkRange()
146
+ }
147
+ }
148
+
149
+ const targetFullRange = new HeightRange(0, presentHeight)
150
+ // Q3: What to fetch...
151
+ let rangeToFetch: HeightRange
152
+ if (missingBulkRange.isEmpty) {
153
+ // If there are no missing bulk headers, we don't need existing bulk range.
154
+ rangeToFetch = targetFullRange.subtract(before.bulk)
155
+ // And if there are live headers in excess of reorgHeightThreshold, they can be skipped as well.
156
+ if (before.live.length > storage.reorgHeightThreshold) {
157
+ rangeToFetch = rangeToFetch.subtract(
158
+ new HeightRange(before.live.minHeight, before.live.maxHeight - storage.reorgHeightThreshold)
159
+ )
160
+ }
161
+ } else {
162
+ // If there are missing bulk headers, ingest from start of missing through present height.
163
+ rangeToFetch = new HeightRange(missingBulkRange.minHeight, presentHeight)
164
+ }
165
+
166
+ const newLiveHeaders = await this.fetchHeaders(before, rangeToFetch, missingBulkRange, priorLiveHeaders)
167
+
168
+ await updateMissingBulkRange()
169
+
170
+ r.liveHeaders = newLiveHeaders
171
+ r.liveRange = HeightRange.from(r.liveHeaders)
172
+ r.done = missingBulkRange.isEmpty && r.liveRange.maxHeight >= presentHeight
173
+
174
+ return r
175
+ }
176
+ }
@@ -0,0 +1,174 @@
1
+ import { Chain } from '../../../../sdk/types'
2
+ import { BlockHeader } from '../Api/BlockHeaderApi'
3
+ import { BulkIngestorBaseOptions } from '../Api/BulkIngestorApi'
4
+ import { BulkIngestorBase } from './BulkIngestorBase'
5
+ import { BulkHeaderFileInfo } from '../util/BulkHeaderFile'
6
+ import { BulkHeaderFilesInfo } from '../util/BulkHeaderFile'
7
+ import { HeightRange, HeightRanges } from '../util/HeightRange'
8
+ import { ChaintracksFetchApi } from '../Api/ChaintracksFetchApi'
9
+ import { WalletError, WERR_INVALID_PARAMETER } from '../../../../sdk'
10
+ import { validateBulkFileData } from '../util/blockHeaderUtilities'
11
+ import { selectBulkHeaderFiles } from '../util/BulkFileDataManager'
12
+
13
+ export interface BulkIngestorCDNOptions extends BulkIngestorBaseOptions {
14
+ /**
15
+ * Required.
16
+ *
17
+ * The name of the JSON resource to request from CDN which describes currently
18
+ * available bulk block header resources.
19
+ */
20
+ jsonResource: string | undefined
21
+
22
+ /**
23
+ * Required.
24
+ *
25
+ * URL to CDN implementing the bulk ingestor CDN service protocol
26
+ */
27
+ cdnUrl: string | undefined
28
+
29
+ maxPerFile: number | undefined
30
+
31
+ fetch: ChaintracksFetchApi
32
+ }
33
+
34
+ export class BulkIngestorCDN extends BulkIngestorBase {
35
+ /**
36
+ *
37
+ * @param chain
38
+ * @param localCachePath defaults to './data/bulk_cdn_headers/'
39
+ * @returns
40
+ */
41
+ static createBulkIngestorCDNOptions(
42
+ chain: Chain,
43
+ cdnUrl: string,
44
+ fetch: ChaintracksFetchApi,
45
+ maxPerFile?: number
46
+ ): BulkIngestorCDNOptions {
47
+ const options: BulkIngestorCDNOptions = {
48
+ ...BulkIngestorBase.createBulkIngestorBaseOptions(chain),
49
+ fetch,
50
+ jsonResource: `${chain}NetBlockHeaders.json`,
51
+ cdnUrl,
52
+ maxPerFile
53
+ }
54
+ return options
55
+ }
56
+
57
+ fetch: ChaintracksFetchApi
58
+ jsonResource: string
59
+ cdnUrl: string
60
+ maxPerFile: number | undefined
61
+
62
+ availableBulkFiles: BulkHeaderFilesInfo | undefined
63
+ selectedFiles: BulkHeaderFileInfo[] | undefined
64
+ currentRange: HeightRange | undefined
65
+
66
+ constructor(options: BulkIngestorCDNOptions) {
67
+ super(options)
68
+ if (!options.jsonResource) throw new Error('The jsonResource options property is required.')
69
+ if (!options.cdnUrl) throw new Error('The cdnUrl options property is required.')
70
+
71
+ this.fetch = options.fetch
72
+ this.jsonResource = options.jsonResource
73
+ this.cdnUrl = options.cdnUrl
74
+ this.maxPerFile = options.maxPerFile
75
+ }
76
+
77
+ override async getPresentHeight(): Promise<number | undefined> {
78
+ return undefined
79
+ }
80
+
81
+ getJsonHttpHeaders(): Record<string, string> {
82
+ const headers: Record<string, string> = {
83
+ Accept: 'application/json'
84
+ }
85
+ return headers
86
+ }
87
+
88
+ /**
89
+ * A BulkFile CDN serves a JSON BulkHeaderFilesInfo resource which lists all the available binary bulk header files available and associated metadata.
90
+ *
91
+ * The term "CDN file" is used for a local bulk file that has a sourceUrl. (Not undefined)
92
+ * The term "incremental file" is used for the local bulk file that holds all the non-CDN bulk headers and must chain to the live headers if there are any.
93
+ *
94
+ * Bulk ingesting from a CDN happens in one of three contexts:
95
+ *
96
+ * 1. Cold Start: No local bulk or live headers.
97
+ * 2. Incremental: Available CDN files extend into an existing incremental file but not into the live headers.
98
+ * 3. Replace: Available CDN files extend into live headers.
99
+ *
100
+ * Context Cold Start:
101
+ * - The CDN files are selected in height order, starting at zero, always choosing the largest count less than the local maximum (maxPerFile).
102
+ *
103
+ * Context Incremental:
104
+ * - Last existing CDN file is updated if CDN now has a higher count.
105
+ * - Additional CDN files are added as in Cold Start.
106
+ * - The existing incremental file is truncated or deleted.
107
+ *
108
+ * Context Replace:
109
+ * - Existing live headers are truncated or deleted.
110
+ * - Proceed as context Incremental.
111
+ *
112
+ * @param before bulk and live range of headers before ingesting any new headers.
113
+ * @param fetchRange total range of header heights needed including live headers
114
+ * @param bulkRange range of missing bulk header heights required.
115
+ * @param priorLiveHeaders
116
+ * @returns
117
+ */
118
+ async fetchHeaders(
119
+ before: HeightRanges,
120
+ fetchRange: HeightRange,
121
+ bulkRange: HeightRange,
122
+ priorLiveHeaders: BlockHeader[]
123
+ ): Promise<BlockHeader[]> {
124
+ const storage = this.storage()
125
+
126
+ const toUrl = (file: string) => this.fetch.pathJoin(this.cdnUrl, file)
127
+
128
+ const url = toUrl(this.jsonResource)
129
+ this.availableBulkFiles = await this.fetch.fetchJson(url)
130
+ if (!this.availableBulkFiles) {
131
+ throw new WERR_INVALID_PARAMETER(
132
+ `${this.jsonResource}`,
133
+ `a valid BulkHeaderFilesInfo JSON resource available from ${url}`
134
+ )
135
+ }
136
+ this.selectedFiles = selectBulkHeaderFiles(
137
+ this.availableBulkFiles.files,
138
+ this.chain,
139
+ this.maxPerFile || this.availableBulkFiles.headersPerFile
140
+ )
141
+ for (const bf of this.selectedFiles) {
142
+ if (!bf.fileHash) {
143
+ throw new WERR_INVALID_PARAMETER(`fileHash`, `valid for alll files in ${this.jsonResource} from ${url}`)
144
+ }
145
+ if (!bf.chain || bf.chain !== this.chain) {
146
+ throw new WERR_INVALID_PARAMETER(`chain`, `"${this.chain}" for all files in ${this.jsonResource} from ${url}`)
147
+ }
148
+ if (!bf.sourceUrl || bf.sourceUrl !== this.cdnUrl) bf.sourceUrl = this.cdnUrl
149
+ }
150
+
151
+ let log = 'BulkIngestorCDN fetchHeaders log:\n'
152
+ log += ` url: ${url}\n`
153
+
154
+ this.currentRange = await storage.bulkManager.getHeightRange()
155
+ log += ` bulk range before: ${this.currentRange}\n`
156
+
157
+ const r = await storage.bulkManager.merge(this.selectedFiles)
158
+
159
+ this.currentRange = await storage.bulkManager.getHeightRange()
160
+ log += ` bulk range after: ${this.currentRange}\n`
161
+ for (const u of r.unchanged) {
162
+ log += ` unchanged: ${u.fileName}, fileId=${u.fileId}\n`
163
+ }
164
+ for (const i of r.inserted) {
165
+ log += ` inserted: ${i.fileName}, fileId=${i.fileId}\n`
166
+ }
167
+ for (const u of r.updated) {
168
+ log += ` updated: ${u.fileName}, fileId=${u.fileId}\n`
169
+ }
170
+ this.log(log)
171
+
172
+ return priorLiveHeaders
173
+ }
174
+ }