diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/interfaces/wallet.cpp | 4 | ||||
-rw-r--r-- | src/key.cpp | 2 | ||||
-rw-r--r-- | src/qt/bitcoin.cpp | 16 | ||||
-rw-r--r-- | src/qt/bitcoingui.h | 5 | ||||
-rw-r--r-- | src/random.cpp | 4 | ||||
-rw-r--r-- | src/script/descriptor.cpp | 18 | ||||
-rw-r--r-- | src/test/bloom_tests.cpp | 18 | ||||
-rw-r--r-- | src/test/random_tests.cpp | 10 | ||||
-rw-r--r-- | src/test/test_bitcoin.h | 5 | ||||
-rw-r--r-- | src/validationinterface.cpp | 10 | ||||
-rw-r--r-- | src/wallet/rpcdump.cpp | 104 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 4 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 9 |
13 files changed, 143 insertions, 66 deletions
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 62ede0a95a..a2cae2a7a7 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -353,7 +353,7 @@ public: LOCK(m_wallet.cs_wallet); auto mi = m_wallet.mapWallet.find(txid); if (mi != m_wallet.mapWallet.end()) { - num_blocks = locked_chain->getHeight().value_or(-1); + num_blocks = locked_chain->getHeight().get_value_or(-1); in_mempool = mi->second.InMempool(); order_form = mi->second.vOrderForm; tx_status = MakeWalletTxStatus(*locked_chain, mi->second); @@ -384,7 +384,7 @@ public: return false; } balances = getBalances(); - num_blocks = locked_chain->getHeight().value_or(-1); + num_blocks = locked_chain->getHeight().get_value_or(-1); return true; } CAmount getBalance() override { return m_wallet.GetBalance(); } diff --git a/src/key.cpp b/src/key.cpp index 80d6589a3c..9d982fc44f 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -246,7 +246,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) secp256k1_ecdsa_recoverable_signature sig; int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, nullptr); assert(ret); - secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, &vchSig[1], &rec, &sig); + ret = secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, &vchSig[1], &rec, &sig); assert(ret); assert(rec != -1); vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index ca26131b95..85d79ee26c 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -218,6 +218,8 @@ BitcoinApplication::~BitcoinApplication() #ifdef ENABLE_WALLET delete paymentServer; paymentServer = nullptr; + delete m_wallet_controller; + m_wallet_controller = nullptr; #endif delete optionsModel; optionsModel = nullptr; @@ -307,18 +309,20 @@ void BitcoinApplication::requestShutdown() qDebug() << __func__ << ": Requesting shutdown"; startThread(); window->hide(); + // Must disconnect node signals otherwise current thread can deadlock since + // no event loop is running. + window->unsubscribeFromCoreSignals(); + // Request node shutdown, which can interrupt long operations, like + // rescanning a wallet. + m_node.startShutdown(); + // Unsetting the client model can cause the current thread to wait for node + // to complete an operation, like wait for a RPC execution to complate. window->setClientModel(nullptr); pollShutdownTimer->stop(); -#ifdef ENABLE_WALLET - delete m_wallet_controller; - m_wallet_controller = nullptr; -#endif delete clientModel; clientModel = nullptr; - m_node.startShutdown(); - // Request shutdown from core thread Q_EMIT requestedShutdown(); } diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index f1b76a6b64..c31cefe603 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -95,6 +95,9 @@ public: */ bool hasTrayIcon() const { return trayIcon; } + /** Disconnect core signals from GUI client */ + void unsubscribeFromCoreSignals(); + protected: void changeEvent(QEvent *e); void closeEvent(QCloseEvent *event); @@ -184,8 +187,6 @@ private: /** Connect core signals to GUI client */ void subscribeToCoreSignals(); - /** Disconnect core signals from GUI client */ - void unsubscribeFromCoreSignals(); /** Update UI with latest network info from model. */ void updateNetworkState(); diff --git a/src/random.cpp b/src/random.cpp index 3b7f7910b0..3277c34d3f 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -514,9 +514,11 @@ void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNG void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); } void RandAddSeedSleep() { ProcRand(nullptr, 0, RNGLevel::SLEEP); } +bool g_mock_deterministic_tests{false}; + uint64_t GetRand(uint64_t nMax) noexcept { - return FastRandomContext().randrange(nMax); + return FastRandomContext(g_mock_deterministic_tests).randrange(nMax); } int GetRandInt(int nMax) noexcept diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index a702be5b78..41e0f2e117 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -226,7 +226,7 @@ protected: * @param pubkeys The evaluations of the m_pubkey_args field. * @param script The evaluation of m_script_arg (or nullptr when m_script_arg is nullptr). * @param out A FlatSigningProvider to put scripts or public keys in that are necessary to the solver. - * The script and pubkeys argument to this function are automatically added. + * The script arguments to this function are automatically added, as is the origin info of the provided pubkeys. * @return A vector with scriptPubKeys for this descriptor. */ virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, const CScript* script, FlatSigningProvider& out) const = 0; @@ -322,7 +322,6 @@ public: for (auto& entry : entries) { pubkeys.push_back(entry.first); out.origins.emplace(entry.first.GetID(), std::move(entry.second)); - out.pubkeys.emplace(entry.first.GetID(), entry.first); } if (m_script_arg) { for (const auto& subscript : subscripts) { @@ -396,7 +395,12 @@ public: class PKHDescriptor final : public DescriptorImpl { protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(keys[0].GetID())); } + std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override + { + CKeyID id = keys[0].GetID(); + out.pubkeys.emplace(id, keys[0]); + return Singleton(GetScriptForDestination(id)); + } public: PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {} }; @@ -405,7 +409,12 @@ public: class WPKHDescriptor final : public DescriptorImpl { protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(WitnessV0KeyHash(keys[0].GetID()))); } + std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override + { + CKeyID id = keys[0].GetID(); + out.pubkeys.emplace(id, keys[0]); + return Singleton(GetScriptForDestination(WitnessV0KeyHash(id))); + } public: WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "wpkh") {} }; @@ -418,6 +427,7 @@ protected: { std::vector<CScript> ret; CKeyID id = keys[0].GetID(); + out.pubkeys.emplace(id, keys[0]); ret.emplace_back(GetScriptForRawPubKey(keys[0])); // P2PK ret.emplace_back(GetScriptForDestination(id)); // P2PKH if (keys[0].IsCompressed()) { diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index c900bee199..f58dd20efc 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -461,6 +461,9 @@ static std::vector<unsigned char> RandomData() BOOST_AUTO_TEST_CASE(rolling_bloom) { + SeedInsecureRand(/* deterministic */ true); + g_mock_deterministic_tests = true; + // last-100-entry, 1% false positive: CRollingBloomFilter rb1(100, 0.01); @@ -485,12 +488,8 @@ BOOST_AUTO_TEST_CASE(rolling_bloom) if (rb1.contains(RandomData())) ++nHits; } - // Run test_bitcoin with --log_level=message to see BOOST_TEST_MESSAGEs: - BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~100 expected)"); - - // Insanely unlikely to get a fp count outside this range: - BOOST_CHECK(nHits > 25); - BOOST_CHECK(nHits < 175); + // Expect about 100 hits + BOOST_CHECK_EQUAL(nHits, 75); BOOST_CHECK(rb1.contains(data[DATASIZE-1])); rb1.reset(); @@ -517,10 +516,8 @@ BOOST_AUTO_TEST_CASE(rolling_bloom) if (rb1.contains(data[i])) ++nHits; } - // Expect about 5 false positives, more than 100 means - // something is definitely broken. - BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~5 expected)"); - BOOST_CHECK(nHits < 100); + // Expect about 5 false positives + BOOST_CHECK_EQUAL(nHits, 6); // last-1000-entry, 0.01% false positive: CRollingBloomFilter rb2(1000, 0.001); @@ -531,6 +528,7 @@ BOOST_AUTO_TEST_CASE(rolling_bloom) for (int i = 0; i < DATASIZE; i++) { BOOST_CHECK(rb2.contains(data[i])); } + g_mock_deterministic_tests = false; } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp index 1057d09471..8194070aba 100644 --- a/src/test/random_tests.cpp +++ b/src/test/random_tests.cpp @@ -21,9 +21,14 @@ BOOST_AUTO_TEST_CASE(osrandom_tests) BOOST_AUTO_TEST_CASE(fastrandom_tests) { // Check that deterministic FastRandomContexts are deterministic + g_mock_deterministic_tests = true; FastRandomContext ctx1(true); FastRandomContext ctx2(true); + for (int i = 10; i > 0; --i) { + BOOST_CHECK_EQUAL(GetRand(std::numeric_limits<uint64_t>::max()), uint64_t{10393729187455219830U}); + BOOST_CHECK_EQUAL(GetRandInt(std::numeric_limits<int>::max()), int{769702006}); + } BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64()); @@ -38,6 +43,11 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests) BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50)); // Check that a nondeterministic ones are not + g_mock_deterministic_tests = false; + for (int i = 10; i > 0; --i) { + BOOST_CHECK(GetRand(std::numeric_limits<uint64_t>::max()) != uint64_t{10393729187455219830U}); + BOOST_CHECK(GetRandInt(std::numeric_limits<int>::max()) != int{769702006}); + } { FastRandomContext ctx3, ctx4; BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 71520232ac..4a06845683 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -35,6 +35,11 @@ std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::os */ extern FastRandomContext g_insecure_rand_ctx; +/** + * Flag to make GetRand in random.h return the same number + */ +extern bool g_mock_deterministic_tests; + static inline void SeedInsecureRand(bool deterministic = false) { g_insecure_rand_ctx = FastRandomContext(deterministic); diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 533d412888..70c274d20e 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -14,6 +14,7 @@ #include <list> #include <atomic> #include <future> +#include <utility> #include <boost/signals2/signal.hpp> @@ -77,7 +78,10 @@ size_t CMainSignals::CallbacksPending() { } void CMainSignals::RegisterWithMempoolSignals(CTxMemPool& pool) { - g_connNotifyEntryRemoved.emplace(&pool, pool.NotifyEntryRemoved.connect(std::bind(&CMainSignals::MempoolEntryRemoved, this, std::placeholders::_1, std::placeholders::_2))); + g_connNotifyEntryRemoved.emplace(std::piecewise_construct, + std::forward_as_tuple(&pool), + std::forward_as_tuple(pool.NotifyEntryRemoved.connect(std::bind(&CMainSignals::MempoolEntryRemoved, this, std::placeholders::_1, std::placeholders::_2))) + ); } void CMainSignals::UnregisterWithMempoolSignals(CTxMemPool& pool) { @@ -103,7 +107,9 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { - g_signals.m_internals->m_connMainSignals.erase(pwalletIn); + if (g_signals.m_internals) { + g_signals.m_internals->m_connMainSignals.erase(pwalletIn); + } } void UnregisterAllValidationInterfaces() { diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 2e62a6979f..32c36ceaeb 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -134,6 +134,9 @@ UniValue importprivkey(const JSONRPCRequest& request) }, }.ToString()); + if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled"); + } WalletRescanReserver reserver(pwallet); bool fRescan = true; @@ -587,8 +590,10 @@ UniValue importwallet(const JSONRPCRequest& request) // Use uiInterface.ShowProgress instead of pwallet.ShowProgress because pwallet.ShowProgress has a cancel button tied to AbortRescan which // we don't want for this progress bar showing the import progress. uiInterface.ShowProgress does not have a cancel button. uiInterface.ShowProgress(strprintf("%s " + _("Importing..."), pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI + std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys; + std::vector<std::pair<CScript, int64_t>> scripts; while (file.good()) { - uiInterface.ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false); + uiInterface.ShowProgress("", std::max(1, std::min(50, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false); std::string line; std::getline(file, line); if (line.empty() || line[0] == '#') @@ -600,13 +605,6 @@ UniValue importwallet(const JSONRPCRequest& request) continue; CKey key = DecodeSecret(vstr[0]); if (key.IsValid()) { - CPubKey pubkey = key.GetPubKey(); - assert(key.VerifyPubKey(pubkey)); - CKeyID keyid = pubkey.GetID(); - if (pwallet->HaveKey(keyid)) { - pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid)); - continue; - } int64_t nTime = DecodeDumpTime(vstr[1]); std::string strLabel; bool fLabel = true; @@ -622,36 +620,67 @@ UniValue importwallet(const JSONRPCRequest& request) fLabel = true; } } - pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(keyid)); - if (!pwallet->AddKeyPubKey(key, pubkey)) { - fGood = false; - continue; - } - pwallet->mapKeyMetadata[keyid].nCreateTime = nTime; - if (fLabel) - pwallet->SetAddressBook(keyid, strLabel, "receive"); - nTimeBegin = std::min(nTimeBegin, nTime); + keys.push_back(std::make_tuple(key, nTime, fLabel, strLabel)); } else if(IsHex(vstr[0])) { - std::vector<unsigned char> vData(ParseHex(vstr[0])); - CScript script = CScript(vData.begin(), vData.end()); - CScriptID id(script); - if (pwallet->HaveCScript(id)) { - pwallet->WalletLogPrintf("Skipping import of %s (script already present)\n", vstr[0]); - continue; - } - if(!pwallet->AddCScript(script)) { - pwallet->WalletLogPrintf("Error importing script %s\n", vstr[0]); - fGood = false; - continue; - } - int64_t birth_time = DecodeDumpTime(vstr[1]); - if (birth_time > 0) { - pwallet->m_script_metadata[id].nCreateTime = birth_time; - nTimeBegin = std::min(nTimeBegin, birth_time); - } + std::vector<unsigned char> vData(ParseHex(vstr[0])); + CScript script = CScript(vData.begin(), vData.end()); + int64_t birth_time = DecodeDumpTime(vstr[1]); + scripts.push_back(std::pair<CScript, int64_t>(script, birth_time)); } } file.close(); + // We now know whether we are importing private keys, so we can error if private keys are disabled + if (keys.size() > 0 && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI + throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when private keys are disabled"); + } + double total = (double)(keys.size() + scripts.size()); + double progress = 0; + for (const auto& key_tuple : keys) { + uiInterface.ShowProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false); + const CKey& key = std::get<0>(key_tuple); + int64_t time = std::get<1>(key_tuple); + bool has_label = std::get<2>(key_tuple); + std::string label = std::get<3>(key_tuple); + + CPubKey pubkey = key.GetPubKey(); + assert(key.VerifyPubKey(pubkey)); + CKeyID keyid = pubkey.GetID(); + if (pwallet->HaveKey(keyid)) { + pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid)); + continue; + } + pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(keyid)); + if (!pwallet->AddKeyPubKey(key, pubkey)) { + fGood = false; + continue; + } + pwallet->mapKeyMetadata[keyid].nCreateTime = time; + if (has_label) + pwallet->SetAddressBook(keyid, label, "receive"); + nTimeBegin = std::min(nTimeBegin, time); + progress++; + } + for (const auto& script_pair : scripts) { + uiInterface.ShowProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false); + const CScript& script = script_pair.first; + int64_t time = script_pair.second; + CScriptID id(script); + if (pwallet->HaveCScript(id)) { + pwallet->WalletLogPrintf("Skipping import of %s (script already present)\n", HexStr(script)); + continue; + } + if(!pwallet->AddCScript(script)) { + pwallet->WalletLogPrintf("Error importing script %s\n", HexStr(script)); + fGood = false; + continue; + } + if (time > 0) { + pwallet->m_script_metadata[id].nCreateTime = time; + nTimeBegin = std::min(nTimeBegin, time); + } + progress++; + } uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI pwallet->UpdateTimeFirstKey(nTimeBegin); } @@ -785,7 +814,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) file << strprintf("# Wallet dump created by Bitcoin %s\n", CLIENT_BUILD); file << strprintf("# * Created on %s\n", FormatISO8601DateTime(GetTime())); const Optional<int> tip_height = locked_chain->getHeight(); - file << strprintf("# * Best block at time of backup was %i (%s),\n", tip_height.value_or(-1), tip_height ? locked_chain->getBlockHash(*tip_height).ToString() : "(missing block hash)"); + file << strprintf("# * Best block at time of backup was %i (%s),\n", tip_height.get_value_or(-1), tip_height ? locked_chain->getBlockHash(*tip_height).ToString() : "(missing block hash)"); file << strprintf("# mined on %s\n", tip_height ? FormatISO8601DateTime(locked_chain->getBlockTime(*tip_height)) : "(missing block time)"); file << "\n"; @@ -958,6 +987,11 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con const bool watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false; const std::string& label = data.exists("label") ? data["label"].get_str() : ""; + // If private keys are disabled, abort if private keys are being imported + if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !keys.isNull()) { + throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled"); + } + // Generate the script and destination for the scriptPubKey provided CScript script; CTxDestination dest; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 213765209c..c96a9b0aff 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3872,6 +3872,10 @@ UniValue sethdseed(const JSONRPCRequest& request) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download"); } + if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed to a wallet with private keys disabled"); + } + auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5c379aacd6..9b643be69a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -251,6 +251,9 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey& secret, const C { AssertLockHeld(cs_wallet); // mapKeyMetadata + // Make sure we aren't adding private keys to private key disabled wallets + assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); + // CCryptoKeyStore has no concept of wallet databases, but calls AddCryptedKey // which is overridden below. To avoid flushes, the database handle is // tunneled through to it. @@ -1717,10 +1720,10 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc } ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI if (block_height && fAbortRescan) { - WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", block_height.value_or(0), progress_current); + WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", block_height.get_value_or(0), progress_current); result.status = ScanResult::USER_ABORT; } else if (block_height && ShutdownRequested()) { - WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height.value_or(0), progress_current); + WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height.get_value_or(0), progress_current); result.status = ScanResult::USER_ABORT; } } @@ -2581,7 +2584,7 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain) */ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_chain) { - uint32_t const height = locked_chain.getHeight().value_or(-1); + uint32_t const height = locked_chain.getHeight().get_value_or(-1); uint32_t locktime; // Discourage fee sniping. // |