diff options
Diffstat (limited to 'src')
59 files changed, 427 insertions, 155 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index ed5cab7f04..ec3d81b76f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -353,6 +353,8 @@ crypto_libbitcoin_crypto_base_a_SOURCES = \ crypto/chacha20.h \ crypto/chacha20.cpp \ crypto/common.h \ + crypto/hkdf_sha256_32.cpp \ + crypto/hkdf_sha256_32.h \ crypto/hmac_sha256.cpp \ crypto/hmac_sha256.h \ crypto/hmac_sha512.cpp \ 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/crypto/hkdf_sha256_32.cpp b/src/crypto/hkdf_sha256_32.cpp new file mode 100644 index 0000000000..9cea5995ec --- /dev/null +++ b/src/crypto/hkdf_sha256_32.cpp @@ -0,0 +1,21 @@ +// Copyright (c) 2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <crypto/hkdf_sha256_32.h> + +#include <assert.h> +#include <string.h> + +CHKDF_HMAC_SHA256_L32::CHKDF_HMAC_SHA256_L32(const unsigned char* ikm, size_t ikmlen, const std::string& salt) +{ + CHMAC_SHA256((const unsigned char*)salt.c_str(), salt.size()).Write(ikm, ikmlen).Finalize(m_prk); +} + +void CHKDF_HMAC_SHA256_L32::Expand32(const std::string& info, unsigned char hash[OUTPUT_SIZE]) +{ + // expand a 32byte key (single round) + assert(info.size() <= 128); + static const unsigned char one[1] = {1}; + CHMAC_SHA256(m_prk, 32).Write((const unsigned char*)info.data(), info.size()).Write(one, 1).Finalize(hash); +} diff --git a/src/crypto/hkdf_sha256_32.h b/src/crypto/hkdf_sha256_32.h new file mode 100644 index 0000000000..fa1e42aec1 --- /dev/null +++ b/src/crypto/hkdf_sha256_32.h @@ -0,0 +1,25 @@ +// Copyright (c) 2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CRYPTO_HKDF_SHA256_32_H +#define BITCOIN_CRYPTO_HKDF_SHA256_32_H + +#include <crypto/hmac_sha256.h> + +#include <stdint.h> +#include <stdlib.h> + +/** A rfc5869 HKDF implementation with HMAC_SHA256 and fixed key output length of 32 bytes (L=32) */ +class CHKDF_HMAC_SHA256_L32 +{ +private: + unsigned char m_prk[32]; + static const size_t OUTPUT_SIZE = 32; + +public: + CHKDF_HMAC_SHA256_L32(const unsigned char* ikm, size_t ikmlen, const std::string& salt); + void Expand32(const std::string& info, unsigned char hash[OUTPUT_SIZE]); +}; + +#endif // BITCOIN_CRYPTO_HKDF_SHA256_32_H diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp index a00331dcb7..edee06cc34 100644 --- a/src/crypto/ripemd160.cpp +++ b/src/crypto/ripemd160.cpp @@ -256,7 +256,7 @@ CRIPEMD160& CRIPEMD160::Write(const unsigned char* data, size_t len) ripemd160::Transform(s, buf); bufsize = 0; } - while (end >= data + 64) { + while (end - data >= 64) { // Process full chunks directly from the source. ripemd160::Transform(s, data); bytes += 64; diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp index 5c601c54a6..3dcdcb186e 100644 --- a/src/crypto/sha1.cpp +++ b/src/crypto/sha1.cpp @@ -163,7 +163,7 @@ CSHA1& CSHA1::Write(const unsigned char* data, size_t len) sha1::Transform(s, buf); bufsize = 0; } - while (end >= data + 64) { + while (end - data >= 64) { // Process full chunks directly from the source. sha1::Transform(s, data); bytes += 64; diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp index bc64135cae..4e6aa363f7 100644 --- a/src/crypto/sha512.cpp +++ b/src/crypto/sha512.cpp @@ -168,7 +168,7 @@ CSHA512& CSHA512::Write(const unsigned char* data, size_t len) sha512::Transform(s, buf); bufsize = 0; } - while (end >= data + 128) { + while (end - data >= 128) { // Process full chunks directly from the source. sha512::Transform(s, data); data += 128; diff --git a/src/init.cpp b/src/init.cpp index c5deb12bd4..b4b4ccb654 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -383,7 +383,7 @@ void SetupServerArgs() gArgs.AddArg("-blocksdir=<dir>", "Specify directory to hold blocks subdirectory for *.dat files (default: <datadir>)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-blocknotify=<cmd>", "Execute command when the best block changes (%s in cmd is replaced by block hash)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-blockreconstructionextratxn=<n>", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), false, OptionsCategory::OPTIONS); - gArgs.AddArg("-blocksonly", strprintf("Whether to operate in a blocks only mode (default: %u)", DEFAULT_BLOCKSONLY), true, OptionsCategory::OPTIONS); + gArgs.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Transactions from the wallet or RPC are not affected. (default: %u)", DEFAULT_BLOCKSONLY), false, OptionsCategory::OPTIONS); gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS); gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS); gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), true, OptionsCategory::OPTIONS); @@ -1426,7 +1426,7 @@ bool AppInitMain(InitInterfaces& interfaces) // see Step 2: parameter interactions for more information about these fListen = gArgs.GetBoolArg("-listen", DEFAULT_LISTEN); fDiscover = gArgs.GetBoolArg("-discover", true); - fRelayTxes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); + g_relay_txes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); for (const std::string& strAddr : gArgs.GetArgs("-externalip")) { CService addrLocal; @@ -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/interfaces/chain.cpp b/src/interfaces/chain.cpp index 59623284d2..6097d80931 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -37,7 +37,7 @@ namespace interfaces { namespace { -class LockImpl : public Chain::Lock +class LockImpl : public Chain::Lock, public UniqueLock<CCriticalSection> { Optional<int> getHeight() override { @@ -155,10 +155,7 @@ class LockImpl : public Chain::Lock return AcceptToMemoryPool(::mempool, state, tx, nullptr /* missing inputs */, nullptr /* txn replaced */, false /* bypass limits */, absurd_fee); } -}; -class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection> -{ using UniqueLock::UniqueLock; }; @@ -249,13 +246,12 @@ class ChainImpl : public Chain public: std::unique_ptr<Chain::Lock> lock(bool try_lock) override { - auto result = MakeUnique<LockingStateImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock); + auto result = MakeUnique<LockImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock); if (try_lock && result && !*result) return {}; // std::move necessary on some compilers due to conversion from - // LockingStateImpl to Lock pointer + // LockImpl to Lock pointer return std::move(result); } - std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); } bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override { CBlockIndex* index; @@ -332,7 +328,11 @@ public: CFeeRate relayMinFee() override { return ::minRelayTxFee; } CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; } CFeeRate relayDustFee() override { return ::dustRelayFee; } - bool getPruneMode() override { return ::fPruneMode; } + bool havePruned() override + { + LOCK(cs_main); + return ::fHavePruned; + } bool p2pEnabled() override { return g_connman != nullptr; } bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !IsInitialBlockDownload(); } bool isInitialBlockDownload() override { return IsInitialBlockDownload(); } diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 0b7249a5ab..e675defd47 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -138,11 +138,6 @@ public: //! unlocked when the returned interface is freed. virtual std::unique_ptr<Lock> lock(bool try_lock = false) = 0; - //! Return Lock interface assuming chain is already locked. This - //! method is temporary and is only used in a few places to avoid changing - //! behavior while code is transitioned to use the Chain::Lock interface. - virtual std::unique_ptr<Lock> assumeLocked() = 0; - //! Return whether node has the block and optionally return block metadata //! or contents. //! @@ -196,8 +191,8 @@ public: //! Relay dust fee setting (-dustrelayfee), reflecting lowest rate it's economical to spend. virtual CFeeRate relayDustFee() = 0; - //! Check if pruning is enabled. - virtual bool getPruneMode() = 0; + //! Check if any block has been pruned. + virtual bool havePruned() = 0; //! Check if p2p enabled. virtual bool p2pEnabled() = 0; diff --git a/src/key.cpp b/src/key.cpp index 9d982fc44f..c17f6a0ae2 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -163,6 +163,12 @@ void CKey::MakeNewKey(bool fCompressedIn) { fCompressed = fCompressedIn; } +bool CKey::Negate() +{ + assert(fValid); + return secp256k1_ec_privkey_negate(secp256k1_context_sign, keydata.data()); +} + CPrivKey CKey::GetPrivKey() const { assert(fValid); CPrivKey privkey; @@ -98,6 +98,9 @@ public: //! Generate a new private key using a cryptographic PRNG. void MakeNewKey(bool fCompressed); + //! Negate private key + bool Negate(); + /** * Convert the private key to a CPrivKey (serialized OpenSSL private key data). * This is expensive. diff --git a/src/net.cpp b/src/net.cpp index 1335804b06..3c6f5a05f3 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -79,7 +79,7 @@ static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // S // bool fDiscover = true; bool fListen = true; -bool fRelayTxes = true; +bool g_relay_txes = !DEFAULT_BLOCKSONLY; CCriticalSection cs_mapLocalHost; std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost); static bool vfLimited[NET_MAX] GUARDED_BY(cs_mapLocalHost) = {}; @@ -519,7 +519,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices) extern bool fDiscover; extern bool fListen; -extern bool fRelayTxes; +extern bool g_relay_txes; /** Subversion as sent to the P2P network in `version` messages */ extern std::string strSubVersion; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index b3facdcd3a..a3b865a69e 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -422,7 +422,7 @@ static void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime) CAddress addrMe = CAddress(CService(), nLocalNodeServices); connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, - nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes)); + nonce, strSubVersion, nNodeStartingHeight, ::g_relay_txes)); if (fLogIPs) { LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid); @@ -2189,7 +2189,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return false; } - bool fBlocksOnly = !fRelayTxes; + bool fBlocksOnly = !g_relay_txes; // Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true if (pfrom->fWhitelisted && gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) @@ -2445,7 +2445,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (strCommand == NetMsgType::TX) { // Stop processing the transaction early if // We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off - if (!fRelayTxes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))) + if (!g_relay_txes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))) { LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom->GetId()); return true; @@ -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/blockchain.cpp b/src/rpc/blockchain.cpp index b8ef758661..56018caf24 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -486,7 +486,10 @@ UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose) const uint256& hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); entryToJSON(pool, info, e); - o.pushKV(hash.ToString(), info); + // Mempool has unique entries so there is no advantage in using + // UniValue::pushKV, which checks if the key already exists in O(N). + // UniValue::__pushKV is used instead which currently is O(1). + o.__pushKV(hash.ToString(), info); } return o; } else { diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index e8cdce623c..e49c3e031f 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -496,7 +496,7 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) obj.pushKV("protocolversion",PROTOCOL_VERSION); if(g_connman) obj.pushKV("localservices", strprintf("%016x", g_connman->GetLocalServices())); - obj.pushKV("localrelay", fRelayTxes); + obj.pushKV("localrelay", g_relay_txes); obj.pushKV("timeoffset", GetTimeOffset()); if (g_connman) { obj.pushKV("networkactive", g_connman->GetNetworkActive()); diff --git a/src/sync.cpp b/src/sync.cpp index e7c0a6f9bc..c2767b200a 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + #include <sync.h> #include <tinyformat.h> diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 64458cd7d4..35911e507f 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -5,12 +5,13 @@ #include <crypto/aes.h> #include <crypto/chacha20.h> #include <crypto/poly1305.h> +#include <crypto/hkdf_sha256_32.h> +#include <crypto/hmac_sha256.h> +#include <crypto/hmac_sha512.h> #include <crypto/ripemd160.h> #include <crypto/sha1.h> #include <crypto/sha256.h> #include <crypto/sha512.h> -#include <crypto/hmac_sha256.h> -#include <crypto/hmac_sha512.h> #include <random.h> #include <util/strencodings.h> #include <test/setup_common.h> @@ -168,6 +169,22 @@ static void TestPoly1305(const std::string &hexmessage, const std::string &hexke BOOST_CHECK(tag == tagres); } +static void TestHKDF_SHA256_32(const std::string &ikm_hex, const std::string &salt_hex, const std::string &info_hex, const std::string &okm_check_hex) { + std::vector<unsigned char> initial_key_material = ParseHex(ikm_hex); + std::vector<unsigned char> salt = ParseHex(salt_hex); + std::vector<unsigned char> info = ParseHex(info_hex); + + + // our implementation only supports strings for the "info" and "salt", stringify them + std::string salt_stringified(reinterpret_cast<char*>(salt.data()), salt.size()); + std::string info_stringified(reinterpret_cast<char*>(info.data()), info.size()); + + CHKDF_HMAC_SHA256_L32 hkdf32(initial_key_material.data(), initial_key_material.size(), salt_stringified); + unsigned char out[32]; + hkdf32.Expand32(info_stringified, out); + BOOST_CHECK(HexStr(out, out + 32) == okm_check_hex); +} + static std::string LongTestString() { std::string ret; for (int i=0; i<200000; i++) { @@ -548,6 +565,26 @@ BOOST_AUTO_TEST_CASE(poly1305_testvector) "13000000000000000000000000000000"); } +BOOST_AUTO_TEST_CASE(hkdf_hmac_sha256_l32_tests) +{ + // Use rfc5869 test vectors but trucated to 32 bytes (our implementation only support length 32) + TestHKDF_SHA256_32( + /* IKM */ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + /* salt */ "000102030405060708090a0b0c", + /* info */ "f0f1f2f3f4f5f6f7f8f9", + /* expected OKM */ "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf"); + TestHKDF_SHA256_32( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f", + "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf", + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c"); + TestHKDF_SHA256_32( + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "", + "", + "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d"); +} + BOOST_AUTO_TEST_CASE(countbits_tests) { FastRandomContext ctx; diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index ceed73b14d..1b95105eab 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -188,4 +188,36 @@ BOOST_AUTO_TEST_CASE(key_signature_tests) BOOST_CHECK(found_small); } +BOOST_AUTO_TEST_CASE(key_key_negation) +{ + // create a dummy hash for signature comparison + unsigned char rnd[8]; + std::string str = "Bitcoin key verification\n"; + GetRandBytes(rnd, sizeof(rnd)); + uint256 hash; + CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize(hash.begin()); + + // import the static test key + CKey key = DecodeSecret(strSecret1C); + + // create a signature + std::vector<unsigned char> vch_sig; + std::vector<unsigned char> vch_sig_cmp; + key.Sign(hash, vch_sig); + + // negate the key twice + BOOST_CHECK(key.GetPubKey().data()[0] == 0x03); + key.Negate(); + // after the first negation, the signature must be different + key.Sign(hash, vch_sig_cmp); + BOOST_CHECK(vch_sig_cmp != vch_sig); + BOOST_CHECK(key.GetPubKey().data()[0] == 0x02); + key.Negate(); + // after the second negation, we should have the original key and thus the + // same signature + key.Sign(hash, vch_sig_cmp); + BOOST_CHECK(vch_sig_cmp == vch_sig); + BOOST_CHECK(key.GetPubKey().data()[0] == 0x03); +} + BOOST_AUTO_TEST_SUITE_END() 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/util/threadnames.cpp b/src/util/threadnames.cpp index 7b0d744aec..b221b0c975 100644 --- a/src/util/threadnames.cpp +++ b/src/util/threadnames.cpp @@ -9,6 +9,11 @@ #include <atomic> #include <thread> +#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) +#include <pthread.h> +#include <pthread_np.h> +#endif + #include <util/threadnames.h> #ifdef HAVE_SYS_PRCTL_H diff --git a/src/validation.cpp b/src/validation.cpp index dcd2350fd8..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); @@ -3951,20 +3952,10 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_RE bool LoadChainTip(const CChainParams& chainparams) { AssertLockHeld(cs_main); + assert(!pcoinsTip->GetBestBlock().IsNull()); // Never called when the coins view is empty if (::ChainActive().Tip() && ::ChainActive().Tip()->GetBlockHash() == pcoinsTip->GetBestBlock()) return true; - if (pcoinsTip->GetBestBlock().IsNull() && mapBlockIndex.size() == 1) { - // In case we just added the genesis block, connect it now, so - // that we always have a ::ChainActive().Tip() when we return. - LogPrintf("%s: Connecting genesis block...\n", __func__); - CValidationState state; - if (!ActivateBestChain(state, chainparams)) { - LogPrintf("%s: failed to activate chain (%s)\n", __func__, FormatStateMessage(state)); - return false; - } - } - // Load pointer to end of best chain CBlockIndex* pindex = LookupBlockIndex(pcoinsTip->GetBestBlock()); if (!pindex) { @@ -4316,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/coincontrol.h b/src/wallet/coincontrol.h index 9257b272bc..12ba032dff 100644 --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index a255177e36..dd56ea10ab 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index fb3bb12a7a..546e3d54eb 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/db.h b/src/wallet/db.h index 762fb83a2f..b3856fbaf9 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp index 78db4df5e5..15ddd5cb97 100644 --- a/src/wallet/feebumper.cpp +++ b/src/wallet/feebumper.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h index f9cbfc5f68..0c4e1cb7dd 100644 --- a/src/wallet/feebumper.h +++ b/src/wallet/feebumper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp index d9ae18ed60..59d05a771a 100644 --- a/src/wallet/fees.cpp +++ b/src/wallet/fees.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 47ef01bfd1..0b8afd5a5d 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index 79c5f439df..54aa12dba8 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/load.h b/src/wallet/load.h index 9bb6f2166e..81f078fd10 100644 --- a/src/wallet/load.h +++ b/src/wallet/load.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/psbtwallet.cpp b/src/wallet/psbtwallet.cpp index 1b17b09763..ce4788dee1 100644 --- a/src/wallet/psbtwallet.cpp +++ b/src/wallet/psbtwallet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 9b6f9dea95..d428fac728 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -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"}, @@ -158,8 +159,11 @@ UniValue importprivkey(const JSONRPCRequest& request) if (!request.params[2].isNull()) fRescan = request.params[2].get_bool(); - if (fRescan && pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode"); + if (fRescan && pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned"); } if (fRescan && !reserver.reserve()) { @@ -217,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{ @@ -286,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"}, @@ -315,8 +322,11 @@ UniValue importaddress(const JSONRPCRequest& request) if (!request.params[2].isNull()) fRescan = request.params[2].get_bool(); - if (fRescan && pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode"); + if (fRescan && pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned"); } WalletRescanReserver reserver(pwallet); @@ -480,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"}, @@ -508,8 +520,11 @@ UniValue importpubkey(const JSONRPCRequest& request) if (!request.params[2].isNull()) fRescan = request.params[2].get_bool(); - if (fRescan && pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode"); + if (fRescan && pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned"); } WalletRescanReserver reserver(pwallet); @@ -559,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"}, }, @@ -574,8 +590,11 @@ UniValue importwallet(const JSONRPCRequest& request) }, }.ToString()); - if (pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode"); + if (pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when blocks are pruned"); } WalletRescanReserver reserver(pwallet); @@ -1347,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 43e18a580d..71d62a47dc 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2641,26 +2641,29 @@ static UniValue loadwallet(const JSONRPCRequest& request) static UniValue createwallet(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) { - throw std::runtime_error( - RPCHelpMan{"createwallet", - "\nCreates and loads a new wallet.\n", - { - {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."}, - {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."}, - {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."}, - }, - RPCResult{ + const RPCHelpMan help{ + "createwallet", + "\nCreates and loads a new wallet.\n", + { + {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."}, + {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."}, + {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."}, + {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."}, + }, + RPCResult{ "{\n" " \"name\" : <wallet_name>, (string) The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path.\n" " \"warning\" : <warning>, (string) Warning message if wallet was not loaded cleanly.\n" "}\n" - }, - RPCExamples{ - HelpExampleCli("createwallet", "\"testwallet\"") + }, + RPCExamples{ + HelpExampleCli("createwallet", "\"testwallet\"") + HelpExampleRpc("createwallet", "\"testwallet\"") - }, - }.ToString()); + }, + }; + + if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { + throw std::runtime_error(help.ToString()); } std::string error; std::string warning; @@ -2670,7 +2673,20 @@ static UniValue createwallet(const JSONRPCRequest& request) flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS; } + bool create_blank = false; // Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted if (!request.params[2].isNull() && request.params[2].get_bool()) { + create_blank = true; + flags |= WALLET_FLAG_BLANK_WALLET; + } + SecureString passphrase; + passphrase.reserve(100); + if (!request.params[3].isNull()) { + passphrase = request.params[3].get_str().c_str(); + if (passphrase.empty()) { + // Empty string is invalid + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Cannot encrypt a wallet with a blank password"); + } + // Born encrypted wallets need to be blank first so that wallet creation doesn't make any unencrypted keys flags |= WALLET_FLAG_BLANK_WALLET; } @@ -2688,6 +2704,29 @@ static UniValue createwallet(const JSONRPCRequest& request) if (!wallet) { throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed."); } + + // Encrypt the wallet if there's a passphrase + if (!passphrase.empty() && !(flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + if (!wallet->EncryptWallet(passphrase)) { + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Wallet created but failed to encrypt."); + } + + if (!create_blank) { + // Unlock the wallet + if (!wallet->Unlock(passphrase)) { + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Wallet was encrypted but could not be unlocked"); + } + + // Set a seed for the wallet + CPubKey master_pub_key = wallet->GenerateNewSeed(); + wallet->SetHDSeed(master_pub_key); + wallet->NewKeyPool(); + + // Relock the wallet + wallet->Lock(); + } + } + AddWallet(wallet); wallet->postInitProcess(); @@ -3413,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."}, @@ -4140,7 +4180,7 @@ static const CRPCCommand commands[] = { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label","address_type"} }, { "wallet", "backupwallet", &backupwallet, {"destination"} }, { "wallet", "bumpfee", &bumpfee, {"txid", "options"} }, - { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank"} }, + { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase"} }, { "wallet", "dumpprivkey", &dumpprivkey, {"address"} }, { "wallet", "dumpwallet", &dumpwallet, {"filename"} }, { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} }, diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h index 90617472cc..1c0523c90b 100644 --- a/src/wallet/rpcwallet.h +++ b/src/wallet/rpcwallet.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index 34b9770e8b..9e7f0ed773 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp index d9b07af329..e4950af4e5 100644 --- a/src/wallet/test/db_tests.cpp +++ b/src/wallet/test/db_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/init_test_fixture.h b/src/wallet/test/init_test_fixture.h index 0f2d9fbd3d..e2b7075085 100644 --- a/src/wallet/test/init_test_fixture.h +++ b/src/wallet/test/init_test_fixture.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp index e1c53c83e2..9e5208b453 100644 --- a/src/wallet/test/init_tests.cpp +++ b/src/wallet/test/init_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp index f774cb4ad1..4753c7f313 100644 --- a/src/wallet/test/psbt_wallet_tests.cpp +++ b/src/wallet/test/psbt_wallet_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp index acc61c984f..2f41813234 100644 --- a/src/wallet/test/wallet_crypto_tests.cpp +++ b/src/wallet/test/wallet_crypto_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Bitcoin Core developers +// Copyright (c) 2014-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp index 6526e69eea..e352c81519 100644 --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h index 1017e61700..c1dbecdf8c 100644 --- a/src/wallet/test/wallet_test_fixture.h +++ b/src/wallet/test/wallet_test_fixture.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 69a78f1fc0..62630c011a 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -368,7 +368,10 @@ public: int changePos = -1; std::string error; CCoinControl dummy; - BOOST_CHECK(wallet->CreateTransaction(*m_locked_chain, {recipient}, tx, reservekey, fee, changePos, error, dummy)); + { + auto locked_chain = m_chain->lock(); + BOOST_CHECK(wallet->CreateTransaction(*locked_chain, {recipient}, tx, reservekey, fee, changePos, error, dummy)); + } CValidationState state; BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservekey, state)); CMutableTransaction blocktx; @@ -387,7 +390,6 @@ public: } std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain(); - std::unique_ptr<interfaces::Chain::Lock> m_locked_chain = m_chain->assumeLocked(); // Temporary. Removed in upcoming lock cleanup std::unique_ptr<CWallet> wallet; }; @@ -399,8 +401,9 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) // address. std::map<CTxDestination, std::vector<COutput>> list; { - LOCK2(cs_main, wallet->cs_wallet); - list = wallet->ListCoins(*m_locked_chain); + auto locked_chain = m_chain->lock(); + LOCK(wallet->cs_wallet); + list = wallet->ListCoins(*locked_chain); } BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); @@ -415,8 +418,9 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) // pubkey. AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */}); { - LOCK2(cs_main, wallet->cs_wallet); - list = wallet->ListCoins(*m_locked_chain); + auto locked_chain = m_chain->lock(); + LOCK(wallet->cs_wallet); + list = wallet->ListCoins(*locked_chain); } BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); @@ -424,9 +428,10 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) // Lock both coins. Confirm number of available coins drops to 0. { - LOCK2(cs_main, wallet->cs_wallet); + auto locked_chain = m_chain->lock(); + LOCK(wallet->cs_wallet); std::vector<COutput> available; - wallet->AvailableCoins(*m_locked_chain, available); + wallet->AvailableCoins(*locked_chain, available); BOOST_CHECK_EQUAL(available.size(), 2U); } for (const auto& group : list) { @@ -436,16 +441,18 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) } } { - LOCK2(cs_main, wallet->cs_wallet); + auto locked_chain = m_chain->lock(); + LOCK(wallet->cs_wallet); std::vector<COutput> available; - wallet->AvailableCoins(*m_locked_chain, available); + wallet->AvailableCoins(*locked_chain, available); BOOST_CHECK_EQUAL(available.size(), 0U); } // Confirm ListCoins still returns same result as before, despite coins // being locked. { - LOCK2(cs_main, wallet->cs_wallet); - list = wallet->ListCoins(*m_locked_chain); + auto locked_chain = m_chain->lock(); + LOCK(wallet->cs_wallet); + list = wallet->ListCoins(*locked_chain); } BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 054329fbd0..260617c666 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4074,7 +4074,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, return nullptr; } - auto locked_chain = chain.assumeLocked(); // Temporary. Removed in upcoming lock cleanup + auto locked_chain = chain.lock(); walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); } else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) { // Make it impossible to disable private keys after creation @@ -4209,10 +4209,13 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, if (tip_height && *tip_height != rescan_height) { - //We can't rescan beyond non-pruned blocks, stop and throw an error - //this might happen if a user uses an old wallet within a pruned node - // or if he ran -disablewallet for a longer time, then decided to re-enable - if (chain.getPruneMode()) { + // We can't rescan beyond non-pruned blocks, stop and throw an error. + // This might happen if a user uses an old wallet within a pruned node + // or if they ran -disablewallet for a longer time, then decided to re-enable + if (chain.havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will load the wallet, + // but fail the rescan with a generic error. int block_height = *tip_height; while (block_height > 0 && locked_chain->haveBlockOnDisk(block_height - 1) && rescan_height != block_height) { --block_height; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 90ce82bb17..5e3bbe2f37 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 3122cd6fa4..ece97e2a75 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp index 1ff1e8b840..5c1b086703 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h index 5b06fd1792..da848a747b 100644 --- a/src/wallet/wallettool.h +++ b/src/wallet/wallettool.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index b227a15556..04c2407a89 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. |