@bsv/sdk 2.1.0 → 2.1.2
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/README.md +7 -7
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/auth/Peer.js +8 -13
- package/dist/cjs/src/auth/Peer.js.map +1 -1
- package/dist/cjs/src/auth/SessionManager.js +4 -7
- package/dist/cjs/src/auth/SessionManager.js.map +1 -1
- package/dist/cjs/src/auth/certificates/MasterCertificate.js +1 -1
- package/dist/cjs/src/auth/certificates/MasterCertificate.js.map +1 -1
- package/dist/cjs/src/auth/certificates/__tests/CompletedProtoWallet.js +1 -1
- package/dist/cjs/src/auth/certificates/__tests/CompletedProtoWallet.js.map +1 -1
- package/dist/cjs/src/auth/clients/AuthFetch.js +32 -32
- package/dist/cjs/src/auth/clients/AuthFetch.js.map +1 -1
- package/dist/cjs/src/auth/transports/SimplifiedFetchTransport.js +4 -4
- package/dist/cjs/src/auth/transports/SimplifiedFetchTransport.js.map +1 -1
- package/dist/cjs/src/compat/ECIES.js +29 -34
- package/dist/cjs/src/compat/ECIES.js.map +1 -1
- package/dist/cjs/src/compat/HD.js +9 -4
- package/dist/cjs/src/compat/HD.js.map +1 -1
- package/dist/cjs/src/compat/Mnemonic.js +12 -12
- package/dist/cjs/src/compat/Mnemonic.js.map +1 -1
- package/dist/cjs/src/identity/ContactsManager.js +212 -234
- package/dist/cjs/src/identity/ContactsManager.js.map +1 -1
- package/dist/cjs/src/identity/IdentityClient.js +199 -63
- package/dist/cjs/src/identity/IdentityClient.js.map +1 -1
- package/dist/cjs/src/kvstore/GlobalKVStore.js +30 -31
- package/dist/cjs/src/kvstore/GlobalKVStore.js.map +1 -1
- package/dist/cjs/src/kvstore/LocalKVStore.js +9 -9
- package/dist/cjs/src/kvstore/LocalKVStore.js.map +1 -1
- package/dist/cjs/src/kvstore/kvStoreInterpreter.js +2 -2
- package/dist/cjs/src/kvstore/kvStoreInterpreter.js.map +1 -1
- package/dist/cjs/src/messages/SignedMessage.js +1 -1
- package/dist/cjs/src/messages/SignedMessage.js.map +1 -1
- package/dist/cjs/src/overlay-tools/Historian.js +1 -1
- package/dist/cjs/src/overlay-tools/Historian.js.map +1 -1
- package/dist/cjs/src/overlay-tools/LookupResolver.js +213 -93
- package/dist/cjs/src/overlay-tools/LookupResolver.js.map +1 -1
- package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js +75 -146
- package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js.map +1 -1
- package/dist/cjs/src/primitives/AESGCM.js +2 -2
- package/dist/cjs/src/primitives/AESGCM.js.map +1 -1
- package/dist/cjs/src/primitives/BigNumber.js +164 -148
- package/dist/cjs/src/primitives/BigNumber.js.map +1 -1
- package/dist/cjs/src/primitives/Curve.js +17 -15
- package/dist/cjs/src/primitives/Curve.js.map +1 -1
- package/dist/cjs/src/primitives/ECDSA.js +12 -7
- package/dist/cjs/src/primitives/ECDSA.js.map +1 -1
- package/dist/cjs/src/primitives/Hash.js +312 -105
- package/dist/cjs/src/primitives/Hash.js.map +1 -1
- package/dist/cjs/src/primitives/JacobianPoint.js +8 -8
- package/dist/cjs/src/primitives/JacobianPoint.js.map +1 -1
- package/dist/cjs/src/primitives/K256.js +3 -3
- package/dist/cjs/src/primitives/K256.js.map +1 -1
- package/dist/cjs/src/primitives/Point.js +36 -40
- package/dist/cjs/src/primitives/Point.js.map +1 -1
- package/dist/cjs/src/primitives/PrivateKey.js +4 -4
- package/dist/cjs/src/primitives/PrivateKey.js.map +1 -1
- package/dist/cjs/src/primitives/PublicKey.js +4 -4
- package/dist/cjs/src/primitives/PublicKey.js.map +1 -1
- package/dist/cjs/src/primitives/Random.js +10 -14
- package/dist/cjs/src/primitives/Random.js.map +1 -1
- package/dist/cjs/src/primitives/ReaderUint8Array.js +6 -6
- package/dist/cjs/src/primitives/ReaderUint8Array.js.map +1 -1
- package/dist/cjs/src/primitives/Schnorr.js +2 -2
- package/dist/cjs/src/primitives/Schnorr.js.map +1 -1
- package/dist/cjs/src/primitives/Secp256r1.js +2 -1
- package/dist/cjs/src/primitives/Secp256r1.js.map +1 -1
- package/dist/cjs/src/primitives/Signature.js +8 -8
- package/dist/cjs/src/primitives/Signature.js.map +1 -1
- package/dist/cjs/src/primitives/SymmetricKey.js +123 -1
- package/dist/cjs/src/primitives/SymmetricKey.js.map +1 -1
- package/dist/cjs/src/primitives/TransactionSignature.js +20 -21
- package/dist/cjs/src/primitives/TransactionSignature.js.map +1 -1
- package/dist/cjs/src/primitives/utils.js +39 -46
- package/dist/cjs/src/primitives/utils.js.map +1 -1
- package/dist/cjs/src/registry/RegistryClient.js +31 -23
- package/dist/cjs/src/registry/RegistryClient.js.map +1 -1
- package/dist/cjs/src/remittance/RemittanceManager.js +19 -18
- package/dist/cjs/src/remittance/RemittanceManager.js.map +1 -1
- package/dist/cjs/src/remittance/modules/BasicBRC29.js.map +1 -1
- package/dist/cjs/src/script/Script.js +93 -170
- package/dist/cjs/src/script/Script.js.map +1 -1
- package/dist/cjs/src/script/ScriptEvaluationError.js +2 -2
- package/dist/cjs/src/script/ScriptEvaluationError.js.map +1 -1
- package/dist/cjs/src/script/Spend.js +14 -12
- package/dist/cjs/src/script/Spend.js.map +1 -1
- package/dist/cjs/src/script/templates/PushDrop.js +22 -18
- package/dist/cjs/src/script/templates/PushDrop.js.map +1 -1
- package/dist/cjs/src/script/templates/RPuzzle.js +2 -4
- package/dist/cjs/src/script/templates/RPuzzle.js.map +1 -1
- package/dist/cjs/src/storage/StorageDownloader.js +42 -9
- package/dist/cjs/src/storage/StorageDownloader.js.map +1 -1
- package/dist/cjs/src/totp/totp.js +1 -1
- package/dist/cjs/src/totp/totp.js.map +1 -1
- package/dist/cjs/src/transaction/Beef.js +239 -192
- package/dist/cjs/src/transaction/Beef.js.map +1 -1
- package/dist/cjs/src/transaction/BeefConstants.js +19 -0
- package/dist/cjs/src/transaction/BeefConstants.js.map +1 -0
- package/dist/cjs/src/transaction/BeefTx.js +12 -12
- package/dist/cjs/src/transaction/BeefTx.js.map +1 -1
- package/dist/cjs/src/transaction/MerklePath.js +4 -4
- package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
- package/dist/cjs/src/transaction/Transaction.js +49 -52
- package/dist/cjs/src/transaction/Transaction.js.map +1 -1
- package/dist/cjs/src/transaction/fee-models/SatoshisPerKilobyte.js +1 -1
- package/dist/cjs/src/transaction/fee-models/SatoshisPerKilobyte.js.map +1 -1
- package/dist/cjs/src/transaction/http/BinaryFetchClient.js +9 -9
- package/dist/cjs/src/transaction/http/BinaryFetchClient.js.map +1 -1
- package/dist/cjs/src/transaction/http/DefaultHttpClient.js +9 -9
- package/dist/cjs/src/transaction/http/DefaultHttpClient.js.map +1 -1
- package/dist/cjs/src/wallet/CachedKeyDeriver.js +1 -1
- package/dist/cjs/src/wallet/CachedKeyDeriver.js.map +1 -1
- package/dist/cjs/src/wallet/WalletClient.js.map +1 -1
- package/dist/cjs/src/wallet/WalletError.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/HTTPWalletJSON.js +5 -4
- package/dist/cjs/src/wallet/substrates/HTTPWalletJSON.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/ReactNativeWebView.js +9 -9
- package/dist/cjs/src/wallet/substrates/ReactNativeWebView.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/WalletWireProcessor.js +92 -92
- package/dist/cjs/src/wallet/substrates/WalletWireProcessor.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/WalletWireTransceiver.js +387 -711
- package/dist/cjs/src/wallet/substrates/WalletWireTransceiver.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/XDM.js +4 -4
- package/dist/cjs/src/wallet/substrates/XDM.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/window.CWI.js +2 -2
- package/dist/cjs/src/wallet/substrates/window.CWI.js.map +1 -1
- package/dist/cjs/src/wallet/validationHelpers.js +9 -9
- package/dist/cjs/src/wallet/validationHelpers.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/auth/Peer.js +25 -13
- package/dist/esm/src/auth/Peer.js.map +1 -1
- package/dist/esm/src/auth/SessionManager.js +4 -7
- package/dist/esm/src/auth/SessionManager.js.map +1 -1
- package/dist/esm/src/auth/certificates/MasterCertificate.js +1 -1
- package/dist/esm/src/auth/certificates/MasterCertificate.js.map +1 -1
- package/dist/esm/src/auth/certificates/__tests/CompletedProtoWallet.js +1 -1
- package/dist/esm/src/auth/certificates/__tests/CompletedProtoWallet.js.map +1 -1
- package/dist/esm/src/auth/clients/AuthFetch.js +32 -32
- package/dist/esm/src/auth/clients/AuthFetch.js.map +1 -1
- package/dist/esm/src/auth/transports/SimplifiedFetchTransport.js +4 -4
- package/dist/esm/src/auth/transports/SimplifiedFetchTransport.js.map +1 -1
- package/dist/esm/src/compat/ECIES.js +29 -34
- package/dist/esm/src/compat/ECIES.js.map +1 -1
- package/dist/esm/src/compat/HD.js +9 -4
- package/dist/esm/src/compat/HD.js.map +1 -1
- package/dist/esm/src/compat/Mnemonic.js +12 -12
- package/dist/esm/src/compat/Mnemonic.js.map +1 -1
- package/dist/esm/src/identity/ContactsManager.js +212 -234
- package/dist/esm/src/identity/ContactsManager.js.map +1 -1
- package/dist/esm/src/identity/IdentityClient.js +199 -63
- package/dist/esm/src/identity/IdentityClient.js.map +1 -1
- package/dist/esm/src/kvstore/GlobalKVStore.js +30 -31
- package/dist/esm/src/kvstore/GlobalKVStore.js.map +1 -1
- package/dist/esm/src/kvstore/LocalKVStore.js +9 -9
- package/dist/esm/src/kvstore/LocalKVStore.js.map +1 -1
- package/dist/esm/src/kvstore/kvStoreInterpreter.js +2 -2
- package/dist/esm/src/kvstore/kvStoreInterpreter.js.map +1 -1
- package/dist/esm/src/messages/SignedMessage.js +1 -1
- package/dist/esm/src/messages/SignedMessage.js.map +1 -1
- package/dist/esm/src/overlay-tools/Historian.js +1 -1
- package/dist/esm/src/overlay-tools/Historian.js.map +1 -1
- package/dist/esm/src/overlay-tools/LookupResolver.js +213 -93
- package/dist/esm/src/overlay-tools/LookupResolver.js.map +1 -1
- package/dist/esm/src/overlay-tools/SHIPBroadcaster.js +74 -146
- package/dist/esm/src/overlay-tools/SHIPBroadcaster.js.map +1 -1
- package/dist/esm/src/primitives/AESGCM.js +2 -2
- package/dist/esm/src/primitives/AESGCM.js.map +1 -1
- package/dist/esm/src/primitives/BigNumber.js +167 -154
- package/dist/esm/src/primitives/BigNumber.js.map +1 -1
- package/dist/esm/src/primitives/Curve.js +17 -15
- package/dist/esm/src/primitives/Curve.js.map +1 -1
- package/dist/esm/src/primitives/ECDSA.js +12 -7
- package/dist/esm/src/primitives/ECDSA.js.map +1 -1
- package/dist/esm/src/primitives/Hash.js +316 -105
- package/dist/esm/src/primitives/Hash.js.map +1 -1
- package/dist/esm/src/primitives/JacobianPoint.js +8 -8
- package/dist/esm/src/primitives/JacobianPoint.js.map +1 -1
- package/dist/esm/src/primitives/K256.js +3 -3
- package/dist/esm/src/primitives/K256.js.map +1 -1
- package/dist/esm/src/primitives/Point.js +36 -40
- package/dist/esm/src/primitives/Point.js.map +1 -1
- package/dist/esm/src/primitives/PrivateKey.js +4 -4
- package/dist/esm/src/primitives/PrivateKey.js.map +1 -1
- package/dist/esm/src/primitives/PublicKey.js +4 -4
- package/dist/esm/src/primitives/PublicKey.js.map +1 -1
- package/dist/esm/src/primitives/Random.js +10 -14
- package/dist/esm/src/primitives/Random.js.map +1 -1
- package/dist/esm/src/primitives/ReaderUint8Array.js +6 -6
- package/dist/esm/src/primitives/ReaderUint8Array.js.map +1 -1
- package/dist/esm/src/primitives/Schnorr.js +1 -1
- package/dist/esm/src/primitives/Schnorr.js.map +1 -1
- package/dist/esm/src/primitives/Secp256r1.js +2 -1
- package/dist/esm/src/primitives/Secp256r1.js.map +1 -1
- package/dist/esm/src/primitives/Signature.js +8 -8
- package/dist/esm/src/primitives/Signature.js.map +1 -1
- package/dist/esm/src/primitives/SymmetricKey.js +123 -1
- package/dist/esm/src/primitives/SymmetricKey.js.map +1 -1
- package/dist/esm/src/primitives/TransactionSignature.js +20 -21
- package/dist/esm/src/primitives/TransactionSignature.js.map +1 -1
- package/dist/esm/src/primitives/utils.js +39 -48
- package/dist/esm/src/primitives/utils.js.map +1 -1
- package/dist/esm/src/registry/RegistryClient.js +31 -23
- package/dist/esm/src/registry/RegistryClient.js.map +1 -1
- package/dist/esm/src/remittance/RemittanceManager.js +19 -18
- package/dist/esm/src/remittance/RemittanceManager.js.map +1 -1
- package/dist/esm/src/remittance/modules/BasicBRC29.js.map +1 -1
- package/dist/esm/src/script/Script.js +93 -170
- package/dist/esm/src/script/Script.js.map +1 -1
- package/dist/esm/src/script/ScriptEvaluationError.js +2 -2
- package/dist/esm/src/script/ScriptEvaluationError.js.map +1 -1
- package/dist/esm/src/script/Spend.js +14 -12
- package/dist/esm/src/script/Spend.js.map +1 -1
- package/dist/esm/src/script/templates/PushDrop.js +4 -3
- package/dist/esm/src/script/templates/PushDrop.js.map +1 -1
- package/dist/esm/src/script/templates/RPuzzle.js +2 -4
- package/dist/esm/src/script/templates/RPuzzle.js.map +1 -1
- package/dist/esm/src/storage/StorageDownloader.js +1 -1
- package/dist/esm/src/storage/StorageDownloader.js.map +1 -1
- package/dist/esm/src/totp/totp.js +1 -1
- package/dist/esm/src/totp/totp.js.map +1 -1
- package/dist/esm/src/transaction/Beef.js +229 -186
- package/dist/esm/src/transaction/Beef.js.map +1 -1
- package/dist/esm/src/transaction/BeefConstants.js +16 -0
- package/dist/esm/src/transaction/BeefConstants.js.map +1 -0
- package/dist/esm/src/transaction/BeefTx.js +3 -3
- package/dist/esm/src/transaction/BeefTx.js.map +1 -1
- package/dist/esm/src/transaction/MerklePath.js +4 -4
- package/dist/esm/src/transaction/MerklePath.js.map +1 -1
- package/dist/esm/src/transaction/Transaction.js +49 -52
- package/dist/esm/src/transaction/Transaction.js.map +1 -1
- package/dist/esm/src/transaction/fee-models/SatoshisPerKilobyte.js +1 -1
- package/dist/esm/src/transaction/fee-models/SatoshisPerKilobyte.js.map +1 -1
- package/dist/esm/src/transaction/http/BinaryFetchClient.js +9 -9
- package/dist/esm/src/transaction/http/BinaryFetchClient.js.map +1 -1
- package/dist/esm/src/transaction/http/DefaultHttpClient.js +9 -9
- package/dist/esm/src/transaction/http/DefaultHttpClient.js.map +1 -1
- package/dist/esm/src/wallet/CachedKeyDeriver.js +1 -1
- package/dist/esm/src/wallet/CachedKeyDeriver.js.map +1 -1
- package/dist/esm/src/wallet/WalletClient.js.map +1 -1
- package/dist/esm/src/wallet/WalletError.js.map +1 -1
- package/dist/esm/src/wallet/substrates/HTTPWalletJSON.js +5 -4
- package/dist/esm/src/wallet/substrates/HTTPWalletJSON.js.map +1 -1
- package/dist/esm/src/wallet/substrates/ReactNativeWebView.js +9 -9
- package/dist/esm/src/wallet/substrates/ReactNativeWebView.js.map +1 -1
- package/dist/esm/src/wallet/substrates/WalletWireProcessor.js +92 -92
- package/dist/esm/src/wallet/substrates/WalletWireProcessor.js.map +1 -1
- package/dist/esm/src/wallet/substrates/WalletWireTransceiver.js +387 -711
- package/dist/esm/src/wallet/substrates/WalletWireTransceiver.js.map +1 -1
- package/dist/esm/src/wallet/substrates/XDM.js +4 -4
- package/dist/esm/src/wallet/substrates/XDM.js.map +1 -1
- package/dist/esm/src/wallet/substrates/window.CWI.js +2 -2
- package/dist/esm/src/wallet/substrates/window.CWI.js.map +1 -1
- package/dist/esm/src/wallet/validationHelpers.js +9 -9
- package/dist/esm/src/wallet/validationHelpers.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/auth/Peer.d.ts +13 -0
- package/dist/types/src/auth/Peer.d.ts.map +1 -1
- package/dist/types/src/auth/SessionManager.d.ts.map +1 -1
- package/dist/types/src/auth/clients/AuthFetch.d.ts.map +1 -1
- package/dist/types/src/compat/ECIES.d.ts.map +1 -1
- package/dist/types/src/compat/HD.d.ts.map +1 -1
- package/dist/types/src/identity/ContactsManager.d.ts +31 -2
- package/dist/types/src/identity/ContactsManager.d.ts.map +1 -1
- package/dist/types/src/identity/IdentityClient.d.ts +75 -10
- package/dist/types/src/identity/IdentityClient.d.ts.map +1 -1
- package/dist/types/src/kvstore/GlobalKVStore.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/LookupResolver.d.ts +73 -2
- package/dist/types/src/overlay-tools/LookupResolver.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts +18 -3
- package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts.map +1 -1
- package/dist/types/src/primitives/BigNumber.d.ts +13 -3
- package/dist/types/src/primitives/BigNumber.d.ts.map +1 -1
- package/dist/types/src/primitives/Curve.d.ts.map +1 -1
- package/dist/types/src/primitives/ECDSA.d.ts.map +1 -1
- package/dist/types/src/primitives/Hash.d.ts +22 -17
- package/dist/types/src/primitives/Hash.d.ts.map +1 -1
- package/dist/types/src/primitives/JacobianPoint.d.ts +3 -1
- package/dist/types/src/primitives/JacobianPoint.d.ts.map +1 -1
- package/dist/types/src/primitives/Point.d.ts.map +1 -1
- package/dist/types/src/primitives/Random.d.ts +2 -2
- package/dist/types/src/primitives/Random.d.ts.map +1 -1
- package/dist/types/src/primitives/ReaderUint8Array.d.ts.map +1 -1
- package/dist/types/src/primitives/Schnorr.d.ts +2 -1
- package/dist/types/src/primitives/Schnorr.d.ts.map +1 -1
- package/dist/types/src/primitives/Secp256r1.d.ts.map +1 -1
- package/dist/types/src/primitives/SymmetricKey.d.ts.map +1 -1
- package/dist/types/src/primitives/utils.d.ts +2 -4
- package/dist/types/src/primitives/utils.d.ts.map +1 -1
- package/dist/types/src/registry/RegistryClient.d.ts.map +1 -1
- package/dist/types/src/remittance/RemittanceManager.d.ts.map +1 -1
- package/dist/types/src/remittance/modules/BasicBRC29.d.ts.map +1 -1
- package/dist/types/src/script/Script.d.ts +15 -8
- package/dist/types/src/script/Script.d.ts.map +1 -1
- package/dist/types/src/script/Spend.d.ts.map +1 -1
- package/dist/types/src/script/templates/PushDrop.d.ts +3 -1
- package/dist/types/src/script/templates/PushDrop.d.ts.map +1 -1
- package/dist/types/src/script/templates/RPuzzle.d.ts.map +1 -1
- package/dist/types/src/transaction/Beef.d.ts +46 -8
- package/dist/types/src/transaction/Beef.d.ts.map +1 -1
- package/dist/types/src/transaction/BeefConstants.d.ts +15 -0
- package/dist/types/src/transaction/BeefConstants.d.ts.map +1 -0
- package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
- package/dist/types/src/wallet/CachedKeyDeriver.d.ts.map +1 -1
- package/dist/types/src/wallet/KeyDeriver.d.ts +1 -1
- package/dist/types/src/wallet/KeyDeriver.d.ts.map +1 -1
- package/dist/types/src/wallet/Wallet.interfaces.d.ts +18 -3
- package/dist/types/src/wallet/Wallet.interfaces.d.ts.map +1 -1
- package/dist/types/src/wallet/WalletClient.d.ts +8 -8
- package/dist/types/src/wallet/WalletClient.d.ts.map +1 -1
- package/dist/types/src/wallet/substrates/HTTPWalletJSON.d.ts +7 -7
- package/dist/types/src/wallet/substrates/HTTPWalletJSON.d.ts.map +1 -1
- package/dist/types/src/wallet/substrates/WalletWireTransceiver.d.ts +36 -7
- package/dist/types/src/wallet/substrates/WalletWireTransceiver.d.ts.map +1 -1
- package/dist/types/src/wallet/substrates/window.CWI.d.ts +9 -9
- package/dist/types/src/wallet/substrates/window.CWI.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +3 -3
- package/package.json +1 -1
- package/src/auth/Peer.ts +26 -13
- package/src/auth/SessionManager.ts +4 -7
- package/src/auth/certificates/MasterCertificate.ts +1 -1
- package/src/auth/certificates/__tests/CompletedProtoWallet.ts +1 -1
- package/src/auth/clients/AuthFetch.ts +41 -41
- package/src/auth/transports/SimplifiedFetchTransport.ts +4 -4
- package/src/compat/ECIES.ts +29 -34
- package/src/compat/HD.ts +10 -5
- package/src/compat/Mnemonic.ts +11 -11
- package/src/compat/__tests/HD.test.ts +19 -0
- package/src/identity/ContactsManager.ts +236 -258
- package/src/identity/IdentityClient.ts +244 -71
- package/src/identity/__tests/IdentityClient.additional.test.ts +150 -1
- package/src/identity/__tests/IdentityClient.test.ts +27 -3
- package/src/kvstore/GlobalKVStore.ts +31 -32
- package/src/kvstore/LocalKVStore.ts +8 -8
- package/src/kvstore/kvStoreInterpreter.ts +2 -2
- package/src/messages/SignedMessage.ts +1 -1
- package/src/overlay-tools/Historian.ts +1 -1
- package/src/overlay-tools/LookupResolver.ts +264 -90
- package/src/overlay-tools/SHIPBroadcaster.ts +92 -168
- package/src/primitives/AESGCM.ts +2 -2
- package/src/primitives/BigNumber.ts +122 -113
- package/src/primitives/Curve.ts +16 -15
- package/src/primitives/ECDSA.ts +10 -8
- package/src/primitives/Hash.ts +381 -146
- package/src/primitives/JacobianPoint.ts +13 -11
- package/src/primitives/K256.ts +3 -3
- package/src/primitives/Point.ts +35 -38
- package/src/primitives/PrivateKey.ts +3 -3
- package/src/primitives/PublicKey.ts +3 -3
- package/src/primitives/Random.ts +11 -14
- package/src/primitives/ReaderUint8Array.ts +7 -7
- package/src/primitives/Schnorr.ts +2 -1
- package/src/primitives/Secp256r1.ts +2 -1
- package/src/primitives/Signature.ts +8 -8
- package/src/primitives/SymmetricKey.ts +145 -1
- package/src/primitives/TransactionSignature.ts +16 -16
- package/src/primitives/__tests/Hash.additional.test.ts +65 -0
- package/src/primitives/__tests/Hash.test.ts +6 -1
- package/src/primitives/utils.ts +37 -47
- package/src/registry/RegistryClient.ts +25 -25
- package/src/remittance/RemittanceManager.ts +17 -18
- package/src/remittance/modules/BasicBRC29.ts +2 -5
- package/src/script/Script.ts +114 -170
- package/src/script/ScriptEvaluationError.ts +2 -2
- package/src/script/Spend.ts +14 -15
- package/src/script/templates/PushDrop.ts +5 -3
- package/src/script/templates/RPuzzle.ts +2 -4
- package/src/storage/StorageDownloader.ts +1 -1
- package/src/totp/totp.ts +1 -1
- package/src/transaction/Beef.ts +241 -203
- package/src/transaction/BeefConstants.ts +16 -0
- package/src/transaction/BeefTx.ts +3 -3
- package/src/transaction/MerklePath.ts +4 -4
- package/src/transaction/Transaction.ts +48 -51
- package/src/transaction/fee-models/SatoshisPerKilobyte.ts +1 -1
- package/src/transaction/http/BinaryFetchClient.ts +8 -8
- package/src/transaction/http/DefaultHttpClient.ts +8 -8
- package/src/wallet/CachedKeyDeriver.ts +8 -6
- package/src/wallet/KeyDeriver.ts +1 -1
- package/src/wallet/Wallet.interfaces.ts +18 -5
- package/src/wallet/WalletClient.ts +9 -9
- package/src/wallet/WalletError.ts +1 -1
- package/src/wallet/__tests/WalletClient.substrate.test.ts +10 -6
- package/src/wallet/substrates/HTTPWalletJSON.ts +22 -21
- package/src/wallet/substrates/ReactNativeWebView.ts +9 -9
- package/src/wallet/substrates/WalletWireProcessor.ts +83 -83
- package/src/wallet/substrates/WalletWireTransceiver.ts +528 -938
- package/src/wallet/substrates/XDM.ts +4 -4
- package/src/wallet/substrates/__tests/HTTPWalletJSON.test.ts +38 -25
- package/src/wallet/substrates/__tests/ReactNativeWebView.test.ts +174 -0
- package/src/wallet/substrates/__tests/window.CWI.test.ts +256 -0
- package/src/wallet/substrates/window.CWI.ts +11 -11
- package/src/wallet/validationHelpers.ts +9 -9
|
@@ -146,7 +146,7 @@ export class GlobalKVStore {
|
|
|
146
146
|
throw new Error('Key must be a non-empty string.')
|
|
147
147
|
}
|
|
148
148
|
if (typeof value !== 'string') {
|
|
149
|
-
throw new
|
|
149
|
+
throw new TypeError('Value must be a string.')
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
const controller = await this.getIdentityKey()
|
|
@@ -186,7 +186,30 @@ export class GlobalKVStore {
|
|
|
186
186
|
const existingEntries = await this.queryOverlay({ key, controller }, { includeToken: true })
|
|
187
187
|
const existingToken = existingEntries.length > 0 ? existingEntries[0].token : undefined
|
|
188
188
|
|
|
189
|
-
if (existingToken
|
|
189
|
+
if (existingToken == null) {
|
|
190
|
+
// Create new token
|
|
191
|
+
const { tx } = await this.wallet.createAction({
|
|
192
|
+
description: tokenSetDescription,
|
|
193
|
+
outputs: [{
|
|
194
|
+
satoshis: tokenAmount ?? this.config.tokenAmount as number,
|
|
195
|
+
lockingScript: lockingScript.toHex(),
|
|
196
|
+
outputDescription: 'KVStore token'
|
|
197
|
+
}],
|
|
198
|
+
options: {
|
|
199
|
+
acceptDelayedBroadcast: this.config.acceptDelayedBroadcast,
|
|
200
|
+
noSend: this.config.overlayBroadcast,
|
|
201
|
+
randomizeOutputs: false
|
|
202
|
+
}
|
|
203
|
+
}, this.config.originator)
|
|
204
|
+
|
|
205
|
+
if (tx == null) {
|
|
206
|
+
throw new Error('Failed to create transaction')
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const transaction = Transaction.fromAtomicBEEF(tx)
|
|
210
|
+
await this.submitToOverlay(transaction)
|
|
211
|
+
return `${transaction.id('hex')}.0`
|
|
212
|
+
} else {
|
|
190
213
|
// Update existing token
|
|
191
214
|
const inputs: CreateActionInput[] = [{
|
|
192
215
|
outpoint: `${existingToken.txid}.${existingToken.outputIndex}`,
|
|
@@ -239,29 +262,6 @@ export class GlobalKVStore {
|
|
|
239
262
|
const transaction = Transaction.fromAtomicBEEF(finalTx)
|
|
240
263
|
await this.submitToOverlay(transaction)
|
|
241
264
|
return `${transaction.id('hex')}.0`
|
|
242
|
-
} else {
|
|
243
|
-
// Create new token
|
|
244
|
-
const { tx } = await this.wallet.createAction({
|
|
245
|
-
description: tokenSetDescription,
|
|
246
|
-
outputs: [{
|
|
247
|
-
satoshis: tokenAmount ?? this.config.tokenAmount as number,
|
|
248
|
-
lockingScript: lockingScript.toHex(),
|
|
249
|
-
outputDescription: 'KVStore token'
|
|
250
|
-
}],
|
|
251
|
-
options: {
|
|
252
|
-
acceptDelayedBroadcast: this.config.acceptDelayedBroadcast,
|
|
253
|
-
noSend: this.config.overlayBroadcast,
|
|
254
|
-
randomizeOutputs: false
|
|
255
|
-
}
|
|
256
|
-
}, this.config.originator)
|
|
257
|
-
|
|
258
|
-
if (tx == null) {
|
|
259
|
-
throw new Error('Failed to create transaction')
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const transaction = Transaction.fromAtomicBEEF(tx)
|
|
263
|
-
await this.submitToOverlay(transaction)
|
|
264
|
-
return `${transaction.id('hex')}.0`
|
|
265
265
|
}
|
|
266
266
|
}, this.topicBroadcaster)
|
|
267
267
|
|
|
@@ -421,9 +421,7 @@ export class GlobalKVStore {
|
|
|
421
421
|
* @private
|
|
422
422
|
*/
|
|
423
423
|
private async getIdentityKey (): Promise<PubKeyHex> {
|
|
424
|
-
|
|
425
|
-
this.cachedIdentityKey = (await this.wallet.getPublicKey({ identityKey: true }, this.config.originator)).publicKey
|
|
426
|
-
}
|
|
424
|
+
this.cachedIdentityKey ??= (await this.wallet.getPublicKey({ identityKey: true }, this.config.originator)).publicKey
|
|
427
425
|
return this.cachedIdentityKey
|
|
428
426
|
}
|
|
429
427
|
|
|
@@ -467,13 +465,13 @@ export class GlobalKVStore {
|
|
|
467
465
|
const signature = decoded.fields.pop() as number[]
|
|
468
466
|
try {
|
|
469
467
|
await anyoneWallet.verifySignature({
|
|
470
|
-
data: decoded.fields.
|
|
468
|
+
data: decoded.fields.flat(),
|
|
471
469
|
signature,
|
|
472
470
|
counterparty: Utils.toHex(decoded.fields[kvProtocol.controller]),
|
|
473
471
|
protocolID: JSON.parse(Utils.toUTF8(decoded.fields[kvProtocol.protocolID])),
|
|
474
472
|
keyID: Utils.toUTF8(decoded.fields[kvProtocol.key])
|
|
475
473
|
})
|
|
476
|
-
} catch (
|
|
474
|
+
} catch (_signatureVerificationError) {
|
|
477
475
|
// Skip all outputs that fail signature verification
|
|
478
476
|
continue
|
|
479
477
|
}
|
|
@@ -483,7 +481,7 @@ export class GlobalKVStore {
|
|
|
483
481
|
if (hasTagsField && decoded.fields[kvProtocol.tags] != null) {
|
|
484
482
|
try {
|
|
485
483
|
tags = JSON.parse(Utils.toUTF8(decoded.fields[kvProtocol.tags]))
|
|
486
|
-
} catch (
|
|
484
|
+
} catch (_tagsParseError) {
|
|
487
485
|
// If tags parsing fails, continue without tags
|
|
488
486
|
tags = undefined
|
|
489
487
|
}
|
|
@@ -514,7 +512,8 @@ export class GlobalKVStore {
|
|
|
514
512
|
}
|
|
515
513
|
|
|
516
514
|
entries.push(entry)
|
|
517
|
-
} catch (
|
|
515
|
+
} catch (_malformedOutputError) {
|
|
516
|
+
// Skip malformed or undecodable outputs rather than failing the entire query
|
|
518
517
|
continue
|
|
519
518
|
}
|
|
520
519
|
}
|
|
@@ -155,7 +155,7 @@ export default class LocalKVStore {
|
|
|
155
155
|
if (outputs.length === 0) {
|
|
156
156
|
return r
|
|
157
157
|
}
|
|
158
|
-
const output = outputs.
|
|
158
|
+
const output = outputs.at(-1)!
|
|
159
159
|
r.outpoint = output.outpoint
|
|
160
160
|
let field: number[]
|
|
161
161
|
try {
|
|
@@ -169,23 +169,23 @@ export default class LocalKVStore {
|
|
|
169
169
|
} catch (error) {
|
|
170
170
|
throw new Error(`Invalid value found. You need to call set to collapse the corrupted state (or relinquish the corrupted ${outputs[0].outpoint} output from the ${this.context} basket) before you can get this value again. Original error: ${error instanceof Error ? error.message : String(error)}`)
|
|
171
171
|
}
|
|
172
|
-
if (
|
|
173
|
-
r.value = Utils.toUTF8(field)
|
|
174
|
-
} else {
|
|
172
|
+
if (this.encrypt) {
|
|
175
173
|
const { plaintext } = await this.wallet.decrypt({
|
|
176
174
|
...this.getProtocol(key),
|
|
177
175
|
ciphertext: field
|
|
178
176
|
}, this.originator)
|
|
179
177
|
r.value = Utils.toUTF8(plaintext)
|
|
178
|
+
} else {
|
|
179
|
+
r.value = Utils.toUTF8(field)
|
|
180
180
|
}
|
|
181
181
|
return r
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
private getInputs (outputs: WalletOutput[]): CreateActionInput[] {
|
|
185
185
|
const inputs: CreateActionInput[] = []
|
|
186
|
-
for (
|
|
186
|
+
for (const output of outputs) {
|
|
187
187
|
inputs.push({
|
|
188
|
-
outpoint:
|
|
188
|
+
outpoint: output.outpoint,
|
|
189
189
|
unlockingScriptLength: 74,
|
|
190
190
|
inputDescription: 'Previous key-value token'
|
|
191
191
|
})
|
|
@@ -197,7 +197,7 @@ export default class LocalKVStore {
|
|
|
197
197
|
const p = this.getProtocol(key)
|
|
198
198
|
const tx = Transaction.fromAtomicBEEF(atomicBEEF)
|
|
199
199
|
const spends: Record<number, SignActionSpend> = {}
|
|
200
|
-
for (
|
|
200
|
+
for (const [i] of outputs.entries()) {
|
|
201
201
|
const unlocker = pushdrop.unlock(p.protocolID, p.keyID, 'self')
|
|
202
202
|
const unlockingScript = await unlocker.sign(tx, i)
|
|
203
203
|
spends[i] = {
|
|
@@ -328,7 +328,7 @@ export default class LocalKVStore {
|
|
|
328
328
|
}
|
|
329
329
|
}, this.originator)
|
|
330
330
|
if (typeof signableTransaction !== 'object') {
|
|
331
|
-
throw new
|
|
331
|
+
throw new TypeError('Wallet did not return a signable transaction when expected.')
|
|
332
332
|
}
|
|
333
333
|
const spends = await this.getSpends(key, outputs, pushdrop, signableTransaction.tx)
|
|
334
334
|
const { txid } = await this.wallet.signAction({
|
|
@@ -25,8 +25,8 @@ export interface KVContext { key: string, protocolID: WalletProtocol }
|
|
|
25
25
|
export const kvStoreInterpreter: InterpreterFunction<string, KVContext> = async (transaction: Transaction, outputIndex: number, ctx?: KVContext): Promise<string | undefined> => {
|
|
26
26
|
try {
|
|
27
27
|
const output = transaction.outputs[outputIndex]
|
|
28
|
-
if (output
|
|
29
|
-
if (ctx
|
|
28
|
+
if (output?.lockingScript == null) return undefined
|
|
29
|
+
if (ctx?.key == null) return undefined
|
|
30
30
|
|
|
31
31
|
// Decode the KVStore token
|
|
32
32
|
const decoded = PushDrop.decode(output.lockingScript)
|
|
@@ -72,7 +72,7 @@ export const verify = (
|
|
|
72
72
|
const verifierRest = reader.read(32)
|
|
73
73
|
const verifierDER = toHex([verifierFirst, ...verifierRest])
|
|
74
74
|
if (typeof recipient !== 'object') {
|
|
75
|
-
throw new
|
|
75
|
+
throw new TypeError(
|
|
76
76
|
`This signature can only be verified with knowledge of a specific private key. The associated public key is: ${verifierDER}`
|
|
77
77
|
)
|
|
78
78
|
}
|
|
@@ -181,7 +181,7 @@ export class Historian<T, C = unknown> {
|
|
|
181
181
|
|
|
182
182
|
// History is built in reverse chronological order during traversal,
|
|
183
183
|
// so we reverse it to return oldest-first
|
|
184
|
-
const chronological = history.
|
|
184
|
+
const chronological = history.toReversed()
|
|
185
185
|
|
|
186
186
|
if (this.historyCache != null) {
|
|
187
187
|
const cacheKey = this.historyKey(startTransaction, context)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Transaction } from '../transaction/index.js'
|
|
2
|
+
import { Beef } from '../transaction/Beef.js'
|
|
2
3
|
import OverlayAdminTokenTemplate from './OverlayAdminTokenTemplate.js'
|
|
3
4
|
import * as Utils from '../primitives/utils.js'
|
|
4
5
|
import { getOverlayHostReputationTracker, HostReputationTracker } from './HostReputationTracker.js'
|
|
@@ -35,9 +36,49 @@ export type LookupAnswer =
|
|
|
35
36
|
beef: number[]
|
|
36
37
|
outputIndex: number
|
|
37
38
|
context?: number[]
|
|
39
|
+
/** Optional txid hint. When present, consumers can skip re-parsing beef to derive the txid. */
|
|
40
|
+
txid?: string
|
|
38
41
|
}>
|
|
39
42
|
}
|
|
40
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Per-call options for {@link LookupResolver.query} and {@link LookupResolver.query$}.
|
|
46
|
+
* All optional; defaults preserve prior behavior.
|
|
47
|
+
*/
|
|
48
|
+
export interface LookupQueryOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Override the grace window (ms) between the first valid response and the resolution of the query.
|
|
51
|
+
* Late responders arriving within this window are merged into the result. Default 80 ms.
|
|
52
|
+
* Raise for identity-style paths (e.g. ~300 ms) where divergence between hosts matters.
|
|
53
|
+
*/
|
|
54
|
+
graceMs?: number
|
|
55
|
+
/**
|
|
56
|
+
* Soft timeout (ms). When set:
|
|
57
|
+
* - `query()` resolves with whatever has arrived as soon as any host answers, or after this timeout.
|
|
58
|
+
* - `query$()` emits a (possibly empty) snapshot after this timeout if no host has answered yet,
|
|
59
|
+
* then continues yielding late-host enrichments until the iterator is broken or final emission.
|
|
60
|
+
*/
|
|
61
|
+
softTimeoutMs?: number
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* One emission from {@link LookupResolver.query$}. Carries the cumulative output set discovered so far
|
|
66
|
+
* plus a small envelope describing progress across hosts. Callers can render fast on the first emission
|
|
67
|
+
* and refine in place as more hosts answer.
|
|
68
|
+
*/
|
|
69
|
+
export interface LookupAnswerProgress {
|
|
70
|
+
type: 'output-list'
|
|
71
|
+
outputs: Array<{ beef: number[], outputIndex: number, context?: number[], txid?: string }>
|
|
72
|
+
/** Parallel array of resolved tx ids for each output (same index as `outputs`). */
|
|
73
|
+
txIds: string[]
|
|
74
|
+
/** True only for the final emission, after every in-flight host has settled. */
|
|
75
|
+
isFinal: boolean
|
|
76
|
+
/** Number of ranked hosts that were queried. */
|
|
77
|
+
hostCount: number
|
|
78
|
+
/** Number of hosts that have settled (success / fail / timeout). */
|
|
79
|
+
completedHosts: number
|
|
80
|
+
}
|
|
81
|
+
|
|
41
82
|
/** Default SLAP trackers */
|
|
42
83
|
export const DEFAULT_SLAP_TRACKERS: string[] = [
|
|
43
84
|
// BSVA clusters
|
|
@@ -119,7 +160,7 @@ export class HTTPSOverlayLookupFacilitator implements OverlayLookupFacilitator {
|
|
|
119
160
|
|
|
120
161
|
constructor (httpClient = defaultFetch, allowHTTP: boolean = false) {
|
|
121
162
|
if (typeof httpClient !== 'function') {
|
|
122
|
-
throw new
|
|
163
|
+
throw new TypeError(
|
|
123
164
|
'HTTPSOverlayLookupFacilitator requires a fetch implementation. ' +
|
|
124
165
|
'In environments without fetch, provide a polyfill or custom implementation.'
|
|
125
166
|
)
|
|
@@ -131,7 +172,7 @@ export class HTTPSOverlayLookupFacilitator implements OverlayLookupFacilitator {
|
|
|
131
172
|
async lookup (
|
|
132
173
|
url: string,
|
|
133
174
|
question: LookupQuestion,
|
|
134
|
-
timeout: number =
|
|
175
|
+
timeout: number = 2000
|
|
135
176
|
): Promise<LookupAnswer> {
|
|
136
177
|
if (!url.startsWith('https:') && !this.allowHTTP) {
|
|
137
178
|
throw new Error(
|
|
@@ -139,7 +180,7 @@ export class HTTPSOverlayLookupFacilitator implements OverlayLookupFacilitator {
|
|
|
139
180
|
)
|
|
140
181
|
}
|
|
141
182
|
|
|
142
|
-
const controller = typeof AbortController
|
|
183
|
+
const controller = typeof AbortController === 'undefined' ? undefined : new AbortController()
|
|
143
184
|
const timer = setTimeout(() => {
|
|
144
185
|
try { controller?.abort() } catch { /* noop */ }
|
|
145
186
|
}, timeout)
|
|
@@ -158,44 +199,61 @@ export class HTTPSOverlayLookupFacilitator implements OverlayLookupFacilitator {
|
|
|
158
199
|
|
|
159
200
|
if (!response.ok) throw new Error(`Failed to facilitate lookup (HTTP ${response.status})`)
|
|
160
201
|
if (response.headers.get('content-type') === 'application/octet-stream') {
|
|
161
|
-
|
|
162
|
-
const r = new Utils.Reader([...new Uint8Array(payload)])
|
|
163
|
-
const nOutpoints = r.readVarIntNum()
|
|
164
|
-
const outpoints: Array<{ txid: string, outputIndex: number, context?: number[] }> = []
|
|
165
|
-
for (let i = 0; i < nOutpoints; i++) {
|
|
166
|
-
const txid = Utils.toHex(r.read(32))
|
|
167
|
-
const outputIndex = r.readVarIntNum()
|
|
168
|
-
const contextLength = r.readVarIntNum()
|
|
169
|
-
let context
|
|
170
|
-
if (contextLength > 0) {
|
|
171
|
-
context = r.read(contextLength)
|
|
172
|
-
}
|
|
173
|
-
outpoints.push({
|
|
174
|
-
txid,
|
|
175
|
-
outputIndex,
|
|
176
|
-
context
|
|
177
|
-
})
|
|
178
|
-
}
|
|
179
|
-
const beef = r.read()
|
|
180
|
-
return {
|
|
181
|
-
type: 'output-list',
|
|
182
|
-
outputs: outpoints.map(x => ({
|
|
183
|
-
outputIndex: x.outputIndex,
|
|
184
|
-
context: x.context,
|
|
185
|
-
beef: Transaction.fromBEEF(beef, x.txid).toBEEF()
|
|
186
|
-
}))
|
|
187
|
-
}
|
|
188
|
-
} else {
|
|
189
|
-
return await response.json()
|
|
202
|
+
return await this.parseOctetStreamLookup(response)
|
|
190
203
|
}
|
|
204
|
+
return await response.json()
|
|
191
205
|
} catch (e) {
|
|
192
206
|
// Normalize timeouts to a consistent error message
|
|
193
|
-
if ((e as
|
|
207
|
+
if ((e as { name?: string })?.name === 'AbortError') {
|
|
208
|
+
throw new Error('Request timed out')
|
|
209
|
+
}
|
|
194
210
|
throw e
|
|
195
211
|
} finally {
|
|
196
212
|
clearTimeout(timer)
|
|
197
213
|
}
|
|
198
214
|
}
|
|
215
|
+
|
|
216
|
+
/** Parse the aggregated octet-stream lookup response into an output-list LookupAnswer. */
|
|
217
|
+
private async parseOctetStreamLookup (response: Response): Promise<LookupAnswer> {
|
|
218
|
+
const payload = await response.arrayBuffer()
|
|
219
|
+
const r = new Utils.Reader([...new Uint8Array(payload)])
|
|
220
|
+
const nOutpoints = r.readVarIntNum()
|
|
221
|
+
const outpoints: Array<{ txid: string, outputIndex: number, context?: number[] }> = []
|
|
222
|
+
for (let i = 0; i < nOutpoints; i++) {
|
|
223
|
+
const txid = Utils.toHex(r.read(32))
|
|
224
|
+
const outputIndex = r.readVarIntNum()
|
|
225
|
+
const contextLength = r.readVarIntNum()
|
|
226
|
+
const context = contextLength > 0 ? r.read(contextLength) : undefined
|
|
227
|
+
outpoints.push({ txid, outputIndex, context })
|
|
228
|
+
}
|
|
229
|
+
const beef = r.read()
|
|
230
|
+
const beefObj = Beef.fromBinary(beef)
|
|
231
|
+
const outputs = await this.extractAtomicOutputs(outpoints, beefObj)
|
|
232
|
+
return { type: 'output-list', outputs }
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Memoize per-txid atomic BEEF extraction, yielding to the event loop between outputs. */
|
|
236
|
+
private async extractAtomicOutputs (
|
|
237
|
+
outpoints: Array<{ txid: string, outputIndex: number, context?: number[] }>,
|
|
238
|
+
beefObj: Beef
|
|
239
|
+
): Promise<Array<{ outputIndex: number, context?: number[], beef: number[], txid: string }>> {
|
|
240
|
+
const beefByTxid = new Map<string, number[]>()
|
|
241
|
+
const outputs: Array<{ outputIndex: number, context?: number[], beef: number[], txid: string }> = new Array(outpoints.length)
|
|
242
|
+
for (let idx = 0; idx < outpoints.length; idx++) {
|
|
243
|
+
const x = outpoints[idx]
|
|
244
|
+
let beefBytes = beefByTxid.get(x.txid)
|
|
245
|
+
if (beefBytes === undefined) {
|
|
246
|
+
beefBytes = beefObj.toBinaryAtomic(x.txid)
|
|
247
|
+
beefByTxid.set(x.txid, beefBytes)
|
|
248
|
+
}
|
|
249
|
+
outputs[idx] = { outputIndex: x.outputIndex, context: x.context, beef: beefBytes, txid: x.txid }
|
|
250
|
+
// Yield to event loop so UI animations and other JS don't starve.
|
|
251
|
+
if (idx > 0 && idx < outpoints.length - 1) {
|
|
252
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 0))
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return outputs
|
|
256
|
+
}
|
|
199
257
|
}
|
|
200
258
|
|
|
201
259
|
/**
|
|
@@ -248,11 +306,53 @@ export default class LookupResolver {
|
|
|
248
306
|
|
|
249
307
|
/**
|
|
250
308
|
* Given a LookupQuestion, returns a LookupAnswer. Aggregates across multiple services and supports resiliency.
|
|
309
|
+
*
|
|
310
|
+
* Optional `options.graceMs` overrides the per-call grace window (default 80 ms).
|
|
311
|
+
* Optional `options.softTimeoutMs` resolves the query early with whatever has arrived once any host has
|
|
312
|
+
* answered (or with an empty result if no host has answered by `softTimeoutMs`).
|
|
251
313
|
*/
|
|
252
314
|
async query (
|
|
253
315
|
question: LookupQuestion,
|
|
254
|
-
timeout?: number
|
|
316
|
+
timeout?: number,
|
|
317
|
+
options?: LookupQueryOptions
|
|
255
318
|
): Promise<LookupAnswer> {
|
|
319
|
+
// Existing fast-but-narrow contract: return at the first cumulative emission
|
|
320
|
+
// (the post-grace aggregate, or the final emission when every host settles
|
|
321
|
+
// before the grace window). Callers wanting progressive enrichment use query$().
|
|
322
|
+
// Take only the first emission, then explicitly close the iterator so the
|
|
323
|
+
// generator's `finally` block runs and clears any outstanding timers.
|
|
324
|
+
const iter = this.query$(question, timeout, options)[Symbol.asyncIterator]()
|
|
325
|
+
let last: LookupAnswerProgress | null = null
|
|
326
|
+
try {
|
|
327
|
+
const { value, done } = await iter.next()
|
|
328
|
+
if (done !== true && value != null) last = value
|
|
329
|
+
} finally {
|
|
330
|
+
await iter.return?.(undefined)
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
type: 'output-list',
|
|
334
|
+
outputs: last?.outputs ?? []
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Iterable form of {@link query}. Emits partial results as hosts answer.
|
|
340
|
+
*
|
|
341
|
+
* Emission order:
|
|
342
|
+
* - First emission: after the grace window expires (or as soon as the soft timeout elapses), containing
|
|
343
|
+
* every output gathered from hosts that answered by then.
|
|
344
|
+
* - Subsequent emissions: re-emitted whenever a late host returns extra outputs that weren't in earlier
|
|
345
|
+
* emissions. Each emission contains the cumulative `outputs` set.
|
|
346
|
+
* - Final emission: `isFinal: true` once all in-flight hosts have settled (success / fail / timeout). The
|
|
347
|
+
* caller can `break` early; outstanding work is bounded by the per-host timeout.
|
|
348
|
+
*
|
|
349
|
+
* No host work runs past its per-host `timeout` — there is no leak risk on early break.
|
|
350
|
+
*/
|
|
351
|
+
async * query$ (
|
|
352
|
+
question: LookupQuestion,
|
|
353
|
+
timeout?: number,
|
|
354
|
+
options?: LookupQueryOptions
|
|
355
|
+
): AsyncIterable<LookupAnswerProgress> {
|
|
256
356
|
let competentHosts: string[] = []
|
|
257
357
|
if (question.service === 'ls_slap') {
|
|
258
358
|
competentHosts = this.networkPreset === 'local' ? ['http://localhost:8080'] : this.slapTrackers
|
|
@@ -282,69 +382,116 @@ export default class LookupResolver {
|
|
|
282
382
|
throw new Error(`All competent hosts for ${question.service} are temporarily unavailable due to backoff.`)
|
|
283
383
|
}
|
|
284
384
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const GRACE_MS = 80
|
|
288
|
-
const answers: LookupAnswer[] = await new Promise<LookupAnswer[]>((resolve) => {
|
|
289
|
-
const collected: LookupAnswer[] = []
|
|
290
|
-
let pending = rankedHosts.length
|
|
291
|
-
let graceTimer: ReturnType<typeof setTimeout> | null = null
|
|
292
|
-
|
|
293
|
-
const tryResolve = (): void => {
|
|
294
|
-
if (graceTimer !== null) clearTimeout(graceTimer)
|
|
295
|
-
resolve(collected)
|
|
296
|
-
}
|
|
385
|
+
const graceMs = options?.graceMs ?? 80
|
|
386
|
+
const softTimeoutMs = options?.softTimeoutMs
|
|
297
387
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
})
|
|
388
|
+
const hostCount = rankedHosts.length
|
|
389
|
+
const outputsMap = new Map<string, { beef: number[], context?: number[], outputIndex: number }>()
|
|
390
|
+
const txIds: string[] = []
|
|
391
|
+
let completedHosts = 0
|
|
392
|
+
let firstResponseAt: number | null = null
|
|
393
|
+
|
|
394
|
+
type Event = { kind: 'answer', answer: LookupAnswer } | { kind: 'done' } | { kind: 'soft' }
|
|
395
|
+
const queue: Event[] = []
|
|
396
|
+
let waiter: ((v: void) => void) | null = null
|
|
397
|
+
const push = (e: Event): void => {
|
|
398
|
+
queue.push(e)
|
|
399
|
+
if (waiter !== null) {
|
|
400
|
+
const w = waiter
|
|
401
|
+
waiter = null
|
|
402
|
+
w()
|
|
314
403
|
}
|
|
315
|
-
}
|
|
404
|
+
}
|
|
316
405
|
|
|
317
|
-
const
|
|
406
|
+
for (const host of rankedHosts) {
|
|
407
|
+
this.lookupHostWithTracking(host, question, timeout)
|
|
408
|
+
.then((answer) => {
|
|
409
|
+
if (answer?.type === 'output-list' && Array.isArray(answer.outputs) && answer.outputs.length > 0) {
|
|
410
|
+
push({ kind: 'answer', answer })
|
|
411
|
+
}
|
|
412
|
+
})
|
|
413
|
+
.catch(() => { /* tracked already */ })
|
|
414
|
+
.finally(() => {
|
|
415
|
+
completedHosts++
|
|
416
|
+
push({ kind: 'done' })
|
|
417
|
+
})
|
|
418
|
+
}
|
|
318
419
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
return beef.join(',')
|
|
420
|
+
let softTimer: ReturnType<typeof setTimeout> | null = null
|
|
421
|
+
if (typeof softTimeoutMs === 'number' && softTimeoutMs >= 0) {
|
|
422
|
+
softTimer = setTimeout(() => push({ kind: 'soft' }), softTimeoutMs)
|
|
323
423
|
}
|
|
324
424
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
425
|
+
let graceTimer: ReturnType<typeof setTimeout> | null = null
|
|
426
|
+
let graceFired = false
|
|
427
|
+
let emittedOnce = false
|
|
428
|
+
|
|
429
|
+
const mergeAnswer = (answer: LookupAnswer): boolean => {
|
|
430
|
+
let added = false
|
|
431
|
+
const now = Date.now()
|
|
432
|
+
for (const output of answer.outputs) {
|
|
433
|
+
const txId = this.resolveTxIdForOutput(output, now)
|
|
434
|
+
if (txId === null) continue
|
|
435
|
+
const uniqKey = `${txId}.${output.outputIndex}`
|
|
436
|
+
if (!outputsMap.has(uniqKey)) {
|
|
437
|
+
outputsMap.set(uniqKey, output)
|
|
438
|
+
txIds.push(txId)
|
|
439
|
+
added = true
|
|
339
440
|
}
|
|
340
|
-
|
|
341
|
-
const uniqKey = `${memo.txId}.${output.outputIndex}`
|
|
342
|
-
outputsMap.set(uniqKey, output)
|
|
343
441
|
}
|
|
442
|
+
return added
|
|
344
443
|
}
|
|
345
|
-
|
|
444
|
+
|
|
445
|
+
const snapshot = (isFinal: boolean): LookupAnswerProgress => ({
|
|
346
446
|
type: 'output-list',
|
|
347
|
-
outputs: Array.from(outputsMap.values())
|
|
447
|
+
outputs: Array.from(outputsMap.values()),
|
|
448
|
+
txIds: txIds.slice(),
|
|
449
|
+
isFinal,
|
|
450
|
+
hostCount,
|
|
451
|
+
completedHosts
|
|
452
|
+
})
|
|
453
|
+
|
|
454
|
+
try {
|
|
455
|
+
while (completedHosts < hostCount) {
|
|
456
|
+
if (queue.length === 0) {
|
|
457
|
+
await new Promise<void>((resolve) => { waiter = resolve })
|
|
458
|
+
}
|
|
459
|
+
const e = queue.shift() as Event
|
|
460
|
+
if (e.kind === 'answer') {
|
|
461
|
+
const added = mergeAnswer(e.answer)
|
|
462
|
+
if (firstResponseAt === null) {
|
|
463
|
+
firstResponseAt = Date.now()
|
|
464
|
+
if (!graceFired && graceMs > 0) {
|
|
465
|
+
graceTimer = setTimeout(() => {
|
|
466
|
+
graceFired = true
|
|
467
|
+
push({ kind: 'soft' })
|
|
468
|
+
}, graceMs)
|
|
469
|
+
} else {
|
|
470
|
+
graceFired = true
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
if (graceFired && added) {
|
|
474
|
+
emittedOnce = true
|
|
475
|
+
yield snapshot(false)
|
|
476
|
+
}
|
|
477
|
+
} else if (e.kind === 'soft') {
|
|
478
|
+
if (!emittedOnce) {
|
|
479
|
+
graceFired = true
|
|
480
|
+
emittedOnce = true
|
|
481
|
+
yield snapshot(false)
|
|
482
|
+
}
|
|
483
|
+
if (typeof softTimeoutMs === 'number' && firstResponseAt !== null) {
|
|
484
|
+
// Soft timeout: caller asked to bail out once any answer is in. Yield final.
|
|
485
|
+
break
|
|
486
|
+
}
|
|
487
|
+
} else if (e.kind === 'done') {
|
|
488
|
+
// continue loop; final emission happens after the loop
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
yield snapshot(true)
|
|
492
|
+
} finally {
|
|
493
|
+
if (graceTimer !== null) clearTimeout(graceTimer)
|
|
494
|
+
if (softTimer !== null) clearTimeout(softTimer)
|
|
348
495
|
}
|
|
349
496
|
}
|
|
350
497
|
|
|
@@ -375,7 +522,7 @@ export default class LookupResolver {
|
|
|
375
522
|
try {
|
|
376
523
|
const hosts = await this.hostsInFlight.get(service)
|
|
377
524
|
if (typeof hosts !== 'object') {
|
|
378
|
-
throw new
|
|
525
|
+
throw new TypeError('Hosts is not defined.')
|
|
379
526
|
}
|
|
380
527
|
return hosts.slice()
|
|
381
528
|
} catch {
|
|
@@ -466,7 +613,7 @@ export default class LookupResolver {
|
|
|
466
613
|
resolve([...allHosts])
|
|
467
614
|
}
|
|
468
615
|
})
|
|
469
|
-
.catch(() => { /* tracker
|
|
616
|
+
.catch(() => { /* tracker failure tracked in reputation */ })
|
|
470
617
|
.finally(() => {
|
|
471
618
|
pending--
|
|
472
619
|
if (pending === 0 && !resolved) {
|
|
@@ -478,7 +625,34 @@ export default class LookupResolver {
|
|
|
478
625
|
})
|
|
479
626
|
}
|
|
480
627
|
|
|
481
|
-
/**
|
|
628
|
+
/**
|
|
629
|
+
* Resolve a txid for an aggregated lookup output. Uses the threaded-through `output.txid`
|
|
630
|
+
* fast path when present; otherwise memoizes Transaction.fromBEEF(beef).id('hex') keyed by
|
|
631
|
+
* the BEEF byte sequence. Returns null when the BEEF is unparseable.
|
|
632
|
+
*/
|
|
633
|
+
private resolveTxIdForOutput (
|
|
634
|
+
output: { txid?: string, beef: number[], outputIndex: number, context?: number[] },
|
|
635
|
+
now: number
|
|
636
|
+
): string | null {
|
|
637
|
+
if (typeof output.txid === 'string' && output.txid.length > 0) {
|
|
638
|
+
return output.txid
|
|
639
|
+
}
|
|
640
|
+
const keyForBeef = Array.isArray(output.beef) ? output.beef.join(',') : ''
|
|
641
|
+
const memo = this.txMemo.get(keyForBeef)
|
|
642
|
+
if (typeof memo === 'object' && memo !== null && memo.expiresAt > now) {
|
|
643
|
+
return memo.txId
|
|
644
|
+
}
|
|
645
|
+
try {
|
|
646
|
+
const txId = Transaction.fromBEEF(output.beef).id('hex')
|
|
647
|
+
if (this.txMemo.size > 4096) this.evictOldest(this.txMemo)
|
|
648
|
+
this.txMemo.set(keyForBeef, { txId, expiresAt: now + this.txMemoTtlMs })
|
|
649
|
+
return txId
|
|
650
|
+
} catch {
|
|
651
|
+
return null
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/** Evict an arbitrary "oldest" entry from a Map (iteration order). */
|
|
482
656
|
private evictOldest<T>(m: Map<string, T>): void {
|
|
483
657
|
const firstKey = m.keys().next().value
|
|
484
658
|
if (firstKey !== undefined) m.delete(firstKey)
|