aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/wallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r--src/wallet/wallet.cpp137
1 files changed, 114 insertions, 23 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index db80745db0..08e480225d 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -14,10 +14,12 @@
#include <key.h>
#include <key_io.h>
#include <optional.h>
+#include <outputtype.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
+#include <psbt.h>
#include <script/descriptor.h>
#include <script/script.h>
#include <script/signingprovider.h>
@@ -32,6 +34,7 @@
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/fees.h>
+#include <wallet/external_signer_scriptpubkeyman.h>
#include <univalue.h>
@@ -259,6 +262,20 @@ std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::strin
wallet_creation_flags |= WALLET_FLAG_BLANK_WALLET;
}
+ // Private keys must be disabled for an external signer wallet
+ if ((wallet_creation_flags & WALLET_FLAG_EXTERNAL_SIGNER) && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ error = Untranslated("Private keys must be disabled when using an external signer");
+ status = DatabaseStatus::FAILED_CREATE;
+ return nullptr;
+ }
+
+ // Descriptor support must be enabled for an external signer wallet
+ if ((wallet_creation_flags & WALLET_FLAG_EXTERNAL_SIGNER) && !(wallet_creation_flags & WALLET_FLAG_DESCRIPTORS)) {
+ error = Untranslated("Descriptor support must be enabled when using an external signer");
+ status = DatabaseStatus::FAILED_CREATE;
+ return nullptr;
+ }
+
// Wallet::Verify will check if we're trying to create a wallet with a duplicate name.
std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
if (!database) {
@@ -3558,6 +3575,38 @@ void ReserveDestination::ReturnDestination()
address = CNoDestination();
}
+#ifdef ENABLE_EXTERNAL_SIGNER
+ExternalSigner CWallet::GetExternalSigner()
+{
+ const std::string command = gArgs.GetArg("-signer", "");
+ if (command == "") throw std::runtime_error(std::string(__func__) + ": restart bitcoind with -signer=<cmd>");
+ 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
+ return signers[0];
+}
+#endif
+
+bool CWallet::DisplayAddress(const CTxDestination& dest)
+{
+#ifdef ENABLE_EXTERNAL_SIGNER
+ CScript scriptPubKey = GetScriptForDestination(dest);
+ const auto spk_man = GetScriptPubKeyMan(scriptPubKey);
+ if (spk_man == nullptr) {
+ return false;
+ }
+ auto signer_spk_man = dynamic_cast<ExternalSignerScriptPubKeyMan*>(spk_man);
+ if (signer_spk_man == nullptr) {
+ return false;
+ }
+ ExternalSigner signer = GetExternalSigner(); // TODO: move signer in spk_man
+ return signer_spk_man->DisplayAddress(scriptPubKey, signer);
+#else
+ return false;
+#endif
+}
+
void CWallet::LockCoin(const COutPoint& output)
{
AssertLockHeld(cs_wallet);
@@ -3836,7 +3885,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
walletInstance->SetupLegacyScriptPubKeyMan();
}
- if (!(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
+ if ((wallet_creation_flags & WALLET_FLAG_EXTERNAL_SIGNER) || !(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
LOCK(walletInstance->cs_wallet);
if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
walletInstance->SetupDescriptorScriptPubKeyMans();
@@ -4443,40 +4492,82 @@ void CWallet::ConnectScriptPubKeyManNotifiers()
void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc)
{
- auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
- m_spk_managers[id] = std::move(spk_manager);
+ if (IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
+#ifdef ENABLE_EXTERNAL_SIGNER
+ auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, desc));
+ m_spk_managers[id] = std::move(spk_manager);
+#else
+ throw std::runtime_error(std::string(__func__) + ": Configure with --enable-external-signer to use external signer wallets");
+#endif
+ } else {
+ auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
+ m_spk_managers[id] = std::move(spk_manager);
+ }
}
void CWallet::SetupDescriptorScriptPubKeyMans()
{
AssertLockHeld(cs_wallet);
- // Make a seed
- CKey seed_key;
- seed_key.MakeNewKey(true);
- CPubKey seed = seed_key.GetPubKey();
- assert(seed_key.VerifyPubKey(seed));
+ if (!IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
+ // Make a seed
+ CKey seed_key;
+ seed_key.MakeNewKey(true);
+ CPubKey seed = seed_key.GetPubKey();
+ assert(seed_key.VerifyPubKey(seed));
- // Get the extended key
- CExtKey master_key;
- master_key.SetSeed(seed_key.begin(), seed_key.size());
+ // Get the extended key
+ CExtKey master_key;
+ master_key.SetSeed(seed_key.begin(), seed_key.size());
- for (bool internal : {false, true}) {
- for (OutputType t : OUTPUT_TYPES) {
- auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, internal));
- if (IsCrypted()) {
- if (IsLocked()) {
- throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
+ for (bool internal : {false, true}) {
+ for (OutputType t : OUTPUT_TYPES) {
+ auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, internal));
+ if (IsCrypted()) {
+ if (IsLocked()) {
+ throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
+ }
+ if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, nullptr)) {
+ throw std::runtime_error(std::string(__func__) + ": Could not encrypt new descriptors");
+ }
}
- if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, nullptr)) {
- throw std::runtime_error(std::string(__func__) + ": Could not encrypt new descriptors");
+ spk_manager->SetupDescriptorGeneration(master_key, t);
+ uint256 id = spk_manager->GetID();
+ m_spk_managers[id] = std::move(spk_manager);
+ AddActiveScriptPubKeyMan(id, t, internal);
+ }
+ }
+ } else {
+#ifdef ENABLE_EXTERNAL_SIGNER
+ ExternalSigner signer = ExternalSignerScriptPubKeyMan::GetExternalSigner();
+
+ // TODO: add account parameter
+ int account = 0;
+ UniValue signer_res = signer.GetDescriptors(account);
+
+ if (!signer_res.isObject()) throw std::runtime_error(std::string(__func__) + ": Unexpected result");
+ for (bool internal : {false, true}) {
+ const UniValue& descriptor_vals = find_value(signer_res, internal ? "internal" : "receive");
+ if (!descriptor_vals.isArray()) throw std::runtime_error(std::string(__func__) + ": Unexpected result");
+ for (const UniValue& desc_val : descriptor_vals.get_array().getValues()) {
+ std::string desc_str = desc_val.getValStr();
+ FlatSigningProvider keys;
+ std::string dummy_error;
+ std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, dummy_error, false);
+ if (!desc->GetOutputType()) {
+ continue;
}
+ OutputType t = *desc->GetOutputType();
+ auto spk_manager = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, internal));
+ spk_manager->SetupDescriptor(std::move(desc));
+ uint256 id = spk_manager->GetID();
+ m_spk_managers[id] = std::move(spk_manager);
+ AddActiveScriptPubKeyMan(id, t, internal);
}
- spk_manager->SetupDescriptorGeneration(master_key, t);
- uint256 id = spk_manager->GetID();
- m_spk_managers[id] = std::move(spk_manager);
- AddActiveScriptPubKeyMan(id, t, internal);
}
+#else
+ throw std::runtime_error(std::string(__func__) + ": Wallets with external signers require Boost::Process library.");
+#endif
}
}