wallet: Migrate non-HD keys to combo() descriptor #31452

pull achow101 wants to merge 1 commits into bitcoin:master from achow101:migrate-nonhd-keys-combo changing 2 files +3 −7
  1. achow101 commented at 8:31 pm on December 9, 2024: member

    Non-HD keys do not have an HD seed ID associated with them, so if this value is the null value (all 0s), then we should not perform any seed ID comparison that would result in excluding the keys from combo() migration.

    This changes the migration of non-HD wallets (or blank wallets with imported private keys) to make a single combo() descriptors for the non-HD/imported keys, rather than pk(), pkh(), sh(wpkh()), and wpkh() descriptors for the keys.

    Implements #31374 (review)

  2. wallet: Migrate non-HD keys to combo() descriptor
    Non-HD keys in legacy wallets without a HD seed ID were being migrated
    to separate pk(), pkh(), sh(wpkh()), and wpkh() descriptors for each key.
    These could be more compactly represented as combo() descriptors, so
    migration should make combo() for them.
    
    It is possible that existing non-HD wallets that were migrated, or
    wallets that started blank and had private keys imported into them have
    run into this issue. However, as the 4 descriptors produce the same output
    scripts as the single combo(), so any previously migrated wallets are
    not missing any output scripts. The only observable difference should be
    performance related, and the wallet size on disk.
    62b2d23edb
  3. DrahtBot commented at 8:31 pm on December 9, 2024: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/31452.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK brunoerg, laanwj, furszy, theStack, rkrux

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

  4. DrahtBot added the label Wallet on Dec 9, 2024
  5. brunoerg approved
  6. brunoerg commented at 8:52 pm on December 9, 2024: contributor

    code review ACK 62b2d23edbad76c1d68bb8c0fc8af54e7c0d7dc8

    Nice find! I noticed this behavior when working on #29694 and checking the number of added keys and number of desc_spkms from the migration data.

  7. laanwj commented at 12:06 pm on December 10, 2024: member

    Using a combo descriptor when possible reduces the amount of descriptors in the migrated wallet, while functionally equivalent to P2PK + P2PKH + P2WPKH + P2SH-P2WPKH. This fixes an oversight where it’s possible, but wasn’t done before.

    As the result is equivalent, it’s not necessary to take any steps for existing wallets (though a hypothetical “wallet optimization” tool could do this).

    Concept and code review ACK 62b2d23edbad76c1d68bb8c0fc8af54e7c0d7dc8

  8. in test/functional/wallet_migration.py:1039 in 62b2d23edb
    1040+        combo_desc = descsum_create(f"combo([{key_origin}]{pubkey_hex})")
    1041 
    1042         # Verify all expected descriptors were migrated
    1043         migrated_desc = [item['desc'] for item in wallet.listdescriptors()['descriptors'] if pubkey.hex() in item['desc']]
    1044-        assert_equal(expected_descs, migrated_desc)
    1045+        assert_equal([combo_desc], migrated_desc)
    


    furszy commented at 3:13 am on December 11, 2024:
    Probably a good idea would be to verify the private key existence here. E.g. listdescriptors(private=True)
  9. furszy commented at 4:02 am on December 11, 2024: member

    Nice catch. ACK 62b2d23edbad76c1d68bb8c0fc8af54e7c0d7dc8

    Non-blocking comment. For the sake of mental peace, it might worth verifying that non-hd very old releases stored scripts after importing standalone private keys. Because if they calculated them in-memory after load, this would pose a different problem.

  10. achow101 commented at 4:06 am on December 11, 2024: member

    For the sake of mental peace, it might worth verifying that non-hd very old releases stored scripts after importing standalone private keys. Because if they calculated them in-memory after load, this would pose a different problem.

    I don’t think it particularly matters since loading a legacy wallet for migration results in calculating all of those scripts in memory anyways and putting them into mapScripts.

  11. bitcoin deleted a comment on Dec 11, 2024
  12. bitcoin deleted a comment on Dec 11, 2024
  13. bitcoin deleted a comment on Dec 11, 2024
  14. furszy commented at 2:58 pm on December 11, 2024: member

    For the sake of mental peace, it might worth verifying that non-hd very old releases stored scripts after importing standalone private keys. Because if they calculated them in-memory after load, this would pose a different problem.

    I don’t think it particularly matters since loading a legacy wallet for migration results in calculating all of those scripts in memory anyways and putting them into mapScripts.

    Are you sure? The loading procedure calls LegacyDataSPKM::LoadKey, which only calls LegacyDataSPKM::AddKeyPubKeyInner, which only calls FillableSigningProvider::AddKeyPubKey which stores the key in mapKeys and calls FillableSigningProvider::ImplicitlyLearnRelatedKeyScripts, which only generates and stores the p2wpkh witness program in mapScripts and nothing else. Am I missing something?

  15. furszy commented at 4:09 pm on December 11, 2024: member

    Ok, following my last comment. After discussing it with @theStack for a while.

    The first part of the LegacyDataSPKM::GetScriptPubKeys() method calculates the p2pkh and p2pk scripts from the private key. That’s how they end up being migrated. They should not be appearing in mapScript. Anyway.. all good.

  16. theStack approved
  17. theStack commented at 8:37 pm on December 11, 2024: contributor
    ACK 62b2d23edbad76c1d68bb8c0fc8af54e7c0d7dc8
  18. in test/functional/wallet_migration.py:1032 in 62b2d23edb
    1031@@ -1032,15 +1032,11 @@ def test_manual_keys_import(self):
    1032         # There should be descriptors containing the imported key for: pk(), pkh(), sh(wpkh()), wpkh()
    


    rkrux commented at 4:02 am on December 12, 2024:
    Comment seems to be outdated now.
  19. in test/functional/wallet_migration.py:1037 in 62b2d23edb
    1037-        sh_wpkh_desc = descsum_create(f'sh(wpkh([{key_origin}]{pubkey_hex}))')
    1038-        wpkh_desc = descsum_create(f'wpkh([{key_origin}]{pubkey_hex})')
    1039-        expected_descs = [pk_desc, pkh_desc, sh_wpkh_desc, wpkh_desc]
    1040+        combo_desc = descsum_create(f"combo([{key_origin}]{pubkey_hex})")
    1041 
    1042         # Verify all expected descriptors were migrated
    


    rkrux commented at 4:19 am on December 12, 2024:
    There’s just one expected ddescriptor now from what I understand.
  20. rkrux approved
  21. rkrux commented at 5:04 am on December 12, 2024: none

    tACK 62b2d23edbad76c1d68bb8c0fc8af54e7c0d7dc8

    I’ve been debugging with the wallet_migration.py test a bit. gethdkeys is available only for descriptor wallets.

    1. It’s not supported for legacy wallets because the output contains the descriptors that using the keys?
    2. Was there no RPC for legacy wallets that tells about the present addresses in the wallet? listdescriptors give a good enough idea for the newer wallets.
  22. fanquake merged this on Dec 13, 2024
  23. fanquake closed this on Dec 13, 2024


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-21 12:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me