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