aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/interfaces.cpp18
-rw-r--r--src/wallet/scriptpubkeyman.cpp38
-rw-r--r--src/wallet/scriptpubkeyman.h6
-rw-r--r--src/wallet/spend.cpp10
-rw-r--r--src/wallet/test/wallet_tests.cpp3
-rw-r--r--src/wallet/wallet.cpp29
-rw-r--r--src/wallet/wallet.h2
7 files changed, 50 insertions, 56 deletions
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index aea6d5534e..4fbc519e39 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -148,7 +148,7 @@ public:
void abortRescan() override { m_wallet->AbortRescan(); }
bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); }
std::string getWalletName() override { return m_wallet->GetName(); }
- util::Result<CTxDestination> getNewDestination(const OutputType type, const std::string label) override
+ util::Result<CTxDestination> getNewDestination(const OutputType type, const std::string& label) override
{
LOCK(m_wallet->cs_wallet);
return m_wallet->GetNewDestination(type, label);
@@ -551,32 +551,34 @@ public:
void setMockTime(int64_t time) override { return SetMockTime(time); }
//! WalletLoader methods
- std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) override
+ util::Result<std::unique_ptr<Wallet>> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, std::vector<bilingual_str>& warnings) override
{
- std::shared_ptr<CWallet> wallet;
DatabaseOptions options;
DatabaseStatus status;
ReadDatabaseArgs(*m_context.args, options);
options.require_create = true;
options.create_flags = wallet_creation_flags;
options.create_passphrase = passphrase;
- return MakeWallet(m_context, CreateWallet(m_context, name, true /* load_on_start */, options, status, error, warnings));
+ bilingual_str error;
+ util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, CreateWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))};
+ return wallet ? std::move(wallet) : util::Error{error};
}
- std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
+ util::Result<std::unique_ptr<Wallet>> loadWallet(const std::string& name, std::vector<bilingual_str>& warnings) override
{
DatabaseOptions options;
DatabaseStatus status;
ReadDatabaseArgs(*m_context.args, options);
options.require_existing = true;
- return MakeWallet(m_context, LoadWallet(m_context, name, true /* load_on_start */, options, status, error, warnings));
+ bilingual_str error;
+ util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, LoadWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))};
+ return wallet ? std::move(wallet) : util::Error{error};
}
util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) override
{
DatabaseStatus status;
bilingual_str error;
util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings))};
- if (!wallet) return util::Error{error};
- return wallet;
+ return wallet ? std::move(wallet) : util::Error{error};
}
std::string getWalletDir() override
{
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index b498ad5a17..7ff017775e 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -292,26 +292,22 @@ bool LegacyScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, WalletBat
return true;
}
-bool LegacyScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, bilingual_str& error)
+util::Result<CTxDestination> LegacyScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool)
{
if (LEGACY_OUTPUT_TYPES.count(type) == 0) {
- error = _("Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and \"bech32\" address types");
- return false;
+ return util::Error{_("Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and \"bech32\" address types")};
}
assert(type != OutputType::BECH32M);
LOCK(cs_KeyStore);
if (!CanGetAddresses(internal)) {
- error = _("Error: Keypool ran out, please call keypoolrefill first");
- return false;
+ return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
}
if (!ReserveKeyFromKeyPool(index, keypool, internal)) {
- error = _("Error: Keypool ran out, please call keypoolrefill first");
- return false;
+ return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
}
- address = GetDestinationForKey(keypool.vchPubKey, type);
- return true;
+ return GetDestinationForKey(keypool.vchPubKey, type);
}
bool LegacyScriptPubKeyMan::TopUpInactiveHDChain(const CKeyID seed_id, int64_t index, bool internal)
@@ -1084,6 +1080,13 @@ CPubKey LegacyScriptPubKeyMan::GenerateNewKey(WalletBatch &batch, CHDChain& hd_c
return pubkey;
}
+//! Try to derive an extended key, throw if it fails.
+static void DeriveExtKey(CExtKey& key_in, unsigned int index, CExtKey& key_out) {
+ if (!key_in.Derive(key_out, index)) {
+ throw std::runtime_error("Could not derive extended key");
+ }
+}
+
void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, CHDChain& hd_chain, bool internal)
{
// for now we use a fixed keypath scheme of m/0'/0'/k
@@ -1101,11 +1104,11 @@ void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata&
// derive m/0'
// use hardened derivation (child keys >= 0x80000000 are hardened after bip32)
- masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT);
+ DeriveExtKey(masterKey, BIP32_HARDENED_KEY_LIMIT, accountKey);
// derive m/0'/0' (external chain) OR m/0'/1' (internal chain)
assert(internal ? m_storage.CanSupportFeature(FEATURE_HD_SPLIT) : true);
- accountKey.Derive(chainChildKey, BIP32_HARDENED_KEY_LIMIT+(internal ? 1 : 0));
+ DeriveExtKey(accountKey, BIP32_HARDENED_KEY_LIMIT+(internal ? 1 : 0), chainChildKey);
// derive child key at next index, skip keys already known to the wallet
do {
@@ -1113,7 +1116,7 @@ void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata&
// childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened child-index-range
// example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649
if (internal) {
- chainChildKey.Derive(childKey, hd_chain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
+ DeriveExtKey(chainChildKey, hd_chain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT, childKey);
metadata.hdKeypath = "m/0'/1'/" + ToString(hd_chain.nInternalChainCounter) + "'";
metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT);
metadata.key_origin.path.push_back(1 | BIP32_HARDENED_KEY_LIMIT);
@@ -1121,7 +1124,7 @@ void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata&
hd_chain.nInternalChainCounter++;
}
else {
- chainChildKey.Derive(childKey, hd_chain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
+ DeriveExtKey(chainChildKey, hd_chain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT, childKey);
metadata.hdKeypath = "m/0'/0'/" + ToString(hd_chain.nExternalChainCounter) + "'";
metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT);
metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT);
@@ -1761,17 +1764,12 @@ bool DescriptorScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, Walle
return true;
}
-bool DescriptorScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, bilingual_str& error)
+util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool)
{
LOCK(cs_desc_man);
auto op_dest = GetNewDestination(type);
index = m_wallet_descriptor.next_index - 1;
- if (op_dest) {
- address = *op_dest;
- } else {
- error = util::ErrorString(op_dest);
- }
- return bool(op_dest);
+ return op_dest;
}
void DescriptorScriptPubKeyMan::ReturnDestination(int64_t index, bool internal, const CTxDestination& addr)
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index afe5d9ea9f..408d162eba 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -179,7 +179,7 @@ public:
virtual bool CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys = false) { return false; }
virtual bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) { return false; }
- virtual bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, bilingual_str& error) { return false; }
+ virtual util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) { return util::Error{Untranslated("Not supported")}; }
virtual void KeepDestination(int64_t index, const OutputType& type) {}
virtual void ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) {}
@@ -366,7 +366,7 @@ public:
bool CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys = false) override;
bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override;
- bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, bilingual_str& error) override;
+ util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) override;
void KeepDestination(int64_t index, const OutputType& type) override;
void ReturnDestination(int64_t index, bool internal, const CTxDestination&) override;
@@ -576,7 +576,7 @@ public:
bool CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys = false) override;
bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override;
- bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, bilingual_str& error) override;
+ util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) override;
void ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) override;
// Tops up the descriptor cache and m_map_script_pub_keys. The cache is stored in the wallet file
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index b359d3e19b..e266cf6c81 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -814,11 +814,13 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
// Reserve a new key pair from key pool. If it fails, provide a dummy
// destination in case we don't need change.
CTxDestination dest;
- bilingual_str dest_err;
- if (!reservedest.GetReservedDestination(dest, true, dest_err)) {
- error = _("Transaction needs a change address, but we can't generate it.") + Untranslated(" ") + dest_err;
+ auto op_dest = reservedest.GetReservedDestination(true);
+ if (!op_dest) {
+ error = _("Transaction needs a change address, but we can't generate it.") + Untranslated(" ") + util::ErrorString(op_dest);
+ } else {
+ dest = *op_dest;
+ scriptChange = GetScriptForDestination(dest);
}
- scriptChange = GetScriptForDestination(dest);
// A valid destination implies a change script (and
// vice-versa). An empty change script will abort later, if the
// change keypool ran out, but change is required.
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 199925b4b1..093f510945 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -919,10 +919,9 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
// Add tx to wallet
const auto& op_dest = wallet.GetNewDestination(OutputType::BECH32M, "");
BOOST_ASSERT(op_dest);
- const CTxDestination& dest = *op_dest;
CMutableTransaction mtx;
- mtx.vout.push_back({COIN, GetScriptForDestination(dest)});
+ mtx.vout.push_back({COIN, GetScriptForDestination(*op_dest)});
mtx.vin.push_back(CTxIn(g_insecure_rand_ctx.rand256(), 0));
const auto& tx_id_to_spend = wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInMempool{})->GetHash();
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 30ba95c3c1..de1078e646 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2359,15 +2359,11 @@ util::Result<CTxDestination> CWallet::GetNewChangeDestination(const OutputType t
{
LOCK(cs_wallet);
- CTxDestination dest;
- bilingual_str error;
ReserveDestination reservedest(this, type);
- if (!reservedest.GetReservedDestination(dest, true, error)) {
- return util::Error{error};
- }
+ auto op_dest = reservedest.GetReservedDestination(true);
+ if (op_dest) reservedest.KeepDestination();
- reservedest.KeepDestination();
- return dest;
+ return op_dest;
}
std::optional<int64_t> CWallet::GetOldestKeyPoolTime() const
@@ -2437,27 +2433,24 @@ std::set<std::string> CWallet::ListAddrBookLabels(const std::string& purpose) co
return label_set;
}
-bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool internal, bilingual_str& error)
+util::Result<CTxDestination> ReserveDestination::GetReservedDestination(bool internal)
{
m_spk_man = pwallet->GetScriptPubKeyMan(type, internal);
if (!m_spk_man) {
- error = strprintf(_("Error: No %s addresses available."), FormatOutputType(type));
- return false;
+ return util::Error{strprintf(_("Error: No %s addresses available."), FormatOutputType(type))};
}
-
if (nIndex == -1)
{
m_spk_man->TopUp();
CKeyPool keypool;
- if (!m_spk_man->GetReservedDestination(type, internal, address, nIndex, keypool, error)) {
- return false;
- }
+ auto op_address = m_spk_man->GetReservedDestination(type, internal, nIndex, keypool);
+ if (!op_address) return op_address;
+ address = *op_address;
fInternal = keypool.fInternal;
}
- dest = address;
- return true;
+ return address;
}
void ReserveDestination::KeepDestination()
@@ -3484,7 +3477,7 @@ void CWallet::LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool intern
// Legacy wallets have only one ScriptPubKeyManager and it's active for all output and change types.
Assert(IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
- WalletLogPrintf("Setting spkMan to active: id = %s, type = %d, internal = %d\n", id.ToString(), static_cast<int>(type), static_cast<int>(internal));
+ WalletLogPrintf("Setting spkMan to active: id = %s, type = %s, internal = %s\n", id.ToString(), FormatOutputType(type), internal ? "true" : "false");
auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;
auto& spk_mans_other = internal ? m_external_spk_managers : m_internal_spk_managers;
auto spk_man = m_spk_managers.at(id).get();
@@ -3502,7 +3495,7 @@ void CWallet::DeactivateScriptPubKeyMan(uint256 id, OutputType type, bool intern
{
auto spk_man = GetScriptPubKeyMan(type, internal);
if (spk_man != nullptr && spk_man->GetID() == id) {
- WalletLogPrintf("Deactivate spkMan: id = %s, type = %d, internal = %d\n", id.ToString(), static_cast<int>(type), static_cast<int>(internal));
+ WalletLogPrintf("Deactivate spkMan: id = %s, type = %s, internal = %s\n", id.ToString(), FormatOutputType(type), internal ? "true" : "false");
WalletBatch batch(GetDatabase());
if (!batch.EraseActiveScriptPubKeyMan(static_cast<uint8_t>(type), internal)) {
throw std::runtime_error(std::string(__func__) + ": erasing active ScriptPubKeyMan id failed");
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 801ac5533a..cf33ea21f2 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -191,7 +191,7 @@ public:
}
//! Reserve an address
- bool GetReservedDestination(CTxDestination& pubkey, bool internal, bilingual_str& error);
+ util::Result<CTxDestination> GetReservedDestination(bool internal);
//! Return reserved address
void ReturnDestination();
//! Keep the address. Do not return it's key to the keypool when this object goes out of scope