aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/qt/bitcoin.cpp16
-rw-r--r--src/qt/bitcoingui.h5
-rw-r--r--src/random.cpp4
-rw-r--r--src/script/descriptor.cpp18
-rw-r--r--src/test/bloom_tests.cpp18
-rw-r--r--src/test/random_tests.cpp10
-rw-r--r--src/test/test_bitcoin.h5
-rw-r--r--src/validationinterface.cpp4
-rw-r--r--src/wallet/db.cpp1
9 files changed, 57 insertions, 24 deletions
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 2e13bef19e..70c274d20e 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -107,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/db.cpp b/src/wallet/db.cpp
index ae40553268..cfa9bdd20e 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -147,6 +147,7 @@ BerkeleyEnvironment::BerkeleyEnvironment(const fs::path& dir_path) : strPath(dir
BerkeleyEnvironment::~BerkeleyEnvironment()
{
+ LOCK(cs_db);
g_dbenvs.erase(strPath);
Close();
}