diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 9 | ||||
-rw-r--r-- | src/Makefile.bench.include | 9 | ||||
-rw-r--r-- | src/Makefile.test.include | 11 | ||||
-rw-r--r-- | src/interfaces/wallet.h | 38 | ||||
-rw-r--r-- | src/key.cpp | 1 | ||||
-rw-r--r-- | src/key.h | 4 | ||||
-rw-r--r-- | src/outputtype.cpp | 2 | ||||
-rw-r--r-- | src/psbt.h | 3 | ||||
-rw-r--r-- | src/pubkey.cpp | 1 | ||||
-rw-r--r-- | src/pubkey.h | 4 | ||||
-rw-r--r-- | src/qt/walletcontroller.cpp | 23 | ||||
-rw-r--r-- | src/script/descriptor.cpp | 11 | ||||
-rw-r--r-- | src/script/sign.cpp | 19 | ||||
-rw-r--r-- | src/script/sign.h | 6 | ||||
-rw-r--r-- | src/test/bip32_tests.cpp | 18 | ||||
-rw-r--r-- | src/test/descriptor_tests.cpp | 7 | ||||
-rw-r--r-- | src/test/fuzz/key.cpp | 2 | ||||
-rw-r--r-- | src/test/fuzz/script.cpp | 1 | ||||
-rw-r--r-- | src/test/rbf_tests.cpp | 2 | ||||
-rw-r--r-- | src/wallet/interfaces.cpp | 18 | ||||
-rw-r--r-- | src/wallet/rpc/addresses.cpp | 2 | ||||
-rw-r--r-- | src/wallet/scriptpubkeyman.cpp | 18 | ||||
-rw-r--r-- | src/wallet/test/wallet_tests.cpp | 3 |
23 files changed, 107 insertions, 105 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 576a448a0d..18c6c25b96 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1065,6 +1065,15 @@ nodist_libbitcoin_ipc_a_SOURCES = $(libbitcoin_ipc_mpgen_output) CLEANFILES += $(libbitcoin_ipc_mpgen_output) endif +%.raw.h: %.raw + @$(MKDIR_P) $(@D) + @{ \ + echo "static unsigned const char $(*F)_raw[] = {" && \ + $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \ + echo "};"; \ + } > "$@.new" && mv -f "$@.new" "$@" + @echo "Generated $@" + include Makefile.minisketch.include include Makefile.crc32c.include diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 532f668668..c5705a8be3 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -93,12 +93,3 @@ bench: $(BENCH_BINARY) FORCE bitcoin_bench_clean : FORCE rm -f $(CLEAN_BITCOIN_BENCH) $(bench_bench_bitcoin_OBJECTS) $(BENCH_BINARY) - -%.raw.h: %.raw - @$(MKDIR_P) $(@D) - @{ \ - echo "static unsigned const char $(*F)_raw[] = {" && \ - $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \ - echo "};"; \ - } > "$@.new" && mv -f "$@.new" "$@" - @echo "Generated $@" diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 9ed5731af1..75a404c50a 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -339,7 +339,7 @@ nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) $(BITCOIN_TESTS): $(GENERATED_TEST_FILES) -CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno test/fuzz/*.gcda test/fuzz/*.gcno test/util/*.gcda test/util/*.gcno $(GENERATED_TEST_FILES) $(BITCOIN_TESTS:=.log) +CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno test/fuzz/*.gcda test/fuzz/*.gcno test/util/*.gcda test/util/*.gcno $(GENERATED_TEST_FILES) $(addsuffix .log,$(basename $(BITCOIN_TESTS))) CLEANFILES += $(CLEAN_BITCOIN_TEST) @@ -415,12 +415,3 @@ endif echo "};};"; \ } > "$@.new" && mv -f "$@.new" "$@" @echo "Generated $@" - -%.raw.h: %.raw - @$(MKDIR_P) $(@D) - @{ \ - echo "static unsigned const char $(*F)_raw[] = {" && \ - $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \ - echo "};"; \ - } > "$@.new" && mv -f "$@.new" "$@" - @echo "Generated $@" diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 63603c7f7b..1148dc7e4c 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -88,7 +88,7 @@ public: virtual std::string getWalletName() = 0; // Get a new address. - virtual util::Result<CTxDestination> getNewDestination(const OutputType type, const std::string label) = 0; + virtual util::Result<CTxDestination> getNewDestination(const OutputType type, const std::string& label) = 0; //! Get public key. virtual bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) = 0; @@ -320,31 +320,31 @@ class WalletLoader : public ChainClient { public: //! Create new wallet. - virtual 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) = 0; + virtual util::Result<std::unique_ptr<Wallet>> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, std::vector<bilingual_str>& warnings) = 0; - //! Load existing wallet. - virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0; + //! Load existing wallet. + virtual util::Result<std::unique_ptr<Wallet>> loadWallet(const std::string& name, std::vector<bilingual_str>& warnings) = 0; - //! Return default wallet directory. - virtual std::string getWalletDir() = 0; + //! Return default wallet directory. + virtual std::string getWalletDir() = 0; - //! Restore backup wallet - virtual util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) = 0; + //! Restore backup wallet + virtual util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) = 0; - //! Return available wallets in wallet directory. - virtual std::vector<std::string> listWalletDir() = 0; + //! Return available wallets in wallet directory. + virtual std::vector<std::string> listWalletDir() = 0; - //! Return interfaces for accessing wallets (if any). - virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0; + //! Return interfaces for accessing wallets (if any). + virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0; - //! Register handler for load wallet messages. This callback is triggered by - //! createWallet and loadWallet above, and also triggered when wallets are - //! loaded at startup or by RPC. - using LoadWalletFn = std::function<void(std::unique_ptr<Wallet> wallet)>; - virtual std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) = 0; + //! Register handler for load wallet messages. This callback is triggered by + //! createWallet and loadWallet above, and also triggered when wallets are + //! loaded at startup or by RPC. + using LoadWalletFn = std::function<void(std::unique_ptr<Wallet> wallet)>; + virtual std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) = 0; - //! Return pointer to internal context, useful for testing. - virtual wallet::WalletContext* context() { return nullptr; } + //! Return pointer to internal context, useful for testing. + virtual wallet::WalletContext* context() { return nullptr; } }; //! Information about one wallet address. diff --git a/src/key.cpp b/src/key.cpp index 9b0971a2dd..199808505d 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -333,6 +333,7 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const } bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const { + if (nDepth == std::numeric_limits<unsigned char>::max()) return false; out.nDepth = nDepth + 1; CKeyID id = key.GetPubKey().GetID(); memcpy(out.vchFingerprint, &id, 4); @@ -146,7 +146,7 @@ public: bool SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256* merkle_root, const uint256& aux) const; //! Derive BIP32 child key. - bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; + [[nodiscard]] bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; /** * Verify thoroughly whether a private key and a public key match. @@ -176,7 +176,7 @@ struct CExtKey { void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); - bool Derive(CExtKey& out, unsigned int nChild) const; + [[nodiscard]] bool Derive(CExtKey& out, unsigned int nChild) const; CExtPubKey Neuter() const; void SetSeed(Span<const std::byte> seed); }; diff --git a/src/outputtype.cpp b/src/outputtype.cpp index 19366295e6..5be9942d7d 100644 --- a/src/outputtype.cpp +++ b/src/outputtype.cpp @@ -91,8 +91,6 @@ CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, case OutputType::BECH32: { CTxDestination witdest = WitnessV0ScriptHash(script); CScript witprog = GetScriptForDestination(witdest); - // Check if the resulting program is solvable (i.e. doesn't use an uncompressed key) - if (!IsSolvable(keystore, witprog)) return ScriptHash(script); // Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours. keystore.AddCScript(witprog); if (type == OutputType::BECH32) { diff --git a/src/psbt.h b/src/psbt.h index eef7d7dd3b..d5c67802c7 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -641,6 +641,9 @@ struct PSBTInput s >> leaf_hashes; size_t after_hashes = s.size(); size_t hashes_len = before_hashes - after_hashes; + if (hashes_len > value_len) { + throw std::ios_base::failure("Input Taproot BIP32 keypath has an invalid length"); + } size_t origin_len = value_len - hashes_len; m_tap_bip32_paths.emplace(xonly, std::make_pair(leaf_hashes, DeserializeKeyOrigin(s, origin_len))); break; diff --git a/src/pubkey.cpp b/src/pubkey.cpp index a4a1be6388..2e37e16690 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -365,6 +365,7 @@ void CExtPubKey::DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VE } bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const { + if (nDepth == std::numeric_limits<unsigned char>::max()) return false; out.nDepth = nDepth + 1; CKeyID id = pubkey.GetID(); memcpy(out.vchFingerprint, &id, 4); diff --git a/src/pubkey.h b/src/pubkey.h index 463efe1b00..0485a38f72 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -218,7 +218,7 @@ public: bool Decompress(); //! Derive BIP32 child pubkey. - bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; + [[nodiscard]] bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; }; class XOnlyPubKey @@ -327,7 +327,7 @@ struct CExtPubKey { void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); void EncodeWithVersion(unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]) const; void DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]); - bool Derive(CExtPubKey& out, unsigned int nChild) const; + [[nodiscard]] bool Derive(CExtPubKey& out, unsigned int nChild) const; }; /** Users of this module must hold an ECCVerifyHandle. The constructor and diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index 6e07dc09a0..443941d3c4 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -262,9 +262,13 @@ void CreateWalletActivity::createWallet() } QTimer::singleShot(500ms, worker(), [this, name, flags] { - std::unique_ptr<interfaces::Wallet> wallet = node().walletLoader().createWallet(name, m_passphrase, flags, m_error_message, m_warning_message); + auto wallet{node().walletLoader().createWallet(name, m_passphrase, flags, m_warning_message)}; - if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet)); + if (wallet) { + m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(*wallet)); + } else { + m_error_message = util::ErrorString(wallet); + } QTimer::singleShot(500ms, this, &CreateWalletActivity::finish); }); @@ -343,9 +347,13 @@ void OpenWalletActivity::open(const std::string& path) tr("Opening Wallet <b>%1</b>…").arg(name.toHtmlEscaped())); QTimer::singleShot(0, worker(), [this, path] { - std::unique_ptr<interfaces::Wallet> wallet = node().walletLoader().loadWallet(path, m_error_message, m_warning_message); + auto wallet{node().walletLoader().loadWallet(path, m_warning_message)}; - if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet)); + if (wallet) { + m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(*wallet)); + } else { + m_error_message = util::ErrorString(wallet); + } QTimer::singleShot(0, this, &OpenWalletActivity::finish); }); @@ -393,8 +401,11 @@ void RestoreWalletActivity::restore(const fs::path& backup_file, const std::stri QTimer::singleShot(0, worker(), [this, backup_file, wallet_name] { auto wallet{node().walletLoader().restoreWallet(backup_file, wallet_name, m_warning_message)}; - m_error_message = util::ErrorString(wallet); - if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(*wallet)); + if (wallet) { + m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(*wallet)); + } else { + m_error_message = util::ErrorString(wallet); + } QTimer::singleShot(0, this, &RestoreWalletActivity::finish); }); diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index db386c9ab8..9bcbe1ceef 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -328,7 +328,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider { if (!GetExtKey(arg, xprv)) return false; for (auto entry : m_path) { - xprv.Derive(xprv, entry); + if (!xprv.Derive(xprv, entry)) return false; if (entry >> 31) { last_hardened = xprv; } @@ -388,14 +388,13 @@ public: } } else { for (auto entry : m_path) { - der = parent_extkey.Derive(parent_extkey, entry); - assert(der); + if (!parent_extkey.Derive(parent_extkey, entry)) return false; } final_extkey = parent_extkey; if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive(final_extkey, pos); assert(m_derive != DeriveType::HARDENED); } - assert(der); + if (!der) return false; final_info_out = final_info_out_tmp; key_out = final_extkey.pubkey; @@ -498,8 +497,8 @@ public: CExtKey extkey; CExtKey dummy; if (!GetDerivedExtKey(arg, extkey, dummy)) return false; - if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos); - if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL); + if (m_derive == DeriveType::UNHARDENED && !extkey.Derive(extkey, pos)) return false; + if (m_derive == DeriveType::HARDENED && !extkey.Derive(extkey, pos | 0x80000000UL)) return false; key = extkey.key; return true; } diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 79cf918c9b..4014ebadbc 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -632,25 +632,6 @@ public: const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator(32, 32); const BaseSignatureCreator& DUMMY_MAXIMUM_SIGNATURE_CREATOR = DummySignatureCreator(33, 32); -bool IsSolvable(const SigningProvider& provider, const CScript& script) -{ - // This check is to make sure that the script we created can actually be solved for and signed by us - // if we were to have the private keys. This is just to make sure that the script is valid and that, - // if found in a transaction, we would still accept and relay that transaction. In particular, - // it will reject witness outputs that require signing with an uncompressed public key. - SignatureData sigs; - // Make sure that STANDARD_SCRIPT_VERIFY_FLAGS includes SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, the most - // important property this function is designed to test for. - static_assert(STANDARD_SCRIPT_VERIFY_FLAGS & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, "IsSolvable requires standard script flags to include WITNESS_PUBKEYTYPE"); - if (ProduceSignature(provider, DUMMY_SIGNATURE_CREATOR, script, sigs)) { - // VerifyScript check is just defensive, and should never fail. - bool verified = VerifyScript(sigs.scriptSig, script, &sigs.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, DUMMY_CHECKER); - assert(verified); - return true; - } - return false; -} - bool IsSegWitOutput(const SigningProvider& provider, const CScript& script) { int version; diff --git a/src/script/sign.h b/src/script/sign.h index 5e58272154..958d673b9f 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -97,12 +97,6 @@ bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout); void UpdateInput(CTxIn& input, const SignatureData& data); -/* Check whether we know how to sign for an output like this, assuming we - * have all private keys. While this function does not need private keys, the passed - * provider is used to look up public keys and redeemscripts by hash. - * Solvability is unrelated to whether we consider this output to be ours. */ -bool IsSolvable(const SigningProvider& provider, const CScript& script); - /** Check whether a scriptPubKey is known to be segwit. */ bool IsSegWitOutput(const SigningProvider& provider, const CScript& script); diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 64cc924239..75b29ae0aa 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -184,4 +184,22 @@ BOOST_AUTO_TEST_CASE(bip32_test5) { } } +BOOST_AUTO_TEST_CASE(bip32_max_depth) { + CExtKey key_parent{DecodeExtKey(test1.vDerive[0].prv)}, key_child; + CExtPubKey pubkey_parent{DecodeExtPubKey(test1.vDerive[0].pub)}, pubkey_child; + + // We can derive up to the 255th depth.. + for (auto i = 0; i++ < 255;) { + BOOST_CHECK(key_parent.Derive(key_child, 0)); + std::swap(key_parent, key_child); + BOOST_CHECK(pubkey_parent.Derive(pubkey_child, 0)); + std::swap(pubkey_parent, pubkey_child); + } + + // But trying to derive a non-existent 256th depth will fail! + BOOST_CHECK(key_parent.nDepth == 255 && pubkey_parent.nDepth == 255); + BOOST_CHECK(!key_parent.Derive(key_child, 0)); + BOOST_CHECK(!pubkey_parent.Derive(pubkey_child, 0)); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index a8c666079d..1eb4b373b4 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -233,7 +233,7 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string& for (const auto& xpub_pair : parent_xpub_cache) { const CExtPubKey& xpub = xpub_pair.second; CExtPubKey der; - xpub.Derive(der, i); + BOOST_CHECK(xpub.Derive(der, i)); pubkeys.insert(der.pubkey); } int count_pks = 0; @@ -265,7 +265,7 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string& const CExtPubKey& xpub = xpub_pair.second; pubkeys.insert(xpub.pubkey); CExtPubKey der; - xpub.Derive(der, i); + BOOST_CHECK(xpub.Derive(der, i)); pubkeys.insert(der.pubkey); } int count_pks = 0; @@ -302,7 +302,6 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string& // For each of the produced scripts, verify solvability, and when possible, try to sign a transaction spending it. for (size_t n = 0; n < spks.size(); ++n) { BOOST_CHECK_EQUAL(ref[n], HexStr(spks[n])); - BOOST_CHECK_EQUAL(IsSolvable(Merge(key_provider, script_provider), spks[n]), (flags & UNSOLVABLE) == 0); if (flags & SIGNABLE) { CMutableTransaction spend; @@ -324,7 +323,7 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string& BOOST_CHECK(inferred->Expand(0, provider_inferred, spks_inferred, provider_inferred)); BOOST_CHECK_EQUAL(spks_inferred.size(), 1U); BOOST_CHECK(spks_inferred[0] == spks[n]); - BOOST_CHECK_EQUAL(IsSolvable(provider_inferred, spks_inferred[0]), !(flags & UNSOLVABLE)); + BOOST_CHECK_EQUAL(InferDescriptor(spks_inferred[0], provider_inferred)->IsSolvable(), !(flags & UNSOLVABLE)); BOOST_CHECK(GetKeyOriginData(provider_inferred, flags) == GetKeyOriginData(script_provider, flags)); } diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp index 6d2d2e2bc5..a76901e473 100644 --- a/src/test/fuzz/key.cpp +++ b/src/test/fuzz/key.cpp @@ -138,8 +138,6 @@ FUZZ_TARGET_INIT(key, initialize_key) assert(tx_multisig_script.size() == 37); FillableSigningProvider fillable_signing_provider; - assert(IsSolvable(fillable_signing_provider, tx_pubkey_script)); - assert(IsSolvable(fillable_signing_provider, tx_multisig_script)); assert(!IsSegWitOutput(fillable_signing_provider, tx_pubkey_script)); assert(!IsSegWitOutput(fillable_signing_provider, tx_multisig_script)); assert(fillable_signing_provider.GetKeys().size() == 0); diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index 69a4b782aa..00d7b7e29a 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -89,7 +89,6 @@ FUZZ_TARGET_INIT(script, initialize_script) const FlatSigningProvider signing_provider; (void)InferDescriptor(script, signing_provider); (void)IsSegWitOutput(signing_provider, script); - (void)IsSolvable(signing_provider, script); (void)RecursiveDynamicUsage(script); diff --git a/src/test/rbf_tests.cpp b/src/test/rbf_tests.cpp index e597081afd..c88cd36688 100644 --- a/src/test/rbf_tests.cpp +++ b/src/test/rbf_tests.cpp @@ -76,7 +76,7 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup) // Create a parent tx5 and child tx6 where both have very low fees const auto tx5 = make_tx(/*inputs=*/ {m_coinbase_txns[2]}, /*output_values=*/ {1099 * CENT}); pool.addUnchecked(entry.Fee(low_fee).FromTx(tx5)); - const auto tx6 = make_tx(/*inputs=*/ {tx3}, /*output_values=*/ {1098 * CENT}); + const auto tx6 = make_tx(/*inputs=*/ {tx5}, /*output_values=*/ {1098 * CENT}); pool.addUnchecked(entry.Fee(low_fee).FromTx(tx6)); // Make tx6's modified fee much higher than its base fee. This should cause it to pass // the fee-related checks despite being low-feerate. 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/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp index 148343a8b0..903a569cb9 100644 --- a/src/wallet/rpc/addresses.cpp +++ b/src/wallet/rpc/addresses.cpp @@ -578,7 +578,7 @@ RPCHelpMan getaddressinfo() if (provider) { auto inferred = InferDescriptor(scriptPubKey, *provider); - bool solvable = inferred->IsSolvable() || IsSolvable(*provider, scriptPubKey); + bool solvable = inferred->IsSolvable(); ret.pushKV("solvable", solvable); if (solvable) { ret.pushKV("desc", inferred->ToString()); diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 9d88b4632e..7ff017775e 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1080,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 @@ -1097,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 { @@ -1109,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); @@ -1117,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); @@ -1449,7 +1456,8 @@ void LegacyScriptPubKeyMan::LearnRelatedScripts(const CPubKey& key, OutputType t CTxDestination witdest = WitnessV0KeyHash(key.GetID()); CScript witprog = GetScriptForDestination(witdest); // Make sure the resulting program is solvable. - assert(IsSolvable(*this, witprog)); + const auto desc = InferDescriptor(witprog, *this); + assert(desc && desc->IsSolvable()); AddCScript(witprog); } } 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(); |