aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramadeuszpawlik <apawlik@protonmail.com>2022-05-28 20:40:51 +0200
committeramadeuszpawlik <apawlik@protonmail.com>2022-06-09 20:34:46 +0200
commit292b1a3e9c98b9ba74b28d149df8554d4ad8e5c0 (patch)
treecbd0c09f79230f5d07ff0c3e03adf52825ad7959
parent8c61374ba782bfd328741fb7a46f32581e524ef6 (diff)
downloadbitcoin-292b1a3e9c98b9ba74b28d149df8554d4ad8e5c0.tar.xz
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.
-rw-r--r--src/qt/walletcontroller.cpp4
-rw-r--r--src/wallet/external_signer_scriptpubkeyman.cpp3
-rwxr-xr-xtest/functional/mocks/invalid_signer.py2
-rwxr-xr-xtest/functional/mocks/multi_signers.py30
-rwxr-xr-xtest/functional/mocks/signer.py2
-rwxr-xr-xtest/functional/rpc_signer.py5
-rwxr-xr-xtest/functional/wallet_signer.py15
7 files changed, 54 insertions, 7 deletions
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index d27ddf1aba..fae4c7cdf1 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -293,6 +293,10 @@ void CreateWalletActivity::create()
} catch (const std::runtime_error& e) {
QMessageBox::critical(nullptr, tr("Can't list signers"), e.what());
}
+ if (signers.size() > 1) {
+ QMessageBox::critical(nullptr, tr("Too many external signers found"), QString::fromStdString("More than one external signer found. Please connect only one at a time."));
+ signers.clear();
+ }
m_create_wallet_dialog->setSigners(signers);
m_create_wallet_dialog->setWindowModality(Qt::ApplicationModal);
diff --git a/src/wallet/external_signer_scriptpubkeyman.cpp b/src/wallet/external_signer_scriptpubkeyman.cpp
index 9d5f58b784..76de51ac3e 100644
--- a/src/wallet/external_signer_scriptpubkeyman.cpp
+++ b/src/wallet/external_signer_scriptpubkeyman.cpp
@@ -45,7 +45,8 @@ ExternalSigner ExternalSignerScriptPubKeyMan::GetExternalSigner() {
std::vector<ExternalSigner> signers;
ExternalSigner::Enumerate(command, signers, Params().NetworkIDString());
if (signers.empty()) throw std::runtime_error(std::string(__func__) + ": No external signers found");
- // TODO: add fingerprint argument in case of multiple signers
+ // TODO: add fingerprint argument instead of failing in case of multiple signers.
+ if (signers.size() > 1) throw std::runtime_error(std::string(__func__) + ": More than one external signer found. Please connect only one at a time.");
return signers[0];
}
diff --git a/test/functional/mocks/invalid_signer.py b/test/functional/mocks/invalid_signer.py
index e30cc9e20b..14f9fed72e 100755
--- a/test/functional/mocks/invalid_signer.py
+++ b/test/functional/mocks/invalid_signer.py
@@ -18,7 +18,7 @@ def perform_pre_checks():
sys.exit(int(mock_result[0]))
def enumerate(args):
- sys.stdout.write(json.dumps([{"fingerprint": "b3c19bfc", "type": "trezor", "model": "trezor_t"}, {"fingerprint": "00000002"}]))
+ sys.stdout.write(json.dumps([{"fingerprint": "b3c19bfc", "type": "trezor", "model": "trezor_t"}]))
def getdescriptors(args):
xpub_pkh = "xpub6CRhJvXV8x2AKWvqi1ZSMFU6cbxzQiYrv3dxSUXCawjMJ1JzpqVsveH4way1yCmJm29KzH1zrVZmVwes4Qo6oXVE1HFn4fdiKrYJngqFFc6"
diff --git a/test/functional/mocks/multi_signers.py b/test/functional/mocks/multi_signers.py
new file mode 100755
index 0000000000..88f93e23de
--- /dev/null
+++ b/test/functional/mocks/multi_signers.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+import argparse
+import json
+import sys
+
+def enumerate(args):
+ sys.stdout.write(json.dumps([{"fingerprint": "00000001", "type": "trezor", "model": "trezor_t"},
+ {"fingerprint": "00000002", "type": "trezor", "model": "trezor_one"}]))
+
+parser = argparse.ArgumentParser(prog='./multi_signers.py', description='External multi-signer mock')
+
+subparsers = parser.add_subparsers(description='Commands', dest='command')
+subparsers.required = True
+
+parser_enumerate = subparsers.add_parser('enumerate', help='list available signers')
+parser_enumerate.set_defaults(func=enumerate)
+
+
+if not sys.stdin.isatty():
+ buffer = sys.stdin.read()
+ if buffer and buffer.rstrip() != "":
+ sys.argv.extend(buffer.rstrip().split(" "))
+
+args = parser.parse_args()
+
+args.func(args)
diff --git a/test/functional/mocks/signer.py b/test/functional/mocks/signer.py
index b732b26a53..c5a8f7b1e9 100755
--- a/test/functional/mocks/signer.py
+++ b/test/functional/mocks/signer.py
@@ -18,7 +18,7 @@ def perform_pre_checks():
sys.exit(int(mock_result[0]))
def enumerate(args):
- sys.stdout.write(json.dumps([{"fingerprint": "00000001", "type": "trezor", "model": "trezor_t"}, {"fingerprint": "00000002"}]))
+ sys.stdout.write(json.dumps([{"fingerprint": "00000001", "type": "trezor", "model": "trezor_t"}]))
def getdescriptors(args):
xpub = "tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B"
diff --git a/test/functional/rpc_signer.py b/test/functional/rpc_signer.py
index f1107197c5..de17b2b929 100755
--- a/test/functional/rpc_signer.py
+++ b/test/functional/rpc_signer.py
@@ -77,10 +77,7 @@ class RPCSignerTest(BitcoinTestFramework):
)
self.clear_mock_result(self.nodes[1])
- result = self.nodes[1].enumeratesigners()
- assert_equal(len(result['signers']), 2)
- assert_equal(result['signers'][0]["fingerprint"], "00000001")
- assert_equal(result['signers'][0]["name"], "trezor_t")
+ assert_equal({'fingerprint': '00000001', 'name': 'trezor_t'} in self.nodes[1].enumeratesigners()['signers'], True)
if __name__ == '__main__':
RPCSignerTest().main()
diff --git a/test/functional/wallet_signer.py b/test/functional/wallet_signer.py
index 8e4e1f5d36..5609ac9bf5 100755
--- a/test/functional/wallet_signer.py
+++ b/test/functional/wallet_signer.py
@@ -32,6 +32,13 @@ class WalletSignerTest(BitcoinTestFramework):
else:
return path
+ def mock_multi_signers_path(self):
+ path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'mocks', 'multi_signers.py')
+ if platform.system() == "Windows":
+ return "py " + path
+ else:
+ return path
+
def set_test_params(self):
self.num_nodes = 2
# The experimental syscall sandbox feature (-sandbox) is not compatible with -signer (which
@@ -58,6 +65,8 @@ class WalletSignerTest(BitcoinTestFramework):
self.test_valid_signer()
self.restart_node(1, [f"-signer={self.mock_invalid_signer_path()}", "-keypool=10"])
self.test_invalid_signer()
+ self.restart_node(1, [f"-signer={self.mock_multi_signers_path()}", "-keypool=10"])
+ self.test_multiple_signers()
def test_valid_signer(self):
self.log.debug(f"-signer={self.mock_signer_path()}")
@@ -212,5 +221,11 @@ class WalletSignerTest(BitcoinTestFramework):
self.log.info('Test invalid external signer')
assert_raises_rpc_error(-1, "Invalid descriptor", self.nodes[1].createwallet, wallet_name='hww_invalid', disable_private_keys=True, descriptors=True, external_signer=True)
+ def test_multiple_signers(self):
+ self.log.debug(f"-signer={self.mock_multi_signers_path()}")
+ self.log.info('Test multiple external signers')
+
+ assert_raises_rpc_error(-1, "GetExternalSigner: More than one external signer found", self.nodes[1].createwallet, wallet_name='multi_hww', disable_private_keys=True, descriptors=True, external_signer=True)
+
if __name__ == '__main__':
WalletSignerTest().main()