@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,420 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2
|
+
import {
|
|
3
|
+
Beef,
|
|
4
|
+
Transaction as BsvTransaction,
|
|
5
|
+
SendWithResult,
|
|
6
|
+
SendWithResultStatus,
|
|
7
|
+
WalletLoggerInterface
|
|
8
|
+
} from '@bsv/sdk'
|
|
9
|
+
import { aggregateActionResults } from '../../utility/aggregateResults'
|
|
10
|
+
import { StorageProvider } from '../StorageProvider'
|
|
11
|
+
import {
|
|
12
|
+
AuthId,
|
|
13
|
+
ReviewActionResult,
|
|
14
|
+
StorageProcessActionArgs,
|
|
15
|
+
StorageProcessActionResults
|
|
16
|
+
} from '../../sdk/WalletStorage.interfaces'
|
|
17
|
+
import { stampLog } from '../../utility/stampLog'
|
|
18
|
+
import {
|
|
19
|
+
randomBytesBase64,
|
|
20
|
+
verifyId,
|
|
21
|
+
verifyInteger,
|
|
22
|
+
verifyOne,
|
|
23
|
+
verifyOneOrNone,
|
|
24
|
+
verifyTruthy
|
|
25
|
+
} from '../../utility/utilityHelpers'
|
|
26
|
+
import { EntityProvenTxReq } from '../schema/entities/EntityProvenTxReq'
|
|
27
|
+
import { WERR_INTERNAL, WERR_INVALID_OPERATION } from '../../sdk/WERR_errors'
|
|
28
|
+
import { TableProvenTxReq } from '../schema/tables/TableProvenTxReq'
|
|
29
|
+
import { TableProvenTx } from '../schema/tables/TableProvenTx'
|
|
30
|
+
import { ProvenTxReqStatus, TransactionStatus } from '../../sdk/types'
|
|
31
|
+
import { parseTxScriptOffsets, TxScriptOffsets } from '../../utility/parseTxScriptOffsets'
|
|
32
|
+
import { TableTransaction } from '../schema/tables/TableTransaction'
|
|
33
|
+
import { TableOutput } from '../schema/tables/TableOutput'
|
|
34
|
+
import { TableCommission } from '../schema/tables/TableCommission'
|
|
35
|
+
import { asArray, asString } from '../../utility/utilityHelpers.noBuffer'
|
|
36
|
+
|
|
37
|
+
export async function processAction(
|
|
38
|
+
storage: StorageProvider,
|
|
39
|
+
auth: AuthId,
|
|
40
|
+
args: StorageProcessActionArgs
|
|
41
|
+
): Promise<StorageProcessActionResults> {
|
|
42
|
+
const logger = args.logger
|
|
43
|
+
logger?.group('storage processAction')
|
|
44
|
+
|
|
45
|
+
const userId = verifyId(auth.userId)
|
|
46
|
+
const r: StorageProcessActionResults = {
|
|
47
|
+
sendWithResults: undefined
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let req: EntityProvenTxReq | undefined
|
|
51
|
+
const txidsOfReqsToShareWithWorld: string[] = [...args.sendWith]
|
|
52
|
+
|
|
53
|
+
if (args.isNewTx) {
|
|
54
|
+
const vargs = await validateCommitNewTxToStorageArgs(storage, userId, args)
|
|
55
|
+
logger?.log(`validated new tx updates to storage`)
|
|
56
|
+
;({ req } = await commitNewTxToStorage(storage, userId, vargs))
|
|
57
|
+
logger?.log(`committed new tx updates to storage `)
|
|
58
|
+
if (!req) throw new WERR_INTERNAL()
|
|
59
|
+
// Add the new txid to sendWith unless there are no others to send and the noSend option is set.
|
|
60
|
+
if (args.isNoSend && !args.isSendWith) {
|
|
61
|
+
logger?.log(`noSend txid ${req.txid}`)
|
|
62
|
+
} else {
|
|
63
|
+
txidsOfReqsToShareWithWorld.push(req.txid)
|
|
64
|
+
logger?.log(`sending txid ${req.txid}`)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const { swr, ndr } = await shareReqsWithWorld(
|
|
69
|
+
storage,
|
|
70
|
+
userId,
|
|
71
|
+
txidsOfReqsToShareWithWorld,
|
|
72
|
+
args.isDelayed,
|
|
73
|
+
undefined,
|
|
74
|
+
logger
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
r.sendWithResults = swr
|
|
78
|
+
r.notDelayedResults = ndr
|
|
79
|
+
|
|
80
|
+
logger?.groupEnd()
|
|
81
|
+
|
|
82
|
+
return r
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface GetReqsAndBeefDetail {
|
|
86
|
+
txid: string
|
|
87
|
+
req?: TableProvenTxReq
|
|
88
|
+
proven?: TableProvenTx
|
|
89
|
+
status: 'readyToSend' | 'alreadySent' | 'error' | 'unknown'
|
|
90
|
+
error?: string
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface GetReqsAndBeefResult {
|
|
94
|
+
beef: Beef
|
|
95
|
+
details: GetReqsAndBeefDetail[]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface PostBeefResultForTxidApi {
|
|
99
|
+
txid: string
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 'success' - The transaction was accepted for processing
|
|
103
|
+
*/
|
|
104
|
+
status: 'success' | 'error'
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* if true, the transaction was already known to this service. Usually treat as a success.
|
|
108
|
+
*
|
|
109
|
+
* Potentially stop posting to additional transaction processors.
|
|
110
|
+
*/
|
|
111
|
+
alreadyKnown?: boolean
|
|
112
|
+
|
|
113
|
+
blockHash?: string
|
|
114
|
+
blockHeight?: number
|
|
115
|
+
merklePath?: string
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Verifies that all the txids are known reqs with ready-to-share status.
|
|
120
|
+
* Assigns a batch identifier and updates all the provenTxReqs.
|
|
121
|
+
* If not isDelayed, triggers an initial attempt to broadcast the batch and returns the results.
|
|
122
|
+
*
|
|
123
|
+
* @param storage
|
|
124
|
+
* @param userId
|
|
125
|
+
* @param txids
|
|
126
|
+
* @param isDelayed
|
|
127
|
+
* @param r Optional. Ignores txids and allows ProvenTxReqs and merged beef to be passed in.
|
|
128
|
+
*/
|
|
129
|
+
export async function shareReqsWithWorld(
|
|
130
|
+
storage: StorageProvider,
|
|
131
|
+
userId: number,
|
|
132
|
+
txids: string[],
|
|
133
|
+
isDelayed: boolean,
|
|
134
|
+
r?: GetReqsAndBeefResult,
|
|
135
|
+
logger?: WalletLoggerInterface
|
|
136
|
+
): Promise<{ swr: SendWithResult[]; ndr: ReviewActionResult[] | undefined }> {
|
|
137
|
+
let swr: SendWithResult[] = []
|
|
138
|
+
let ndr: ReviewActionResult[] | undefined = undefined
|
|
139
|
+
|
|
140
|
+
if (!r && txids.length < 1) return { swr, ndr }
|
|
141
|
+
|
|
142
|
+
// Collect what we know about these sendWith transaction txids from storage.
|
|
143
|
+
r ||= await storage.getReqsAndBeefToShareWithWorld(txids, [])
|
|
144
|
+
|
|
145
|
+
const readyToSendReqs: EntityProvenTxReq[] = []
|
|
146
|
+
for (const getReq of r.details) {
|
|
147
|
+
let status: SendWithResultStatus = 'failed'
|
|
148
|
+
if (getReq.status === 'alreadySent') status = 'unproven'
|
|
149
|
+
else if (getReq.status === 'readyToSend') {
|
|
150
|
+
status = 'sending'
|
|
151
|
+
readyToSendReqs.push(new EntityProvenTxReq(getReq.req!))
|
|
152
|
+
}
|
|
153
|
+
swr.push({
|
|
154
|
+
txid: getReq.txid,
|
|
155
|
+
status
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Filter original txids down to reqIds that are available and need sending
|
|
160
|
+
const readyToSendReqIds = readyToSendReqs.map(r => r.id)
|
|
161
|
+
const transactionIds = readyToSendReqs.map(r => r.notify.transactionIds || []).flat()
|
|
162
|
+
|
|
163
|
+
// If there are reqs to send, verify that we have a valid aggregate beef for them.
|
|
164
|
+
// If isDelayed, this (or a different beef) will have to be rebuilt at the time of sending.
|
|
165
|
+
if (readyToSendReqs.length > 0) {
|
|
166
|
+
const beefIsValid = await r.beef.verify(await storage.getServices().getChainTracker())
|
|
167
|
+
if (!beefIsValid) {
|
|
168
|
+
logger?.error(`VERIFY FALSE BEEF: ${r.beef.toLogString()}`)
|
|
169
|
+
throw new WERR_INTERNAL(`merged Beef failed validation.`)
|
|
170
|
+
}
|
|
171
|
+
logger?.log(`beef is valid`)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Set req batch property for the reqs being sent
|
|
175
|
+
// If delayed, also bump status to 'unsent' and we're done here
|
|
176
|
+
const batch = txids.length > 1 ? randomBytesBase64(16) : undefined
|
|
177
|
+
if (isDelayed) {
|
|
178
|
+
// Just bump the req status to 'unsent' to enable background sending...
|
|
179
|
+
if (readyToSendReqIds.length > 0) {
|
|
180
|
+
await storage.transaction(async trx => {
|
|
181
|
+
await storage.updateProvenTxReq(readyToSendReqIds, { status: 'unsent', batch }, trx)
|
|
182
|
+
await storage.updateTransaction(transactionIds, { status: 'sending' }, trx)
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
return { swr, ndr }
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (readyToSendReqIds.length < 1) {
|
|
189
|
+
return { swr, ndr }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (batch) {
|
|
193
|
+
// Keep batch values in sync...
|
|
194
|
+
for (const req of readyToSendReqs) req.batch = batch
|
|
195
|
+
await storage.updateProvenTxReq(readyToSendReqIds, { batch })
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
//
|
|
199
|
+
// Handle the NON-DELAYED-SEND-NOW case
|
|
200
|
+
//
|
|
201
|
+
const prtn = await storage.attemptToPostReqsToNetwork(readyToSendReqs, undefined, logger)
|
|
202
|
+
|
|
203
|
+
const { swr: swrRes, rar } = await aggregateActionResults(storage, swr, prtn)
|
|
204
|
+
return { swr: swrRes, ndr: rar }
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
interface ReqTxStatus {
|
|
208
|
+
req: ProvenTxReqStatus
|
|
209
|
+
tx: TransactionStatus
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
interface ValidCommitNewTxToStorageArgs {
|
|
213
|
+
// validated input args
|
|
214
|
+
|
|
215
|
+
reference: string
|
|
216
|
+
txid: string
|
|
217
|
+
rawTx: number[]
|
|
218
|
+
isNoSend: boolean
|
|
219
|
+
isDelayed: boolean
|
|
220
|
+
isSendWith: boolean
|
|
221
|
+
log?: string
|
|
222
|
+
|
|
223
|
+
// validated dependent args
|
|
224
|
+
|
|
225
|
+
tx: BsvTransaction
|
|
226
|
+
txScriptOffsets: TxScriptOffsets
|
|
227
|
+
transactionId: number
|
|
228
|
+
transaction: TableTransaction
|
|
229
|
+
inputOutputs: TableOutput[]
|
|
230
|
+
outputOutputs: TableOutput[]
|
|
231
|
+
commission: TableCommission | undefined
|
|
232
|
+
beef: Beef
|
|
233
|
+
|
|
234
|
+
req: EntityProvenTxReq
|
|
235
|
+
outputUpdates: { id: number; update: Partial<TableOutput> }[]
|
|
236
|
+
transactionUpdate: Partial<TableTransaction>
|
|
237
|
+
postStatus?: ReqTxStatus
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async function validateCommitNewTxToStorageArgs(
|
|
241
|
+
storage: StorageProvider,
|
|
242
|
+
userId: number,
|
|
243
|
+
params: StorageProcessActionArgs
|
|
244
|
+
): Promise<ValidCommitNewTxToStorageArgs> {
|
|
245
|
+
if (!params.reference || !params.txid || !params.rawTx)
|
|
246
|
+
throw new WERR_INVALID_OPERATION('One or more expected params are undefined.')
|
|
247
|
+
let tx: BsvTransaction
|
|
248
|
+
try {
|
|
249
|
+
tx = BsvTransaction.fromBinary(params.rawTx)
|
|
250
|
+
} catch (e: unknown) {
|
|
251
|
+
throw new WERR_INVALID_OPERATION('Parsing serialized transaction failed.')
|
|
252
|
+
}
|
|
253
|
+
if (params.txid !== tx.id('hex'))
|
|
254
|
+
throw new WERR_INVALID_OPERATION(`Hash of serialized transaction doesn't match expected txid`)
|
|
255
|
+
if (!(await storage.getServices()).nLockTimeIsFinal(tx)) {
|
|
256
|
+
throw new WERR_INVALID_OPERATION(`This transaction is not final.
|
|
257
|
+
Ensure that the transaction meets the rules for being a finalized
|
|
258
|
+
which can be found at https://wiki.bitcoinsv.io/index.php/NLocktime_and_nSequence`)
|
|
259
|
+
}
|
|
260
|
+
const txScriptOffsets = parseTxScriptOffsets(params.rawTx)
|
|
261
|
+
const transaction = verifyOne(
|
|
262
|
+
await storage.findTransactions({
|
|
263
|
+
partial: { userId, reference: params.reference }
|
|
264
|
+
})
|
|
265
|
+
)
|
|
266
|
+
if (!transaction.isOutgoing) throw new WERR_INVALID_OPERATION('isOutgoing is not true')
|
|
267
|
+
if (!transaction.inputBEEF) throw new WERR_INVALID_OPERATION()
|
|
268
|
+
const beef = Beef.fromBinary(asArray(transaction.inputBEEF))
|
|
269
|
+
// TODO: Could check beef validates transaction inputs...
|
|
270
|
+
// Transaction must have unsigned or unprocessed status
|
|
271
|
+
if (transaction.status !== 'unsigned' && transaction.status !== 'unprocessed')
|
|
272
|
+
throw new WERR_INVALID_OPERATION(`invalid transaction status ${transaction.status}`)
|
|
273
|
+
const transactionId = verifyId(transaction.transactionId)
|
|
274
|
+
const outputOutputs = await storage.findOutputs({
|
|
275
|
+
partial: { userId, transactionId }
|
|
276
|
+
})
|
|
277
|
+
const inputOutputs = await storage.findOutputs({
|
|
278
|
+
partial: { userId, spentBy: transactionId }
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
const commission = verifyOneOrNone(await storage.findCommissions({ partial: { transactionId, userId } }))
|
|
282
|
+
if (storage.commissionSatoshis > 0) {
|
|
283
|
+
// A commission is required...
|
|
284
|
+
if (!commission) throw new WERR_INTERNAL()
|
|
285
|
+
const commissionValid = tx.outputs.some(
|
|
286
|
+
x => x.satoshis === commission.satoshis && x.lockingScript.toHex() === asString(commission.lockingScript!)
|
|
287
|
+
)
|
|
288
|
+
if (!commissionValid)
|
|
289
|
+
throw new WERR_INVALID_OPERATION('Transaction did not include an output to cover service fee.')
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const req = EntityProvenTxReq.fromTxid(params.txid, params.rawTx, transaction.inputBEEF)
|
|
293
|
+
req.addNotifyTransactionId(transactionId)
|
|
294
|
+
|
|
295
|
+
// "Processing" a transaction is the final step of creating a new one.
|
|
296
|
+
// If it is to be sent to the network directly (prior to return from processAction),
|
|
297
|
+
// then there is status pre-send and post-send.
|
|
298
|
+
// Otherwise there is no post-send status.
|
|
299
|
+
// Note that isSendWith trumps isNoSend, e.g. isNoSend && !isSendWith
|
|
300
|
+
//
|
|
301
|
+
// Determine what status the req and transaction should have pre- at the end of processing.
|
|
302
|
+
// Pre-Status (to newReq/newTx) Post-Status (to all sent reqs/txs)
|
|
303
|
+
// req tx req tx
|
|
304
|
+
// isNoSend noSend noSend
|
|
305
|
+
// !isNoSend && isDelayed unsent unprocessed
|
|
306
|
+
// !isNoSend && !isDelayed unprocessed unprocessed sending/unmined sending/unproven This is the only case that sends immediately.
|
|
307
|
+
let postStatus: ReqTxStatus | undefined = undefined
|
|
308
|
+
let status: ReqTxStatus
|
|
309
|
+
if (params.isNoSend && !params.isSendWith) status = { req: 'nosend', tx: 'nosend' }
|
|
310
|
+
else if (!params.isNoSend && params.isDelayed) status = { req: 'unsent', tx: 'unprocessed' }
|
|
311
|
+
else if (!params.isNoSend && !params.isDelayed) {
|
|
312
|
+
status = { req: 'unprocessed', tx: 'unprocessed' }
|
|
313
|
+
postStatus = { req: 'unmined', tx: 'unproven' }
|
|
314
|
+
} else throw new WERR_INTERNAL('logic error')
|
|
315
|
+
|
|
316
|
+
req.status = status.req
|
|
317
|
+
const vargs: ValidCommitNewTxToStorageArgs = {
|
|
318
|
+
reference: params.reference,
|
|
319
|
+
txid: params.txid,
|
|
320
|
+
rawTx: params.rawTx,
|
|
321
|
+
isSendWith: !!params.sendWith && params.sendWith.length > 0,
|
|
322
|
+
isDelayed: params.isDelayed,
|
|
323
|
+
isNoSend: params.isNoSend,
|
|
324
|
+
// Properties with values added during validation.
|
|
325
|
+
tx,
|
|
326
|
+
txScriptOffsets,
|
|
327
|
+
transactionId,
|
|
328
|
+
transaction,
|
|
329
|
+
inputOutputs,
|
|
330
|
+
outputOutputs,
|
|
331
|
+
commission,
|
|
332
|
+
beef,
|
|
333
|
+
req,
|
|
334
|
+
outputUpdates: [],
|
|
335
|
+
// update txid, status in transactions table and drop rawTransaction value
|
|
336
|
+
transactionUpdate: {
|
|
337
|
+
txid: params.txid,
|
|
338
|
+
rawTx: undefined,
|
|
339
|
+
inputBEEF: undefined,
|
|
340
|
+
status: status.tx
|
|
341
|
+
},
|
|
342
|
+
postStatus
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// update outputs with txid, script offsets and lengths, drop long output scripts from outputs table
|
|
346
|
+
// outputs spendable will be updated for change to true and all others to !!o.tracked when tx has been broadcast
|
|
347
|
+
// MAX_OUTPUTSCRIPT_LENGTH is limit for scripts left in outputs table
|
|
348
|
+
for (const o of vargs.outputOutputs) {
|
|
349
|
+
const vout = verifyInteger(o.vout)
|
|
350
|
+
const offset = vargs.txScriptOffsets.outputs[vout]
|
|
351
|
+
const rawTxScript = asString(vargs.rawTx.slice(offset.offset, offset.offset + offset.length))
|
|
352
|
+
if (o.lockingScript && rawTxScript !== asString(o.lockingScript))
|
|
353
|
+
throw new WERR_INVALID_OPERATION(
|
|
354
|
+
`rawTx output locking script for vout ${vout} not equal to expected output script.`
|
|
355
|
+
)
|
|
356
|
+
if (tx.outputs[vout].lockingScript.toHex() !== rawTxScript)
|
|
357
|
+
throw new WERR_INVALID_OPERATION(
|
|
358
|
+
`parsed transaction output locking script for vout ${vout} not equal to expected output script.`
|
|
359
|
+
)
|
|
360
|
+
const update: Partial<TableOutput> = {
|
|
361
|
+
txid: vargs.txid,
|
|
362
|
+
spendable: true, // spendability is gated by transaction status. Remains true until the output is spent.
|
|
363
|
+
scriptLength: offset.length,
|
|
364
|
+
scriptOffset: offset.offset
|
|
365
|
+
}
|
|
366
|
+
if (offset.length > (await storage.getSettings()).maxOutputScript)
|
|
367
|
+
// Remove long lockingScript data from outputs table, will be read from rawTx in proven_tx or proven_tx_reqs tables.
|
|
368
|
+
update.lockingScript = undefined
|
|
369
|
+
vargs.outputUpdates.push({ id: o.outputId!, update })
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return vargs
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export interface CommitNewTxResults {
|
|
376
|
+
req: EntityProvenTxReq
|
|
377
|
+
log?: string
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async function commitNewTxToStorage(
|
|
381
|
+
storage: StorageProvider,
|
|
382
|
+
userId: number,
|
|
383
|
+
vargs: ValidCommitNewTxToStorageArgs
|
|
384
|
+
): Promise<CommitNewTxResults> {
|
|
385
|
+
let log = vargs.log
|
|
386
|
+
|
|
387
|
+
log = stampLog(log, `start storage commitNewTxToStorage`)
|
|
388
|
+
|
|
389
|
+
let req: EntityProvenTxReq | undefined
|
|
390
|
+
|
|
391
|
+
await storage.transaction(async trx => {
|
|
392
|
+
log = stampLog(log, `... storage commitNewTxToStorage storage transaction start`)
|
|
393
|
+
|
|
394
|
+
// Create initial 'nosend' proven_tx_req record to store signed, valid rawTx and input beef
|
|
395
|
+
req = await vargs.req.insertOrMerge(storage, trx)
|
|
396
|
+
|
|
397
|
+
log = stampLog(log, `... storage commitNewTxToStorage req inserted`)
|
|
398
|
+
|
|
399
|
+
for (const ou of vargs.outputUpdates) {
|
|
400
|
+
await storage.updateOutput(ou.id, ou.update, trx)
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
log = stampLog(log, `... storage commitNewTxToStorage outputs updated`)
|
|
404
|
+
|
|
405
|
+
await storage.updateTransaction(vargs.transactionId, vargs.transactionUpdate, trx)
|
|
406
|
+
|
|
407
|
+
log = stampLog(log, `... storage commitNewTxToStorage storage transaction end`)
|
|
408
|
+
})
|
|
409
|
+
|
|
410
|
+
log = stampLog(log, `... storage commitNewTxToStorage storage transaction await done`)
|
|
411
|
+
|
|
412
|
+
const r: CommitNewTxResults = {
|
|
413
|
+
req: verifyTruthy(req),
|
|
414
|
+
log
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
log = stampLog(log, `end storage commitNewTxToStorage`)
|
|
418
|
+
|
|
419
|
+
return r
|
|
420
|
+
}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { Beef } from '@bsv/sdk'
|
|
2
|
+
import { Knex } from 'knex'
|
|
3
|
+
import { StorageKnex } from '../StorageKnex'
|
|
4
|
+
import { PurgeParams, PurgeResults, StorageGetBeefOptions, TrxToken } from '../../sdk/WalletStorage.interfaces'
|
|
5
|
+
import { WalletError } from '../../sdk/WalletError'
|
|
6
|
+
import { TableTransaction } from '../schema/tables/TableTransaction'
|
|
7
|
+
import { TableOutput } from '../schema/tables/TableOutput'
|
|
8
|
+
import { TableOutputTagMap } from '../schema/tables/TableOutputTagMap'
|
|
9
|
+
import { TableTxLabelMap } from '../schema/tables/TableTxLabelMap'
|
|
10
|
+
import { TableCommission } from '../schema/tables/TableCommission'
|
|
11
|
+
|
|
12
|
+
export async function purgeData(storage: StorageKnex, params: PurgeParams, trx?: TrxToken): Promise<PurgeResults> {
|
|
13
|
+
const r: PurgeResults = { count: 0, log: '' }
|
|
14
|
+
const defaultAge = 1000 * 60 * 60 * 24 * 14
|
|
15
|
+
|
|
16
|
+
const runPurgeQuery = async <T extends object>(pq: PurgeQuery): Promise<void> => {
|
|
17
|
+
try {
|
|
18
|
+
pq.sql = pq.q.toString()
|
|
19
|
+
const count = await pq.q
|
|
20
|
+
if (count > 0) {
|
|
21
|
+
r.count += count
|
|
22
|
+
r.log += `${count} ${pq.log}\n`
|
|
23
|
+
}
|
|
24
|
+
} catch (eu: unknown) {
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
26
|
+
const e = WalletError.fromUnknown(eu)
|
|
27
|
+
throw eu
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (params.purgeCompleted) {
|
|
32
|
+
const age = params.purgeCompletedAge || defaultAge
|
|
33
|
+
const before = toSqlWhereDate(new Date(Date.now() - age))
|
|
34
|
+
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
const qs: PurgeQuery[] = []
|
|
37
|
+
|
|
38
|
+
// select * from transactions where updated_at < '2024-08-20' and status = 'completed' and not provenTxId is null and (not truncatedExternalInputs is null or not beef is null or not rawTx is null)
|
|
39
|
+
qs.push({
|
|
40
|
+
log: 'conpleted transactions purged of transient data',
|
|
41
|
+
q: storage
|
|
42
|
+
.toDb(trx)('transactions')
|
|
43
|
+
.update({
|
|
44
|
+
inputBEEF: null,
|
|
45
|
+
rawTx: null
|
|
46
|
+
})
|
|
47
|
+
.where('updated_at', '<', before)
|
|
48
|
+
.where('status', 'completed')
|
|
49
|
+
.whereNotNull('provenTxId')
|
|
50
|
+
.where(function () {
|
|
51
|
+
this.orWhereNotNull('inputBEEF')
|
|
52
|
+
this.orWhereNotNull('rawTx')
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const completedReqs = await storage
|
|
57
|
+
.toDb(trx)<{ provenTxReqId: number }>('proven_tx_reqs')
|
|
58
|
+
.select('provenTxReqId')
|
|
59
|
+
.where('updated_at', '<', before)
|
|
60
|
+
.where('status', 'completed')
|
|
61
|
+
.whereNotNull('provenTxId')
|
|
62
|
+
.where('notified', 1)
|
|
63
|
+
const completedReqIds = completedReqs.map(o => o.provenTxReqId)
|
|
64
|
+
|
|
65
|
+
if (completedReqIds.length > 0) {
|
|
66
|
+
qs.push({
|
|
67
|
+
log: 'completed proven_tx_reqs deleted',
|
|
68
|
+
q: storage.toDb(trx)('proven_tx_reqs').whereIn('provenTxReqId', completedReqIds).delete()
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (const q of qs) await runPurgeQuery(q)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (params.purgeFailed) {
|
|
76
|
+
const age = params.purgeFailedAge || defaultAge
|
|
77
|
+
const before = toSqlWhereDate(new Date(Date.now() - age))
|
|
78
|
+
|
|
79
|
+
const qs: PurgeQuery[] = []
|
|
80
|
+
|
|
81
|
+
const failedTxsQ = storage
|
|
82
|
+
.toDb(trx)<{ transactionId: number }>('transactions')
|
|
83
|
+
.select('transactionId')
|
|
84
|
+
.where('updated_at', '<', before)
|
|
85
|
+
.where('status', 'failed')
|
|
86
|
+
const txs = await failedTxsQ
|
|
87
|
+
const failedTxIds = txs.map(tx => tx.transactionId)
|
|
88
|
+
|
|
89
|
+
await deleteTransactions(failedTxIds, qs, 'failed', true)
|
|
90
|
+
|
|
91
|
+
const invalidReqs = await storage
|
|
92
|
+
.toDb(trx)<{ provenTxReqId: number }>('proven_tx_reqs')
|
|
93
|
+
.select('provenTxReqId')
|
|
94
|
+
.where('updated_at', '<', before)
|
|
95
|
+
.where('status', 'invalid')
|
|
96
|
+
const invalidReqIds = invalidReqs.map(o => o.provenTxReqId)
|
|
97
|
+
if (invalidReqIds.length > 0)
|
|
98
|
+
qs.push({
|
|
99
|
+
log: 'invalid proven_tx_reqs deleted',
|
|
100
|
+
q: storage.toDb(trx)('proven_tx_reqs').whereIn('provenTxReqId', invalidReqIds).delete()
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
const doubleSpendReqs = await storage
|
|
104
|
+
.toDb(trx)<{ provenTxReqId: number }>('proven_tx_reqs')
|
|
105
|
+
.select('provenTxReqId')
|
|
106
|
+
.where('updated_at', '<', before)
|
|
107
|
+
.where('status', 'doubleSpend')
|
|
108
|
+
const doubleSpendReqIds = doubleSpendReqs.map(o => o.provenTxReqId)
|
|
109
|
+
if (doubleSpendReqIds.length > 0)
|
|
110
|
+
qs.push({
|
|
111
|
+
log: 'doubleSpend proven_tx_reqs deleted',
|
|
112
|
+
q: storage.toDb(trx)('proven_tx_reqs').whereIn('provenTxReqId', doubleSpendReqIds).delete()
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
for (const q of qs) await runPurgeQuery(q)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (params.purgeSpent) {
|
|
119
|
+
const age = params.purgeSpentAge || defaultAge
|
|
120
|
+
const before = toSqlWhereDate(new Date(Date.now() - age))
|
|
121
|
+
|
|
122
|
+
const beef = new Beef()
|
|
123
|
+
const utxos = await storage.findOutputs({
|
|
124
|
+
partial: { spendable: true },
|
|
125
|
+
txStatus: ['sending', 'unproven', 'completed', 'nosend']
|
|
126
|
+
})
|
|
127
|
+
for (const utxo of utxos) {
|
|
128
|
+
// Figure out all the txids required to prove the validity of this utxo and merge proofs into beef.
|
|
129
|
+
const options: StorageGetBeefOptions = {
|
|
130
|
+
mergeToBeef: beef,
|
|
131
|
+
ignoreServices: true
|
|
132
|
+
}
|
|
133
|
+
if (utxo.txid) await storage.getBeefForTransaction(utxo.txid, options)
|
|
134
|
+
}
|
|
135
|
+
const proofTxids: Record<string, boolean> = {}
|
|
136
|
+
for (const btx of beef.txs) proofTxids[btx.txid] = true
|
|
137
|
+
|
|
138
|
+
let qs: PurgeQuery[] = []
|
|
139
|
+
|
|
140
|
+
const spentTxsQ = storage
|
|
141
|
+
.toDb(trx)<TableTransaction>('transactions')
|
|
142
|
+
.where('updated_at', '<', before)
|
|
143
|
+
.where('status', 'completed')
|
|
144
|
+
.whereRaw(
|
|
145
|
+
`not exists(select outputId from outputs as o where o.transactionId = transactions.transactionId and o.spendable = 1)`
|
|
146
|
+
)
|
|
147
|
+
const txs: TableTransaction[] = await spentTxsQ
|
|
148
|
+
// Save any spent txid still needed to prove a utxo:
|
|
149
|
+
const nptxs = txs.filter(t => !proofTxids[t.txid || ''])
|
|
150
|
+
let spentTxIds = nptxs.map(tx => tx.transactionId)
|
|
151
|
+
|
|
152
|
+
if (spentTxIds.length > 0) {
|
|
153
|
+
const update: Partial<TableOutput> = {
|
|
154
|
+
spentBy: null as unknown as undefined
|
|
155
|
+
}
|
|
156
|
+
qs.push({
|
|
157
|
+
log: 'spent outputs no longer tracked by spentBy',
|
|
158
|
+
q: storage
|
|
159
|
+
.toDb(trx)<TableOutput>('outputs')
|
|
160
|
+
.update(storage.validatePartialForUpdate(update, undefined, ['spendable']))
|
|
161
|
+
.where('spendable', false)
|
|
162
|
+
.whereIn('spentBy', spentTxIds)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
await deleteTransactions(spentTxIds, qs, 'spent', false)
|
|
166
|
+
|
|
167
|
+
for (const q of qs) await runPurgeQuery(q)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Delete proven_txs no longer referenced by remaining transactions.
|
|
172
|
+
const qs: PurgeQuery[] = []
|
|
173
|
+
qs.push({
|
|
174
|
+
log: 'orphan proven_txs deleted',
|
|
175
|
+
q: storage
|
|
176
|
+
.toDb(trx)('proven_txs')
|
|
177
|
+
.whereRaw(
|
|
178
|
+
`not exists(select * from transactions as t where t.txid = proven_txs.txid or t.provenTxId = proven_txs.provenTxId)`
|
|
179
|
+
)
|
|
180
|
+
.whereRaw(
|
|
181
|
+
`not exists(select * from proven_tx_reqs as r where r.txid = proven_txs.txid or r.provenTxId = proven_txs.provenTxId)`
|
|
182
|
+
)
|
|
183
|
+
.delete()
|
|
184
|
+
})
|
|
185
|
+
for (const q of qs) await runPurgeQuery(q)
|
|
186
|
+
|
|
187
|
+
return r
|
|
188
|
+
|
|
189
|
+
async function deleteTransactions(
|
|
190
|
+
transactionIds: number[],
|
|
191
|
+
qs: PurgeQuery[],
|
|
192
|
+
reason: string,
|
|
193
|
+
markNotSpentBy: boolean
|
|
194
|
+
) {
|
|
195
|
+
if (transactionIds.length > 0) {
|
|
196
|
+
const outputs = await storage
|
|
197
|
+
.toDb(trx)<{ outputId: number }>('outputs')
|
|
198
|
+
.select('outputId')
|
|
199
|
+
.whereIn('transactionId', transactionIds)
|
|
200
|
+
const outputIds = outputs.map(o => o.outputId)
|
|
201
|
+
if (outputIds.length > 0) {
|
|
202
|
+
qs.push({
|
|
203
|
+
log: `${reason} output_tags_map deleted`,
|
|
204
|
+
q: storage.toDb(trx)<TableOutputTagMap>('output_tags_map').whereIn('outputId', outputIds).delete()
|
|
205
|
+
})
|
|
206
|
+
qs.push({
|
|
207
|
+
log: `${reason} outputs deleted`,
|
|
208
|
+
q: storage.toDb(trx)<TableOutput>('outputs').whereIn('outputId', outputIds).delete()
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
qs.push({
|
|
213
|
+
log: `${reason} tx_labels_map deleted`,
|
|
214
|
+
q: storage.toDb(trx)<TableTxLabelMap>('tx_labels_map').whereIn('transactionId', transactionIds).delete()
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
qs.push({
|
|
218
|
+
log: `${reason} commissions deleted`,
|
|
219
|
+
q: storage.toDb(trx)<TableCommission>('commissions').whereIn('transactionId', transactionIds).delete()
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
if (markNotSpentBy) {
|
|
223
|
+
qs.push({
|
|
224
|
+
log: 'unspent outputs updated to spendable',
|
|
225
|
+
q: storage
|
|
226
|
+
.toDb(trx)<TableOutput>('outputs')
|
|
227
|
+
.update({ spendable: true, spentBy: null as unknown as undefined })
|
|
228
|
+
.whereIn('spentBy', transactionIds)
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
qs.push({
|
|
233
|
+
log: `${reason} transactions deleted`,
|
|
234
|
+
q: storage.toDb(trx)<TableTransaction>('transactions').whereIn('transactionId', transactionIds).delete()
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
interface PurgeQuery {
|
|
241
|
+
q: Knex.QueryBuilder<any, number>
|
|
242
|
+
sql?: string
|
|
243
|
+
log: string
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function toSqlWhereDate(d: Date): string {
|
|
247
|
+
let s = d.toISOString()
|
|
248
|
+
s = s.replace('T', ' ')
|
|
249
|
+
s = s.replace('Z', '')
|
|
250
|
+
return s
|
|
251
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Beef } from '@bsv/sdk'
|
|
2
|
+
import { Knex } from 'knex'
|
|
3
|
+
import { StorageIdb } from '../StorageIdb'
|
|
4
|
+
import { PurgeParams, PurgeResults, TrxToken } from '../../sdk/WalletStorage.interfaces'
|
|
5
|
+
|
|
6
|
+
export async function purgeDataIdb(storage: StorageIdb, params: PurgeParams, trx?: TrxToken): Promise<PurgeResults> {
|
|
7
|
+
const r: PurgeResults = { count: 0, log: '' }
|
|
8
|
+
// TODO: implement purgeDataIdb
|
|
9
|
+
return r
|
|
10
|
+
}
|