-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: mnemonic support for descriptor wallets #6570
base: develop
Are you sure you want to change the base?
Conversation
This pull request has conflicts, please rebase. |
e2f9de2
to
36f3516
Compare
6fd861d
to
3bc5159
Compare
3bc5159
to
f80cd34
Compare
WalkthroughThe pull request introduces modifications across multiple components of the wallet system. Template signatures in the serialization module have been revised to support more flexible string types. In the RPC layer, additional fields for mnemonic and mnemonic passphrase are conditionally included in descriptor listings, and the wallet encryption message now directs users to record the new mnemonic seed. The descriptor script public key management components have been extensively updated to incorporate mnemonic handling, including new parameters for mnemonic storage, encryption, and decryption. The wallet setup and upgrade processes now pass mnemonic data, and corresponding database methods have been modified to store this information. Test files have been updated to reflect these changes by verifying mnemonic consistency, adjusting parameters related to HD wallets, and enabling previously commented-out test scripts for mnemonic functionality. ✨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (13)
test/functional/wallet_mnemonicbits.py (1)
35-50
: Refine membership test and validate descriptor coverage.
- The expression
assert not "mnemonic" in ...
at line 35 should be replaced withassert "mnemonic" not in ...
to adhere to Python best practices (E713).- The checks comprehensively test descriptor presence and ensure that mnemonic usage remains consistent across descriptors.
Example diff to fix the membership test style:
-assert not "mnemonic" in self.nodes[0].listdescriptors()['descriptors'][0] +assert "mnemonic" not in self.nodes[0].listdescriptors()['descriptors'][0]🧰 Tools
🪛 Ruff (0.8.2)
36-36: Test for membership should be
not in
Convert to
not in
(E713)
src/wallet/walletdb.cpp (1)
264-264
: Add inline comment for potential future mnemonic usage.The commented-out mnemonic parameters hint at possible expansions for
WriteDescriptor
. Retaining this comment clarifies future extension paths without complicating the current implementation.src/wallet/scriptpubkeyman.cpp (7)
1848-1848
: Add unit tests for mnemonic handling.
The// TODO: test for mnemonics
comment indicates missing coverage. Consider creating tests that validate both encrypted and unencrypted mnemonic usage and confirm end-to-end correctness.Would you like help drafting these tests?
1878-1878
: Use more secure buffers for mnemonic data.
Storing sensitive keys and mnemonics instd::vector<unsigned char>
might leave remnants in memory after usage. Consider consistently usingSecureVector
or explicit overwrites to reduce the risk of memory disclosures.Also applies to: 1882-1896
1902-1903
: Clear mnemonic details more securely.
Callingm_mnemonics.clear()
alone might not guarantee secure wiping of memory. For additional safety, consider using a secure wrapper or explicit zeroization to prevent data remnants in memory.
2090-2098
: Eliminate duplication noted in the// TODO:
comment.
Code for generating a seed from mnemonic and passphrase repeats logic from elsewhere. Centralizing the seed derivation steps in a shared utility would simplify future maintenance.
2120-2120
: Improve error feedback.
WhenAddDescriptorKeyWithDB
fails, the exception message is minimal. Consider clarifying the reason in the error string to aid debugging.
2423-2423
: Unify crypted key addition flow.
AddCryptedKey
mirrors some encryption steps found in other routines. Extract a common helper to handle crypted key insertion consistently and reduce code sprawl.
2483-2540
: Ensure a robust single-mnemonic policy.
GetMnemonicString
currently supports only one mnemonic per descriptor and logs an error if multiple versions are found. Long-term, you may need to handle multi-mnemonic or multi-wallet scenarios. Also consider adding explicit zeroization or secure memory usage here for in-memory mnemonic data.src/wallet/wallet.cpp (3)
42-42
: Consider moving bip39 dependency to appropriate module.The inline comment and the updated include line suggest that
<wallet/bip39.h>
should be refactored intoscriptpubkeyman.cpp
. If you decide to proceed, ensure the bip39 functionality is neatly encapsulated there to avoid bloating wallet-wide dependencies.
4307-4311
: Refactor and ensure robust mnemonic handling.
- Lines 4310-4311 mention a “TODO: remove duplicated code with
CHDChain::SetMnemonic
”. Factor out the shared logic into a helper to maintain DRY principles.- Properly handle potential edge cases around custom mnemonic bit sizes.
- Ensure thorough testing of invalid/partial mnemonics and error messages (line 4315).
- Line 4335 calls
SetupDescriptorGeneration
; confirm consistent encryption states for the new spk_man if the wallet is locked or re-locked.Also applies to: 4313-4318, 4335-4335
4416-4418
: Implement descriptor-level mnemonic.The TODO comment at line 4416 suggests a missing implementation for mnemonic-based descriptor creation within
AddDescriptor()
. If desired, the code fromSetupDescriptorScriptPubKeyMans
can be adapted or refactored here, ensuring consistent encryption and seed handling.src/wallet/wallettool.cpp (1)
52-52
: Add documentation for the mnemonic parameters.The empty strings represent default values for mnemonic and mnemonic passphrase. Consider adding a comment to clarify this, especially since these parameters are part of the new BIP39 support.
- wallet_instance->SetupDescriptorScriptPubKeyMans("", ""); + // Initialize descriptor wallet with empty mnemonic and passphrase + wallet_instance->SetupDescriptorScriptPubKeyMans("", ""); // mnemonic, mnemonic_passphrase
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
src/serialize.h
(3 hunks)src/wallet/rpcdump.cpp
(2 hunks)src/wallet/rpcwallet.cpp
(1 hunks)src/wallet/scriptpubkeyman.cpp
(9 hunks)src/wallet/scriptpubkeyman.h
(4 hunks)src/wallet/wallet.cpp
(8 hunks)src/wallet/wallet.h
(1 hunks)src/wallet/walletdb.cpp
(5 hunks)src/wallet/walletdb.h
(1 hunks)src/wallet/wallettool.cpp
(1 hunks)test/functional/test_runner.py
(1 hunks)test/functional/wallet_descriptor.py
(1 hunks)test/functional/wallet_dump.py
(1 hunks)test/functional/wallet_importmulti.py
(0 hunks)test/functional/wallet_keypool_hd.py
(0 hunks)test/functional/wallet_mnemonicbits.py
(2 hunks)
💤 Files with no reviewable changes (2)
- test/functional/wallet_importmulti.py
- test/functional/wallet_keypool_hd.py
✅ Files skipped from review due to trivial changes (2)
- test/functional/wallet_descriptor.py
- src/wallet/rpcwallet.cpp
🧰 Additional context used
🪛 Ruff (0.8.2)
test/functional/wallet_mnemonicbits.py
36-36: Test for membership should be not in
Convert to not in
(E713)
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: linux64_multiprocess-build / Build source
- GitHub Check: linux64_tsan-build / Build source
- GitHub Check: win64-build / Build source
- GitHub Check: linux64_ubsan-build / Build source
🔇 Additional comments (34)
test/functional/wallet_mnemonicbits.py (6)
27-32
: Ensure mnemonic invariance post-encryption.These lines verify the mnemonic before and after wallet encryption. The approach looks solid for detecting any unintentional mnemonic changes.
51-51
: Confirm default mnemonic length logic.Verifying that the default mnemonic remains 12 words is a key baseline check. The assertion ensures user configurations haven't inadvertently changed default behavior.
54-62
: Test coverage for different mnemonic bit sizes.Restarting the node with different
-mnemonicbits
values and creating separate wallets ensures thorough coverage and helps catch issues related to varied entropy lengths.
65-74
: Validate descriptor-based HD wallet creation.Creating a blank descriptor wallet (
wallet_256
) and upgrading it to HD ensures the descriptors are properly set up, and the mnemonic word count checks confirm consistency for 12, 15, 18, 21, and 24-word sets.
75-82
: Confirm legacy HD wallet behavior.This block parallels the descriptor-based path but exercises the legacy codepath. The consistent word count checks help validate that both approaches produce the expected mnemonic lengths.
83-84
: Re-check mnemonic consistency after multiple wallet operations.Comparing the final mnemonic with the pre-encryption mnemonic ensures no unintended side-effects from repeated creation, encryption, and node restarts.
src/wallet/scriptpubkeyman.h (5)
513-517
: Organize mnemonic-related type definitions.Introducing
Mnemonic
,MnemonicMap
,CryptedMnemonic
, andCryptedMnemonicMap
is a clean approach for grouping mnemonic data. These aliases improve clarity by explicitly referencing pairs of mnemonic/passphrase and their encrypted forms.
525-526
: Leverage fine-grained storage for mnemonic data.Storing
m_mnemonics
andm_crypted_mnemonics
in separate maps avoids conflating plaintext and encrypted data. This design choice improves maintainability and clarifies the encryption lifecycle.
531-531
: Add mnemonic parameters to database method.
AddDescriptorKeyWithDB
now accepts mnemonic/passphrase parameters, allowing the descriptor key addition workflow to simultaneously persist mnemonic data. Ensure corresponding calls handle these parameters consistently.
599-600
: Enable explicit addition of keys and mnemonics.By extending
AddKey
andAddCryptedKey
with mnemonic support, the code merges standard or encrypted keys with associated mnemonic data in a single interface, consolidating key creation steps.
612-612
: Expose mnemonic retrieval.
GetMnemonicString
provides a straightforward way to retrieve the mnemonic and passphrase, and can be a critical piece for external usage or UI integration. Ensure any call-sites handle passphrase sensitivity securely.src/wallet/walletdb.cpp (7)
244-245
: Extend descriptor key writing to include mnemonic data.These lines demonstrate storing both the private key hash and mnemonic fields. This integration ensures that descriptors carry the relevant seed phrase data for future recovery or reference.
Also applies to: 252-252
255-258
: Support encrypted descriptor keys alongside mnemonics.
WriteCryptedDescriptorKey
accommodates encrypted private keys as well as optional mnemonic data. This allows a more secure approach, ensuring confidential mnemonic storage.
339-340
: Persist additional mnemonic fields in scan state.Maintaining both plaintext and encrypted mnemonic data in
CWalletScanState
ensures uniform handling during wallet loading. Verify all transitions from scan to final wallet state are robust.
709-723
: Safely parse plaintext mnemonic from database.By wrapping the read logic in a try/catch block, the code gracefully handles older wallets or missing mnemonic data. The fallback to an empty string is appropriate for legacy scenarios.
741-755
: Handle encrypted mnemonic data gracefully.Similar to plaintext mnemonics, this block ensures safe reading of encrypted data. Catching
std::ios_base::failure
avoids crashes when older or incomplete wallet records lack mnemonic info.
900-906
: Finalize plain-text mnemonic insertion into descriptor keys.This segment merges any existing mnemonic parameters from the scan state into the in-memory descriptor structure. Empty strings default to no mnemonic, ensuring backward compatibility.
910-915
: Integrate encrypted mnemonic data on load.Similarly, crypted mnemonics from the scan state are applied to descriptor keys if present. This preserves encryption boundaries and streamlines loading new or migrated wallets.
src/wallet/scriptpubkeyman.cpp (6)
16-16
: Ensure BIP39 library usage is properly tested and secure.
The inclusion of<wallet/bip39.h>
introduces mnemonic handling. Verify that every new mnemonic-related branch is thoroughly covered by unit or functional tests, and consider any potential security implications of introducing the BIP39 library.
1875-1876
: Avoid productionassert
for external inputs.
Usingassert(pubkey.GetID() == key_in.first)
could cause the wallet to terminate if a mismatch ever occurs in production. Consider gracefully handling key mismatches by returning an appropriate error code instead of asserting.
1898-1899
: Storing encrypted mnemonics looks correct.
Implementation for populatingm_crypted_mnemonics
and writing to the batch is straightforward and aligned with the rest of the encryption flow.
2033-2033
: New function signature to handle descriptor key insertion.
This method now accepts mnemonic parameters, aligning with in-wallet handling of BIP39 data. The signature looks consistent with your design.
2080-2080
: Verify derivation path assumptions for descriptor generation.
SetupDescriptorGeneration
introduces new descriptor logic (BIP44 style path). Confirm that it matches your chain’s derivation policies, and consider exposing a way for users to specify custom paths if needed.
2100-2100
: Storing creation time.
UsingGetTime()
to mark descriptor creation keeps consistency with other wallet metadata. This appears correct for tracking.src/wallet/wallet.cpp (2)
339-339
: Verify empty mnemonic arguments.Calling
SetupDescriptorScriptPubKeyMans("", "")
creates descriptor managers with empty mnemonic/passphrase. Verify that this is intentional and doesn't break downstream operations that assume valid mnemonic data.
3702-3704
: Double-check descriptor upgrade logic.When upgrading to HD (
UpgradeToHD
), the code branches to descriptor logic underWALLET_FLAG_DESCRIPTORS
. Confirm if skipping the legacy code path is correct, and consider clarifying behavior for non-legacy descriptor wallets upgrading to HD.test/functional/wallet_dump.py (1)
90-90
: LGTM! Simplified test configuration.Removing
-usehd=1
is appropriate since descriptor wallets now handle HD and mnemonic functionality by default.src/wallet/walletdb.h (1)
215-216
: LGTM! Secure implementation of mnemonic storage.The implementation properly handles both unencrypted and encrypted mnemonic storage:
- Uses
SecureString
for sensitive data in memory- Uses
vector<unsigned char>
for encrypted storagetest/functional/test_runner.py (1)
297-297
: LGTM! Activated descriptor wallet mnemonic tests.Enabling
wallet_mnemonicbits.py --descriptors
ensures proper testing of the new BIP39 mnemonic support in descriptor wallets.src/serialize.h (2)
820-821
: LGTM! Template signature change improves flexibility.The template signature change from a single parameter to three parameters allows for more flexible string serialization by supporting different allocator and character types.
823-829
:❓ Verification inconclusive
Verify if SecureString serialization is still needed.
The SecureString serialization code has been commented out. Since this PR adds mnemonic support and mnemonics need to be stored securely, we should verify if an alternative secure serialization mechanism is in place.
Run the following script to check for alternative SecureString serialization implementations:
🏁 Script executed:
#!/bin/bash # Description: Check for SecureString serialization implementations # Search for SecureString serialization in the codebase rg -A 5 "SecureString.*[Ss]erializ" # Search for mnemonic-related serialization rg -A 5 "mnemonic.*[Ss]erializ"Length of output: 71
SecureString Serialization Verification Needed for Mnemonic Storage
The recent searches did not reveal any alternative implementations for SecureString serialization or mnemonic-related serialization in the codebase. Please verify manually that no new secure serialization mechanism has been introduced elsewhere. If secure serialization for mnemonics is required, consider re-enabling or replacing the commented-out SecureString serialization code.
- Location under review:
src/serialize.h
(lines 823-829)- Next step: Manually confirm if a secure serialization mechanism exists or needs to be implemented for mnemonic secure storage.
src/wallet/wallet.h (1)
1070-1070
:✅ Verification successful
LGTM! Method signature change adds secure mnemonic support.
The addition of
mnemonic
andmnemonic_passphrase
parameters of typeSecureString
ensures secure handling of sensitive mnemonic data in descriptor wallets. This change aligns with the PR objective of adding BIP39 support.Run the following script to verify consistent mnemonic handling across the codebase:
🏁 Script executed:
#!/bin/bash # Description: Verify consistent mnemonic handling # Check for mnemonic-related function signatures ast-grep --pattern $'void $_(const SecureString& mnemonic, const SecureString $_)' # Check for potential security issues in mnemonic handling rg -A 5 "mnemonic.*=|=.*mnemonic"Length of output: 24145
LGTM! Secure Mnemonic Support Verified
The updated method signature for
SetupDescriptorScriptPubKeyMans
—now accepting bothmnemonic
andmnemonic_passphrase
of typeSecureString
—has been verified across the codebase. Searches confirmed that mnemonic and mnemonic passphrase handling is consistent in wallet initialization, descriptor key management, and associated tests. This change aligns perfectly with the PR objective of adding BIP39 support and securely managing sensitive data.src/wallet/rpcdump.cpp (2)
1967-1968
: LGTM! Documentation update for mnemonic fields.The RPCResult documentation correctly specifies the new mnemonic fields and their conditions for inclusion in the response.
2015-2022
:❓ Verification inconclusive
Verify secure handling of mnemonic data.
The code retrieves and exposes sensitive mnemonic data. While the implementation correctly:
- Uses SecureString for mnemonic storage
- Only includes mnemonic data when private=true
- Checks for empty mnemonic before including
Consider adding additional security measures:
Also verify that the RPC connection is using TLS to prevent mnemonic exposure during transit:
🏁 Script executed:
#!/bin/bash # Check if the mnemonic data is properly cleared from memory ast-grep --pattern $'SecureString $var; $$$ $var.clear();'Length of output: 229
🌐 Web query:
What are the best practices for securing sensitive data in Bitcoin RPC responses?
💡 Result:
Securing sensitive data in Bitcoin RPC responses requires a multi-layered approach combining encryption, access control, and operational safeguards. Here are the critical best practices:
1. Network Security
- Restrict RPC exposure: Bind RPC interfaces to
localhost
by default and only allow remote access through VPNs or SSH tunnels[1][7]. Avoid public internet exposure due to unencrypted credentials[1][3].- Use encrypted connections: Implement HTTPS with TLS 1.2+/SSL for all RPC communications[2][3][8]. QuickNode's Endpoint Armor provides secure URL templates for this purpose[10].
- Configure firewalls: Limit inbound/outbound traffic to trusted IP ranges using tools like
ufw
oriptables
[7].
2. Authentication & Authorization
- Use
.cookie
authentication: Prefer Bitcoin Core's auto-generated credentials stored in.cookie
files over staticrpcuser
/rpcpassword
[1][9].- Implement RBAC/ACLs: Restrict methods like
sendtoaddress
to specific user roles[2][7]. For multi-wallet setups:# Access wallet-specific endpoints curl --user alice localhost:8332/wallet/walletname/getbalance[2]
- Rotate credentials: Regularly update API keys/tokens if using services like Alchemy or Infura[2][3].
3. Data Handling
- Sanitize outputs: Display serialized data (e.g., raw transactions) exclusively in hex format to prevent script injection[1][9].
- Validate inputs: Check parameters like
wallet_name
increatewallet
for path traversal attempts[1].- Escape special characters: Use libraries like
jq
when processing JSON-RPC responses:bitcoin-cli getrawtransaction TXID | jq -r .hex[2]
4. Operational Security
- Update regularly: Patch Bitcoin Core and dependencies to address vulnerabilities like CVE-2023-12345[4][6][7].
- Monitor logs: Audit
/debug.log
for suspicious activity patterns[1][3].- Limit privileges: Run
bitcoind
under a non-root user account with restricted filesystem permissions[1][7].
5. Architectural Controls
| Control | Implementation Example | Source | |------------------------|----------------------------------|--------| | Rate limiting | 100 req/minute per IP | [5][7] | | Request validation | Whitelist allowed RPC methods | [8] | | Encrypted storage | LUKS for wallet.dat files | [8] | | Fail2ban integration | Block brute-force attempts | [8] |By combining these measures, you create defense-in-depth against common attack vectors while maintaining compatibility with standard Bitcoin JSON-RPC workflows[1][8][9].
Citations:
- 1: https://github.com/bitcoin/bitcoin/blob/master/doc/JSON-RPC-interface.md
- 2: https://goldrush.dev/guides/a-deep-dive-into-the-architecture-of-rpc-nodes/
- 3: https://www.quillaudits.com/blog/web3-security/security-tips-for-rpc-endpoint-users
- 4: https://www.bydfi.com/en/questions/what-are-the-best-practices-for-implementing-web-rpc-in-a-cryptocurrency-exchange
- 5: https://groups.google.com/g/bitcoindev/c/RQcBMqZPLAE/m/IwT_2KtwAgAJ
- 6: http://www.bydfi.com/en/questions/what-are-the-best-practices-for-implementing-rpc-s-in-a-cryptocurrency-exchange
- 7: https://editverse.com/bitcoin-node-security/
- 8: https://en.bitcoin.it/wiki/API_reference_(JSON-RPC)
- 9: https://www.cyfrin.io/blog/blockchain-rpc-node-guide
- 10: https://www.quicknode.com/docs/bitcoin
Action Required: Further Manual Security Verification Needed
- The automated AST search did not conclusively verify that
SecureString
instances (e.g., mnemonic data) are explicitly cleared from memory. The absence of output (aside from unrelated UTF-8 errors) suggests that this check requires manual confirmation—please ensure that either the destructor ofSecureString
or explicit.clear()
calls are properly clearing sensitive data once used.- Based on the latest best practices for Bitcoin RPC security, confirm that the RPC connection is secured via TLS (or an equivalent encryption method) to guard sensitive data during transit.
Please review and verify these points manually before finalizing this implementation.
std::vector<unsigned char> crypted_mnemonic; | ||
std::vector<unsigned char> crypted_mnemonic_passphrase; | ||
CKeyingMaterial secret(key.begin(), key.end()); | ||
CKeyingMaterial mnemonic_secret(mnemonic.begin(), mnemonic.end()); | ||
CKeyingMaterial mnemonic_passphrase_secret(mnemonic_passphrase.begin(), mnemonic_passphrase.end()); | ||
if (!m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) { | ||
return EncryptSecret(encryption_key, secret, pubkey.GetHash(), crypted_secret); | ||
if (!EncryptSecret(encryption_key, secret, pubkey.GetHash(), crypted_secret)) return false; | ||
if (!mnemonic.empty()) { | ||
if (!EncryptSecret(encryption_key, mnemonic_secret, pubkey.GetHash(), crypted_mnemonic)) { | ||
return false; | ||
} | ||
if (!EncryptSecret(encryption_key, mnemonic_passphrase_secret, pubkey.GetHash(), crypted_mnemonic_passphrase)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
})) { | ||
return false; | ||
} | ||
|
||
m_map_crypted_keys[pubkey.GetID()] = make_pair(pubkey, crypted_secret); | ||
return batch.WriteCryptedDescriptorKey(GetID(), pubkey, crypted_secret); | ||
m_crypted_mnemonics[pubkey.GetID()] = make_pair(crypted_mnemonic, crypted_mnemonic_passphrase); | ||
return batch.WriteCryptedDescriptorKey(GetID(), pubkey, crypted_secret, crypted_mnemonic, crypted_mnemonic_passphrase); | ||
} else { | ||
m_map_keys[pubkey.GetID()] = key; | ||
return batch.WriteDescriptorKey(GetID(), pubkey, key.GetPrivKey()); | ||
m_mnemonics[pubkey.GetID()] = make_pair(mnemonic, mnemonic_passphrase); | ||
return batch.WriteDescriptorKey(GetID(), pubkey, key.GetPrivKey(), mnemonic, mnemonic_passphrase); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Refactor to reduce duplication in encryption logic.
The added logic for encrypting private keys, mnemonic, and passphrase largely duplicates earlier code blocks. Extracting a helper function can improve maintainability and reduce potential inconsistencies.
@@ -2354,21 +2401,34 @@ | |||
} | |||
} | |||
|
|||
bool DescriptorScriptPubKeyMan::AddKey(const CKeyID& key_id, const CKey& key) | |||
bool DescriptorScriptPubKeyMan::AddKey(const CKeyID& key_id, const CKey& key, const SecureString& mnemonic, const SecureString& mnemonic_passphrase) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid duplication with AddDescriptorKeyWithDB
.
This new AddKey
method partially overlaps with the logic in AddDescriptorKeyWithDB
. Consider consolidating them to reduce the overhead of multiple mnemonic-handling paths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
test/functional/wallet_mnemonicbits.py (1)
50-52
: Use Python's 'not in' operator for membership testing.The membership test should use Python's
not in
operator for better readability and adherence to PEP 8 style guidelines.- assert not "mnemonic" in self.nodes[0].listdescriptors()['descriptors'][0] + assert "mnemonic" not in self.nodes[0].listdescriptors()['descriptors'][0]🧰 Tools
🪛 Ruff (0.8.2)
51-51: Test for membership should be
not in
Convert to
not in
(E713)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
test/functional/wallet_mnemonicbits.py
(2 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
test/functional/wallet_mnemonicbits.py
51-51: Test for membership should be not in
Convert to not in
(E713)
⏰ Context from checks skipped due to timeout of 90000ms (6)
- GitHub Check: x86_64-w64-mingw32 / Build depends
- GitHub Check: x86_64-apple-darwin / Build depends
- GitHub Check: x86_64-pc-linux-gnu_multiprocess / Build depends
- GitHub Check: arm-linux-gnueabihf / Build depends
- GitHub Check: x86_64-pc-linux-gnu_nowallet / Build depends
- GitHub Check: x86_64-pc-linux-gnu / Build depends
🔇 Additional comments (7)
test/functional/wallet_mnemonicbits.py (7)
27-29
: LGTM: Effective mnemonic retrieval handling for both wallet types.The code correctly handles mnemonic retrieval for both descriptor and legacy wallets. For descriptor wallets, it uses the
listdescriptors(True)
RPC and accesses the mnemonic from the second descriptor (index 1), while for legacy wallets, it uses thedumphdinfo()
RPC.
30-49
: LGTM: Well-structured encryption test with appropriate assertions.The code properly tests wallet encryption behavior for both wallet types:
- For descriptor wallets, it correctly verifies that encryption creates new private keys, making old descriptors inactive and new ones active
- For legacy wallets, it confirms that the mnemonic remains unchanged after encryption
- Good comment explaining that descriptor wallet encryption creates new private keys
The assertion checking for exactly 2 inactive descriptors with the old mnemonic is appropriate.
53-57
: LGTM: Good validation of mnemonic consistency across descriptors.These assertions correctly verify that:
- Both descriptors have mnemonics with the standard 12-word length
- The same mnemonic is used across descriptors
This ensures the mnemonic implementation for descriptor wallets is working as expected.
58-65
: LGTM: Thorough descriptor counting with clear explanation.The code properly counts the total number of descriptors and those containing mnemonics:
- Good comment explaining why one descriptor doesn't have a mnemonic (imported coinbase private key)
- Clear assertion that there should be 4 descriptors with mnemonics (2 active, 2 inactive)
- Verification of the total descriptor count (5)
80-89
: LGTM: Comprehensive testing of different mnemonic bit lengths for descriptor wallets.The code thoroughly tests descriptor wallets with different mnemonic bit lengths:
- Creates a blank descriptor wallet and uses
upgradetohd()
to test that functionality- Correctly checks mnemonic word counts for each bit length (128→12, 160→15, 192→18, 224→21, 256→24)
- Good comment explaining why index 1 is used for the default wallet (index 0 is for coinbase private key)
- Uses the correct RPC methods for descriptor wallets
90-96
: LGTM: Proper handling for legacy wallet mnemonic verification.The code correctly handles the legacy wallet case:
- Creates a blank HD legacy wallet with appropriate parameters
- Uses
upgradetohd()
to initialize the HD wallet- Properly verifies mnemonic word counts across different bit lengths using
dumphdinfo()
98-99
: LGTM: Effective final verification of mnemonic persistence.The code correctly retrieves and verifies that the mnemonic in the default wallet matches the one saved before encryption, ensuring mnemonic persistence works as expected across both descriptor and legacy wallet types.
31316ed
to
7a6bf5f
Compare
Last 2 pushes to fix intermittent failure in functional test and remove duplicated code, commits are squashed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
test/functional/wallet_mnemonicbits.py
(2 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
test/functional/wallet_mnemonicbits.py
45-45: SyntaxError: Expected a statement
45-46: SyntaxError: Expected a statement
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: x86_64-w64-mingw32 / Build depends
- GitHub Check: arm-linux-gnueabihf / Build depends
- GitHub Check: x86_64-pc-linux-gnu / Build depends
- GitHub Check: x86_64-pc-linux-gnu_multiprocess / Build depends
- GitHub Check: x86_64-pc-linux-gnu_nowallet / Build depends
🔇 Additional comments (6)
test/functional/wallet_mnemonicbits.py (6)
33-38
: LGTM: Effectively verifies mnemonic presence in descriptor wallets.The code correctly checks that the initial descriptor doesn't contain a mnemonic by default, but does contain it when the
True
parameter is passed tolistdescriptors
. The additional check for mnemonic equality between descriptors ensures consistency.
39-58
: Comprehensive mnemonic validation logic for descriptor wallets.This section thoroughly verifies the mnemonic structure and behavior in descriptor wallets by:
- Counting mnemonics across descriptors
- Verifying active/inactive states
- Checking the expected total number of descriptors
The comments explaining the expected descriptor counts are particularly helpful for future maintenance.
🧰 Tools
🪛 Ruff (0.8.2)
45-45: SyntaxError: Expected a statement
45-46: SyntaxError: Expected a statement
59-62
: Effective handling of legacy wallet case.The code appropriately falls back to the legacy wallet verification pattern when descriptors are not enabled, maintaining backward compatibility while adding new functionality.
76-84
: Well-structured testing of different mnemonic bit lengths for descriptor wallets.The implementation correctly tests each mnemonic bit length configuration and verifies the appropriate number of words for each. The descriptive comments alongside each assertion make the test's intent clear.
85-92
: Comprehensive parallel testing of legacy wallets.The code maintains parallel tests for legacy wallets, ensuring that both wallet types are thoroughly tested with various mnemonic bit lengths.
94-95
: Proper final verification of mnemonic persistence.This final check ensures that the original wallet's mnemonic remains consistent throughout the test, which is a crucial validation for wallet security and reliability.
if 'mnemonic' not in desc: | ||
# skip imported coinbase private key | ||
continue | ||
assert_equal(desc['mnemonic'].split()), 12) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix syntax error in assertion statement.
There's a syntax error in this line. The parentheses are mismatched and the len()
function is missing.
- assert_equal(desc['mnemonic'].split()), 12)
+ assert_equal(len(desc['mnemonic'].split()), 12)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
assert_equal(desc['mnemonic'].split()), 12) | |
assert_equal(len(desc['mnemonic'].split()), 12) |
🧰 Tools
🪛 Ruff (0.8.2)
45-45: SyntaxError: Expected a statement
45-46: SyntaxError: Expected a statement
7a6bf5f
to
f08e935
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
test/functional/wallet_mnemonicbits.py (1)
45-45
:⚠️ Potential issueFix syntax error in assertion statement.
There's a syntax error in this line. The parentheses are mismatched and the
len()
function is missing.- assert_equal(desc['mnemonic'].split()), 12) + assert_equal(len(desc['mnemonic'].split()), 12)
🧹 Nitpick comments (2)
test/functional/wallet_mnemonicbits.py (2)
77-77
: Consider clarifying createwallet parameters.The createwallet call has six parameters, but their meaning isn't immediately clear from context. Consider adding a brief inline comment or using named arguments for better readability.
- self.nodes[0].createwallet("wallet_256", False, True, "", False, True) # blank Descriptors + # Parameters: name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors + self.nodes[0].createwallet("wallet_256", False, True, "", False, True) # blank Descriptors
80-84
: Consider using constants for expected word counts.The code uses magic numbers (12, 15, 18, 21, 24) for the expected word counts based on mnemonic bits. Consider defining constants at the class level for better readability and maintainability.
+ # At the class level + MNEMONIC_WORDS = { + 128: 12, # Default + 160: 15, + 192: 18, + 224: 21, + 256: 24 + } # Then in the test - assert_equal(len(self.nodes[0].get_wallet_rpc(self.default_wallet_name).listdescriptors(True)["descriptors"][1]["mnemonic"].split()), 12) # 12 words by default + assert_equal(len(self.nodes[0].get_wallet_rpc(self.default_wallet_name).listdescriptors(True)["descriptors"][1]["mnemonic"].split()), self.MNEMONIC_WORDS[128]) # Default
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
test/functional/wallet_mnemonicbits.py
(2 hunks)
🔇 Additional comments (8)
test/functional/wallet_mnemonicbits.py (8)
28-29
: LGTM! Robust mnemonic retrieval based on wallet type.The code now properly handles mnemonic retrieval for both descriptor and legacy wallets, ensuring the test can work with either wallet type.
30-32
: LGTM! Wallet encryption preparation.Properly encrypts the wallet and unlocks it with the passphrase, a necessary step to test mnemonic persistence.
32-58
: LGTM! Comprehensive descriptor wallet mnemonic validation.This code block effectively tests several key aspects of descriptor wallet mnemonic functionality:
- Verifies that public descriptors don't expose mnemonics while private ones do
- Confirms mnemonic consistency across descriptors
- Validates the standard 12-word length for BIP39 mnemonics
- Checks active/inactive status relationship with mnemonics
- Verifies the expected number of descriptors with mnemonics
The validation logic is thorough and covers important edge cases.
59-62
: LGTM! Legacy wallet mnemonic validation.Properly validates the expected behavior for legacy wallets, confirming the default 12-word mnemonic length and persistence after encryption.
72-72
: LGTM! Wallet unlocking for tests.Correctly unlocks the default wallet before proceeding with additional tests.
76-84
: LGTM! Comprehensive descriptor wallet mnemonic length testing.This section thoroughly tests the descriptor wallet functionality with different mnemonic bit lengths, verifying that each wallet has the expected number of words based on the configured bit length (128→12, 160→15, 192→18, 224→21, 256→24).
The commented explanation on line 79 is helpful to understand why index 1 is used for the default wallet.
85-92
: LGTM! Comprehensive legacy wallet mnemonic length testing.This section properly tests the legacy wallet functionality with different mnemonic bit lengths, ensuring each wallet has the expected number of words.
94-95
: LGTM! Final mnemonic consistency verification.This correctly verifies that the mnemonic of the default wallet still matches what was captured before encryption, confirming mnemonic persistence.
Issue being fixed or feature implemented
Descriptor wallets doesn't support yet mnemonics (BIP39), which are supported only by legacy (non-descriptor) wallet.
What was done?
This PR adds basic support BIP39 to descriptor wallets:
upgradetohd
now support descriptor wallets and let to set specifict mnemonic with passphrase to newly created walletlistdescriptors
if existsHow Has This Been Tested?
Functional test
wallet_mnemonicbits.py
support--descriptors
nowFunctional test
wallet_upgradetohd.py
is updated alsoBreaking Changes
N/A
Checklist: