aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bench/rollingbloom.cpp9
-rw-r--r--src/bloom.cpp5
-rw-r--r--src/init.cpp1
-rw-r--r--src/net_processing.cpp21
-rw-r--r--src/qt/bitcoingui.cpp15
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/qt/walletmodel.h11
-rw-r--r--src/random.cpp58
-rw-r--r--src/random.h2
-rw-r--r--src/rpc/misc.cpp2
-rw-r--r--src/test/versionbits_tests.cpp30
-rw-r--r--src/txdb.cpp1
-rw-r--r--src/validation.cpp2
-rw-r--r--src/wallet/rpcdump.cpp20
-rw-r--r--src/wallet/rpcwallet.cpp3
15 files changed, 135 insertions, 47 deletions
diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp
index 0a99ea3184..4016530dac 100644
--- a/src/bench/rollingbloom.cpp
+++ b/src/bench/rollingbloom.cpp
@@ -28,4 +28,13 @@ static void RollingBloom(benchmark::State& state)
}
}
+static void RollingBloomReset(benchmark::State& state)
+{
+ CRollingBloomFilter filter(120000, 0.000001);
+ while (state.KeepRunning()) {
+ filter.reset();
+ }
+}
+
BENCHMARK(RollingBloom, 1500 * 1000);
+BENCHMARK(RollingBloomReset, 20000);
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 7732cee275..a061925089 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -14,6 +14,7 @@
#include <math.h>
#include <stdlib.h>
+#include <algorithm>
#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
#define LN2 0.6931471805599453094172321214581765680755001343602552
@@ -304,7 +305,5 @@ void CRollingBloomFilter::reset()
nTweak = GetRand(std::numeric_limits<unsigned int>::max());
nEntriesThisGeneration = 0;
nGeneration = 1;
- for (std::vector<uint64_t>::iterator it = data.begin(); it != data.end(); it++) {
- *it = 0;
- }
+ std::fill(data.begin(), data.end(), 0);
}
diff --git a/src/init.cpp b/src/init.cpp
index 944200e24d..b4b4ccb654 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1522,6 +1522,7 @@ bool AppInitMain(InitInterfaces& interfaces)
// Note that it also sets fReindex based on the disk flag!
// From here on out fReindex and fReset mean something different!
if (!LoadBlockIndex(chainparams)) {
+ if (ShutdownRequested()) break;
strLoadError = _("Error loading block database");
break;
}
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index cb2b9f8c03..a3b865a69e 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -3288,23 +3288,22 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
if (m_enable_bip61) {
connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message")));
}
- if (strstr(e.what(), "end of data"))
- {
+ if (strstr(e.what(), "end of data")) {
// Allow exceptions from under-length message on vRecv
LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
- }
- else if (strstr(e.what(), "size too large"))
- {
+ } else if (strstr(e.what(), "size too large")) {
// Allow exceptions from over-long size
LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
- }
- else if (strstr(e.what(), "non-canonical ReadCompactSize()"))
- {
+ } else if (strstr(e.what(), "non-canonical ReadCompactSize()")) {
// Allow exceptions from non-canonical encoding
LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
- }
- else
- {
+ } else if (strstr(e.what(), "Superfluous witness record")) {
+ // Allow exceptions from illegal witness encoding
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
+ } else if (strstr(e.what(), "Unknown transaction optional data")) {
+ // Allow exceptions from unknown witness encoding
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
+ } else {
PrintExceptionContinue(&e, "ProcessMessages()");
}
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index abf9136eee..ff66df376b 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -370,9 +370,18 @@ void BitcoinGUI::createActions()
connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked);
connect(m_open_wallet_action->menu(), &QMenu::aboutToShow, [this] {
m_open_wallet_action->menu()->clear();
- for (std::string path : m_wallet_controller->getWalletsAvailableToOpen()) {
+ std::vector<std::string> available_wallets = m_wallet_controller->getWalletsAvailableToOpen();
+ std::vector<std::string> wallets = m_node.listWalletDir();
+ for (const auto& path : wallets) {
QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path);
QAction* action = m_open_wallet_action->menu()->addAction(name);
+
+ if (std::find(available_wallets.begin(), available_wallets.end(), path) == available_wallets.end()) {
+ // This wallet is already loaded
+ action->setEnabled(false);
+ continue;
+ }
+
connect(action, &QAction::triggered, [this, name, path] {
OpenWalletActivity* activity = m_wallet_controller->openWallet(path);
@@ -400,6 +409,10 @@ void BitcoinGUI::createActions()
assert(invoked);
});
}
+ if (wallets.empty()) {
+ QAction* action = m_open_wallet_action->menu()->addAction(tr("No wallets available"));
+ action->setEnabled(false);
+ }
});
connect(m_close_wallet_action, &QAction::triggered, [this] {
m_wallet_controller->closeWallet(walletFrame->currentWalletModel(), this);
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index fd392b7cf7..a2b295df21 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -482,7 +482,7 @@ WalletModel::UnlockContext::~UnlockContext()
}
}
-void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
+void WalletModel::UnlockContext::CopyFrom(UnlockContext&& rhs)
{
// Transfer context; old object no longer relocks wallet
*this = rhs;
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index b123befbb4..54428aec08 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -194,15 +194,18 @@ public:
bool isValid() const { return valid; }
- // Copy operator and constructor transfer the context
- UnlockContext(const UnlockContext& obj) { CopyFrom(obj); }
- UnlockContext& operator=(const UnlockContext& rhs) { CopyFrom(rhs); return *this; }
+ // Copy constructor is disabled.
+ UnlockContext(const UnlockContext&) = delete;
+ // Move operator and constructor transfer the context
+ UnlockContext(UnlockContext&& obj) { CopyFrom(std::move(obj)); }
+ UnlockContext& operator=(UnlockContext&& rhs) { CopyFrom(std::move(rhs)); return *this; }
private:
WalletModel *wallet;
bool valid;
mutable bool relock; // mutable, as it can be set to false by copying
- void CopyFrom(const UnlockContext& rhs);
+ UnlockContext& operator=(const UnlockContext&) = default;
+ void CopyFrom(UnlockContext&& rhs);
};
UnlockContext requestUnlock();
diff --git a/src/random.cpp b/src/random.cpp
index b08de60fbe..de26e6de1a 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -237,6 +237,34 @@ static void SeedHardwareSlow(CSHA512& hasher) noexcept {
#endif
}
+/** Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher. */
+static void Strengthen(const unsigned char (&seed)[32], int microseconds, CSHA512& hasher) noexcept
+{
+ CSHA512 inner_hasher;
+ inner_hasher.Write(seed, sizeof(seed));
+
+ // Hash loop
+ unsigned char buffer[64];
+ int64_t stop = GetTimeMicros() + microseconds;
+ do {
+ for (int i = 0; i < 1000; ++i) {
+ inner_hasher.Finalize(buffer);
+ inner_hasher.Reset();
+ inner_hasher.Write(buffer, sizeof(buffer));
+ }
+ // Benchmark operation and feed it into outer hasher.
+ int64_t perf = GetPerformanceCounter();
+ hasher.Write((const unsigned char*)&perf, sizeof(perf));
+ } while (GetTimeMicros() < stop);
+
+ // Produce output from inner state and feed it to outer hasher.
+ inner_hasher.Finalize(buffer);
+ hasher.Write(buffer, sizeof(buffer));
+ // Try to clean up.
+ inner_hasher.Reset();
+ memory_cleanse(buffer, sizeof(buffer));
+}
+
static void RandAddSeedPerfmon(CSHA512& hasher)
{
#ifdef WIN32
@@ -529,7 +557,23 @@ static void SeedSlow(CSHA512& hasher) noexcept
SeedTimestamp(hasher);
}
-static void SeedSleep(CSHA512& hasher)
+/** Extract entropy from rng, strengthen it, and feed it into hasher. */
+static void SeedStrengthen(CSHA512& hasher, RNGState& rng) noexcept
+{
+ static std::atomic<int64_t> last_strengthen{0};
+ int64_t last_time = last_strengthen.load();
+ int64_t current_time = GetTimeMicros();
+ if (current_time > last_time + 60000000) { // Only run once a minute
+ // Generate 32 bytes of entropy from the RNG, and a copy of the entropy already in hasher.
+ unsigned char strengthen_seed[32];
+ rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), CSHA512(hasher), false);
+ // Strengthen it for 10ms (100ms on first run), and feed it into hasher.
+ Strengthen(strengthen_seed, last_time == 0 ? 100000 : 10000, hasher);
+ last_strengthen = current_time;
+ }
+}
+
+static void SeedSleep(CSHA512& hasher, RNGState& rng)
{
// Everything that the 'fast' seeder includes
SeedFast(hasher);
@@ -545,9 +589,12 @@ static void SeedSleep(CSHA512& hasher)
// Windows performance monitor data (once every 10 minutes)
RandAddSeedPerfmon(hasher);
+
+ // Strengthen every minute
+ SeedStrengthen(hasher, rng);
}
-static void SeedStartup(CSHA512& hasher) noexcept
+static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept
{
#ifdef WIN32
RAND_screen();
@@ -561,6 +608,9 @@ static void SeedStartup(CSHA512& hasher) noexcept
// Windows performance monitor data.
RandAddSeedPerfmon(hasher);
+
+ // Strengthen
+ SeedStrengthen(hasher, rng);
}
enum class RNGLevel {
@@ -585,7 +635,7 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level)
SeedSlow(hasher);
break;
case RNGLevel::SLEEP:
- SeedSleep(hasher);
+ SeedSleep(hasher, rng);
break;
}
@@ -593,7 +643,7 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level)
if (!rng.MixExtract(out, num, std::move(hasher), false)) {
// On the first invocation, also seed with SeedStartup().
CSHA512 startup_hasher;
- SeedStartup(startup_hasher);
+ SeedStartup(startup_hasher, rng);
rng.MixExtract(out, num, std::move(startup_hasher), true);
}
diff --git a/src/random.h b/src/random.h
index 2f9c0f5a36..75d037738d 100644
--- a/src/random.h
+++ b/src/random.h
@@ -43,6 +43,7 @@
* - RandAddSeedSleep() seeds everything that fast seeding includes, but additionally:
* - A high-precision timestamp before and after sleeping 1ms.
* - (On Windows) Once every 10 minutes, performance monitoring data from the OS.
+ - - Once every minute, strengthen the entropy for 10 ms using repeated SHA512.
* These just exploit the fact the system is idle to improve the quality of the RNG
* slightly.
*
@@ -51,6 +52,7 @@
* - 256 bits from the hardware RNG (rdseed or rdrand) when available.
* - (On Windows) Performance monitoring data from the OS.
* - (On Windows) Through OpenSSL, the screen contents.
+ * - Strengthen the entropy for 100 ms using repeated SHA512.
*
* When mixing in new entropy, H = SHA512(entropy || old_rng_state) is computed, and
* (up to) the first 32 bytes of H are produced as output, while the last 32 bytes
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 7008a83143..72a2919712 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -204,7 +204,7 @@ UniValue deriveaddresses(const JSONRPCRequest& request)
},
RPCExamples{
"First three native segwit receive addresses\n" +
- HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#trd0mf0l\" \"[0,2]\"")
+ HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu\" \"[0,2]\"")
}}.ToString()
);
}
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index 38d91b6647..0ca3a17974 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -271,12 +271,12 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// Before MedianTimePast of the chain has crossed nStartTime, the bit
// should not be set.
CBlockIndex *lastBlock = nullptr;
- lastBlock = firstChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = firstChain.Mine(mainnetParams.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
- // Mine 2011 more blocks at the old time, and check that CBV isn't setting the bit yet.
- for (int i=1; i<2012; i++) {
- lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ // Mine more blocks (4 less than the adjustment period) at the old time, and check that CBV isn't setting the bit yet.
+ for (uint32_t i = 1; i < mainnetParams.nMinerConfirmationWindow - 4; i++) {
+ lastBlock = firstChain.Mine(mainnetParams.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
// This works because VERSIONBITS_LAST_OLD_BLOCK_VERSION happens
// to be 4, and the bit we're testing happens to be bit 28.
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
@@ -284,13 +284,13 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// Now mine 5 more blocks at the start time -- MTP should not have passed yet, so
// CBV should still not yet set the bit.
nTime = nStartTime;
- for (int i=2012; i<=2016; i++) {
- lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ for (uint32_t i = mainnetParams.nMinerConfirmationWindow - 4; i <= mainnetParams.nMinerConfirmationWindow; i++) {
+ lastBlock = firstChain.Mine(mainnetParams.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
}
// Advance to the next period and transition to STARTED,
- lastBlock = firstChain.Mine(6048, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = firstChain.Mine(mainnetParams.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
// so ComputeBlockVersion should now set the bit,
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
// and should also be using the VERSIONBITS_TOP_BITS.
@@ -298,8 +298,8 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// Check that ComputeBlockVersion will set the bit until nTimeout
nTime += 600;
- int blocksToMine = 4032; // test blocks for up to 2 time periods
- int nHeight = 6048;
+ uint32_t blocksToMine = mainnetParams.nMinerConfirmationWindow * 2; // test blocks for up to 2 time periods
+ uint32_t nHeight = mainnetParams.nMinerConfirmationWindow * 3;
// These blocks are all before nTimeout is reached.
while (nTime < nTimeout && blocksToMine > 0) {
lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
@@ -313,7 +313,7 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
nTime = nTimeout;
// FAILED is only triggered at the end of a period, so CBV should be setting
// the bit until the period transition.
- for (int i=0; i<2015; i++) {
+ for (uint32_t i = 0; i < mainnetParams.nMinerConfirmationWindow - 1; i++) {
lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
nHeight += 1;
@@ -329,20 +329,20 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// Mine one period worth of blocks, and check that the bit will be on for the
// next period.
- lastBlock = secondChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine(mainnetParams.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
// Mine another period worth of blocks, signaling the new bit.
- lastBlock = secondChain.Mine(4032, nTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();
+ lastBlock = secondChain.Mine(mainnetParams.nMinerConfirmationWindow * 2, nTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();
// After one period of setting the bit on each block, it should have locked in.
// We keep setting the bit for one more period though, until activation.
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
// Now check that we keep mining the block until the end of this period, and
// then stop at the beginning of the next period.
- lastBlock = secondChain.Mine(6047, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
- BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
- lastBlock = secondChain.Mine(6048, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine((mainnetParams.nMinerConfirmationWindow * 3) - 1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1 << bit)) != 0);
+ lastBlock = secondChain.Mine(mainnetParams.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
// Finally, verify that after a soft fork has activated, CBV no longer uses
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 8447352c54..494b87ad48 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -255,6 +255,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
// Load mapBlockIndex
while (pcursor->Valid()) {
boost::this_thread::interruption_point();
+ if (ShutdownRequested()) return false;
std::pair<char, uint256> key;
if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
CDiskBlockIndex diskindex;
diff --git a/src/validation.cpp b/src/validation.cpp
index b2d84f4c95..436c62261b 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -3861,6 +3861,7 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
sort(vSortedByHeight.begin(), vSortedByHeight.end());
for (const std::pair<int, CBlockIndex*>& item : vSortedByHeight)
{
+ if (ShutdownRequested()) return false;
CBlockIndex* pindex = item.second;
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
@@ -4306,6 +4307,7 @@ bool RewindBlockIndex(const CChainParams& params) {
return false;
}
+ LOCK(cs_main);
if (::ChainActive().Tip() != nullptr) {
// FlushStateToDisk can possibly read ::ChainActive(). Be conservative
// and skip it here, we're about to -reindex-chainstate anyway, so
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 3861b5524f..d428fac728 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -116,7 +116,8 @@ UniValue importprivkey(const JSONRPCRequest& request)
"\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n"
"Hint: use importmulti to import more than one private key.\n"
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
- "may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n",
+ "may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key (see dumpprivkey)"},
{"label", RPCArg::Type::STR, /* default */ "current label if address exists, otherwise \"\"", "An optional label"},
@@ -220,7 +221,8 @@ UniValue abortrescan(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 0)
throw std::runtime_error(
RPCHelpMan{"abortrescan",
- "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n",
+ "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{},
RPCResults{},
RPCExamples{
@@ -289,8 +291,10 @@ UniValue importaddress(const JSONRPCRequest& request)
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
"may report that the imported address exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
"If you have the full public key, you should call importpubkey instead of this.\n"
+ "Hint: use importmulti to import more than one address.\n"
"\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
- "as change, and not show up in many RPCs.\n",
+ "as change, and not show up in many RPCs.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Bitcoin address (or hex-encoded script)"},
{"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"},
@@ -486,8 +490,10 @@ UniValue importpubkey(const JSONRPCRequest& request)
throw std::runtime_error(
RPCHelpMan{"importpubkey",
"\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
+ "Hint: use importmulti to import more than one public key.\n"
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
- "may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n",
+ "may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"pubkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The hex-encoded public key"},
{"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"},
@@ -568,7 +574,8 @@ UniValue importwallet(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
RPCHelpMan{"importwallet",
- "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n",
+ "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet file"},
},
@@ -1359,7 +1366,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
"If an address/script is imported without all of the private keys required to spend from that address, it will be watchonly. The 'watchonly' option must be set to true in this case or a warning will be returned.\n"
"Conversely, if all the private keys are provided and the address/script is spendable, the watchonly option must be set to false, or a warning will be returned.\n"
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
- "may report that the imported keys, addresses or scripts exists but related transactions are still missing.\n",
+ "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"requests", RPCArg::Type::ARR, RPCArg::Optional::NO, "Data to be imported",
{
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 96a74a338a..71d62a47dc 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3452,7 +3452,8 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 2) {
throw std::runtime_error(
RPCHelpMan{"rescanblockchain",
- "\nRescan the local blockchain for wallet related transactions.\n",
+ "\nRescan the local blockchain for wallet related transactions.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"start_height", RPCArg::Type::NUM, /* default */ "0", "block height where the rescan should start"},
{"stop_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "the last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call."},