Skip to content

Commit a7129f8

Browse files
committed
Merge bitcoin/bitcoin#24313: Improve display address handling for external signer
4357158 wallet: return and display signer error (Sjors Provoost) dc55531 wallet: compare address returned by displayaddress (Sjors Provoost) 6c1a2cc test: use h marker for external signer mock (Sjors Provoost) Pull request description: * HWI returns the requested address: as a sanity check, we now compare that to what we expected * external signer documentation now reflects that HWI alternatives must implement this check * both RPC and GUI will now return an error text, rather than just fail (the GUI even failed silently in some cases) ACKs for top commit: brunoerg: ACK 4357158 achow101: ACK 4357158 Tree-SHA512: 4f56edf3846745c8e7d08ef55cf29e8bb468256457149377c5f02da097931f9ca0c06bdbd856dc2385cde4fd11e4dc3b634c5a48814ff27f5562c8a25d43da93
2 parents 7c17f20 + 4357158 commit a7129f8

13 files changed

+68
-38
lines changed

doc/external-signer.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ Example, display the first native SegWit receive address on Testnet:
150150

151151
The command MUST be able to figure out the address type from the descriptor.
152152

153+
The command MUST return an object containing `{"address": "[the address]"}`.
154+
As a sanity check, for devices that support this, it SHOULD ask the device to derive the address.
155+
153156
If <descriptor> contains a master key fingerprint, the command MUST fail if it does not match the fingerprint known by the device.
154157

155158
If <descriptor> contains an xpub, the command MUST fail if it does not match the xpub known by the device.

src/interfaces/wallet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ class Wallet
127127
virtual bool setAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& value) = 0;
128128

129129
//! Display address on external signer
130-
virtual bool displayAddress(const CTxDestination& dest) = 0;
130+
virtual util::Result<void> displayAddress(const CTxDestination& dest) = 0;
131131

132132
//! Lock coin.
133133
virtual bool lockCoin(const COutPoint& output, const bool write_to_db) = 0;

src/qt/walletmodel.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -569,16 +569,17 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
569569
return true;
570570
}
571571

572-
bool WalletModel::displayAddress(std::string sAddress) const
572+
void WalletModel::displayAddress(std::string sAddress) const
573573
{
574574
CTxDestination dest = DecodeDestination(sAddress);
575-
bool res = false;
576575
try {
577-
res = m_wallet->displayAddress(dest);
576+
util::Result<void> result = m_wallet->displayAddress(dest);
577+
if (!result) {
578+
QMessageBox::warning(nullptr, tr("Signer error"), QString::fromStdString(util::ErrorString(result).translated));
579+
}
578580
} catch (const std::runtime_error& e) {
579581
QMessageBox::critical(nullptr, tr("Can't display address"), e.what());
580582
}
581-
return res;
582583
}
583584

584585
bool WalletModel::isWalletEnabled()

src/qt/walletmodel.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ class WalletModel : public QObject
130130
UnlockContext requestUnlock();
131131

132132
bool bumpFee(uint256 hash, uint256& new_hash);
133-
bool displayAddress(std::string sAddress) const;
133+
void displayAddress(std::string sAddress) const;
134134

135135
static bool isWalletEnabled();
136136

src/wallet/external_signer_scriptpubkeyman.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
#include <wallet/external_signer_scriptpubkeyman.h>
1010

1111
#include <iostream>
12+
#include <key_io.h>
1213
#include <memory>
1314
#include <stdexcept>
1415
#include <string>
16+
#include <univalue.h>
1517
#include <utility>
1618
#include <vector>
1719

@@ -51,15 +53,26 @@ ExternalSigner ExternalSignerScriptPubKeyMan::GetExternalSigner() {
5153
return signers[0];
5254
}
5355

