GetExternalSigner(): fail if multiple signers are found #25235

pull amadeuszpawlik wants to merge 1 commits into bitcoin:master from amadeuszpawlik:fail_with_multiple_ext_signers changing 7 files +54 −7
  1. amadeuszpawlik commented at 7:00 pm on May 28, 2022: contributor

    If there are multiple external signers, GetExternalSigner() will just pick the first one in the list. If the user has two or more hardware wallets connected at the same time, he might not notice this.

    This PR adds a check and fails with suitable message, forcing the user to disconnect all but one external signer, so that there is no ambiguity as to which external signer was used.

  2. fanquake requested review from Sjors on May 28, 2022
  3. amadeuszpawlik commented at 7:21 pm on May 28, 2022: contributor
    Resolves #22636
  4. DrahtBot added the label Wallet on May 28, 2022
  5. in src/wallet/external_signer_scriptpubkeyman.cpp:49 in 30351825e6 outdated
    44@@ -45,7 +45,8 @@ ExternalSigner ExternalSignerScriptPubKeyMan::GetExternalSigner() {
    45     std::vector<ExternalSigner> signers;
    46     ExternalSigner::Enumerate(command, signers, Params().NetworkIDString());
    47     if (signers.empty()) throw std::runtime_error(std::string(__func__) + ": No external signers found");
    48-    // TODO: add fingerprint argument in case of multiple signers
    49+    // TODO: add fingerprint argument instead of failing in case of multiple signers.
    50+    if (signers.size() > 1) throw std::runtime_error(std::string(__func__) + ": More than one external signer found");
    


    Sjors commented at 8:57 am on May 30, 2022:
    Suggested text: More than one external signer found. Please connect only one at a time.
  6. Sjors commented at 9:06 am on May 30, 2022: member

    Concept ACK

    Maybe add test/functional/mocks/multi_signers.py to cover the error message. It would only need the enumerate stub. This can later be expanded as we improve multisig support.

    There are two scenarios where GetExternalSigner is called:

    1. When creating a new wallet
    2. When displaying an address

    For the first scenario ideally we want the user to pick one, but this would involve adding a fingerprint argument to the RPC call and expanding the GUI to select a device.

    For the second scenario ideally we want to display the address on both devices, if it’s a multisig wallet. This would involve changing DisplayAddress to perform a two stage operation: first call enumerate, and then call GetExternalSigner for each fingerprint it recognises.

    Until then though, I think it’s fine to just tell the user to only connect one external signer at a time.

    The only caveat I can think of is that a user might have one device permanently connected to their machine, e.g. a signer for their lightning node, that they don’t want to use as a Bitcoin Core wallet. But that use case is handled poorly with or without this PR.

  7. amadeuszpawlik force-pushed on May 31, 2022
  8. amadeuszpawlik commented at 4:17 pm on May 31, 2022: contributor
    @Sjors thanks for the input, test added!
  9. amadeuszpawlik force-pushed on May 31, 2022
  10. amadeuszpawlik marked this as ready for review on Jun 1, 2022
  11. Sjors commented at 4:24 pm on June 2, 2022: member
    Looks good at first glance, will review and test in more detail.
  12. achow101 commented at 5:02 pm on June 2, 2022: member

    ACK 8e121cb43cd34239567c148e167c48d93097d1dc

    It would really be preferable to allow the user to choose which signer rather than forcing one at a time, but this is fine for now.

  13. Rspigler commented at 1:30 am on June 3, 2022: contributor

    Concept ACK.

    Agree with @Sjors about the multisig additions we would have to make

  14. furszy approved
  15. furszy commented at 1:55 pm on June 4, 2022: member
    Code review ACK 8e121cb4
  16. in test/functional/rpc_signer.py:83 in 8e121cb43c outdated
    77@@ -78,7 +78,7 @@ def run_test(self):
    78         self.clear_mock_result(self.nodes[1])
    79 
    80         result = self.nodes[1].enumeratesigners()
    81-        assert_equal(len(result['signers']), 2)
    82+        assert_equal(len(result['signers']), 1)
    83         assert_equal(result['signers'][0]["fingerprint"], "00000001")
    84         assert_equal(result['signers'][0]["name"], "trezor_t")
    


    jonatack commented at 9:00 am on June 6, 2022:

    This whole section can now be one line.

    0-        result = self.nodes[1].enumeratesigners()
    1-        assert_equal(len(result['signers']), 1)
    2-        assert_equal(result['signers'][0]["fingerprint"], "00000001")
    3-        assert_equal(result['signers'][0]["name"], "trezor_t")
    4+        assert_equal(self.nodes[1].enumeratesigners(), {'signers': [{'fingerprint': '00000001', 'name': 'trezor_t'}]})
    

    Sjors commented at 9:17 am on June 6, 2022:
    The reason I made this more verbose initially is because we might add extra fields. Maybe use a Python way to check “at least these fields are present and have the right value”?

    amadeuszpawlik commented at 7:08 pm on June 6, 2022:
    I took both points into account, please check my update
  17. in test/functional/mocks/multi_signers.py:7 in 8e121cb43c outdated
    0@@ -0,0 +1,30 @@
    1+#!/usr/bin/env python3
    2+# Copyright (c) 2022 The Bitcoin Core developers
    3+# Distributed under the MIT software license, see the accompanying
    4+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
    5+
    6+import sys
    7+import argparse
    8+import json
    


    jonatack commented at 9:01 am on June 6, 2022:
    nit, sort
  18. jonatack commented at 9:03 am on June 6, 2022: contributor
    Nice work, ACK 8e121cb43cd34239567c148e167c48d93097d1dc with one suggested simplification
  19. amadeuszpawlik force-pushed on Jun 6, 2022
  20. Sjors commented at 11:22 am on June 9, 2022: member

    c4f2d06ecc4c48b9d080be35e0ec03dfdf75ffe5 looks good, and works with bitcoind.

    However, the GUI crashes when creating a new wallet. One solution is to add a check in CreateWalletActivity::create() in walletcontroller.cpp right before it calls setSigners().

  21. GetExternalSigner(): fail if multiple signers are found
    If there are multiple external signers, `GetExternalSigner()` will
    just pick the first one in the list. If the user has two or more
    hardware wallets connected at the same time, he might not notice this.
    
    This PR adds a check and fails with suitable message.
    292b1a3e9c
  22. amadeuszpawlik force-pushed on Jun 9, 2022
  23. amadeuszpawlik commented at 6:38 pm on June 9, 2022: contributor
    Thanks @Sjors, I didn’t catch that one. I added a check as you proposed - if multiple signers are found, we prompt an error and clear the list of signers. That way the user can still proceed to create a wallet, but the option for external signers is inactive (as the signer list is empty).
  24. Sjors commented at 1:21 pm on June 10, 2022: member
    tACK 292b1a3e9c98b9ba74b28d149df8554d4ad8e5c0
  25. achow101 commented at 11:21 pm on June 14, 2022: member
    ACK 292b1a3e9c98b9ba74b28d149df8554d4ad8e5c0
  26. DrahtBot commented at 1:41 am on June 21, 2022: contributor

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

    Conflicts

    No conflicts as of last run.

  27. theStack commented at 11:45 am on July 28, 2022: contributor
    Concept ACK
  28. fanquake merged this on Aug 13, 2022
  29. fanquake closed this on Aug 13, 2022

  30. sidhujag referenced this in commit 87d1411423 on Aug 15, 2022
  31. bitcoin locked this on Jan 12, 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-07-05 16:12 UTC

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