Handle tss txp deletion; Add cli session restoration; Bug fixes & improvements - #4206
Open
kajoseph wants to merge 11 commits into
Open
Handle tss txp deletion; Add cli session restoration; Bug fixes & improvements#4206kajoseph wants to merge 11 commits into
kajoseph wants to merge 11 commits into
Conversation
…ss sign session var name
MichaelAJay
reviewed
Jul 29, 2026
MichaelAJay
reviewed
Jul 29, 2026
MichaelAJay
reviewed
Jul 29, 2026
MichaelAJay
reviewed
Jul 29, 2026
MichaelAJay
reviewed
Jul 29, 2026
MichaelAJay
reviewed
Jul 29, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves Threshold Signature Scheme (TSS) reliability and CLI UX/security by cleaning up server-side signing sessions when a tx proposal is deleted, adding CLI session restoration for interrupted TSS signing, and tightening wallet encryption/sensitive-data handling.
Changes:
- Delete associated TSS signing sessions when removing a pending tx proposal; harden TSS auth public-key lookup.
- Add CLI TSS session persistence/restoration and better cancellation handling; add password confirmation prompts across CLI flows.
- Improve TSS key/keygen safety (true-copy serialization, buffer zeroing/cleanup), plus assorted CLI fixes and test additions.
Reviewed changes
Copilot reviewed 30 out of 31 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/bitcore-wallet-service/src/lib/storage.ts | Adds storage helper to remove a TSS signing session document. |
| packages/bitcore-wallet-service/src/lib/server.ts | Deletes TSS signing sessions when a tx proposal is removed. |
| packages/bitcore-wallet-service/src/lib/routes/middleware/authTssRequest.ts | Prevents crashes when TSS sign session round/publicKey data is missing. |
| packages/bitcore-wallet-client/test/log.test.ts | Adds expanded logger behavior tests (levels/format/filtering/trace). |
| packages/bitcore-wallet-client/test/index.test.ts | Adds tests asserting expected public exports from the client index. |
| packages/bitcore-wallet-client/src/lib/tsssign.ts | Adds restore-session password support; emits unsubscribe event on unsubscribe. |
| packages/bitcore-wallet-client/src/lib/tsskey.ts | Ensures toObj() deep-copies buffers; zeroes keyshare buffers on encrypt; adds keygen cleanup hook. |
| packages/bitcore-wallet-client/src/lib/credentials.ts | Tightens completeness check for TSS credentials (requires >1 participant). |
| packages/bitcore-wallet-client/src/lib/common/encryption.ts | Adds explicit Buffer return types for decrypt methods. |
| packages/bitcore-tss/test/ecdsa.test.js | Adds tests for keygen cleanup and minor formatting fixes. |
| packages/bitcore-tss/test/data/vectors.ecdsa.js | Normalizes formatting/quoting in test vectors. |
| packages/bitcore-tss/ecdsa/keygen.js | Returns copied keyshare buffers; adds cleanup API and post-cleanup guard. |
| packages/bitcore-cli/types/wallet.d.ts | Renames password prompt method in wallet interface. |
| packages/bitcore-cli/test/wallets/btc-singlesig.json | Updates fixture to store encrypted key material instead of plaintext. |
| packages/bitcore-cli/test/proposals.test.ts | Updates CLI proposal flows for password prompts and prevents test exits. |
| packages/bitcore-cli/test/prompts.test.ts | Adds coverage for password confirmation behavior. |
| packages/bitcore-cli/test/create.test.ts | Updates create flows for password confirmation prompts. |
| packages/bitcore-cli/src/wallet.ts | Adds “encrypt on load” prompt; prevents saving unencrypted sensitive data; adds state dir usage; renames password method. |
| packages/bitcore-cli/src/tss.ts | Adds TSS session persistence/restoration to disk; handles session-not-found errors; improves cancel flow. |
| packages/bitcore-cli/src/prompts.ts | Implements password confirmation and retry/back behavior. |
| packages/bitcore-cli/src/filestorage.ts | Adds per-wallet .state/<walletName> directory helper for CLI state files. |
| packages/bitcore-cli/src/errors.ts | Adds ProcessCancelled error type. |
| packages/bitcore-cli/src/commands/txproposals.ts | Sorts txps by nonce/createdOn; normalizes gasLimit/nonce printing via BigInt. |
| packages/bitcore-cli/src/commands/join/joinThresholdSig.ts | Adds password confirmation; cleans up TSS keygen memory buffers. |
| packages/bitcore-cli/src/commands/join/joinMultiSig.ts | Adds password confirmation. |
| packages/bitcore-cli/src/commands/export.ts | Adds password confirmation for export file encryption. |
| packages/bitcore-cli/src/commands/create/createThresholdSig.ts | Adds password confirmation; uses spinner cancel hook; cleans up TSS keygen memory buffers. |
| packages/bitcore-cli/src/commands/create/createSingleSig.ts | Adds password confirmation. |
| packages/bitcore-cli/src/commands/create/createMultiSig.ts | Adds password confirmation. |
| packages/bitcore-cli/src/cli.ts | Fixes token selection to update persistent opts correctly. |
| eslint.config.mjs | Applies CommonJS linting mode to bitcore-tss package JS files. |
Comments suppressed due to low confidence (3)
packages/bitcore-cli/src/tss.ts:51
- Session restore currently assumes
passwordis always provided and tries to decrypt unconditionally. Ifpasswordis missing/empty,decryptWithPasswordwill throw and block signing (even though signing could proceed without persistence).
// Restore a previously-interrupted TSS session if it exists
if (fs.existsSync(storedSessionFile)) {
const storedSession = Encryption.decryptWithPassword(fs.readFileSync(storedSessionFile, 'utf8'), password);
await tssSign.restoreSession({ session: storedSession.toString(), password });
storedSession.fill(0); // Clear sensitive data from memory
packages/bitcore-cli/src/tss.ts:61
- After introducing
sessionIdfor persistence,tssSign.startshould use the same id; otherwise the state filename won’t correspond to the server session id (and restores won’t work reliably).
try {
await tssSign.start({
id,
messageHash,
derivationPath,
password
});
packages/bitcore-cli/src/wallet.ts:596
getWalletPassword()only prompts whenisWalletEncrypted()is true, but TSS signing/decryption requires a password whenever the TSS keychain is encrypted (even if the wallet’s xPriv/mnemonic are not). As-is, TSS signing can passundefinedintoTssKey.get()/Encryption.decryptWithPassword()and fail.
async getWalletPassword(): Promise<string> {
let password;
if (this.isWalletEncrypted()) {
password = await getPassword('Wallet password:', {
hidden: true,
validate: (input) => {
try {
this.#walletData.key.get(input);
} catch {
return 'Invalid password. Please try again.';
}
}
});
}
return password;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+3261
to
+3266
| try { | ||
| if (Array.isArray(txp.inputPaths)) { | ||
| const inputPaths = txp.inputPaths.length ? txp.inputPaths : ['m/0/0']; // doesn't actually matter what's in the array | ||
| await Promise.all(inputPaths.map((_, i) => this.storage.removeTssSigSession({ id: `${txp.id}:input${i}` }))); | ||
| } | ||
| } catch (err) { |
Comment on lines
+29
to
+39
| const { host, chain, walletData, stateStoragePath, messageHash, derivationPath, password, id, logMessageWaiting, logMessageCompleted } = args; | ||
| const storedSessionFile = path.join(stateStoragePath, id); | ||
|
|
||
| const transformISignature = (signature: TssSign.ISignature): string => { | ||
| return Transactions.transformSignatureObject({ chain, obj: signature }); | ||
| }; | ||
|
|
||
| const storeSession = (session: string) => { | ||
| const encrypted = JSON.stringify(Encryption.encryptWithPassword(session, password)); | ||
| fs.writeFileSync(storedSessionFile, encrypted, 'utf8'); | ||
| }; |
Comment on lines
199
to
+202
| return { | ||
| privateKeyShare: keyShare, | ||
| reducedPrivateKeyShare: rKeyShare, | ||
| commonKeyChain: commonKeyChain | ||
| privateKeyShare: Buffer.copyBytesFrom(keyShare), | ||
| reducedPrivateKeyShare: Buffer.copyBytesFrom(rKeyShare), | ||
| commonKeyChain: commonKeyChain // string |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
If walletA is in the process of signing a txp and walletB deletes the txp, then walletA will be spinning indefinitely. This PR deletes corresponding TSS signing sessions when deleting a txp. This will cause walletA's session to error with a "Session not found" error, leaving it up to the client to handle appropriately (as seen in CLI).
This PR adds support for TSS session restoration in case a session is interrupted.
This PR adds confirmation for password setting (would hate for someone to mistype their password only to find out later).
This PR makes the
.toObjmethod make true copies of TssKey data. Without this, there was a race condition where exporting at the end of tss key creation may mean the unencrypted keyshare is saved to the wallet file. To that end, I also added a sanity check in thesavemethod to ensure sensitive data does not get saved to disk.This PR adds cleanup methods to the TSS keygen classes to zero out memory buffers that contain sensitive data.
This PR fixes a variety of CLI bugs.
Changelog
.toObj()Testing Notes
Add any helpful notes for reviewers to test your code here.
Checklist