54-
bool ExternalSignerScriptPubKeyMan::DisplayAddress(const CScript scriptPubKey, const ExternalSigner &signer) const
56+
util::Result<void> ExternalSignerScriptPubKeyMan::DisplayAddress(const CTxDestination& dest, const ExternalSigner &signer) const
5557
{
5658
// TODO: avoid the need to infer a descriptor from inside a descriptor wallet
59+
const CScript& scriptPubKey = GetScriptForDestination(dest);
5760
auto provider = GetSolvingProvider(scriptPubKey);
5861
auto descriptor = InferDescriptor(scriptPubKey, *provider);
5962

60-
signer.DisplayAddress(descriptor->ToString());
61-
// TODO inspect result
62-
return true;
63+
const UniValue& result = signer.DisplayAddress(descriptor->ToString());
64+
65+
const UniValue& error = result.find_value("error");
66+
if (error.isStr()) return util::Error{strprintf(_("Signer returned error: %s"), error.getValStr())};
67+
68+
const UniValue& ret_address = result.find_value("address");
69+
if (!ret_address.isStr()) return util::Error{_("Signer did not echo address")};
70+
71+
if (ret_address.getValStr() != EncodeDestination(dest)) {
72+
return util::Error{strprintf(_("Signer echoed unexpected address %s"), ret_address.getValStr())};
73+
}
74+
75+
return util::Result<void>();
6376
}
6477

6578
// If sign is true, transaction must previously have been filled

src/wallet/external_signer_scriptpubkeyman.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
#include <memory>
1111

12+
struct bilingual_str;
13+
1214
namespace wallet {
1315
class ExternalSignerScriptPubKeyMan : public DescriptorScriptPubKeyMan
1416
{
@@ -27,7 +29,11 @@ class ExternalSignerScriptPubKeyMan : public DescriptorScriptPubKeyMan
2729

2830
static ExternalSigner GetExternalSigner();
2931

30-
bool DisplayAddress(const CScript scriptPubKey, const ExternalSigner &signer) const;
32+
/**
33+
* Display address on the device and verify that the returned value matches.
34+
* @returns nothing or an error message
35+
*/
36+
util::Result<void> DisplayAddress(const CTxDestination& dest, const ExternalSigner& signer) const;
3137

3238
TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override;
3339
};

src/wallet/interfaces.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ class WalletImpl : public Wallet
247247
return value.empty() ? m_wallet->EraseAddressReceiveRequest(batch, dest, id)
248248
: m_wallet->SetAddressReceiveRequest(batch, dest, id, value);
249249
}
250-
bool displayAddress(const CTxDestination& dest) override
250+
util::Result<void> displayAddress(const CTxDestination& dest) override
251251
{
252252
LOCK(m_wallet->cs_wallet);
253253
return m_wallet->DisplayAddress(dest);

src/wallet/rpc/addresses.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -789,9 +789,8 @@ RPCHelpMan walletdisplayaddress()
789789
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
790790
}
791791

792-
if (!pwallet->DisplayAddress(dest)) {
793-
throw JSONRPCError(RPC_MISC_ERROR, "Failed to display address");
794-
}
792+
util::Result<void> res = pwallet->DisplayAddress(dest);
793+
if (!res) throw JSONRPCError(RPC_MISC_ERROR, util::ErrorString(res).original);
795794

796795
UniValue result(UniValue::VOBJ);
797796
result.pushKV("address", request.params[0].get_str());

src/wallet/scriptpubkeyman.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
#include <unordered_map>
2828

2929
enum class OutputType;
30-
struct bilingual_str;
3130

3231
namespace wallet {
3332
struct MigrationData;

src/wallet/wallet.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2667,7 +2667,7 @@ void ReserveDestination::ReturnDestination()
26672667
address = CNoDestination();
26682668
}
26692669

2670-
bool CWallet::DisplayAddress(const CTxDestination& dest)
2670+
util::Result<void> CWallet::DisplayAddress(const CTxDestination& dest)
26712671
{
26722672
CScript scriptPubKey = GetScriptForDestination(dest);
26732673
for (const auto& spk_man : GetScriptPubKeyMans(scriptPubKey)) {
@@ -2676,9 +2676,9 @@ bool CWallet::DisplayAddress(const CTxDestination& dest)
26762676
continue;
26772677
}
26782678
ExternalSigner signer = ExternalSignerScriptPubKeyMan::GetExternalSigner();
2679-
return signer_spk_man->DisplayAddress(scriptPubKey, signer);
2679+
return signer_spk_man->DisplayAddress(dest, signer);
26802680
}
2681-
return false;
2681+
return util::Error{_("There is no ScriptPubKeyManager for this address")};
26822682
}
26832683

26842684
bool CWallet::LockCoin(const COutPoint& output, WalletBatch* batch)

0 commit comments

Comments
 (0)