diff options
Diffstat (limited to 'src')
108 files changed, 1043 insertions, 2034 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include index f515774b79..c4ee5f5fcc 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -84,6 +84,7 @@ BITCOIN_TESTS =\ test/sigopcount_tests.cpp \ test/skiplist_tests.cpp \ test/streams_tests.cpp \ + test/sync_tests.cpp \ test/timedata_tests.cpp \ test/torcontrol_tests.cpp \ test/transaction_tests.cpp \ @@ -106,7 +107,6 @@ endif if ENABLE_WALLET BITCOIN_TESTS += \ - wallet/test/accounting_tests.cpp \ wallet/test/psbt_wallet_tests.cpp \ wallet/test/wallet_tests.cpp \ wallet/test/wallet_crypto_tests.cpp \ diff --git a/src/bech32.cpp b/src/bech32.cpp index c55f22b9b7..d6b29391a9 100644 --- a/src/bech32.cpp +++ b/src/bech32.cpp @@ -62,7 +62,7 @@ uint32_t PolyMod(const data& v) // v, it corresponds to x^2 + v0*x + v1 mod g(x). As 1 mod g(x) = 1, that is the starting value // for `c`. uint32_t c = 1; - for (auto v_i : v) { + for (const auto v_i : v) { // We want to update `c` to correspond to a polynomial with one extra term. If the initial // value of `c` consists of the coefficients of c(x) = f(x) mod g(x), we modify it to // correspond to c'(x) = (f(x) * x + v_i) mod g(x), where v_i is the next input to @@ -149,7 +149,7 @@ std::string Encode(const std::string& hrp, const data& values) { data combined = Cat(values, checksum); std::string ret = hrp + '1'; ret.reserve(ret.size() + combined.size()); - for (auto c : combined) { + for (const auto c : combined) { ret += CHARSET[c]; } return ret; diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp index bab22f5984..5b0cf27e04 100644 --- a/src/bench/crypto_hash.cpp +++ b/src/bench/crypto_hash.cpp @@ -80,18 +80,16 @@ static void SipHash_32b(benchmark::State& state) static void FastRandom_32bit(benchmark::State& state) { FastRandomContext rng(true); - uint32_t x = 0; while (state.KeepRunning()) { - x += rng.rand32(); + rng.rand32(); } } static void FastRandom_1bit(benchmark::State& state) { FastRandomContext rng(true); - uint32_t x = 0; while (state.KeepRunning()) { - x += rng.randbool(); + rng.randbool(); } } diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp index 0ec7c158cc..3908a7d231 100644 --- a/src/bench/mempool_eviction.cpp +++ b/src/bench/mempool_eviction.cpp @@ -16,7 +16,7 @@ static void AddTx(const CTransactionRef& tx, const CAmount& nFee, CTxMemPool& po bool spendsCoinbase = false; unsigned int sigOpCost = 4; LockPoints lp; - pool.addUnchecked(tx->GetHash(), CTxMemPoolEntry( + pool.addUnchecked(CTxMemPoolEntry( tx, nFee, nTime, nHeight, spendsCoinbase, sigOpCost, lp)); } diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp index 43e7635047..0a99ea3184 100644 --- a/src/bench/rollingbloom.cpp +++ b/src/bench/rollingbloom.cpp @@ -12,7 +12,6 @@ static void RollingBloom(benchmark::State& state) CRollingBloomFilter filter(120000, 0.000001); std::vector<unsigned char> data(32); uint32_t count = 0; - uint64_t match = 0; while (state.KeepRunning()) { count++; data[0] = count; @@ -25,7 +24,7 @@ static void RollingBloom(benchmark::State& state) data[1] = count >> 16; data[2] = count >> 8; data[3] = count; - match += filter.contains(data); + filter.contains(data); } } diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index c9414e67c7..89149de4bb 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -35,6 +35,7 @@ static void SetupCliArgs() { const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN); const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET); + const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST); gArgs.AddArg("-?", "This help message", false, OptionsCategory::OPTIONS); gArgs.AddArg("-version", "Print version and exit", false, OptionsCategory::OPTIONS); @@ -47,7 +48,7 @@ static void SetupCliArgs() gArgs.AddArg("-rpcconnect=<ip>", strprintf("Send commands to node running on <ip> (default: %s)", DEFAULT_RPCCONNECT), false, OptionsCategory::OPTIONS); gArgs.AddArg("-rpccookiefile=<loc>", _("Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)"), false, OptionsCategory::OPTIONS); gArgs.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", false, OptionsCategory::OPTIONS); - gArgs.AddArg("-rpcport=<port>", strprintf("Connect to JSON-RPC on <port> (default: %u or testnet: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()), false, OptionsCategory::OPTIONS); + gArgs.AddArg("-rpcport=<port>", strprintf("Connect to JSON-RPC on <port> (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), false, OptionsCategory::OPTIONS); gArgs.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections", false, OptionsCategory::OPTIONS); gArgs.AddArg("-rpcwait", "Wait for RPC server to start", false, OptionsCategory::OPTIONS); gArgs.AddArg("-rpcwallet=<walletname>", "Send RPC for non-default wallet on RPC server (needs to exactly match corresponding -wallet option passed to bitcoind)", false, OptionsCategory::OPTIONS); diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 20f0218ac1..9ee3e8eee7 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -385,7 +385,7 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s CScript scriptPubKey = GetScriptForMultisig(required, pubkeys); if (bSegWit) { - for (CPubKey& pubkey : pubkeys) { + for (const CPubKey& pubkey : pubkeys) { if (!pubkey.IsCompressed()) { throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs"); } diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp index 38fcfacf7f..91623fe70a 100644 --- a/src/blockfilter.cpp +++ b/src/blockfilter.cpp @@ -208,7 +208,7 @@ static GCSFilter::ElementSet BasicFilterElements(const CBlock& block, for (const CTransactionRef& tx : block.vtx) { for (const CTxOut& txout : tx->vout) { const CScript& script = txout.scriptPubKey; - if (script[0] == OP_RETURN) continue; + if (script.empty() || script[0] == OP_RETURN) continue; elements.emplace(script.begin(), script.end()); } } @@ -216,6 +216,7 @@ static GCSFilter::ElementSet BasicFilterElements(const CBlock& block, for (const CTxUndo& tx_undo : block_undo.vtxundo) { for (const Coin& prevout : tx_undo.vprevout) { const CScript& script = prevout.out.scriptPubKey; + if (script.empty()) continue; elements.emplace(script.begin(), script.end()); } } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 93bb3e7647..b80cc2c259 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -4,16 +4,15 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <chainparams.h> -#include <consensus/merkle.h> +#include <chainparamsseeds.h> +#include <consensus/merkle.h> #include <tinyformat.h> #include <util.h> #include <utilstrencodings.h> #include <assert.h> -#include <chainparamsseeds.h> - static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) { CMutableTransaction txNew; @@ -62,14 +61,6 @@ void CChainParams::UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64 /** * Main network */ -/** - * What makes a good checkpoint block? - * + Is surrounded by blocks with reasonable timestamps - * (no blocks before with a timestamp after, none after with - * timestamp before) - * + Contains no strange transactions - */ - class CMainParams : public CChainParams { public: CMainParams() { diff --git a/src/cuckoocache.h b/src/cuckoocache.h index 15f6873961..4d0b094fa2 100644 --- a/src/cuckoocache.h +++ b/src/cuckoocache.h @@ -397,7 +397,7 @@ public: std::array<uint32_t, 8> locs = compute_hashes(e); // Make sure we have not already inserted this element // If we have, make sure that it does not get deleted - for (uint32_t loc : locs) + for (const uint32_t loc : locs) if (table[loc] == e) { please_keep(loc); epoch_flags[loc] = last_epoch; @@ -405,7 +405,7 @@ public: } for (uint8_t depth = 0; depth < depth_limit; ++depth) { // First try to insert to an empty slot, if one exists - for (uint32_t loc : locs) { + for (const uint32_t loc : locs) { if (!collection_flags.bit_is_set(loc)) continue; table[loc] = std::move(e); @@ -467,7 +467,7 @@ public: inline bool contains(const Element& e, const bool erase) const { std::array<uint32_t, 8> locs = compute_hashes(e); - for (uint32_t loc : locs) + for (const uint32_t loc : locs) if (table[loc] == e) { if (erase) allow_erase(loc); diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index f5fb715800..58d8cc2c9d 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -78,7 +78,7 @@ static void SetMaxOpenFiles(leveldb::Options *options) { // do not interfere with select() loops. On 64-bit Unix hosts this value is // also OK, because up to that amount LevelDB will use an mmap // implementation that does not use extra file descriptors (the fds are - // closed after being mmaped). + // closed after being mmap'ed). // // Increasing the value beyond the default is dangerous because LevelDB will // fall back to a non-mmap implementation when the file count is too large. diff --git a/src/fs.cpp b/src/fs.cpp index 570ed3e2ee..2dbc13643b 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -1,5 +1,12 @@ #include <fs.h> +#ifndef WIN32 +#include <fcntl.h> +#else +#include <codecvt> +#include <windows.h> +#endif + namespace fsbridge { FILE *fopen(const fs::path& p, const char *mode) @@ -7,9 +14,82 @@ FILE *fopen(const fs::path& p, const char *mode) return ::fopen(p.string().c_str(), mode); } -FILE *freopen(const fs::path& p, const char *mode, FILE *stream) +#ifndef WIN32 + +static std::string GetErrorReason() { + return std::strerror(errno); +} + +FileLock::FileLock(const fs::path& file) +{ + fd = open(file.string().c_str(), O_RDWR); + if (fd == -1) { + reason = GetErrorReason(); + } +} + +FileLock::~FileLock() +{ + if (fd != -1) { + close(fd); + } +} + +bool FileLock::TryLock() +{ + if (fd == -1) { + return false; + } + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + if (fcntl(fd, F_SETLK, &lock) == -1) { + reason = GetErrorReason(); + return false; + } + return true; +} +#else + +static std::string GetErrorReason() { + wchar_t* err; + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<WCHAR*>(&err), 0, nullptr); + std::wstring err_str(err); + LocalFree(err); + return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(err_str); +} + +FileLock::FileLock(const fs::path& file) +{ + hFile = CreateFileW(file.wstring().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile == INVALID_HANDLE_VALUE) { + reason = GetErrorReason(); + } +} + +FileLock::~FileLock() +{ + if (hFile != INVALID_HANDLE_VALUE) { + CloseHandle(hFile); + } +} + +bool FileLock::TryLock() { - return ::freopen(p.string().c_str(), mode, stream); + if (hFile == INVALID_HANDLE_VALUE) { + return false; + } + _OVERLAPPED overlapped = {0}; + if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, 0, 0, &overlapped)) { + reason = GetErrorReason(); + return false; + } + return true; } +#endif } // fsbridge @@ -18,7 +18,26 @@ namespace fs = boost::filesystem; /** Bridge operations to C stdio */ namespace fsbridge { FILE *fopen(const fs::path& p, const char *mode); - FILE *freopen(const fs::path& p, const char *mode, FILE *stream); + + class FileLock + { + public: + FileLock() = delete; + FileLock(const FileLock&) = delete; + FileLock(FileLock&&) = delete; + explicit FileLock(const fs::path& file); + ~FileLock(); + bool TryLock(); + std::string GetReason() { return reason; } + + private: + std::string reason; +#ifndef WIN32 + int fd = -1; +#else + void* hFile = (void*)-1; // INVALID_HANDLE_VALUE +#endif + }; }; #endif // BITCOIN_FS_H diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 0fdc3e5ff3..326f7f6b64 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -69,7 +69,7 @@ class WorkQueue { private: /** Mutex protects entire object */ - std::mutex cs; + Mutex cs; std::condition_variable cond; std::deque<std::unique_ptr<WorkItem>> queue; bool running; @@ -88,7 +88,7 @@ public: /** Enqueue a work item */ bool Enqueue(WorkItem* item) { - std::unique_lock<std::mutex> lock(cs); + LOCK(cs); if (queue.size() >= maxDepth) { return false; } @@ -102,7 +102,7 @@ public: while (true) { std::unique_ptr<WorkItem> i; { - std::unique_lock<std::mutex> lock(cs); + WAIT_LOCK(cs, lock); while (running && queue.empty()) cond.wait(lock); if (!running) @@ -116,7 +116,7 @@ public: /** Interrupt and exit loops */ void Interrupt() { - std::unique_lock<std::mutex> lock(cs); + LOCK(cs); running = false; cond.notify_all(); } diff --git a/src/init.cpp b/src/init.cpp index 2131a6adc0..a3b04c6c44 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -51,13 +51,13 @@ #ifndef WIN32 #include <signal.h> +#include <sys/stat.h> #endif #include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/split.hpp> #include <boost/bind.hpp> -#include <boost/interprocess/sync/file_lock.hpp> #include <boost/thread.hpp> #include <openssl/crypto.h> @@ -343,8 +343,10 @@ void SetupServerArgs() { const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN); const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET); + const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST); const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN); const auto testnetChainParams = CreateChainParams(CBaseChainParams::TESTNET); + const auto regtestChainParams = CreateChainParams(CBaseChainParams::REGTEST); // Hidden Options std::vector<std::string> hidden_args = {"-rpcssl", "-benchmark", "-h", "-help", "-socks", "-tor", "-debugnet", "-whitelistalwaysrelay", @@ -366,7 +368,7 @@ void SetupServerArgs() 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); gArgs.AddArg("-dbcache=<n>", strprintf("Set database cache size in megabytes (%d to %d, default: %d)", nMinDbCache, nMaxDbCache, nDefaultDbCache), false, OptionsCategory::OPTIONS); - gArgs.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (0 to disable; default: %s)", DEFAULT_DEBUGLOGFILE), false, OptionsCategory::OPTIONS); + gArgs.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (-nodebuglogfile to disable; default: %s)", DEFAULT_DEBUGLOGFILE), false, OptionsCategory::OPTIONS); gArgs.AddArg("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER), true, OptionsCategory::OPTIONS); gArgs.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-loadblock=<file>", "Imports blocks from external blk000??.dat file on startup", false, OptionsCategory::OPTIONS); @@ -386,7 +388,7 @@ void SetupServerArgs() "Warning: Reverting this setting requires re-downloading the entire blockchain. " "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024), false, OptionsCategory::OPTIONS); gArgs.AddArg("-reindex", "Rebuild chain state and block index from the blk*.dat files on disk", false, OptionsCategory::OPTIONS); - gArgs.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks", false, OptionsCategory::OPTIONS); + gArgs.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks. When in pruning mode or if blocks on disk might be corrupted, use full -reindex instead.", false, OptionsCategory::OPTIONS); #ifndef WIN32 gArgs.AddArg("-sysperms", "Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)", false, OptionsCategory::OPTIONS); #else @@ -398,7 +400,7 @@ void SetupServerArgs() gArgs.AddArg("-banscore=<n>", strprintf("Threshold for disconnecting misbehaving peers (default: %u)", DEFAULT_BANSCORE_THRESHOLD), false, OptionsCategory::CONNECTION); gArgs.AddArg("-bantime=<n>", strprintf("Number of seconds to keep misbehaving peers from reconnecting (default: %u)", DEFAULT_MISBEHAVING_BANTIME), false, OptionsCategory::CONNECTION); gArgs.AddArg("-bind=<addr>", "Bind to given address and always listen on it. Use [host]:port notation for IPv6", false, OptionsCategory::CONNECTION); - gArgs.AddArg("-connect=<ip>", "Connect only to the specified node; -connect=0 disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", false, OptionsCategory::CONNECTION); + gArgs.AddArg("-connect=<ip>", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", false, OptionsCategory::CONNECTION); gArgs.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", false, OptionsCategory::CONNECTION); gArgs.AddArg("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP), false, OptionsCategory::CONNECTION); gArgs.AddArg("-dnsseed", "Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)", false, OptionsCategory::CONNECTION); @@ -412,12 +414,12 @@ void SetupServerArgs() gArgs.AddArg("-maxsendbuffer=<n>", strprintf("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER), false, OptionsCategory::CONNECTION); gArgs.AddArg("-maxtimeadjustment", strprintf("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)", DEFAULT_MAX_TIME_ADJUSTMENT), false, OptionsCategory::CONNECTION); gArgs.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)", DEFAULT_MAX_UPLOAD_TARGET), false, OptionsCategory::CONNECTION); - gArgs.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)", false, OptionsCategory::CONNECTION); + gArgs.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor hidden services, set -noonion to disable (default: -proxy)", false, OptionsCategory::CONNECTION); gArgs.AddArg("-onlynet=<net>", "Make outgoing connections only through network <net> (ipv4, ipv6 or onion). Incoming connections are not affected by this option. This option can be specified multiple times to allow multiple networks.", false, OptionsCategory::CONNECTION); gArgs.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), false, OptionsCategory::CONNECTION); gArgs.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), false, OptionsCategory::CONNECTION); - gArgs.AddArg("-port=<port>", strprintf("Listen for connections on <port> (default: %u or testnet: %u)", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort()), false, OptionsCategory::CONNECTION); - gArgs.AddArg("-proxy=<ip:port>", "Connect through SOCKS5 proxy", false, OptionsCategory::CONNECTION); + gArgs.AddArg("-port=<port>", strprintf("Listen for connections on <port> (default: %u, testnet: %u, regtest: %u)", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), false, OptionsCategory::CONNECTION); + gArgs.AddArg("-proxy=<ip:port>", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled)", false, OptionsCategory::CONNECTION); gArgs.AddArg("-proxyrandomize", strprintf("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)", DEFAULT_PROXYRANDOMIZE), false, OptionsCategory::CONNECTION); gArgs.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes.", false, OptionsCategory::CONNECTION); gArgs.AddArg("-timeout=<n>", strprintf("Specify connection timeout in milliseconds (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT), false, OptionsCategory::CONNECTION); @@ -452,8 +454,8 @@ void SetupServerArgs() gArgs.AddArg("-checkblocks=<n>", strprintf("How many blocks to check at startup (default: %u, 0 = all)", DEFAULT_CHECKBLOCKS), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-checklevel=<n>", strprintf("How thorough the block verification of -checkblocks is (0-4, default: %u)", DEFAULT_CHECKLEVEL), true, OptionsCategory::DEBUG_TEST); - gArgs.AddArg("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. (default: %u)", defaultChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST); - gArgs.AddArg("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u)", defaultChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST); + gArgs.AddArg("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST); + gArgs.AddArg("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages", true, OptionsCategory::DEBUG_TEST); @@ -465,7 +467,7 @@ void SetupServerArgs() gArgs.AddArg("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)", true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-addrmantest", "Allows to test address relay on localhost", true, OptionsCategory::DEBUG_TEST); - gArgs.AddArg("-debug=<category>", strprintf("Output debugging information (default: %u, supplying <category> is optional)", 0) + ". " + + gArgs.AddArg("-debug=<category>", "Output debugging information (default: -nodebug, supplying <category> is optional). " "If <category> is not supplied or if <category> = 1, output all debugging information. <category> can be: " + ListLogCategories() + ".", false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-debugexclude=<category>", strprintf("Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories."), false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-help-debug", "Show all debugging options (usage: --help -help-debug)", false, OptionsCategory::DEBUG_TEST); @@ -478,7 +480,7 @@ void SetupServerArgs() gArgs.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), true, OptionsCategory::DEBUG_TEST); - gArgs.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -daemon. To disable logging to file, set debuglogfile=0)", false, OptionsCategory::DEBUG_TEST); + gArgs.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -daemon. To disable logging to file, set -nodebuglogfile)", false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-shrinkdebugfile", "Shrink debug.log file on client startup (default: 1 when no -debug)", false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", false, OptionsCategory::DEBUG_TEST); @@ -507,7 +509,7 @@ void SetupServerArgs() gArgs.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)", false, OptionsCategory::RPC); gArgs.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", false, OptionsCategory::RPC); gArgs.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", false, OptionsCategory::RPC); - gArgs.AddArg("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()), false, OptionsCategory::RPC); + gArgs.AddArg("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), false, OptionsCategory::RPC); gArgs.AddArg("-rpcserialversion", strprintf("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)", DEFAULT_RPC_SERIALIZE_VERSION), false, OptionsCategory::RPC); gArgs.AddArg("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT), true, OptionsCategory::RPC); gArgs.AddArg("-rpcthreads=<n>", strprintf("Set the number of threads to service RPC calls (default: %d)", DEFAULT_HTTP_THREADS), false, OptionsCategory::RPC); @@ -561,17 +563,17 @@ static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex } static bool fHaveGenesis = false; -static CWaitableCriticalSection cs_GenesisWait; -static CConditionVariable condvar_GenesisWait; +static Mutex g_genesis_wait_mutex; +static std::condition_variable g_genesis_wait_cv; static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex) { if (pBlockIndex != nullptr) { { - WaitableLock lock_GenesisWait(cs_GenesisWait); + LOCK(g_genesis_wait_mutex); fHaveGenesis = true; } - condvar_GenesisWait.notify_all(); + g_genesis_wait_cv.notify_all(); } } @@ -1661,12 +1663,12 @@ bool AppInitMain() // Wait for genesis block to be processed { - WaitableLock lock(cs_GenesisWait); + WAIT_LOCK(g_genesis_wait_mutex, lock); // We previously could hang here if StartShutdown() is called prior to // ThreadImport getting started, so instead we just wait on a timer to // check ShutdownRequested() regularly. while (!fHaveGenesis && !ShutdownRequested()) { - condvar_GenesisWait.wait_for(lock, std::chrono::milliseconds(500)); + g_genesis_wait_cv.wait_for(lock, std::chrono::milliseconds(500)); } uiInterface.NotifyBlockTip_disconnect(BlockNotifyGenesisWait); } diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp index 80f461f4d3..ddf9b342d8 100644 --- a/src/interfaces/handler.cpp +++ b/src/interfaces/handler.cpp @@ -15,7 +15,7 @@ namespace { class HandlerImpl : public Handler { public: - HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {} + explicit HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {} void disconnect() override { m_connection.disconnect(); } diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 703c0811ac..566ae37509 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -31,7 +31,7 @@ namespace { class PendingWalletTxImpl : public PendingWalletTx { public: - PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_key(&wallet) {} + explicit PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_key(&wallet) {} const CTransaction& get() override { return *m_tx; } @@ -39,12 +39,11 @@ public: bool commit(WalletValueMap value_map, WalletOrderForm order_form, - std::string from_account, std::string& reject_reason) override { LOCK2(cs_main, m_wallet.cs_wallet); CValidationState state; - if (!m_wallet.CommitTransaction(m_tx, std::move(value_map), std::move(order_form), std::move(from_account), m_key, g_connman.get(), state)) { + if (!m_wallet.CommitTransaction(m_tx, std::move(value_map), std::move(order_form), m_key, g_connman.get(), state)) { reject_reason = state.GetRejectReason(); return false; } @@ -117,7 +116,7 @@ static WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, class WalletImpl : public Wallet { public: - WalletImpl(const std::shared_ptr<CWallet>& wallet) : m_shared_wallet(wallet), m_wallet(*wallet.get()) {} + explicit WalletImpl(const std::shared_ptr<CWallet>& wallet) : m_shared_wallet(wallet), m_wallet(*wallet.get()) {} bool encryptWallet(const SecureString& wallet_passphrase) override { diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index ae54d42442..44240a5726 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -289,7 +289,6 @@ public: //! Send pending transaction and commit to wallet. virtual bool commit(WalletValueMap value_map, WalletOrderForm order_form, - std::string from_account, std::string& reject_reason) = 0; }; diff --git a/src/key_io.cpp b/src/key_io.cpp index 5c5e2dc031..c6a541cdb1 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -24,7 +24,7 @@ private: const CChainParams& m_params; public: - DestinationEncoder(const CChainParams& params) : m_params(params) {} + explicit DestinationEncoder(const CChainParams& params) : m_params(params) {} std::string operator()(const CKeyID& id) const { diff --git a/src/logging.cpp b/src/logging.cpp index 6557dddffb..0ae4f8121e 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -219,13 +219,13 @@ void BCLog::Logger::LogPrintStr(const std::string &str) // reopen the log file, if requested if (m_reopen_file) { m_reopen_file = false; - m_fileout = fsbridge::freopen(m_file_path, "a", m_fileout); - if (!m_fileout) { - return; + FILE* new_fileout = fsbridge::fopen(m_file_path, "a"); + if (new_fileout) { + setbuf(new_fileout, nullptr); // unbuffered + fclose(m_fileout); + m_fileout = new_fileout; } - setbuf(m_fileout, nullptr); // unbuffered } - FileWriteStr(strTimestamped, m_fileout); } } diff --git a/src/net.cpp b/src/net.cpp index df2cb54b7a..c51a1b4a74 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -344,7 +344,7 @@ CNode* CConnman::FindNode(const CService& addr) bool CConnman::CheckIncomingNonce(uint64_t nonce) { LOCK(cs_vNodes); - for (CNode* pnode : vNodes) { + for (const CNode* pnode : vNodes) { if (!pnode->fSuccessfullyConnected && !pnode->fInbound && pnode->GetLocalNonce() == nonce) return false; } @@ -1227,7 +1227,7 @@ void CConnman::ThreadSocketHandler() if(vNodesSize != nPrevNodeCount) { nPrevNodeCount = vNodesSize; if(clientInterface) - clientInterface->NotifyNumConnectionsChanged(nPrevNodeCount); + clientInterface->NotifyNumConnectionsChanged(vNodesSize); } // @@ -1614,7 +1614,7 @@ void CConnman::ThreadDNSAddressSeed() LOCK(cs_vNodes); int nRelevant = 0; - for (auto pnode : vNodes) { + for (const CNode* pnode : vNodes) { nRelevant += pnode->fSuccessfullyConnected && !pnode->fFeeler && !pnode->fOneShot && !pnode->m_manual_connection && !pnode->fInbound; } if (nRelevant >= 2) { @@ -1733,7 +1733,7 @@ int CConnman::GetExtraOutboundCount() int nOutbound = 0; { LOCK(cs_vNodes); - for (CNode* pnode : vNodes) { + for (const CNode* pnode : vNodes) { if (!pnode->fInbound && !pnode->m_manual_connection && !pnode->fFeeler && !pnode->fDisconnect && !pnode->fOneShot && pnode->fSuccessfullyConnected) { ++nOutbound; } @@ -1803,7 +1803,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) std::set<std::vector<unsigned char> > setConnected; { LOCK(cs_vNodes); - for (CNode* pnode : vNodes) { + for (const CNode* pnode : vNodes) { if (!pnode->fInbound && !pnode->m_manual_connection) { // Netgroups for inbound and addnode peers are not excluded because our goal here // is to not use multiple of our limited outbound slots on a single netgroup @@ -2065,7 +2065,7 @@ void CConnman::ThreadMessageHandler() pnode->Release(); } - std::unique_lock<std::mutex> lock(mutexMsgProc); + WAIT_LOCK(mutexMsgProc, lock); if (!fMoreWork) { condMsgProc.wait_until(lock, std::chrono::steady_clock::now() + std::chrono::milliseconds(100), [this] { return fMsgProcWake; }); } @@ -2347,7 +2347,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) flagInterruptMsgProc = false; { - std::unique_lock<std::mutex> lock(mutexMsgProc); + LOCK(mutexMsgProc); fMsgProcWake = false; } @@ -427,7 +427,7 @@ private: bool fMsgProcWake; std::condition_variable condMsgProc; - std::mutex mutexMsgProc; + Mutex mutexMsgProc; std::atomic<bool> flagInterruptMsgProc; CThreadInterrupt interruptNet; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index a6a8814dff..b48a3bd221 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -70,7 +70,7 @@ struct COrphanTx { NodeId fromPeer; int64_t nTimeExpire; }; -static CCriticalSection g_cs_orphans; +CCriticalSection g_cs_orphans; std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(g_cs_orphans); void EraseOrphansFor(NodeId peer); @@ -882,7 +882,7 @@ void PeerLogicValidation::BlockConnected(const std::shared_ptr<const CBlock>& pb // Erase orphan transactions included or precluded by this block if (vOrphanErase.size()) { int nErased = 0; - for (uint256 &orphanHash : vOrphanErase) { + for (const uint256& orphanHash : vOrphanErase) { nErased += EraseOrphanTx(orphanHash); } LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased); @@ -2288,7 +2288,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } } - for (uint256 hash : vEraseQueue) + for (const uint256& hash : vEraseQueue) EraseOrphanTx(hash); } else if (fMissingInputs) diff --git a/src/netbase.cpp b/src/netbase.cpp index 9750173987..4b63757f3d 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -19,8 +19,6 @@ #include <fcntl.h> #endif -#include <boost/algorithm/string/case_conv.hpp> // for to_lower() - #if !defined(MSG_NOSIGNAL) #define MSG_NOSIGNAL 0 #endif @@ -37,7 +35,7 @@ static const int SOCKS5_RECV_TIMEOUT = 20 * 1000; static std::atomic<bool> interruptSocks5Recv(false); enum Network ParseNetwork(std::string net) { - boost::to_lower(net); + Downcase(net); if (net == "ipv4") return NET_IPV4; if (net == "ipv6") return NET_IPV6; if (net == "onion") return NET_ONION; diff --git a/src/policy/fees.h b/src/policy/fees.h index 136fb481f7..2733c5a7de 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -22,51 +22,6 @@ class CTxMemPoolEntry; class CTxMemPool; class TxConfirmStats; -/** \class CBlockPolicyEstimator - * The BlockPolicyEstimator is used for estimating the feerate needed - * for a transaction to be included in a block within a certain number of - * blocks. - * - * At a high level the algorithm works by grouping transactions into buckets - * based on having similar feerates and then tracking how long it - * takes transactions in the various buckets to be mined. It operates under - * the assumption that in general transactions of higher feerate will be - * included in blocks before transactions of lower feerate. So for - * example if you wanted to know what feerate you should put on a transaction to - * be included in a block within the next 5 blocks, you would start by looking - * at the bucket with the highest feerate transactions and verifying that a - * sufficiently high percentage of them were confirmed within 5 blocks and - * then you would look at the next highest feerate bucket, and so on, stopping at - * the last bucket to pass the test. The average feerate of transactions in this - * bucket will give you an indication of the lowest feerate you can put on a - * transaction and still have a sufficiently high chance of being confirmed - * within your desired 5 blocks. - * - * Here is a brief description of the implementation: - * When a transaction enters the mempool, we track the height of the block chain - * at entry. All further calculations are conducted only on this set of "seen" - * transactions. Whenever a block comes in, we count the number of transactions - * in each bucket and the total amount of feerate paid in each bucket. Then we - * calculate how many blocks Y it took each transaction to be mined. We convert - * from a number of blocks to a number of periods Y' each encompassing "scale" - * blocks. This is tracked in 3 different data sets each up to a maximum - * number of periods. Within each data set we have an array of counters in each - * feerate bucket and we increment all the counters from Y' up to max periods - * representing that a tx was successfully confirmed in less than or equal to - * that many periods. We want to save a history of this information, so at any - * time we have a counter of the total number of transactions that happened in a - * given feerate bucket and the total number that were confirmed in each of the - * periods or less for any bucket. We save this history by keeping an - * exponentially decaying moving average of each one of these stats. This is - * done for a different decay in each of the 3 data sets to keep relevant data - * from different time horizons. Furthermore we also keep track of the number - * unmined (in mempool or left mempool without being included in a block) - * transactions in each bucket and for how many blocks they have been - * outstanding and use both of these numbers to increase the number of transactions - * we've seen in that feerate bucket when calculating an estimate for any number - * of confirmations below the number of blocks they've been outstanding. - */ - /* Identifier for each of the 3 different TxConfirmStats which will track * history over different time horizons. */ enum class FeeEstimateHorizon { @@ -130,7 +85,50 @@ struct FeeCalculation int returnedTarget = 0; }; -/** +/** \class CBlockPolicyEstimator + * The BlockPolicyEstimator is used for estimating the feerate needed + * for a transaction to be included in a block within a certain number of + * blocks. + * + * At a high level the algorithm works by grouping transactions into buckets + * based on having similar feerates and then tracking how long it + * takes transactions in the various buckets to be mined. It operates under + * the assumption that in general transactions of higher feerate will be + * included in blocks before transactions of lower feerate. So for + * example if you wanted to know what feerate you should put on a transaction to + * be included in a block within the next 5 blocks, you would start by looking + * at the bucket with the highest feerate transactions and verifying that a + * sufficiently high percentage of them were confirmed within 5 blocks and + * then you would look at the next highest feerate bucket, and so on, stopping at + * the last bucket to pass the test. The average feerate of transactions in this + * bucket will give you an indication of the lowest feerate you can put on a + * transaction and still have a sufficiently high chance of being confirmed + * within your desired 5 blocks. + * + * Here is a brief description of the implementation: + * When a transaction enters the mempool, we track the height of the block chain + * at entry. All further calculations are conducted only on this set of "seen" + * transactions. Whenever a block comes in, we count the number of transactions + * in each bucket and the total amount of feerate paid in each bucket. Then we + * calculate how many blocks Y it took each transaction to be mined. We convert + * from a number of blocks to a number of periods Y' each encompassing "scale" + * blocks. This is tracked in 3 different data sets each up to a maximum + * number of periods. Within each data set we have an array of counters in each + * feerate bucket and we increment all the counters from Y' up to max periods + * representing that a tx was successfully confirmed in less than or equal to + * that many periods. We want to save a history of this information, so at any + * time we have a counter of the total number of transactions that happened in a + * given feerate bucket and the total number that were confirmed in each of the + * periods or less for any bucket. We save this history by keeping an + * exponentially decaying moving average of each one of these stats. This is + * done for a different decay in each of the 3 data sets to keep relevant data + * from different time horizons. Furthermore we also keep track of the number + * unmined (in mempool or left mempool without being included in a block) + * transactions in each bucket and for how many blocks they have been + * outstanding and use both of these numbers to increase the number of transactions + * we've seen in that feerate bucket when calculating an estimate for any number + * of confirmations below the number of blocks they've been outstanding. + * * We want to be able to estimate feerates that are needed on tx's to be included in * a certain number of blocks. Every time a block is added to the best chain, this class records * stats on the transactions included in that block diff --git a/src/prevector.h b/src/prevector.h index 7a13b98214..6ddb6f321f 100644 --- a/src/prevector.h +++ b/src/prevector.h @@ -248,32 +248,32 @@ public: prevector() : _size(0), _union{{}} {} - explicit prevector(size_type n) : _size(0) { + explicit prevector(size_type n) : prevector() { resize(n); } - explicit prevector(size_type n, const T& val) : _size(0) { + explicit prevector(size_type n, const T& val) : prevector() { change_capacity(n); _size += n; fill(item_ptr(0), n, val); } template<typename InputIterator> - prevector(InputIterator first, InputIterator last) : _size(0) { + prevector(InputIterator first, InputIterator last) : prevector() { size_type n = last - first; change_capacity(n); _size += n; fill(item_ptr(0), first, last); } - prevector(const prevector<N, T, Size, Diff>& other) : _size(0) { + prevector(const prevector<N, T, Size, Diff>& other) : prevector() { size_type n = other.size(); change_capacity(n); _size += n; fill(item_ptr(0), other.begin(), other.end()); } - prevector(prevector<N, T, Size, Diff>&& other) : _size(0) { + prevector(prevector<N, T, Size, Diff>&& other) : prevector() { swap(other); } diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 380a3ddb84..2f88e15d21 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -71,7 +71,7 @@ public: QList<AddressTableEntry> cachedAddressTable; AddressTableModel *parent; - AddressTablePriv(AddressTableModel *_parent): + explicit AddressTablePriv(AddressTableModel *_parent): parent(_parent) {} void refreshAddressTable(interfaces::Wallet& wallet) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 712d20b71e..f1d3074c2f 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -416,7 +416,7 @@ void BitcoinApplication::requestShutdown() #ifdef ENABLE_WALLET window->removeAllWallets(); - for (WalletModel *walletModel : m_wallet_models) { + for (const WalletModel* walletModel : m_wallet_models) { delete walletModel; } m_wallet_models.clear(); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 5321cd94fd..632ce0750a 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -614,8 +614,11 @@ void BitcoinGUI::createTrayIconMenu() #endif // Configuration of the tray icon (or dock icon) icon menu +#ifndef Q_OS_MAC + // Note: On Mac, the dock icon's menu already has show / hide action. trayIconMenu->addAction(toggleHideAction); trayIconMenu->addSeparator(); +#endif trayIconMenu->addAction(sendCoinsMenuAction); trayIconMenu->addAction(receiveCoinsMenuAction); trayIconMenu->addSeparator(); @@ -1273,7 +1276,7 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event) void UnitDisplayStatusBarControl::createContextMenu() { menu = new QMenu(this); - for (BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) + for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) { QAction *menuAction = new QAction(QString(BitcoinUnits::longName(u)), this); menuAction->setData(QVariant(u)); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 61cd6f76cc..dcaca10557 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -212,7 +212,7 @@ private: void setEncryptionStatus(int status); /** Set the hd-enabled status as shown in the UI. - @param[in] status current hd enabled status + @param[in] hdEnabled current hd enabled status @see WalletModel::EncryptionStatus */ void setHDStatus(int hdEnabled); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 59a751fb12..8cfedca57f 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -65,7 +65,7 @@ public: interfaces::Node::NodesStats nodes_stats; node.getNodesStats(nodes_stats); cachedNodeStats.reserve(nodes_stats.size()); - for (auto& node_stats : nodes_stats) + for (const auto& node_stats : nodes_stats) { CNodeCombinedStats stats; stats.nodeStats = std::get<0>(node_stats); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 66e36f0b67..ad13b20ebe 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -82,7 +82,7 @@ class RPCExecutor : public QObject { Q_OBJECT public: - RPCExecutor(interfaces::Node& node) : m_node(node) {} + explicit RPCExecutor(interfaces::Node& node) : m_node(node) {} public Q_SLOTS: void request(const QString &command, const QString &walletID); @@ -142,7 +142,7 @@ public: * - Within single quotes, no escaping is possible and no special interpretation takes place * * @param[in] node optional node to execute command on - * @param[out] result stringified Result from the executed command(chain) + * @param[out] strResult stringified result from the executed command(chain) * @param[in] strCommand Command line to split * @param[in] fExecute set true if you want the command to be executed * @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index eed71397ab..6f66bc19e1 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -348,7 +348,7 @@ void SendCoinsDialog::on_sendButton_clicked() questionString.append("<hr />"); CAmount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee; QStringList alternativeUnits; - for (BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) + for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) { if(u != model->getOptionsModel()->getDisplayUnit()) alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount)); diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 0b111cc6d7..1eff4f6b65 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -200,7 +200,7 @@ void SplashScreen::unsubscribeFromCoreSignals() // Disconnect signals from client m_handler_init_message->disconnect(); m_handler_show_progress->disconnect(); - for (auto& handler : m_connected_wallet_handlers) { + for (const auto& handler : m_connected_wallet_handlers) { handler->disconnect(); } m_connected_wallet_handlers.clear(); diff --git a/src/qt/test/util.h b/src/qt/test/util.h index 324386c139..5363c94547 100644 --- a/src/qt/test/util.h +++ b/src/qt/test/util.h @@ -5,7 +5,7 @@ * Press "Ok" button in message box dialog. * * @param text - Optionally store dialog text. - * @param msec - Number of miliseconds to pause before triggering the callback. + * @param msec - Number of milliseconds to pause before triggering the callback. */ void ConfirmMessage(QString* text = nullptr, int msec = 0); diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp index f087e7569c..3aed3f2b97 100644 --- a/src/qt/trafficgraphwidget.cpp +++ b/src/qt/trafficgraphwidget.cpp @@ -141,10 +141,10 @@ void TrafficGraphWidget::updateRates() } float tmax = 0.0f; - for (float f : vSamplesIn) { + for (const float f : vSamplesIn) { if(f > tmax) tmax = f; } - for (float f : vSamplesOut) { + for (const float f : vSamplesOut) { if(f > tmax) tmax = f; } fMax = tmax; diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 6286ddc0e0..59332be754 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -152,13 +152,13 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall else { isminetype fAllFromMe = ISMINE_SPENDABLE; - for (isminetype mine : wtx.txin_is_mine) + for (const isminetype mine : wtx.txin_is_mine) { if(fAllFromMe > mine) fAllFromMe = mine; } isminetype fAllToMe = ISMINE_SPENDABLE; - for (isminetype mine : wtx.txout_is_mine) + for (const isminetype mine : wtx.txout_is_mine) { if(fAllToMe > mine) fAllToMe = mine; } diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index c767de5eda..d1a7527ac7 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -77,14 +77,14 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface { bool involvesWatchAddress = false; isminetype fAllFromMe = ISMINE_SPENDABLE; - for (isminetype mine : wtx.txin_is_mine) + for (const isminetype mine : wtx.txin_is_mine) { if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; if(fAllFromMe > mine) fAllFromMe = mine; } isminetype fAllToMe = ISMINE_SPENDABLE; - for (isminetype mine : wtx.txout_is_mine) + for (const isminetype mine : wtx.txout_is_mine) { if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; if(fAllToMe > mine) fAllToMe = mine; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 4fa941b630..b4be068904 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -60,7 +60,7 @@ struct TxLessThan class TransactionTablePriv { public: - TransactionTablePriv(TransactionTableModel *_parent) : + explicit TransactionTablePriv(TransactionTableModel *_parent) : parent(_parent) { } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 18a5bda9c3..f7cc94ae32 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -253,7 +253,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran auto& newTx = transaction.getWtx(); std::string rejectReason; - if (!newTx->commit({} /* mapValue */, std::move(vOrderForm), {} /* fromAccount */, rejectReason)) + if (!newTx->commit({} /* mapValue */, std::move(vOrderForm), rejectReason)) return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(rejectReason)); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/random.cpp b/src/random.cpp index 6c5ad5ac96..503d5b3636 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -12,6 +12,7 @@ #include <wincrypt.h> #endif #include <logging.h> // for LogPrint() +#include <sync.h> // for WAIT_LOCK #include <utiltime.h> // for GetTime() #include <stdlib.h> @@ -295,7 +296,7 @@ void RandAddSeedSleep() } -static std::mutex cs_rng_state; +static Mutex cs_rng_state; static unsigned char rng_state[32] = {0}; static uint64_t rng_counter = 0; @@ -305,7 +306,7 @@ static void AddDataToRng(void* data, size_t len) { hasher.Write((const unsigned char*)data, len); unsigned char buf[64]; { - std::unique_lock<std::mutex> lock(cs_rng_state); + WAIT_LOCK(cs_rng_state, lock); hasher.Write(rng_state, sizeof(rng_state)); hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter)); ++rng_counter; @@ -337,7 +338,7 @@ void GetStrongRandBytes(unsigned char* out, int num) // Combine with and update state { - std::unique_lock<std::mutex> lock(cs_rng_state); + WAIT_LOCK(cs_rng_state, lock); hasher.Write(rng_state, sizeof(rng_state)); hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter)); ++rng_counter; diff --git a/src/rest.cpp b/src/rest.cpp index 12358cf50d..6ba15172fa 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -464,7 +464,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) oss >> fCheckMemPool; oss >> vOutPoints; } - } catch (const std::ios_base::failure& e) { + } catch (const std::ios_base::failure&) { // abort in case of unreadable binary data return RESTERR(req, HTTP_BAD_REQUEST, "Parse error"); } diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index a77fea8ea8..6fb04ab005 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -50,7 +50,7 @@ struct CUpdatedBlock int height; }; -static std::mutex cs_blockchange; +static Mutex cs_blockchange; static std::condition_variable cond_blockchange; static CUpdatedBlock latestblock; @@ -225,7 +225,7 @@ static UniValue waitfornewblock(const JSONRPCRequest& request) CUpdatedBlock block; { - std::unique_lock<std::mutex> lock(cs_blockchange); + WAIT_LOCK(cs_blockchange, lock); block = latestblock; if(timeout) cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); @@ -267,7 +267,7 @@ static UniValue waitforblock(const JSONRPCRequest& request) CUpdatedBlock block; { - std::unique_lock<std::mutex> lock(cs_blockchange); + WAIT_LOCK(cs_blockchange, lock); if(timeout) cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();}); else @@ -310,7 +310,7 @@ static UniValue waitforblockheight(const JSONRPCRequest& request) CUpdatedBlock block; { - std::unique_lock<std::mutex> lock(cs_blockchange); + WAIT_LOCK(cs_blockchange, lock); if(timeout) cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();}); else @@ -426,7 +426,7 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK UniValue spent(UniValue::VARR); const CTxMemPool::txiter &it = mempool.mapTx.find(tx.GetHash()); const CTxMemPool::setEntries &setChildren = mempool.GetMemPoolChildren(it); - for (const CTxMemPool::txiter &childiter : setChildren) { + for (CTxMemPool::txiter childiter : setChildren) { spent.push_back(childiter->GetTx().GetHash().ToString()); } @@ -2058,7 +2058,7 @@ UniValue scantxoutset(const JSONRPCRequest& request) "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n" "unhardened or hardened child keys.\n" "In the latter case, a range needs to be specified by below if different from 1000.\n" - "For more information on output descriptors, see the documentation at TODO\n" + "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n" "\nArguments:\n" "1. \"action\" (string, required) The action to execute\n" " \"start\" for starting a scan\n" diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index 544bc62c36..add335eb8a 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -16,8 +16,7 @@ class UniValue; static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5; /** - * Get the difficulty of the net wrt to the given block index, or the chain tip if - * not provided. + * Get the difficulty of the net wrt to the given block index. * * @return A floating point number that is a multiple of the main net minimum * difficulty (4295032833 hashes). diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index c7f3e38ac0..784d6416cf 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -40,15 +40,11 @@ static const CRPCConvertParam vRPCConvertParams[] = { "settxfee", 0, "amount" }, { "sethdseed", 0, "newkeypool" }, { "getreceivedbyaddress", 1, "minconf" }, - { "getreceivedbyaccount", 1, "minconf" }, { "getreceivedbylabel", 1, "minconf" }, { "listreceivedbyaddress", 0, "minconf" }, { "listreceivedbyaddress", 1, "include_empty" }, { "listreceivedbyaddress", 2, "include_watchonly" }, { "listreceivedbyaddress", 3, "address_filter" }, - { "listreceivedbyaccount", 0, "minconf" }, - { "listreceivedbyaccount", 1, "include_empty" }, - { "listreceivedbyaccount", 2, "include_watchonly" }, { "listreceivedbylabel", 0, "minconf" }, { "listreceivedbylabel", 1, "include_empty" }, { "listreceivedbylabel", 2, "include_watchonly" }, @@ -59,15 +55,9 @@ static const CRPCConvertParam vRPCConvertParams[] = { "waitforblockheight", 1, "timeout" }, { "waitforblock", 1, "timeout" }, { "waitfornewblock", 0, "timeout" }, - { "move", 2, "amount" }, - { "move", 3, "minconf" }, - { "sendfrom", 2, "amount" }, - { "sendfrom", 3, "minconf" }, { "listtransactions", 1, "count" }, { "listtransactions", 2, "skip" }, { "listtransactions", 3, "include_watchonly" }, - { "listaccounts", 0, "minconf" }, - { "listaccounts", 1, "include_watchonly" }, { "walletpassphrase", 1, "timeout" }, { "getblocktemplate", 0, "template_request" }, { "listsinceblock", 1, "target_confirmations" }, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 623b0bd86a..621b86eec8 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -470,7 +470,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) { checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1); - WaitableLock lock(g_best_block_mutex); + WAIT_LOCK(g_best_block_mutex, lock); while (g_best_block == hashWatchedChain && IsRPCRunning()) { if (g_best_block_cv.wait_until(lock, checktxtime) == std::cv_status::timeout) @@ -922,7 +922,7 @@ static UniValue estimaterawfee(const JSONRPCRequest& request) UniValue result(UniValue::VOBJ); - for (FeeEstimateHorizon horizon : {FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}) { + for (const FeeEstimateHorizon horizon : {FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}) { CFeeRate feeRate; EstimationResult buckets; diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 40418545c1..b7d05cef11 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -19,11 +19,6 @@ #include <timedata.h> #include <util.h> #include <utilstrencodings.h> -#ifdef ENABLE_WALLET -#include <wallet/rpcwallet.h> -#include <wallet/wallet.h> -#include <wallet/walletdb.h> -#endif #include <warnings.h> #include <stdint.h> @@ -67,29 +62,18 @@ static UniValue validateaddress(const JSONRPCRequest& request) ret.pushKV("isvalid", isValid); if (isValid) { + std::string currentAddress = EncodeDestination(dest); + ret.pushKV("address", currentAddress); -#ifdef ENABLE_WALLET - if (HasWallets() && IsDeprecatedRPCEnabled("validateaddress")) { - ret.pushKVs(getaddressinfo(request)); - } -#endif - if (ret["address"].isNull()) { - std::string currentAddress = EncodeDestination(dest); - ret.pushKV("address", currentAddress); - - CScript scriptPubKey = GetScriptForDestination(dest); - ret.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())); + CScript scriptPubKey = GetScriptForDestination(dest); + ret.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())); - UniValue detail = DescribeAddress(dest); - ret.pushKVs(detail); - } + UniValue detail = DescribeAddress(dest); + ret.pushKVs(detail); } return ret; } -// Needed even with !ENABLE_WALLET, to pass (ignored) pointers around -class CWallet; - static UniValue createmultisig(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) @@ -130,8 +114,7 @@ static UniValue createmultisig(const JSONRPCRequest& request) if (IsHex(keys[i].get_str()) && (keys[i].get_str().length() == 66 || keys[i].get_str().length() == 130)) { pubkeys.push_back(HexToPubKey(keys[i].get_str())); } else { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid public key: %s\nNote that from v0.16, createmultisig no longer accepts addresses." - " Users must use addmultisigaddress to create multisig addresses with addresses known to the wallet.", keys[i].get_str())); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid public key: %s\n.", keys[i].get_str())); } } @@ -461,7 +444,7 @@ static const CRPCCommand commands[] = // --------------------- ------------------------ ----------------------- ---------- { "control", "getmemoryinfo", &getmemoryinfo, {"mode"} }, { "control", "logging", &logging, {"include", "exclude"}}, - { "util", "validateaddress", &validateaddress, {"address"} }, /* uses wallet if enabled */ + { "util", "validateaddress", &validateaddress, {"address"} }, { "util", "createmultisig", &createmultisig, {"nrequired","keys"} }, { "util", "verifymessage", &verifymessage, {"address","signature","message"} }, { "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} }, diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 343b7d3b05..169a452659 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -164,7 +164,7 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) obj.pushKV("synced_headers", statestats.nSyncHeight); obj.pushKV("synced_blocks", statestats.nCommonHeight); UniValue heights(UniValue::VARR); - for (int height : statestats.vHeightInFlight) { + for (const int height : statestats.vHeightInFlight) { heights.push_back(height); } obj.pushKV("inflight", heights); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 7ca097f8cf..6acf383646 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -27,9 +27,6 @@ #include <txmempool.h> #include <uint256.h> #include <utilstrencodings.h> -#ifdef ENABLE_WALLET -#include <wallet/rpcwallet.h> -#endif #include <future> #include <stdint.h> @@ -824,8 +821,7 @@ UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival view.AddCoin(out, std::move(newcoin), true); } - // if redeemScript given and not using the local wallet (private keys - // given), add redeemScript to the keystore so it can be signed: + // if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed if (is_temp_keystore && (scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash())) { RPCTypeCheckObj(prevOut, { @@ -980,102 +976,10 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) UniValue signrawtransaction(const JSONRPCRequest& request) { -#ifdef ENABLE_WALLET - std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); - CWallet* const pwallet = wallet.get(); -#endif - - if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) - throw std::runtime_error( - "signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n" - "\nDEPRECATED. Sign inputs for raw transaction (serialized, hex-encoded).\n" - "The second optional argument (may be null) is an array of previous transaction outputs that\n" - "this transaction depends on but may not yet be in the block chain.\n" - "The third optional argument (may be null) is an array of base58-encoded private\n" - "keys that, if given, will be the only keys used to sign the transaction.\n" -#ifdef ENABLE_WALLET - + HelpRequiringPassphrase(pwallet) + "\n" -#endif - "\nArguments:\n" - "1. \"hexstring\" (string, required) The transaction hex string\n" - "2. \"prevtxs\" (string, optional) An json array of previous dependent transaction outputs\n" - " [ (json array of json objects, or 'null' if none provided)\n" - " {\n" - " \"txid\":\"id\", (string, required) The transaction id\n" - " \"vout\":n, (numeric, required) The output number\n" - " \"scriptPubKey\": \"hex\", (string, required) script key\n" - " \"redeemScript\": \"hex\", (string, required for P2SH or P2WSH) redeem script\n" - " \"amount\": value (numeric, required) The amount spent\n" - " }\n" - " ,...\n" - " ]\n" - "3. \"privkeys\" (string, optional) A json array of base58-encoded private keys for signing\n" - " [ (json array of strings, or 'null' if none provided)\n" - " \"privatekey\" (string) private key in base58-encoding\n" - " ,...\n" - " ]\n" - "4. \"sighashtype\" (string, optional, default=ALL) The signature hash type. Must be one of\n" - " \"ALL\"\n" - " \"NONE\"\n" - " \"SINGLE\"\n" - " \"ALL|ANYONECANPAY\"\n" - " \"NONE|ANYONECANPAY\"\n" - " \"SINGLE|ANYONECANPAY\"\n" - - "\nResult:\n" - "{\n" - " \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n" - " \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n" - " \"errors\" : [ (json array of objects) Script verification errors (if there are any)\n" - " {\n" - " \"txid\" : \"hash\", (string) The hash of the referenced, previous transaction\n" - " \"vout\" : n, (numeric) The index of the output to spent and used as input\n" - " \"scriptSig\" : \"hex\", (string) The hex-encoded signature script\n" - " \"sequence\" : n, (numeric) Script sequence number\n" - " \"error\" : \"text\" (string) Verification or signing error related to the input\n" - " }\n" - " ,...\n" - " ]\n" - "}\n" - - "\nExamples:\n" - + HelpExampleCli("signrawtransaction", "\"myhex\"") - + HelpExampleRpc("signrawtransaction", "\"myhex\"") - ); - - if (!IsDeprecatedRPCEnabled("signrawtransaction")) { - throw JSONRPCError(RPC_METHOD_DEPRECATED, "signrawtransaction is deprecated and will be fully removed in v0.18. " - "To use signrawtransaction in v0.17, restart bitcoind with -deprecatedrpc=signrawtransaction.\n" - "Projects should transition to using signrawtransactionwithkey and signrawtransactionwithwallet before upgrading to v0.18"); - } - - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true); - - // Make a JSONRPCRequest to pass on to the right signrawtransaction* command - JSONRPCRequest new_request; - new_request.id = request.id; - new_request.params.setArray(); - - // For signing with private keys - if (!request.params[2].isNull()) { - new_request.params.push_back(request.params[0]); - // Note: the prevtxs and privkeys are reversed for signrawtransactionwithkey - new_request.params.push_back(request.params[2]); - new_request.params.push_back(request.params[1]); - new_request.params.push_back(request.params[3]); - return signrawtransactionwithkey(new_request); - } else { -#ifdef ENABLE_WALLET - // Otherwise sign with the wallet which does not take a privkeys parameter - new_request.params.push_back(request.params[0]); - new_request.params.push_back(request.params[1]); - new_request.params.push_back(request.params[3]); - return signrawtransactionwithwallet(new_request); -#else - // If we have made it this far, then wallet is disabled and no private keys were given, so fail here. - throw JSONRPCError(RPC_INVALID_PARAMETER, "No private keys available."); -#endif - } + // This method should be removed entirely in V0.19, along with the entries in the + // CRPCCommand table and rpc/client.cpp. + throw JSONRPCError(RPC_METHOD_DEPRECATED, "signrawtransaction was removed in v0.18.\n" + "Clients should transition to using signrawtransactionwithkey and signrawtransactionwithwallet"); } static UniValue sendrawtransaction(const JSONRPCRequest& request) @@ -1084,7 +988,7 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) throw std::runtime_error( "sendrawtransaction \"hexstring\" ( allowhighfees )\n" "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" - "\nAlso see createrawtransaction and signrawtransaction calls.\n" + "\nAlso see createrawtransaction and signrawtransactionwithkey calls.\n" "\nArguments:\n" "1. \"hexstring\" (string, required) The hex string of the raw transaction)\n" "2. allowhighfees (boolean, optional, default=false) Allow high fees\n" @@ -1094,7 +998,7 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) "\nCreate a transaction\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + "Sign the transaction, and get back the hex\n" - + HelpExampleCli("signrawtransaction", "\"myhex\"") + + + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + "\nSend the transaction (signed hex)\n" + HelpExampleCli("sendrawtransaction", "\"signedhex\"") + "\nAs a json rpc call\n" @@ -1199,7 +1103,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) "\nCreate a transaction\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + "Sign the transaction, and get back the hex\n" - + HelpExampleCli("signrawtransaction", "\"myhex\"") + + + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + "\nTest acceptance of the transaction (signed hex)\n" + HelpExampleCli("testmempoolaccept", "\"signedhex\"") + "\nAs a json rpc call\n" @@ -1458,11 +1362,8 @@ UniValue decodepsbt(const JSONRPCRequest& request) UniValue keypath(UniValue::VOBJ); keypath.pushKV("pubkey", HexStr(entry.first)); - uint32_t fingerprint = entry.second.at(0); - keypath.pushKV("master_fingerprint", strprintf("%08x", bswap_32(fingerprint))); - - entry.second.erase(entry.second.begin()); - keypath.pushKV("path", WriteHDKeypath(entry.second)); + keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint))); + keypath.pushKV("path", WriteHDKeypath(entry.second.path)); keypaths.push_back(keypath); } in.pushKV("bip32_derivs", keypaths); @@ -1520,12 +1421,8 @@ UniValue decodepsbt(const JSONRPCRequest& request) for (auto entry : output.hd_keypaths) { UniValue keypath(UniValue::VOBJ); keypath.pushKV("pubkey", HexStr(entry.first)); - - uint32_t fingerprint = entry.second.at(0); - keypath.pushKV("master_fingerprint", strprintf("%08x", bswap_32(fingerprint))); - - entry.second.erase(entry.second.begin()); - keypath.pushKV("path", WriteHDKeypath(entry.second)); + keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint))); + keypath.pushKV("path", WriteHDKeypath(entry.second.path)); keypaths.push_back(keypath); } out.pushKV("bip32_derivs", keypaths); @@ -1646,8 +1543,7 @@ UniValue finalizepsbt(const JSONRPCRequest& request) for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { PSBTInput& input = psbtx.inputs.at(i); - SignatureData sigdata; - complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, *psbtx.tx, input, sigdata, i, 1); + complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, *psbtx.tx, input, i, 1); } UniValue result(UniValue::VOBJ); @@ -1748,7 +1644,7 @@ UniValue converttopsbt(const JSONRPCRequest& request) " will continue. If false, RPC will fail if any signatures are present.\n" "3. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction.\n" " If iswitness is not present, heuristic tests will be used in decoding. If true, only witness deserializaion\n" - " will be tried. If false, only non-witness deserialization wil be tried. Only has an effect if\n" + " will be tried. If false, only non-witness deserialization will be tried. Only has an effect if\n" " permitsigdata is true.\n" "\nResult:\n" " \"psbt\" (string) The resulting raw transaction (base64-encoded string)\n" @@ -1808,7 +1704,7 @@ static const CRPCCommand commands[] = { "rawtransactions", "decodescript", &decodescript, {"hexstring"} }, { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees"} }, { "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} }, - { "rawtransactions", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */ + { "hidden", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} }, { "rawtransactions", "signrawtransactionwithkey", &signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} }, { "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","allowhighfees"} }, { "rawtransactions", "decodepsbt", &decodepsbt, {"psbt"} }, diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index e46bf2f765..7d7e83fea8 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -16,7 +16,6 @@ #include <boost/bind.hpp> #include <boost/signals2/signal.hpp> -#include <boost/algorithm/string/case_conv.hpp> // for to_upper() #include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/split.hpp> @@ -192,9 +191,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& if (!category.empty()) strRet += "\n"; category = pcmd->category; - std::string firstLetter = category.substr(0,1); - boost::to_upper(firstLetter); - strRet += "== " + firstLetter + category.substr(1) + " ==\n"; + strRet += "== " + Capitalize(category) + " ==\n"; } } strRet += strHelp + "\n"; diff --git a/src/scheduler.h b/src/scheduler.h index 0c2551cf4f..953d6c37de 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -111,7 +111,7 @@ public: /** * Add a callback to be executed. Callbacks are executed serially * and memory is release-acquire consistent between callback executions. - * Practially, this means that callbacks can behave as if they are executed + * Practically, this means that callbacks can behave as if they are executed * in order by a single thread. */ void AddToProcessQueue(std::function<void (void)> func); diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index f366b99ec3..45b097dde6 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -373,7 +373,7 @@ enum class ParseScriptContext { P2WSH, }; -/** Parse a constant. If succesful, sp is updated to skip the constant and return true. */ +/** Parse a constant. If successful, sp is updated to skip the constant and return true. */ bool Const(const std::string& str, Span<const char>& sp) { if ((size_t)sp.size() >= str.size() && std::equal(str.begin(), str.end(), sp.begin())) { @@ -383,7 +383,7 @@ bool Const(const std::string& str, Span<const char>& sp) return false; } -/** Parse a function call. If succesful, sp is updated to be the function's argument(s). */ +/** Parse a function call. If successful, sp is updated to be the function's argument(s). */ bool Func(const std::string& str, Span<const char>& sp) { if ((size_t)sp.size() >= str.size() + 2 && sp[str.size()] == '(' && sp[sp.size() - 1] == ')' && std::equal(str.begin(), str.end(), sp.begin())) { diff --git a/src/script/descriptor.h b/src/script/descriptor.h index e079c72e92..87e07369c7 100644 --- a/src/script/descriptor.h +++ b/src/script/descriptor.h @@ -22,55 +22,8 @@ // they can be included inside by changing public keys to private keys (WIF // format), and changing xpubs by xprvs. // -// 1. Examples -// -// A P2PK descriptor with a fixed public key: -// - pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798) -// -// A P2SH-P2WSH-P2PKH descriptor with a fixed public key: -// - sh(wsh(pkh(02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13))) -// -// A bare 1-of-2 multisig descriptor: -// - multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc) -// -// A chain of P2PKH outputs (this needs the corresponding private key to derive): -// - pkh(xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw/1'/2/*) -// -// 2. Grammar description: -// -// X: xpub or xprv encoded extended key -// I: decimal encoded integer -// H: Hex encoded byte array -// A: Address in P2PKH, P2SH, or Bech32 encoding -// -// S (Scripts): -// * pk(P): Pay-to-pubkey (P2PK) output for public key P. -// * pkh(P): Pay-to-pubkey-hash (P2PKH) output for public key P. -// * wpkh(P): Pay-to-witness-pubkey-hash (P2WPKH) output for public key P. -// * sh(S): Pay-to-script-hash (P2SH) output for script S -// * wsh(S): Pay-to-witness-script-hash (P2WSH) output for script S -// * combo(P): combination of P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH for public key P. -// * multi(I,L): k-of-n multisig for given public keys -// * addr(A): Output to address -// * raw(H): scriptPubKey with raw bytes -// -// P (Public keys): -// * H: fixed public key (or WIF-encoded private key) -// * E: extended public key -// * E/*: (ranged) all unhardened direct children of an extended public key -// * E/*': (ranged) all hardened direct children of an extended public key -// -// L (Comma-separated lists of public keys): -// * P -// * L,P -// -// E (Extended public keys): -// * X -// * E/I: unhardened child -// * E/I': hardened child -// * E/Ih: hardened child (alternative notation) -// -// The top level is S. +// Reference documentation about the descriptor language can be found in +// doc/descriptors.md. /** Interface for parsed descriptor objects. */ struct Descriptor { diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 23af1bd97f..d779910425 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -50,10 +50,6 @@ static bool GetCScript(const SigningProvider& provider, const SignatureData& sig static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, const CKeyID& address, CPubKey& pubkey) { - if (provider.GetPubKey(address, pubkey)) { - sigdata.misc_pubkeys.emplace(pubkey.GetID(), pubkey); - return true; - } // Look for pubkey in all partial sigs const auto it = sigdata.signatures.find(address); if (it != sigdata.signatures.end()) { @@ -63,7 +59,15 @@ static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, c // Look for pubkey in pubkey list const auto& pk_it = sigdata.misc_pubkeys.find(address); if (pk_it != sigdata.misc_pubkeys.end()) { - pubkey = pk_it->second; + pubkey = pk_it->second.first; + return true; + } + // Query the underlying provider + if (provider.GetPubKey(address, pubkey)) { + KeyOriginInfo info; + if (provider.GetKeyOrigin(address, info)) { + sigdata.misc_pubkeys.emplace(address, std::make_pair(pubkey, std::move(info))); + } return true; } return false; @@ -232,7 +236,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato return sigdata.complete; } -bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash) +bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash) { // if this input has a final scriptsig or scriptwitness, don't do anything with it if (!input.final_script_sig.empty() || !input.final_script_witness.IsNull()) { @@ -240,6 +244,7 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t } // Fill SignatureData with input info + SignatureData sigdata; input.FillSignatureData(sigdata); // Get UTXO @@ -271,6 +276,16 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t // Verify that a witness signature was produced in case one was required. if (require_witness_sig && !sigdata.witness) return false; input.FromSignatureData(sigdata); + + // If both UTXO types are present, drop the unnecessary one. + if (input.non_witness_utxo && !input.witness_utxo.IsNull()) { + if (sigdata.witness) { + input.non_witness_utxo = nullptr; + } else { + input.witness_utxo.SetNull(); + } + } + return sig_complete; } @@ -541,7 +556,7 @@ void PSBTInput::FillSignatureData(SignatureData& sigdata) const sigdata.witness_script = witness_script; } for (const auto& key_pair : hd_keypaths) { - sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair.first); + sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); } } @@ -569,6 +584,9 @@ void PSBTInput::FromSignatureData(const SignatureData& sigdata) if (witness_script.empty() && !sigdata.witness_script.empty()) { witness_script = sigdata.witness_script; } + for (const auto& entry : sigdata.misc_pubkeys) { + hd_keypaths.emplace(entry.second); + } } void PSBTInput::Merge(const PSBTInput& input) @@ -610,7 +628,7 @@ void PSBTOutput::FillSignatureData(SignatureData& sigdata) const sigdata.witness_script = witness_script; } for (const auto& key_pair : hd_keypaths) { - sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair.first); + sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); } } @@ -622,6 +640,9 @@ void PSBTOutput::FromSignatureData(const SignatureData& sigdata) if (witness_script.empty() && !sigdata.witness_script.empty()) { witness_script = sigdata.witness_script; } + for (const auto& entry : sigdata.misc_pubkeys) { + hd_keypaths.emplace(entry.second); + } } bool PSBTOutput::IsNull() const @@ -638,14 +659,26 @@ void PSBTOutput::Merge(const PSBTOutput& output) if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script; } -bool PublicOnlySigningProvider::GetCScript(const CScriptID &scriptid, CScript& script) const +bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return m_provider->GetCScript(scriptid, script); } -bool PublicOnlySigningProvider::GetPubKey(const CKeyID &address, CPubKey& pubkey) const +bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const +{ + return m_provider->GetPubKey(keyid, pubkey); +} + +bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const +{ + if (m_hide_secret) return false; + return m_provider->GetKey(keyid, key); +} + +bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { - return m_provider->GetPubKey(address, pubkey); + if (m_hide_origin) return false; + return m_provider->GetKeyOrigin(keyid, info); } bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); } diff --git a/src/script/sign.h b/src/script/sign.h index 7ade715ee2..18b7320998 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -20,6 +20,12 @@ class CTransaction; struct CMutableTransaction; +struct KeyOriginInfo +{ + unsigned char fingerprint[4]; + std::vector<uint32_t> path; +}; + /** An interface to be implemented by keystores that support signing. */ class SigningProvider { @@ -28,19 +34,24 @@ public: virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; } virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; } virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; } + virtual bool GetKeyOrigin(const CKeyID& id, KeyOriginInfo& info) const { return false; } }; extern const SigningProvider& DUMMY_SIGNING_PROVIDER; -class PublicOnlySigningProvider : public SigningProvider +class HidingSigningProvider : public SigningProvider { private: + const bool m_hide_secret; + const bool m_hide_origin; const SigningProvider* m_provider; public: - PublicOnlySigningProvider(const SigningProvider* provider) : m_provider(provider) {} - bool GetCScript(const CScriptID &scriptid, CScript& script) const; - bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const; + HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {} + bool GetCScript(const CScriptID& scriptid, CScript& script) const override; + bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override; + bool GetKey(const CKeyID& keyid, CKey& key) const override; + bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; }; struct FlatSigningProvider final : public SigningProvider @@ -98,7 +109,7 @@ struct SignatureData { CScript witness_script; ///< The witnessScript (if any) for the input. witnessScripts are used in P2WSH outputs. CScriptWitness scriptWitness; ///< The scriptWitness of an input. Contains complete signatures or the traditional partial signatures format. scriptWitness is part of a transaction input per BIP 144. std::map<CKeyID, SigPair> signatures; ///< BIP 174 style partial signatures for the input. May contain all signatures necessary for producing a final scriptSig or scriptWitness. - std::map<CKeyID, CPubKey> misc_pubkeys; + std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> misc_pubkeys; SignatureData() {} explicit SignatureData(const CScript& script) : scriptSig(script) {} @@ -155,7 +166,7 @@ void UnserializeFromVector(Stream& s, X&... args) // Deserialize HD keypaths into a map template<typename Stream> -void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths) +void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, KeyOriginInfo>& hd_keypaths) { // Make sure that the key is the size of pubkey + 1 if (key.size() != CPubKey::PUBLIC_KEY_SIZE + 1 && key.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1) { @@ -172,25 +183,31 @@ void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std // Read in key path uint64_t value_len = ReadCompactSize(s); - std::vector<uint32_t> keypath; - for (unsigned int i = 0; i < value_len; i += sizeof(uint32_t)) { + if (value_len % 4 || value_len == 0) { + throw std::ios_base::failure("Invalid length for HD key path"); + } + + KeyOriginInfo keypath; + s >> keypath.fingerprint; + for (unsigned int i = 4; i < value_len; i += sizeof(uint32_t)) { uint32_t index; s >> index; - keypath.push_back(index); + keypath.path.push_back(index); } // Add to map - hd_keypaths.emplace(pubkey, keypath); + hd_keypaths.emplace(pubkey, std::move(keypath)); } // Serialize HD keypaths to a stream from a map template<typename Stream> -void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths, uint8_t type) +void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, KeyOriginInfo>& hd_keypaths, uint8_t type) { for (auto keypath_pair : hd_keypaths) { SerializeToVector(s, type, MakeSpan(keypath_pair.first)); - WriteCompactSize(s, keypath_pair.second.size() * sizeof(uint32_t)); - for (auto& path : keypath_pair.second) { + WriteCompactSize(s, (keypath_pair.second.path.size() + 1) * sizeof(uint32_t)); + s << keypath_pair.second.fingerprint; + for (const auto& path : keypath_pair.second.path) { s << path; } } @@ -205,7 +222,7 @@ struct PSBTInput CScript witness_script; CScript final_script_sig; CScriptWitness final_script_witness; - std::map<CPubKey, std::vector<uint32_t>> hd_keypaths; + std::map<CPubKey, KeyOriginInfo> hd_keypaths; std::map<CKeyID, SigPair> partial_sigs; std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown; int sighash_type = 0; @@ -418,7 +435,7 @@ struct PSBTOutput { CScript redeem_script; CScript witness_script; - std::map<CPubKey, std::vector<uint32_t>> hd_keypaths; + std::map<CPubKey, KeyOriginInfo> hd_keypaths; std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown; bool IsNull() const; @@ -687,7 +704,7 @@ bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, C bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType); /** Signs a PSBTInput, verifying that all provided data matches what is being signed. */ -bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash = 1); +bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash = SIGHASH_ALL); /** Extract signature data from a transaction input, and insert it. */ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout); diff --git a/src/streams.h b/src/streams.h index d4a309be3c..dc20f7a9da 100644 --- a/src/streams.h +++ b/src/streams.h @@ -529,7 +529,7 @@ public: explicit BitStreamReader(IStream& istream) : m_istream(istream) {} /** Read the specified number of bits from the stream. The data is returned - * in the nbits least signficant bits of a 64-bit uint. + * in the nbits least significant bits of a 64-bit uint. */ uint64_t Read(int nbits) { if (nbits < 0 || nbits > 64) { diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index 070b3ed80e..8d577cf521 100644 --- a/src/support/lockedpool.cpp +++ b/src/support/lockedpool.cpp @@ -75,7 +75,7 @@ void* Arena::alloc(size_t size) // Create the used-chunk, taking its space from the end of the free-chunk const size_t size_remaining = size_ptr_it->first - size; - auto alloced = chunks_used.emplace(size_ptr_it->second + size_remaining, size).first; + auto allocated = chunks_used.emplace(size_ptr_it->second + size_remaining, size).first; chunks_free_end.erase(size_ptr_it->second + size_ptr_it->first); if (size_ptr_it->first == size) { // whole chunk is used up @@ -88,7 +88,7 @@ void* Arena::alloc(size_t size) } size_to_free_chunk.erase(size_ptr_it); - return reinterpret_cast<void*>(alloced->first); + return reinterpret_cast<void*>(allocated->first); } void Arena::free(void *ptr) diff --git a/src/sync.cpp b/src/sync.cpp index 255eb4f00b..c9aa98dcd6 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -100,7 +100,11 @@ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, } LogPrintf(" %s\n", i.second.ToString()); } - assert(false); + if (g_debug_lockorder_abort) { + fprintf(stderr, "Assertion failed: detected inconsistent lock order at %s:%i, details in debug log.\n", __FILE__, __LINE__); + abort(); + } + throw std::logic_error("potential deadlock detected"); } static void push_lock(void* c, const CLockLocation& locklocation) @@ -189,4 +193,6 @@ void DeleteLock(void* cs) } } +bool g_debug_lockorder_abort = true; + #endif /* DEBUG_LOCKORDER */ diff --git a/src/sync.h b/src/sync.h index 11c1253757..40709bdd7f 100644 --- a/src/sync.h +++ b/src/sync.h @@ -46,14 +46,42 @@ LEAVE_CRITICAL_SECTION(mutex); // no RAII // // /////////////////////////////// +#ifdef DEBUG_LOCKORDER +void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); +void LeaveCritical(); +std::string LocksHeld(); +void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) ASSERT_EXCLUSIVE_LOCK(cs); +void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); +void DeleteLock(void* cs); + /** - * Template mixin that adds -Wthread-safety locking - * annotations to a subset of the mutex API. + * Call abort() if a potential lock order deadlock bug is detected, instead of + * just logging information and throwing a logic_error. Defaults to true, and + * set to false in DEBUG_LOCKORDER unit tests. + */ +extern bool g_debug_lockorder_abort; +#else +void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} +void static inline LeaveCritical() {} +void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) ASSERT_EXCLUSIVE_LOCK(cs) {} +void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {} +void static inline DeleteLock(void* cs) {} +#endif +#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) +#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs) + +/** + * Template mixin that adds -Wthread-safety locking annotations and lock order + * checking to a subset of the mutex API. */ template <typename PARENT> class LOCKABLE AnnotatedMixin : public PARENT { public: + ~AnnotatedMixin() { + DeleteLock((void*)this); + } + void lock() EXCLUSIVE_LOCK_FUNCTION() { PARENT::lock(); @@ -68,64 +96,36 @@ public: { return PARENT::try_lock(); } -}; -#ifdef DEBUG_LOCKORDER -void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); -void LeaveCritical(); -std::string LocksHeld(); -void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) ASSERT_EXCLUSIVE_LOCK(cs); -void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); -void DeleteLock(void* cs); -#else -void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} -void static inline LeaveCritical() {} -void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) ASSERT_EXCLUSIVE_LOCK(cs) {} -void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {} -void static inline DeleteLock(void* cs) {} -#endif -#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) -#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs) + using UniqueLock = std::unique_lock<PARENT>; +}; /** * Wrapped mutex: supports recursive locking, but no waiting * TODO: We should move away from using the recursive lock by default. */ -class CCriticalSection : public AnnotatedMixin<std::recursive_mutex> -{ -public: - ~CCriticalSection() { - DeleteLock((void*)this); - } -}; +typedef AnnotatedMixin<std::recursive_mutex> CCriticalSection; /** Wrapped mutex: supports waiting but not recursive locking */ -typedef AnnotatedMixin<std::mutex> CWaitableCriticalSection; - -/** Just a typedef for std::condition_variable, can be wrapped later if desired */ -typedef std::condition_variable CConditionVariable; - -/** Just a typedef for std::unique_lock, can be wrapped later if desired */ -typedef std::unique_lock<std::mutex> WaitableLock; +typedef AnnotatedMixin<std::mutex> Mutex; #ifdef DEBUG_LOCKCONTENTION void PrintLockContention(const char* pszName, const char* pszFile, int nLine); #endif -/** Wrapper around std::unique_lock<CCriticalSection> */ -class SCOPED_LOCKABLE CCriticalBlock +/** Wrapper around std::unique_lock style lock for Mutex. */ +template <typename Mutex, typename Base = typename Mutex::UniqueLock> +class SCOPED_LOCKABLE UniqueLock : public Base { private: - std::unique_lock<CCriticalSection> lock; - void Enter(const char* pszName, const char* pszFile, int nLine) { - EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex())); + EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex())); #ifdef DEBUG_LOCKCONTENTION - if (!lock.try_lock()) { + if (!Base::try_lock()) { PrintLockContention(pszName, pszFile, nLine); #endif - lock.lock(); + Base::lock(); #ifdef DEBUG_LOCKCONTENTION } #endif @@ -133,15 +133,15 @@ private: bool TryEnter(const char* pszName, const char* pszFile, int nLine) { - EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true); - lock.try_lock(); - if (!lock.owns_lock()) + EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()), true); + Base::try_lock(); + if (!Base::owns_lock()) LeaveCritical(); - return lock.owns_lock(); + return Base::owns_lock(); } public: - CCriticalBlock(CCriticalSection& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, std::defer_lock) + UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock) { if (fTry) TryEnter(pszName, pszFile, nLine); @@ -149,35 +149,41 @@ public: Enter(pszName, pszFile, nLine); } - CCriticalBlock(CCriticalSection* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) + UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) { if (!pmutexIn) return; - lock = std::unique_lock<CCriticalSection>(*pmutexIn, std::defer_lock); + *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock); if (fTry) TryEnter(pszName, pszFile, nLine); else Enter(pszName, pszFile, nLine); } - ~CCriticalBlock() UNLOCK_FUNCTION() + ~UniqueLock() UNLOCK_FUNCTION() { - if (lock.owns_lock()) + if (Base::owns_lock()) LeaveCritical(); } operator bool() { - return lock.owns_lock(); + return Base::owns_lock(); } }; +template<typename MutexArg> +using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>; + #define PASTE(x, y) x ## y #define PASTE2(x, y) PASTE(x, y) -#define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__) -#define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__) -#define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true) +#define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__) +#define LOCK2(cs1, cs2) \ + DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \ + DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__); +#define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true) +#define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__) #define ENTER_CRITICAL_SECTION(cs) \ { \ diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index d2c7c8cb1d..5131fe8235 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -63,7 +63,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest) CBlock block(BuildBlockTestCase()); LOCK(pool.cs); - pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(block.vtx[2])); + pool.addUnchecked(entry.FromTx(block.vtx[2])); BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); // Do a simple ShortTxIDs RT @@ -163,7 +163,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) CBlock block(BuildBlockTestCase()); LOCK(pool.cs); - pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(block.vtx[2])); + pool.addUnchecked(entry.FromTx(block.vtx[2])); BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); uint256 txhash; @@ -233,7 +233,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) CBlock block(BuildBlockTestCase()); LOCK(pool.cs); - pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(block.vtx[1])); + pool.addUnchecked(entry.FromTx(block.vtx[1])); BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); uint256 txhash; diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp index e3cb05f09e..773de343ea 100644 --- a/src/test/blockfilter_tests.cpp +++ b/src/test/blockfilter_tests.cpp @@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE(gcsfilter_test) BOOST_AUTO_TEST_CASE(blockfilter_basic_test) { - CScript included_scripts[5], excluded_scripts[2]; + CScript included_scripts[5], excluded_scripts[3]; // First two are outputs on a single transaction. included_scripts[0] << std::vector<unsigned char>(0, 65) << OP_CHECKSIG; @@ -67,6 +67,7 @@ BOOST_AUTO_TEST_CASE(blockfilter_basic_test) CMutableTransaction tx_2; tx_2.vout.emplace_back(300, included_scripts[2]); tx_2.vout.emplace_back(0, excluded_scripts[0]); + tx_2.vout.emplace_back(400, excluded_scripts[2]); // Script is empty CBlock block; block.vtx.push_back(MakeTransactionRef(tx_1)); @@ -74,8 +75,9 @@ BOOST_AUTO_TEST_CASE(blockfilter_basic_test) CBlockUndo block_undo; block_undo.vtxundo.emplace_back(); - block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(400, included_scripts[3]), 1000, true); - block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(500, included_scripts[4]), 10000, false); + block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(500, included_scripts[3]), 1000, true); + block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(600, included_scripts[4]), 10000, false); + block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(700, excluded_scripts[2]), 100000, false); BlockFilter block_filter(BlockFilterType::BASIC, block, block_undo); const GCSFilter& filter = block_filter.GetFilter(); diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp index 39d0061c1c..2732598b4f 100644 --- a/src/test/checkqueue_tests.cpp +++ b/src/test/checkqueue_tests.cpp @@ -155,7 +155,7 @@ static void Correct_Queue_range(std::vector<size_t> range) } // Make vChecks here to save on malloc (this test can be slow...) std::vector<FakeCheckCheckCompletion> vChecks; - for (auto i : range) { + for (const size_t i : range) { size_t total = i; FakeCheckCheckCompletion::n_calls = 0; CCheckQueueControl<FakeCheckCheckCompletion> control(small_queue.get()); @@ -253,7 +253,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure) } for (auto times = 0; times < 10; ++times) { - for (bool end_fails : {true, false}) { + for (const bool end_fails : {true, false}) { CCheckQueueControl<FailingCheck> control(fail_queue.get()); { std::vector<FailingCheck> vChecks; diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 63b91b74c0..6f4b5ecd26 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -508,7 +508,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization) Coin cc4; ss4 >> cc4; BOOST_CHECK_MESSAGE(false, "We should have thrown"); - } catch (const std::ios_base::failure& e) { + } catch (const std::ios_base::failure&) { } // Very large scriptPubKey (3*10^9 bytes) past the end of the stream @@ -521,7 +521,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization) Coin cc5; ss5 >> cc5; BOOST_CHECK_MESSAGE(false, "We should have thrown"); - } catch (const std::ios_base::failure& e) { + } catch (const std::ios_base::failure&) { } } @@ -719,7 +719,7 @@ static void CheckAddCoinBase(CAmount base_value, CAmount cache_value, CAmount mo test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, coinbase), coinbase); test.cache.SelfTest(); GetCoinsMapEntry(test.cache.map(), result_value, result_flags); - } catch (std::logic_error& e) { + } catch (std::logic_error&) { result_value = FAIL; result_flags = NO_ENTRY; } @@ -736,7 +736,7 @@ static void CheckAddCoinBase(CAmount base_value, CAmount cache_value, CAmount mo template <typename... Args> static void CheckAddCoin(Args&&... args) { - for (CAmount base_value : {ABSENT, PRUNED, VALUE1}) + for (const CAmount base_value : {ABSENT, PRUNED, VALUE1}) CheckAddCoinBase(base_value, std::forward<Args>(args)...); } @@ -780,7 +780,7 @@ void CheckWriteCoins(CAmount parent_value, CAmount child_value, CAmount expected WriteCoinsViewEntry(test.cache, child_value, child_flags); test.cache.SelfTest(); GetCoinsMapEntry(test.cache.map(), result_value, result_flags); - } catch (std::logic_error& e) { + } catch (std::logic_error&) { result_value = FAIL; result_flags = NO_ENTRY; } @@ -848,10 +848,10 @@ BOOST_AUTO_TEST_CASE(ccoins_write) // they would be too repetitive (the parent cache is never updated in these // cases). The loop below covers these cases and makes sure the parent cache // is always left unchanged. - for (CAmount parent_value : {ABSENT, PRUNED, VALUE1}) - for (CAmount child_value : {ABSENT, PRUNED, VALUE2}) - for (char parent_flags : parent_value == ABSENT ? ABSENT_FLAGS : FLAGS) - for (char child_flags : child_value == ABSENT ? ABSENT_FLAGS : CLEAN_FLAGS) + for (const CAmount parent_value : {ABSENT, PRUNED, VALUE1}) + for (const CAmount child_value : {ABSENT, PRUNED, VALUE2}) + for (const char parent_flags : parent_value == ABSENT ? ABSENT_FLAGS : FLAGS) + for (const char child_flags : child_value == ABSENT ? ABSENT_FLAGS : CLEAN_FLAGS) CheckWriteCoins(parent_value, child_value, parent_value, parent_flags, child_flags, parent_flags); } diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp index ec7aba34ca..dbceb9d2e0 100644 --- a/src/test/cuckoocache_tests.cpp +++ b/src/test/cuckoocache_tests.cpp @@ -82,11 +82,11 @@ static double test_cache(size_t megabytes, double load) */ std::vector<uint256> hashes_insert_copy = hashes; /** Do the insert */ - for (uint256& h : hashes_insert_copy) + for (const uint256& h : hashes_insert_copy) set.insert(h); /** Count the hits */ uint32_t count = 0; - for (uint256& h : hashes) + for (const uint256& h : hashes) count += set.contains(h, false); double hit_rate = ((double)count) / ((double)n_insert); return hit_rate; @@ -323,7 +323,7 @@ static void test_cache_generations() reads.push_back(inserts[i]); for (uint32_t i = n_insert - (n_insert / 4); i < n_insert; ++i) reads.push_back(inserts[i]); - for (auto h : inserts) + for (const auto& h : inserts) c.insert(h); } }; diff --git a/src/test/data/blockfilters.json b/src/test/data/blockfilters.json index 2f00728ff6..134b788eed 100644 --- a/src/test/data/blockfilters.json +++ b/src/test/data/blockfilters.json @@ -3,6 +3,8 @@ [0,"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943","0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000",[],"0000000000000000000000000000000000000000000000000000000000000000","019dfca8","21584579b7eb08997773e5aeff3a7f932700042d0ed2a6129012b7d7ae81b750","Genesis block"], [2,"000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820","0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d235340101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0432e7494d010e062f503253482fffffffff0100f2052a010000002321038a7f6ef1c8ca0c588aa53fa860128077c9e6c11e6830f4d7ee4e763a56b7718fac00000000",[],"d7bdac13a59d745b1add0d2ce852f1a0442e8945fc1bf3848d3cbffd88c24fe1","0174a170","186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0",""], [3,"000000008b896e272758da5297bcd98fdc6d97c9b765ecec401e286dc1fdbe10","0100000020782a005255b657696ea057d5b98f34defcf75196f64f6eeac8026c0000000041ba5afc532aae03151b8aa87b65e1594f97504a768e010c98c0add79216247186e7494dffff001d058dc2b60101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0486e7494d0151062f503253482fffffffff0100f2052a01000000232103f6d9ff4c12959445ca5549c811683bf9c88e637b222dd2e0311154c4c85cf423ac00000000",[],"186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0","016cf7a0","8d63aadf5ab7257cb6d2316a57b16f517bff1c6388f124ec4c04af1212729d2a",""], +[49291,"0000000018b07dca1b28b4b5a119f6d6e71698ce1ed96f143f54179ce177a19c","02000000abfaf47274223ca2fea22797e44498240e482cb4c2f2baea088962f800000000604b5b52c32305b15d7542071d8b04e750a547500005d4010727694b6e72a776e55d0d51ffff001d211806480201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0d038bc0000102062f503253482fffffffff01a078072a01000000232102971dd6034ed0cf52450b608d196c07d6345184fcb14deb277a6b82d526a6163dac0000000001000000081cefd96060ecb1c4fbe675ad8a4f8bdc61d634c52b3a1c4116dee23749fe80ff000000009300493046022100866859c21f306538152e83f115bcfbf59ab4bb34887a88c03483a5dff9895f96022100a6dfd83caa609bf0516debc2bf65c3df91813a4842650a1858b3f61cfa8af249014730440220296d4b818bb037d0f83f9f7111665f49532dfdcbec1e6b784526e9ac4046eaa602204acf3a5cb2695e8404d80bf49ab04828bcbe6fc31d25a2844ced7a8d24afbdff01ffffffff1cefd96060ecb1c4fbe675ad8a4f8bdc61d634c52b3a1c4116dee23749fe80ff020000009400483045022100e87899175991aa008176cb553c6f2badbb5b741f328c9845fcab89f8b18cae2302200acce689896dc82933015e7230e5230d5cff8a1ffe82d334d60162ac2c5b0c9601493046022100994ad29d1e7b03e41731a4316e5f4992f0d9b6e2efc40a1ccd2c949b461175c502210099b69fdc2db00fbba214f16e286f6a49e2d8a0d5ffc6409d87796add475478d601ffffffff1e4a6d2d280ea06680d6cf8788ac90344a9c67cca9b06005bbd6d3f6945c8272010000009500493046022100a27400ba52fd842ce07398a1de102f710a10c5599545e6c95798934352c2e4df022100f6383b0b14c9f64b6718139f55b6b9494374755b86bae7d63f5d3e583b57255a01493046022100fdf543292f34e1eeb1703b264965339ec4a450ec47585009c606b3edbc5b617b022100a5fbb1c8de8aaaa582988cdb23622838e38de90bebcaab3928d949aa502a65d401ffffffff1e4a6d2d280ea06680d6cf8788ac90344a9c67cca9b06005bbd6d3f6945c8272020000009400493046022100ac626ac3051f875145b4fe4cfe089ea895aac73f65ab837b1ac30f5d875874fa022100bc03e79fa4b7eb707fb735b95ff6613ca33adeaf3a0607cdcead4cfd3b51729801483045022100b720b04a5c5e2f61b7df0fcf334ab6fea167b7aaede5695d3f7c6973496adbf1022043328c4cc1cdc3e5db7bb895ccc37133e960b2fd3ece98350f774596badb387201ffffffff23a8733e349c97d6cd90f520fdd084ba15ce0a395aad03cd51370602bb9e5db3010000004a00483045022100e8556b72c5e9c0da7371913a45861a61c5df434dfd962de7b23848e1a28c86ca02205d41ceda00136267281be0974be132ac4cda1459fe2090ce455619d8b91045e901ffffffff6856d609b881e875a5ee141c235e2a82f6b039f2b9babe82333677a5570285a6000000006a473044022040a1c631554b8b210fbdf2a73f191b2851afb51d5171fb53502a3a040a38d2c0022040d11cf6e7b41fe1b66c3d08f6ada1aee07a047cb77f242b8ecc63812c832c9a012102bcfad931b502761e452962a5976c79158a0f6d307ad31b739611dac6a297c256ffffffff6856d609b881e875a5ee141c235e2a82f6b039f2b9babe82333677a5570285a601000000930048304502205b109df098f7e932fbf71a45869c3f80323974a826ee2770789eae178a21bfc8022100c0e75615e53ee4b6e32b9bb5faa36ac539e9c05fa2ae6b6de5d09c08455c8b9601483045022009fb7d27375c47bea23b24818634df6a54ecf72d52e0c1268fb2a2c84f1885de022100e0ed4f15d62e7f537da0d0f1863498f9c7c0c0a4e00e4679588c8d1a9eb20bb801ffffffffa563c3722b7b39481836d5edfc1461f97335d5d1e9a23ade13680d0e2c1c371f030000006c493046022100ecc38ae2b1565643dc3c0dad5e961a5f0ea09cab28d024f92fa05c922924157e022100ebc166edf6fbe4004c72bfe8cf40130263f98ddff728c8e67b113dbd621906a601210211a4ed241174708c07206601b44a4c1c29e5ad8b1f731c50ca7e1d4b2a06dc1fffffffff02d0223a00000000001976a91445db0b779c0b9fa207f12a8218c94fc77aff504588ac80f0fa02000000000000000000",["5221033423007d8f263819a2e42becaaf5b06f34cb09919e06304349d950668209eaed21021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae","52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae","522102a7ae1e0971fc1689bd66d2a7296da3a1662fd21a53c9e38979e0f090a375c12d21022adb62335f41eb4e27056ac37d462cda5ad783fa8e0e526ed79c752475db285d52ae","52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821022adb62335f41eb4e27056ac37d462cda5ad783fa8e0e526ed79c752475db285d52ae","512103b9d1d0e2b4355ec3cdef7c11a5c0beff9e8b8d8372ab4b4e0aaf30e80173001951ae","76a9149144761ebaccd5b4bbdc2a35453585b5637b2f8588ac","522103f1848b40621c5d48471d9784c8174ca060555891ace6d2b03c58eece946b1a9121020ee5d32b54d429c152fdc7b1db84f2074b0564d35400d89d11870f9273ec140c52ae","76a914f4fa1cc7de742d135ea82c17adf0bb9cf5f4fb8388ac"],"ed47705334f4643892ca46396eb3f4196a5e30880589e4009ef38eae895d4a13","0afbc2920af1b027f31f87b592276eb4c32094bb4d3697021b4c6380","b6d98692cec5145f67585f3434ec3c2b3030182e1cb3ec58b855c5c164dfaaa3","Tx pays to empty output script"], +[180480,"00000000fd3ceb2404ff07a785c7fdcc76619edc8ed61bd25134eaa22084366a","020000006058aa080a655aa991a444bd7d1f2defd9a3bbe68aabb69030cf3b4e00000000d2e826bfd7ef0beaa891a7eedbc92cd6a544a6cb61c7bdaa436762eb2123ef9790f5f552ffff001d0002c90f0501000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0300c102024608062f503253482fffffffff01c0c6072a01000000232102e769e60137a4df6b0df8ebd387cca44c4c57ae74cc0114a8e8317c8f3bfd85e9ac00000000010000000381a0802911a01ffb025c4dea0bc77963e8c1bb46313b71164c53f72f37fe5248010000000151ffffffffc904b267833d215e2128bd9575242232ac2bc311550c7fc1f0ef6f264b40d14c010000000151ffffffffdf0915666649dba81886519c531649b7b02180b4af67d6885e871299e9d5f775000000000151ffffffff0180817dcb00000000232103bb52138972c48a132fc1f637858c5189607dd0f7fe40c4f20f6ad65f2d389ba4ac0000000001000000018da38b434fba82d66052af74fc5e4e94301b114d9bc03f819dc876398404c8b4010000006c493046022100fe738b7580dc5fb5168e51fc61b5aed211125eb71068031009a22d9bbad752c5022100be5086baa384d40bcab0fa586e4f728397388d86e18b66cc417dc4f7fa4f9878012103f233299455134caa2687bdf15cb0becdfb03bd0ff2ff38e65ec6b7834295c34fffffffff022ebc1400000000001976a9147779b7fba1c1e06b717069b80ca170e8b04458a488ac9879c40f000000001976a9142a0307cd925dbb66b534c4db33003dd18c57015788ac0000000001000000026139a62e3422a602de36c873a225c1d3ca5aeee598539ceecb9f0dc8d1ad0f83010000006b483045022100ad9f32b4a0a2ddc19b5a74eba78123e57616f1b3cfd72ce68c03ea35a3dda1f002200dbd22aa6da17213df5e70dfc3b2611d40f70c98ed9626aa5e2cde9d97461f0a012103ddb295d2f1e8319187738fb4b230fdd9aa29d0e01647f69f6d770b9ab24eea90ffffffff983c82c87cf020040d671956525014d5c2b28c6d948c85e1a522362c0059eeae010000006b4830450221009ca544274c786d30a5d5d25e17759201ea16d3aedddf0b9e9721246f7ef6b32e02202cfa5564b6e87dfd9fd98957820e4d4e6238baeb0f65fe305d91506bb13f5f4f012103c99113deac0d5d044e3ac0346abc02501542af8c8d3759f1382c72ff84e704f7ffffffff02c0c62d00000000001976a914ae19d27efe12f5a886dc79af37ad6805db6f922d88ac70ce2000000000001976a9143b8d051d37a07ea1042067e93efe63dbf73920b988ac000000000100000002be566e8cd9933f0c75c4a82c027f7d0c544d5c101d0607ef6ae5d07b98e7f1dc000000006b483045022036a8cdfd5ea7ebc06c2bfb6e4f942bbf9a1caeded41680d11a3a9f5d8284abad022100cacb92a5be3f39e8bc14db1710910ef7b395fa1e18f45d41c28d914fcdde33be012102bf59abf110b5131fae0a3ce1ec379329b4c896a6ae5d443edb68529cc2bc7816ffffffff96cf67645b76ceb23fe922874847456a15feee1655082ff32d25a6bf2c0dfc90000000006a47304402203471ca2001784a5ac0abab583581f2613523da47ec5f53df833c117b5abd81500220618a2847723d57324f2984678db556dbca1a72230fc7e39df04c2239942ba942012102925c9794fd7bb9f8b29e207d5fc491b1150135a21f505041858889fa4edf436fffffffff026c840f00000000001976a914797fb8777d7991d8284d88bfd421ce520f0f843188ac00ca9a3b000000001976a9146d10f3f592699265d10b106eda37c3ce793f7a8588ac00000000",["","","","76a9142903b138c24be9e070b3e73ec495d77a204615e788ac","76a91433a1941fd9a37b9821d376f5a51bd4b52fa50e2888ac","76a914e4374e8155d0865742ca12b8d4d14d41b57d682f88ac","76a914001fa7459a6cfc64bdc178ba7e7a21603bb2568f88ac","76a914f6039952bc2b307aeec5371bfb96b66078ec17f688ac"],"b109139671dbedc2b6fcd499a5480a7461ae458af8ff9411d819aa64ba6995d1","0db414c859a07e8205876354a210a75042d0463404913d61a8e068e58a3ae2aa080026","a0af77e0a7ed20ea78d2def3200cc24f08217dcd51755c7c7feb0e2ba8316c2d","Tx spends from empty output script"], [926485,"000000000000015d6077a411a8f5cc95caf775ccf11c54e27df75ce58d187313","0000002060bbab0edbf3ef8a49608ee326f8fd75c473b7e3982095e2d100000000000000c30134f8c9b6d2470488d7a67a888f6fa12f8692e0c3411fbfb92f0f68f67eedae03ca57ef13021acc22dc4105010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2f0315230e0004ae03ca57043e3d1e1d0c8796bf579aef0c0000000000122f4e696e6a61506f6f6c2f5345475749542fffffffff038427a112000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9ed5c748e121c0fe146d973a4ac26fa4a68b0549d46ee22d25f50a5e46fe1b377ee00000000000000002952534b424c4f434b3acd16772ad61a3c5f00287480b720f6035d5e54c9efc71be94bb5e3727f10909001200000000000000000000000000000000000000000000000000000000000000000000000000100000000010145310e878941a1b2bc2d33797ee4d89d95eaaf2e13488063a2aa9a74490f510a0100000023220020b6744de4f6ec63cc92f7c220cdefeeb1b1bed2b66c8e5706d80ec247d37e65a1ffffffff01002d3101000000001976a9143ebc40e411ed3c76f86711507ab952300890397288ac0400473044022001dd489a5d4e2fbd8a3ade27177f6b49296ba7695c40dbbe650ea83f106415fd02200b23a0602d8ff1bdf79dee118205fc7e9b40672bf31563e5741feb53fb86388501483045022100f88f040e90cc5dc6c6189d04718376ac19ed996bf9e4a3c29c3718d90ffd27180220761711f16c9e3a44f71aab55cbc0634907a1fa8bb635d971a9a01d368727bea10169522103b3623117e988b76aaabe3d63f56a4fc88b228a71e64c4cc551d1204822fe85cb2103dd823066e096f72ed617a41d3ca56717db335b1ea47a1b4c5c9dbdd0963acba621033d7c89bd9da29fa8d44db7906a9778b53121f72191184a9fee785c39180e4be153ae00000000010000000120925534261de4dcebb1ed5ab1b62bfe7a3ef968fb111dc2c910adfebc6e3bdf010000006b483045022100f50198f5ae66211a4f485190abe4dc7accdabe3bc214ebc9ea7069b97097d46e0220316a70a03014887086e335fc1b48358d46cd6bdc9af3b57c109c94af76fc915101210316cff587a01a2736d5e12e53551b18d73780b83c3bfb4fcf209c869b11b6415effffffff0220a10700000000001976a91450333046115eaa0ac9e0216565f945070e44573988ac2e7cd01a000000001976a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac00000000010000000203a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322010000006a47304402204efc3d70e4ca3049c2a425025edf22d5ca355f9ec899dbfbbeeb2268533a0f2b02204780d3739653035af4814ea52e1396d021953f948c29754edd0ee537364603dc012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff03a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322000000006a47304402202d96defdc5b4af71d6ba28c9a6042c2d5ee7bc6de565d4db84ef517445626e03022022da80320e9e489c8f41b74833dfb6a54a4eb5087cdb46eb663eef0b25caa526012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a914b7e6f7ff8658b2d1fb107e3d7be7af4742e6b1b3876f88fc00000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac0000000001000000043ffd60d3818431c495b89be84afac205d5d1ed663009291c560758bbd0a66df5010000006b483045022100f344607de9df42049688dcae8ff1db34c0c7cd25ec05516e30d2bc8f12ac9b2f022060b648f6a21745ea6d9782e17bcc4277b5808326488a1f40d41e125879723d3a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffffa5379401cce30f84731ef1ba65ce27edf2cc7ce57704507ebe8714aa16a96b92010000006a473044022020c37a63bf4d7f564c2192528709b6a38ab8271bd96898c6c2e335e5208661580220435c6f1ad4d9305d2c0a818b2feb5e45d443f2f162c0f61953a14d097fd07064012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff70e731e193235ff12c3184510895731a099112ffca4b00246c60003c40f843ce000000006a473044022053760f74c29a879e30a17b5f03a5bb057a5751a39f86fa6ecdedc36a1b7db04c022041d41c9b95f00d2d10a0373322a9025dba66c942196bc9d8adeb0e12d3024728012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff66b7a71b3e50379c8e85fc18fe3f1a408fc985f257036c34702ba205cef09f6f000000006a4730440220499bf9e2db3db6e930228d0661395f65431acae466634d098612fd80b08459ee022040e069fc9e3c60009f521cef54c38aadbd1251aee37940e6018aadb10f194d6a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a9148fc37ad460fdfbd2b44fe446f6e3071a4f64faa6878f447f0b000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac00000000",["a914feb8a29635c56d9cd913122f90678756bf23887687","76a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac"],"da49977ba1ee0d620a2c4f8f646b03cd0d230f5c6c994722e3ba884889f0be1a","09027acea61b6cc3fb33f5d52f7d088a6b2f75d234e89ca800","4cd9dd007a325199102f1fc0b7d77ca25ee3c84d46018c4353ecfcb56c0d3e7a","Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"], [987876,"0000000000000c00901f2049055e2a437c819d79a3d54fd63e6af796cd7b8a79","000000202694f74969fdb542090e95a56bc8aa2d646e27033850e32f1c5f000000000000f7e53676b3f12d5beb524ed617f2d25f5a93b5f4f52c1ba2678260d72712f8dd0a6dfe5740257e1a4b1768960101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1603e4120ff9c30a1c216900002f424d4920546573742fffffff0001205fa012000000001e76a914c486de584a735ec2f22da7cd9681614681f92173d83d0aa68688ac00000000",[],"e9d729b72d533c29abe5276d5cf6c152f3723f10efe000b1e0c9ca5265a8beb6","010c0b40","e6137ae5a8424c40da1e5023c16975cc97b09300b4c050e6b1c713add3836c40","Coinbase tx has unparseable output script"], [1263442,"000000006f27ddfe1dd680044a34548f41bed47eba9e6f0b310da21423bc5f33","000000201c8d1a529c39a396db2db234d5ec152fa651a2872966daccbde028b400000000083f14492679151dbfaa1a825ef4c18518e780c1f91044180280a7d33f4a98ff5f45765aaddc001d38333b9a02010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff230352471300fe5f45765afe94690a000963676d696e6572343208000000000000000000ffffffff024423a804000000001976a914f2c25ac3d59f3d674b1d1d0a25c27339aaac0ba688ac0000000000000000266a24aa21a9edcb26cb3052426b9ebb4d19c819ef87c19677bbf3a7c46ef0855bd1b2abe83491012000000000000000000000000000000000000000000000000000000000000000000000000002000000000101d20978463906ba4ff5e7192494b88dd5eb0de85d900ab253af909106faa22cc5010000000004000000014777ff000000000016001446c29eabe8208a33aa1023c741fa79aa92e881ff0347304402207d7ca96134f2bcfdd6b536536fdd39ad17793632016936f777ebb32c22943fda02206014d2fb8a6aa58279797f861042ba604ebd2f8f61e5bddbd9d3be5a245047b201004b632103eeaeba7ce5dc2470221e9517fb498e8d6bd4e73b85b8be655196972eb9ccd5566754b2752103a40b74d43df244799d041f32ce1ad515a6cd99501701540e38750d883ae21d3a68ac00000000",["002027a5000c7917f785d8fc6e5a55adfca8717ecb973ebb7743849ff956d896a7ed"],"a4a4d6c6034da8aa06f01fe71f1fffbd79e032006b07f6c7a2c60a66aa310c01","0385acb4f0fe889ef0","3588f34fbbc11640f9ed40b2a66a4e096215d50389691309c1dac74d4268aa81","Includes witness data"] diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 4dff1e5c72..9957ac074b 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -26,7 +26,7 @@ BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(dbwrapper) { // Perform tests both obfuscated and non-obfuscated. - for (bool obfuscate : {false, true}) { + for (const bool obfuscate : {false, true}) { fs::path ph = SetDataDir(std::string("dbwrapper").append(obfuscate ? "_true" : "_false")); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); char key = 'k'; @@ -46,7 +46,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper) BOOST_AUTO_TEST_CASE(dbwrapper_batch) { // Perform tests both obfuscated and non-obfuscated. - for (bool obfuscate : {false, true}) { + for (const bool obfuscate : {false, true}) { fs::path ph = SetDataDir(std::string("dbwrapper_batch").append(obfuscate ? "_true" : "_false")); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); @@ -82,7 +82,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch) BOOST_AUTO_TEST_CASE(dbwrapper_iterator) { // Perform tests both obfuscated and non-obfuscated. - for (bool obfuscate : {false, true}) { + for (const bool obfuscate : {false, true}) { fs::path ph = SetDataDir(std::string("dbwrapper_iterator").append(obfuscate ? "_true" : "_false")); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); @@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(iterator_ordering) if (x & 1) BOOST_CHECK(dbw.Write(key, value)); } - for (int seek_start : {0x00, 0x80}) { + for (const int seek_start : {0x00, 0x80}) { it->Seek((uint8_t)seek_start); for (unsigned int x=seek_start; x<255; ++x) { uint8_t key; @@ -262,7 +262,7 @@ struct StringContentsSerializer { try { READWRITE(c); str.push_back(c); - } catch (const std::ios_base::failure& e) { + } catch (const std::ios_base::failure&) { break; } } @@ -291,7 +291,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering) } std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator()); - for (int seek_start : {0, 5}) { + for (const int seek_start : {0, 5}) { snprintf(buf, sizeof(buf), "%d", seek_start); StringContentsSerializer seek_key(buf); it->Seek(seek_key); diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index fdf7397bff..52bbe96b96 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -31,7 +31,8 @@ struct COrphanTx { NodeId fromPeer; int64_t nTimeExpire; }; -extern std::map<uint256, COrphanTx> mapOrphanTransactions; +extern CCriticalSection g_cs_orphans; +extern std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(g_cs_orphans); static CService ip(uint32_t i) { @@ -324,7 +325,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) static CTransactionRef RandomOrphan() { std::map<uint256, COrphanTx>::iterator it; - LOCK(cs_main); + LOCK2(cs_main, g_cs_orphans); it = mapOrphanTransactions.lower_bound(InsecureRand256()); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); @@ -394,7 +395,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) BOOST_CHECK(!AddOrphanTx(MakeTransactionRef(tx), i)); } - LOCK(cs_main); + LOCK2(cs_main, g_cs_orphans); // Test EraseOrphansFor: for (NodeId i = 0; i < 3; i++) { diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index f189222be8..e739b84a48 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -64,7 +64,7 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std: BOOST_CHECK_EQUAL(pub, pub2); // Check that both can be serialized with private key back to the private version, but not without private key. - std::string prv1, prv2; + std::string prv1; BOOST_CHECK(parse_priv->ToPrivateString(keys_priv, prv1)); BOOST_CHECK_EQUAL(prv, prv1); BOOST_CHECK(!parse_priv->ToPrivateString(keys_pub, prv1)); diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index eec7b38af7..7592330b10 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -24,7 +24,7 @@ static void ResetArgs(const std::string& strArg) // Convert to char*: std::vector<const char*> vecChar; - for (std::string& s : vecArg) + for (const std::string& s : vecArg) vecChar.push_back(s.c_str()); std::string error; diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp index 7e475ac610..a0c10d8ddd 100644 --- a/src/test/key_io_tests.cpp +++ b/src/test/key_io_tests.cpp @@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(key_io_invalid) std::string exp_base58string = test[0].get_str(); // must be invalid as public and as private key - for (auto chain : { CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::REGTEST }) { + for (const auto& chain : { CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::REGTEST }) { SelectParams(chain); destination = DecodeDestination(exp_base58string); BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey in mainnet:" + strTest); diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index e416de098e..0e15464fd9 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -63,17 +63,17 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) BOOST_CHECK_EQUAL(testPool.size(), poolSize); // Just the parent: - testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); + testPool.addUnchecked(entry.FromTx(txParent)); poolSize = testPool.size(); testPool.removeRecursive(txParent); BOOST_CHECK_EQUAL(testPool.size(), poolSize - 1); // Parent, children, grandchildren: - testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); + testPool.addUnchecked(entry.FromTx(txParent)); for (int i = 0; i < 3; i++) { - testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i])); - testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); + testPool.addUnchecked(entry.FromTx(txChild[i])); + testPool.addUnchecked(entry.FromTx(txGrandChild[i])); } // Remove Child[0], GrandChild[0] should be removed: poolSize = testPool.size(); @@ -95,8 +95,8 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) // Add children and grandchildren, but NOT the parent (simulate the parent being in a block) for (int i = 0; i < 3; i++) { - testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i])); - testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); + testPool.addUnchecked(entry.FromTx(txChild[i])); + testPool.addUnchecked(entry.FromTx(txGrandChild[i])); } // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be // put into the mempool (maybe because it is non-standard): @@ -128,28 +128,28 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1)); /* highest fee */ CMutableTransaction tx2 = CMutableTransaction(); tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx2.vout[0].nValue = 2 * COIN; - pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2)); + pool.addUnchecked(entry.Fee(20000LL).FromTx(tx2)); /* lowest fee */ CMutableTransaction tx3 = CMutableTransaction(); tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx3.vout[0].nValue = 5 * COIN; - pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3)); + pool.addUnchecked(entry.Fee(0LL).FromTx(tx3)); /* 2nd highest fee */ CMutableTransaction tx4 = CMutableTransaction(); tx4.vout.resize(1); tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx4.vout[0].nValue = 6 * COIN; - pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4)); + pool.addUnchecked(entry.Fee(15000LL).FromTx(tx4)); /* equal fee rate to tx1, but newer */ CMutableTransaction tx5 = CMutableTransaction(); @@ -157,7 +157,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx5.vout[0].nValue = 11 * COIN; entry.nTime = 1; - pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx5)); BOOST_CHECK_EQUAL(pool.size(), 5U); std::vector<std::string> sortedOrder; @@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx6.vout.resize(1); tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx6.vout[0].nValue = 20 * COIN; - pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6)); + pool.addUnchecked(entry.Fee(0LL).FromTx(tx6)); BOOST_CHECK_EQUAL(pool.size(), 6U); // Check that at this point, tx6 is sorted low sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString()); @@ -198,7 +198,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); BOOST_CHECK(setAncestorsCalculated == setAncestors); - pool.addUnchecked(tx7.GetHash(), entry.FromTx(tx7), setAncestors); + pool.addUnchecked(entry.FromTx(tx7), setAncestors); BOOST_CHECK_EQUAL(pool.size(), 7U); // Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ... @@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx8.vout[0].nValue = 10 * COIN; setAncestors.insert(pool.mapTx.find(tx7.GetHash())); - pool.addUnchecked(tx8.GetHash(), entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors); + pool.addUnchecked(entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors); // Now tx8 should be sorted low, but tx6/tx both high sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString()); @@ -230,7 +230,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx9.vout.resize(1); tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx9.vout[0].nValue = 1 * COIN; - pool.addUnchecked(tx9.GetHash(), entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors); + pool.addUnchecked(entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors); // tx9 should be sorted low BOOST_CHECK_EQUAL(pool.size(), 9U); @@ -256,7 +256,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(4).FromTx(tx10), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); BOOST_CHECK(setAncestorsCalculated == setAncestors); - pool.addUnchecked(tx10.GetHash(), entry.FromTx(tx10), setAncestors); + pool.addUnchecked(entry.FromTx(tx10), setAncestors); /** * tx8 and tx9 should both now be sorted higher @@ -301,14 +301,14 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1)); /* highest fee */ CMutableTransaction tx2 = CMutableTransaction(); tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx2.vout[0].nValue = 2 * COIN; - pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2)); + pool.addUnchecked(entry.Fee(20000LL).FromTx(tx2)); uint64_t tx2Size = GetVirtualTransactionSize(tx2); /* lowest fee */ @@ -316,21 +316,21 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx3.vout[0].nValue = 5 * COIN; - pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3)); + pool.addUnchecked(entry.Fee(0LL).FromTx(tx3)); /* 2nd highest fee */ CMutableTransaction tx4 = CMutableTransaction(); tx4.vout.resize(1); tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx4.vout[0].nValue = 6 * COIN; - pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4)); + pool.addUnchecked(entry.Fee(15000LL).FromTx(tx4)); /* equal fee rate to tx1, but newer */ CMutableTransaction tx5 = CMutableTransaction(); tx5.vout.resize(1); tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx5.vout[0].nValue = 11 * COIN; - pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx5)); BOOST_CHECK_EQUAL(pool.size(), 5U); std::vector<std::string> sortedOrder; @@ -359,7 +359,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) tx6.vout[0].nValue = 20 * COIN; uint64_t tx6Size = GetVirtualTransactionSize(tx6); - pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6)); + pool.addUnchecked(entry.Fee(0LL).FromTx(tx6)); BOOST_CHECK_EQUAL(pool.size(), 6U); // Ties are broken by hash if (tx3.GetHash() < tx6.GetHash()) @@ -381,7 +381,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) /* set the fee to just below tx2's feerate when including ancestor */ CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1; - pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7)); + pool.addUnchecked(entry.Fee(fee).FromTx(tx7)); BOOST_CHECK_EQUAL(pool.size(), 7U); sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString()); CheckSort<ancestor_score>(pool, sortedOrder); @@ -413,7 +413,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) // Check that we sort by min(feerate, ancestor_feerate): // set the fee so that the ancestor feerate is above tx1/5, // but the transaction's own feerate is lower - pool.addUnchecked(tx8.GetHash(), entry.Fee(5000LL).FromTx(tx8)); + pool.addUnchecked(entry.Fee(5000LL).FromTx(tx8)); sortedOrder.insert(sortedOrder.end()-1, tx8.GetHash().ToString()); CheckSort<ancestor_score>(pool, sortedOrder); } @@ -431,7 +431,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1)); CMutableTransaction tx2 = CMutableTransaction(); tx2.vin.resize(1); @@ -439,7 +439,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL; tx2.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2)); + pool.addUnchecked(entry.Fee(5000LL).FromTx(tx2)); pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing BOOST_CHECK(pool.exists(tx1.GetHash())); @@ -449,7 +449,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) BOOST_CHECK(pool.exists(tx1.GetHash())); BOOST_CHECK(!pool.exists(tx2.GetHash())); - pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2)); + pool.addUnchecked(entry.FromTx(tx2)); CMutableTransaction tx3 = CMutableTransaction(); tx3.vin.resize(1); tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0); @@ -457,7 +457,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL; tx3.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3)); + pool.addUnchecked(entry.Fee(20000LL).FromTx(tx3)); pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP) BOOST_CHECK(!pool.exists(tx1.GetHash())); @@ -520,10 +520,10 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL; tx7.vout[1].nValue = 10 * COIN; - pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4)); - pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5)); - pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6)); - pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7)); + pool.addUnchecked(entry.Fee(7000LL).FromTx(tx4)); + pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5)); + pool.addUnchecked(entry.Fee(1100LL).FromTx(tx6)); + pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7)); // we only require this to remove, at max, 2 txn, because it's not clear what we're really optimizing for aside from that pool.TrimToSize(pool.DynamicMemoryUsage() - 1); @@ -532,8 +532,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) BOOST_CHECK(!pool.exists(tx7.GetHash())); if (!pool.exists(tx5.GetHash())) - pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5)); - pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7)); + pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5)); + pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7)); pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7 BOOST_CHECK(pool.exists(tx4.GetHash())); @@ -541,8 +541,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) BOOST_CHECK(pool.exists(tx6.GetHash())); BOOST_CHECK(!pool.exists(tx7.GetHash())); - pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5)); - pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7)); + pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5)); + pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7)); std::vector<CTransactionRef> vtx; SetMockTime(42); @@ -603,7 +603,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // [tx1] // CTransactionRef tx1 = make_tx(/* output_values */ {10 * COIN}); - pool.addUnchecked(tx1->GetHash(), entry.Fee(10000LL).FromTx(tx1)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1)); // Ancestors / descendants should be 1 / 1 (itself / itself) pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants); @@ -615,7 +615,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // [tx1].0 <- [tx2] // CTransactionRef tx2 = make_tx(/* output_values */ {495 * CENT, 5 * COIN}, /* inputs */ {tx1}); - pool.addUnchecked(tx2->GetHash(), entry.Fee(10000LL).FromTx(tx2)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx2)); // Ancestors / descendants should be: // transaction ancestors descendants @@ -634,7 +634,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // [tx1].0 <- [tx2].0 <- [tx3] // CTransactionRef tx3 = make_tx(/* output_values */ {290 * CENT, 200 * CENT}, /* inputs */ {tx2}); - pool.addUnchecked(tx3->GetHash(), entry.Fee(10000LL).FromTx(tx3)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx3)); // Ancestors / descendants should be: // transaction ancestors descendants @@ -659,7 +659,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // \---1 <- [tx4] // CTransactionRef tx4 = make_tx(/* output_values */ {290 * CENT, 250 * CENT}, /* inputs */ {tx2}, /* input_indices */ {1}); - pool.addUnchecked(tx4->GetHash(), entry.Fee(10000LL).FromTx(tx4)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx4)); // Ancestors / descendants should be: // transaction ancestors descendants @@ -696,13 +696,13 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) CTransactionRef& tyi = *ty[i]; tyi = make_tx(/* output_values */ {v}, /* inputs */ i > 0 ? std::vector<CTransactionRef>{*ty[i - 1]} : std::vector<CTransactionRef>{}); v -= 50 * CENT; - pool.addUnchecked(tyi->GetHash(), entry.Fee(10000LL).FromTx(tyi)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tyi)); pool.GetTransactionAncestry(tyi->GetHash(), ancestors, descendants); BOOST_CHECK_EQUAL(ancestors, i+1); BOOST_CHECK_EQUAL(descendants, i+1); } CTransactionRef ty6 = make_tx(/* output_values */ {5 * COIN}, /* inputs */ {tx3, ty5}); - pool.addUnchecked(ty6->GetHash(), entry.Fee(10000LL).FromTx(ty6)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(ty6)); // Ancestors / descendants should be: // transaction ancestors descendants diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 2b9641b6d4..eb0e4219d3 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -29,7 +29,7 @@ BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup) // BOOST_CHECK_EXCEPTION predicates to check the specific validation error class HasReason { public: - HasReason(const std::string& reason) : m_reason(reason) {} + explicit HasReason(const std::string& reason) : m_reason(reason) {} bool operator() (const std::runtime_error& e) const { return std::string(e.what()).find(m_reason) != std::string::npos; }; @@ -115,19 +115,19 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vout[0].nValue = 5000000000LL - 1000; // This tx has a low fee: 1000 satoshis uint256 hashParentTx = tx.GetHash(); // save this txid for later use - mempool.addUnchecked(hashParentTx, entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a medium fee: 10000 satoshis tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = 5000000000LL - 10000; uint256 hashMediumFeeTx = tx.GetHash(); - mempool.addUnchecked(hashMediumFeeTx, entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a high fee, but depends on the first transaction tx.vin[0].prevout.hash = hashParentTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee uint256 hashHighFeeTx = tx.GetHash(); - mempool.addUnchecked(hashHighFeeTx, entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + mempool.addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx); @@ -138,7 +138,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vin[0].prevout.hash = hashHighFeeTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee uint256 hashFreeTx = tx.GetHash(); - mempool.addUnchecked(hashFreeTx, entry.Fee(0).FromTx(tx)); + mempool.addUnchecked(entry.Fee(0).FromTx(tx)); size_t freeTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); // Calculate a fee on child transaction that will put the package just @@ -148,7 +148,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vin[0].prevout.hash = hashFreeTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse; uint256 hashLowFeeTx = tx.GetHash(); - mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse).FromTx(tx)); + mempool.addUnchecked(entry.Fee(feeToUse).FromTx(tx)); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); // Verify that the free tx and the low fee tx didn't get selected for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { @@ -162,7 +162,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& mempool.removeRecursive(tx); tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee hashLowFeeTx = tx.GetHash(); - mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse+2).FromTx(tx)); + mempool.addUnchecked(entry.Fee(feeToUse+2).FromTx(tx)); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx); @@ -175,7 +175,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vout[0].nValue = 5000000000LL - 100000000; tx.vout[1].nValue = 100000000; // 1BTC output uint256 hashFreeTx2 = tx.GetHash(); - mempool.addUnchecked(hashFreeTx2, entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); // This tx can't be mined by itself tx.vin[0].prevout.hash = hashFreeTx2; @@ -183,7 +183,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& feeToUse = blockMinFeeRate.GetFee(freeTxSize); tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse; uint256 hashLowFeeTx2 = tx.GetHash(); - mempool.addUnchecked(hashLowFeeTx2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); + mempool.addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); // Verify that this tx isn't selected. @@ -196,7 +196,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& // as well. tx.vin[0].prevout.n = 1; tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee - mempool.addUnchecked(tx.GetHash(), entry.Fee(10000).FromTx(tx)); + mempool.addUnchecked(entry.Fee(10000).FromTx(tx)); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2); } @@ -277,7 +277,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) hash = tx.GetHash(); bool spendsCoinbase = i == 0; // only first tx spends coinbase // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } @@ -292,7 +292,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) hash = tx.GetHash(); bool spendsCoinbase = i == 0; // only first tx spends coinbase // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); tx.vin[0].prevout.hash = hash; } BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); @@ -312,7 +312,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue -= LOWFEE; hash = tx.GetHash(); bool spendsCoinbase = i == 0; // only first tx spends coinbase - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); @@ -320,7 +320,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // orphan in mempool, template creation fails hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); mempool.clear(); @@ -329,7 +329,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin.resize(2); tx.vin[1].scriptSig = CScript() << OP_1; @@ -337,7 +337,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[1].prevout.n = 0; tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); mempool.clear(); @@ -348,7 +348,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 0; hash = tx.GetHash(); // give it a fee so it'll get mined - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); // Should throw bad-cb-multiple BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple")); mempool.clear(); @@ -359,10 +359,10 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE; tx.vout[0].scriptPubKey = CScript() << OP_1; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); mempool.clear(); @@ -401,12 +401,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) script = CScript() << OP_0; tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script)); hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end()); tx.vout[0].nValue -= LOWFEE; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); // Should throw block-validation-failed BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed")); mempool.clear(); @@ -440,7 +440,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].scriptPubKey = CScript() << OP_1; tx.nLockTime = 0; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 2))); // Sequence locks pass on 2nd block @@ -450,7 +450,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((chainActive.Tip()->GetMedianTimePast()+1-chainActive[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block prevheights[0] = baseheight + 2; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail @@ -466,7 +466,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) prevheights[0] = baseheight + 3; tx.nLockTime = chainActive.Tip()->nHeight + 1; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(!CheckFinalTx(tx, flags)); // Locktime fails BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast())); // Locktime passes on 2nd block @@ -477,7 +477,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) prevheights.resize(1); prevheights[0] = baseheight + 4; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(!CheckFinalTx(tx, flags)); // Locktime fails BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 4c56938ec9..eaa8b16182 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read) unsigned char pchMsgTmp[4]; ssPeers1 >> pchMsgTmp; ssPeers1 >> addrman1; - } catch (const std::exception& e) { + } catch (const std::exception&) { exceptionThrown = true; } @@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted) unsigned char pchMsgTmp[4]; ssPeers1 >> pchMsgTmp; ssPeers1 >> addrman1; - } catch (const std::exception& e) { + } catch (const std::exception&) { exceptionThrown = true; } // Even through de-serialization failed addrman is not left in a clean state. diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 9c1af6bdf6..8072eb922d 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -302,4 +302,22 @@ BOOST_AUTO_TEST_CASE(netbase_getgroup) BOOST_CHECK(CreateInternal("baz.net").GetGroup() == internal_group); } +BOOST_AUTO_TEST_CASE(netbase_parsenetwork) +{ + BOOST_CHECK_EQUAL(ParseNetwork("ipv4"), NET_IPV4); + BOOST_CHECK_EQUAL(ParseNetwork("ipv6"), NET_IPV6); + BOOST_CHECK_EQUAL(ParseNetwork("onion"), NET_ONION); + BOOST_CHECK_EQUAL(ParseNetwork("tor"), NET_ONION); + + BOOST_CHECK_EQUAL(ParseNetwork("IPv4"), NET_IPV4); + BOOST_CHECK_EQUAL(ParseNetwork("IPv6"), NET_IPV6); + BOOST_CHECK_EQUAL(ParseNetwork("ONION"), NET_ONION); + BOOST_CHECK_EQUAL(ParseNetwork("TOR"), NET_ONION); + + BOOST_CHECK_EQUAL(ParseNetwork(":)"), NET_UNROUTABLE); + BOOST_CHECK_EQUAL(ParseNetwork("tÖr"), NET_UNROUTABLE); + BOOST_CHECK_EQUAL(ParseNetwork("\xfe\xff"), NET_UNROUTABLE); + BOOST_CHECK_EQUAL(ParseNetwork(""), NET_UNROUTABLE); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp index 26a0b495d9..2022ed6659 100644 --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 4; k++) { // add 4 fee txs tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique uint256 hash = tx.GetHash(); - mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); + mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); txHashes[j].push_back(hash); } } @@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 4; k++) { // add 4 fee txs tx.vin[0].prevout.n = 10000*blocknum+100*j+k; uint256 hash = tx.GetHash(); - mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); + mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); txHashes[j].push_back(hash); } } @@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 4; k++) { // add 4 fee txs tx.vin[0].prevout.n = 10000*blocknum+100*j+k; uint256 hash = tx.GetHash(); - mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); + mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); CTransactionRef ptx = mpool.get(hash); if (ptx) block.push_back(ptx); diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index 2af0ab22da..12ec00ce02 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(manythreads) boost::mutex counterMutex[10]; int counter[10] = { 0 }; - FastRandomContext rng(42); + FastRandomContext rng{/* fDeterministic */ true}; auto zeroToNine = [](FastRandomContext& rc) -> int { return rc.randrange(10); }; // [0, 9] auto randomMsec = [](FastRandomContext& rc) -> int { return -11 + (int)rc.randrange(1012); }; // [-11, 1000] auto randomDelta = [](FastRandomContext& rc) -> int { return -1000 + (int)rc.randrange(2001); }; // [-1000, 1000] @@ -138,11 +138,13 @@ BOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered) // the callbacks should run in exactly the order in which they were enqueued for (int i = 0; i < 100; ++i) { queue1.AddToProcessQueue([i, &counter1]() { - assert(i == counter1++); + bool expectation = i == counter1++; + assert(expectation); }); queue2.AddToProcessQueue([i, &counter2]() { - assert(i == counter2++); + bool expectation = i == counter2++; + assert(expectation); }); } diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index bc671394c0..67c377778f 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -937,17 +937,19 @@ BOOST_AUTO_TEST_CASE(script_build) } } +#ifdef UPDATE_JSON_TESTS std::string strGen; - +#endif for (TestBuilder& test : tests) { test.Test(); std::string str = JSONPrettyPrint(test.GetJSON()); -#ifndef UPDATE_JSON_TESTS +#ifdef UPDATE_JSON_TESTS + strGen += str + ",\n"; +#else if (tests_set.count(str) == 0) { BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment()); } #endif - strGen += str + ",\n"; } #ifdef UPDATE_JSON_TESTS diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index bcd2a9c7b6..c0754618fb 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -146,7 +146,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test) BOOST_AUTO_TEST_CASE(findearliestatleast_edge_test) { std::list<CBlockIndex> blocks; - for (unsigned int timeMax : {100, 100, 100, 200, 200, 200, 300, 300, 300}) { + for (const unsigned int timeMax : {100, 100, 100, 200, 200, 200, 300, 300, 300}) { CBlockIndex* prev = blocks.empty() ? nullptr : &blocks.back(); blocks.emplace_back(); blocks.back().nHeight = prev ? prev->nHeight + 1 : 0; diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp new file mode 100644 index 0000000000..df0380546e --- /dev/null +++ b/src/test/sync_tests.cpp @@ -0,0 +1,52 @@ +// Copyright (c) 2012-2017 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 <sync.h> +#include <test/test_bitcoin.h> + +#include <boost/test/unit_test.hpp> + +namespace { +template <typename MutexType> +void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2) +{ + { + LOCK2(mutex1, mutex2); + } + bool error_thrown = false; + try { + LOCK2(mutex2, mutex1); + } catch (const std::logic_error& e) { + BOOST_CHECK_EQUAL(e.what(), "potential deadlock detected"); + error_thrown = true; + } + #ifdef DEBUG_LOCKORDER + BOOST_CHECK(error_thrown); + #else + BOOST_CHECK(!error_thrown); + #endif +} +} // namespace + +BOOST_FIXTURE_TEST_SUITE(sync_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(potential_deadlock_detected) +{ + #ifdef DEBUG_LOCKORDER + bool prev = g_debug_lockorder_abort; + g_debug_lockorder_abort = false; + #endif + + CCriticalSection rmutex1, rmutex2; + TestPotentialDeadLockDetected(rmutex1, rmutex2); + + Mutex mutex1, mutex2; + TestPotentialDeadLockDetected(mutex1, mutex2); + + #ifdef DEBUG_LOCKORDER + g_debug_lockorder_abort = prev; + #endif +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index a89bf785f1..0d7c9f0abf 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -29,7 +29,7 @@ void CConnmanTest::AddNode(CNode& node) void CConnmanTest::ClearNodes() { LOCK(g_connman->cs_vNodes); - for (CNode* node : g_connman->vNodes) { + for (const CNode* node : g_connman->vNodes) { delete node; } g_connman->vNodes.clear(); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 33f0a83b7e..c527ad448c 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -65,7 +65,7 @@ unsigned int ParseScriptFlags(std::string strFlags) std::vector<std::string> words; boost::algorithm::split(words, strFlags, boost::algorithm::is_any_of(",")); - for (std::string word : words) + for (const std::string& word : words) { if (!mapFlagNames.count(word)) BOOST_ERROR("Bad test: unknown verification flag '" << word << "'"); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index b2960446eb..c74eb7531a 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -245,7 +245,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArg) testArgs.ParseParameters(7, (char**)argv_test, error); // Each letter should be set. - for (char opt : "abcdef") + for (const char opt : "abcdef") BOOST_CHECK(testArgs.IsArgSet({'-', opt}) || !opt); // Nothing else should be in the map @@ -394,7 +394,7 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream) && test_args.GetArg("-iii", "xxx") == "xxx" ); - for (bool def : {false, true}) { + for (const bool def : {false, true}) { BOOST_CHECK(test_args.GetBoolArg("-a", def) && test_args.GetBoolArg("-b", def) && !test_args.GetBoolArg("-ccc", def) @@ -1217,4 +1217,43 @@ BOOST_AUTO_TEST_CASE(test_DirIsWritable) fs::remove(tmpdirname); } +BOOST_AUTO_TEST_CASE(test_ToLower) +{ + BOOST_CHECK_EQUAL(ToLower('@'), '@'); + BOOST_CHECK_EQUAL(ToLower('A'), 'a'); + BOOST_CHECK_EQUAL(ToLower('Z'), 'z'); + BOOST_CHECK_EQUAL(ToLower('['), '['); + BOOST_CHECK_EQUAL(ToLower(0), 0); + BOOST_CHECK_EQUAL(ToLower(255), 255); + + std::string testVector; + Downcase(testVector); + BOOST_CHECK_EQUAL(testVector, ""); + + testVector = "#HODL"; + Downcase(testVector); + BOOST_CHECK_EQUAL(testVector, "#hodl"); + + testVector = "\x00\xfe\xff"; + Downcase(testVector); + BOOST_CHECK_EQUAL(testVector, "\x00\xfe\xff"); +} + +BOOST_AUTO_TEST_CASE(test_ToUpper) +{ + BOOST_CHECK_EQUAL(ToUpper('`'), '`'); + BOOST_CHECK_EQUAL(ToUpper('a'), 'A'); + BOOST_CHECK_EQUAL(ToUpper('z'), 'Z'); + BOOST_CHECK_EQUAL(ToUpper('{'), '{'); + BOOST_CHECK_EQUAL(ToUpper(0), 0); + BOOST_CHECK_EQUAL(ToUpper(255), 255); +} + +BOOST_AUTO_TEST_CASE(test_Capitalize) +{ + BOOST_CHECK_EQUAL(Capitalize(""), ""); + BOOST_CHECK_EQUAL(Capitalize("bitcoin"), "Bitcoin"); + BOOST_CHECK_EQUAL(Capitalize("\x00\xfe\xff"), "\x00\xfe\xff"); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 37c4f79133..4316f37999 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -23,7 +23,7 @@ BOOST_FIXTURE_TEST_SUITE(validation_block_tests, RegtestingSetup) struct TestSubscriber : public CValidationInterface { uint256 m_expected_tip; - TestSubscriber(uint256 tip) : m_expected_tip(tip) {} + explicit TestSubscriber(uint256 tip) : m_expected_tip(tip) {} void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override { diff --git a/src/threadinterrupt.cpp b/src/threadinterrupt.cpp index d08d52e4a9..340106ed99 100644 --- a/src/threadinterrupt.cpp +++ b/src/threadinterrupt.cpp @@ -5,6 +5,8 @@ #include <threadinterrupt.h> +#include <sync.h> + CThreadInterrupt::CThreadInterrupt() : flag(false) {} CThreadInterrupt::operator bool() const @@ -20,7 +22,7 @@ void CThreadInterrupt::reset() void CThreadInterrupt::operator()() { { - std::unique_lock<std::mutex> lock(mut); + LOCK(mut); flag.store(true, std::memory_order_release); } cond.notify_all(); @@ -28,7 +30,7 @@ void CThreadInterrupt::operator()() bool CThreadInterrupt::sleep_for(std::chrono::milliseconds rel_time) { - std::unique_lock<std::mutex> lock(mut); + WAIT_LOCK(mut, lock); return !cond.wait_for(lock, rel_time, [this]() { return flag.load(std::memory_order_acquire); }); } diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h index c30bd3d657..9c6fccfcde 100644 --- a/src/threadinterrupt.h +++ b/src/threadinterrupt.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_THREADINTERRUPT_H #define BITCOIN_THREADINTERRUPT_H +#include <sync.h> + #include <atomic> #include <chrono> #include <condition_variable> @@ -28,7 +30,7 @@ public: private: std::condition_variable cond; - std::mutex mut; + Mutex mut; std::atomic<bool> flag; }; diff --git a/src/threadsafety.h b/src/threadsafety.h index a2f45e5fce..47e6b2ea38 100644 --- a/src/threadsafety.h +++ b/src/threadsafety.h @@ -10,7 +10,7 @@ // TL;DR Add GUARDED_BY(mutex) to member variables. The others are // rarely necessary. Ex: int nFoo GUARDED_BY(cs_foo); // -// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety +// See https://clang.llvm.org/docs/ThreadSafetyAnalysis.html // for documentation. The clang compiler can do advanced static analysis // of locking when given the -Wthread-safety option. #define LOCKABLE __attribute__((lockable)) diff --git a/src/timedata.cpp b/src/timedata.cpp index 1599508306..291111feb2 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -94,7 +94,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) { // If nobody has a time different than ours but within 5 minutes of ours, give a warning bool fMatch = false; - for (int64_t nOffset : vSorted) + for (const int64_t nOffset : vSorted) if (nOffset != 0 && abs64(nOffset) < 5 * 60) fMatch = true; @@ -109,7 +109,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) } if (LogAcceptCategory(BCLog::NET)) { - for (int64_t n : vSorted) { + for (const int64_t n : vSorted) { LogPrint(BCLog::NET, "%+d ", n); /* Continued */ } LogPrint(BCLog::NET, "| "); /* Continued */ diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 8bada4dce8..39434e4bb6 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -20,13 +20,10 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee, int64_t _nTime, unsigned int _entryHeight, - bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp): - tx(_tx), nFee(_nFee), nTime(_nTime), entryHeight(_entryHeight), + bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp) + : tx(_tx), nFee(_nFee), nTxWeight(GetTransactionWeight(*tx)), nUsageSize(RecursiveDynamicUsage(tx)), nTime(_nTime), entryHeight(_entryHeight), spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp) { - nTxWeight = GetTransactionWeight(*tx); - nUsageSize = RecursiveDynamicUsage(tx); - nCountWithDescendants = 1; nSizeWithDescendants = GetTxSize(); nModFeesWithDescendants = nFee; @@ -196,7 +193,7 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntr } const setEntries & setMemPoolParents = GetMemPoolParents(stageit); - for (const txiter &phash : setMemPoolParents) { + for (txiter phash : setMemPoolParents) { // If this is a new ancestor, add it. if (setAncestors.count(phash) == 0) { parentHashes.insert(phash); @@ -355,7 +352,7 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n) nTransactionsUpdated += n; } -void CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate) +void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate) { NotifyEntryAdded(entry.GetSharedTx()); // Add to memory pool without checking anything. @@ -367,7 +364,7 @@ void CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, // Update transaction for any feeDelta created by PrioritiseTransaction // TODO: refactor so that the fee delta is calculated before inserting // into mapTx. - std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash); + std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(entry.GetTx().GetHash()); if (pos != mapDeltas.end()) { const CAmount &delta = pos->second; if (delta) { @@ -457,7 +454,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries& setDescendants stage.erase(it); const setEntries &setChildren = GetMemPoolChildren(it); - for (const txiter &childiter : setChildren) { + for (txiter childiter : setChildren) { if (!setDescendants.count(childiter)) { stage.insert(childiter); } @@ -640,8 +637,6 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children); bool fDependsWait = false; setEntries setParentCheck; - int64_t parentSizes = 0; - int64_t parentSigOpCost = 0; for (const CTxIn &txin : tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); @@ -649,10 +644,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const const CTransaction& tx2 = it2->GetTx(); assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); fDependsWait = true; - if (setParentCheck.insert(it2).second) { - parentSizes += it2->GetTxSize(); - parentSigOpCost += it2->GetSigOpCost(); - } + setParentCheck.insert(it2); } else { assert(pcoins->HaveCoin(txin.prevout)); } @@ -907,7 +899,7 @@ size_t CTxMemPool::DynamicMemoryUsage() const { void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason) { AssertLockHeld(cs); UpdateForRemoveFromMempool(stage, updateDescendants); - for (const txiter& it : stage) { + for (txiter it : stage) { removeUnchecked(it, reason); } } @@ -928,13 +920,13 @@ int CTxMemPool::Expire(int64_t time) { return stage.size(); } -void CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool validFeeEstimate) +void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, bool validFeeEstimate) { setEntries setAncestors; uint64_t nNoLimit = std::numeric_limits<uint64_t>::max(); std::string dummy; CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); - return addUnchecked(hash, entry, setAncestors, validFeeEstimate); + return addUnchecked(entry, setAncestors, validFeeEstimate); } void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add) diff --git a/src/txmempool.h b/src/txmempool.h index f8915cec31..2163b5eb21 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -65,14 +65,14 @@ class CTxMemPool; class CTxMemPoolEntry { private: - CTransactionRef tx; - CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups - size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize()) - size_t nUsageSize; //!< ... and total memory usage - int64_t nTime; //!< Local time when entering the mempool - unsigned int entryHeight; //!< Chain height when entering the mempool - bool spendsCoinbase; //!< keep track of transactions that spend a coinbase - int64_t sigOpCost; //!< Total sigop cost + const CTransactionRef tx; + const CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups + const size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize()) + const size_t nUsageSize; //!< ... and total memory usage + const int64_t nTime; //!< Local time when entering the mempool + const unsigned int entryHeight; //!< Chain height when entering the mempool + const bool spendsCoinbase; //!< keep track of transactions that spend a coinbase + const int64_t sigOpCost; //!< Total sigop cost int64_t feeDelta; //!< Used for determining the priority of the transaction for mining in a block LockPoints lockPoints; //!< Track the height and time at which tx was final @@ -540,8 +540,8 @@ public: // Note that addUnchecked is ONLY called from ATMP outside of tests // and any other callers may break wallet's in-mempool tracking (due to // lack of CValidationInterface::TransactionAddedToMempool callbacks). - void addUnchecked(const uint256& hash, const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs); - void addUnchecked(const uint256& hash, const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs); + void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs); + void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN); void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main); diff --git a/src/util.cpp b/src/util.cpp index 1aab85264f..84d8175389 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -71,7 +71,6 @@ #include <malloc.h> #endif -#include <boost/interprocess/sync/file_lock.hpp> #include <boost/thread.hpp> #include <openssl/crypto.h> #include <openssl/rand.h> @@ -139,7 +138,7 @@ instance_of_cinit; * cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks * is called. */ -static std::map<std::string, std::unique_ptr<boost::interprocess::file_lock>> dir_locks; +static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks; /** Mutex to protect dir_locks. */ static std::mutex cs_dir_locks; @@ -156,18 +155,13 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b // Create empty lock file if it doesn't exist. FILE* file = fsbridge::fopen(pathLockFile, "a"); if (file) fclose(file); - - try { - auto lock = MakeUnique<boost::interprocess::file_lock>(pathLockFile.string().c_str()); - if (!lock->try_lock()) { - return false; - } - if (!probe_only) { - // Lock successful and we're not just probing, put it into the map - dir_locks.emplace(pathLockFile.string(), std::move(lock)); - } - } catch (const boost::interprocess::interprocess_exception& e) { - return error("Error while attempting to lock directory %s: %s", directory.string(), e.what()); + auto lock = MakeUnique<fsbridge::FileLock>(pathLockFile); + if (!lock->TryLock()) { + return error("Error while attempting to lock directory %s: %s", directory.string(), lock->GetReason()); + } + if (!probe_only) { + // Lock successful and we're not just probing, put it into the map + dir_locks.emplace(pathLockFile.string(), std::move(lock)); } return true; } @@ -222,7 +216,7 @@ public: /** Determine whether to use config settings in the default section, * See also comments around ArgsManager::ArgsManager() below. */ - static inline bool UseDefaultSection(const ArgsManager& am, const std::string& arg) + static inline bool UseDefaultSection(const ArgsManager& am, const std::string& arg) EXCLUSIVE_LOCKS_REQUIRED(am.cs_args) { return (am.m_network == CBaseChainParams::MAIN || am.m_network_only_args.count(arg) == 0); } @@ -301,7 +295,7 @@ public: /* Special test for -testnet and -regtest args, because we * don't want to be confused by craziness like "[regtest] testnet=1" */ - static inline bool GetNetBoolArg(const ArgsManager &am, const std::string& net_arg) + static inline bool GetNetBoolArg(const ArgsManager &am, const std::string& net_arg) EXCLUSIVE_LOCKS_REQUIRED(am.cs_args) { std::pair<bool,std::string> found_result(false,std::string()); found_result = GetArgHelper(am.m_override_args, net_arg, true); @@ -378,6 +372,8 @@ ArgsManager::ArgsManager() : void ArgsManager::WarnForSectionOnlyArgs() { + LOCK(cs_args); + // if there's no section selected, don't worry if (m_network.empty()) return; @@ -406,6 +402,7 @@ void ArgsManager::WarnForSectionOnlyArgs() void ArgsManager::SelectConfigNetwork(const std::string& network) { + LOCK(cs_args); m_network = network; } @@ -474,6 +471,7 @@ bool ArgsManager::IsArgKnown(const std::string& key) const arg_no_net = std::string("-") + key.substr(option_index + 1, std::string::npos); } + LOCK(cs_args); for (const auto& arg_map : m_available_args) { if (arg_map.second.count(arg_no_net)) return true; } @@ -577,6 +575,7 @@ void ArgsManager::AddArg(const std::string& name, const std::string& help, const eq_index = name.size(); } + LOCK(cs_args); std::map<std::string, Arg>& arg_map = m_available_args[cat]; auto ret = arg_map.emplace(name.substr(0, eq_index), Arg(name.substr(eq_index, name.size() - eq_index), help, debug_only)); assert(ret.second); // Make sure an insertion actually happened @@ -594,6 +593,7 @@ std::string ArgsManager::GetHelpMessage() const const bool show_debug = gArgs.GetBoolArg("-help-debug", false); std::string usage = ""; + LOCK(cs_args); for (const auto& arg_map : m_available_args) { switch(arg_map.first) { case OptionsCategory::OPTIONS: @@ -818,11 +818,11 @@ static std::string TrimString(const std::string& str, const std::string& pattern return str.substr(front, end - front + 1); } -static std::vector<std::pair<std::string, std::string>> GetConfigOptions(std::istream& stream) +static bool GetConfigOptions(std::istream& stream, std::string& error, std::vector<std::pair<std::string, std::string>> &options) { - std::vector<std::pair<std::string, std::string>> options; std::string str, prefix; std::string::size_type pos; + int linenr = 1; while (std::getline(stream, str)) { if ((pos = str.find('#')) != std::string::npos) { str = str.substr(0, pos); @@ -832,21 +832,34 @@ static std::vector<std::pair<std::string, std::string>> GetConfigOptions(std::is if (!str.empty()) { if (*str.begin() == '[' && *str.rbegin() == ']') { prefix = str.substr(1, str.size() - 2) + '.'; + } else if (*str.begin() == '-') { + error = strprintf("parse error on line %i: %s, options in configuration file must be specified without leading -", linenr, str); + return false; } else if ((pos = str.find('=')) != std::string::npos) { std::string name = prefix + TrimString(str.substr(0, pos), pattern); std::string value = TrimString(str.substr(pos + 1), pattern); options.emplace_back(name, value); + } else { + error = strprintf("parse error on line %i: %s", linenr, str); + if (str.size() >= 2 && str.substr(0, 2) == "no") { + error += strprintf(", if you intended to specify a negated option, use %s=1 instead", str); + } + return false; } } + ++linenr; } - return options; + return true; } bool ArgsManager::ReadConfigStream(std::istream& stream, std::string& error, bool ignore_invalid_keys) { LOCK(cs_args); - - for (const std::pair<std::string, std::string>& option : GetConfigOptions(stream)) { + std::vector<std::pair<std::string, std::string>> options; + if (!GetConfigOptions(stream, error, options)) { + return false; + } + for (const std::pair<std::string, std::string>& option : options) { std::string strKey = std::string("-") + option.first; std::string strValue = option.second; @@ -886,7 +899,12 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) } // if there is an -includeconf in the override args, but it is empty, that means the user // passed '-noincludeconf' on the command line, in which case we should not include anything - if (m_override_args.count("-includeconf") == 0) { + bool emptyIncludeConf; + { + LOCK(cs_args); + emptyIncludeConf = m_override_args.count("-includeconf") == 0; + } + if (emptyIncludeConf) { std::string chain_id = GetChainName(); std::vector<std::string> includeconf(GetArgs("-includeconf")); { @@ -946,6 +964,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) std::string ArgsManager::GetChainName() const { + LOCK(cs_args); bool fRegTest = ArgsManagerHelper::GetNetBoolArg(*this, "-regtest"); bool fTestNet = ArgsManagerHelper::GetNetBoolArg(*this, "-testnet"); diff --git a/src/util.h b/src/util.h index e93489c1ed..7bf9fdbe12 100644 --- a/src/util.h +++ b/src/util.h @@ -142,11 +142,11 @@ protected: }; mutable CCriticalSection cs_args; - std::map<std::string, std::vector<std::string>> m_override_args; - std::map<std::string, std::vector<std::string>> m_config_args; - std::string m_network; - std::set<std::string> m_network_only_args; - std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args; + std::map<std::string, std::vector<std::string>> m_override_args GUARDED_BY(cs_args); + std::map<std::string, std::vector<std::string>> m_config_args GUARDED_BY(cs_args); + std::string m_network GUARDED_BY(cs_args); + std::set<std::string> m_network_only_args GUARDED_BY(cs_args); + std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args); bool ReadConfigStream(std::istream& stream, std::string& error, bool ignore_invalid_keys = false); @@ -262,7 +262,10 @@ public: /** * Clear available arguments */ - void ClearArgs() { m_available_args.clear(); } + void ClearArgs() { + LOCK(cs_args); + m_available_args.clear(); + } /** * Get the help string diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index a06d88cb19..4940267bae 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -7,6 +7,7 @@ #include <tinyformat.h> +#include <algorithm> #include <cstdlib> #include <cstring> #include <errno.h> @@ -71,7 +72,7 @@ bool IsHexNumber(const std::string& str) if (str.size() > 2 && *str.begin() == '0' && *(str.begin()+1) == 'x') { starting_location = 2; } - for (auto c : str.substr(starting_location)) { + for (const char c : str.substr(starting_location)) { if (HexDigit(c) < 0) return false; } // Return false for empty string or "0x". @@ -544,3 +545,55 @@ bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out) return true; } +bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath) +{ + std::stringstream ss(keypath_str); + std::string item; + bool first = true; + while (std::getline(ss, item, '/')) { + if (item.compare("m") == 0) { + if (first) { + first = false; + continue; + } + return false; + } + // Finds whether it is hardened + uint32_t path = 0; + size_t pos = item.find("'"); + if (pos != std::string::npos) { + // The hardened tick can only be in the last index of the string + if (pos != item.size() - 1) { + return false; + } + path |= 0x80000000; + item = item.substr(0, item.size() - 1); // Drop the last character which is the hardened tick + } + + // Ensure this is only numbers + if (item.find_first_not_of( "0123456789" ) != std::string::npos) { + return false; + } + uint32_t number; + if (!ParseUInt32(item, &number)) { + return false; + } + path |= number; + + keypath.push_back(path); + first = false; + } + return true; +} + +void Downcase(std::string& str) +{ + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c){return ToLower(c);}); +} + +std::string Capitalize(std::string str) +{ + if (str.empty()) return str; + str[0] = ToUpper(str.front()); + return str; +} diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index 5f2211b5dc..846a3917a2 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -183,4 +183,51 @@ bool ConvertBits(const O& outfn, I it, I end) { return true; } +/** Parse an HD keypaths like "m/7/0'/2000". */ +bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath); + +/** + * Converts the given character to its lowercase equivalent. + * This function is locale independent. It only converts uppercase + * characters in the standard 7-bit ASCII range. + * @param[in] c the character to convert to lowercase. + * @return the lowercase equivalent of c; or the argument + * if no conversion is possible. + */ +constexpr unsigned char ToLower(unsigned char c) +{ + return (c >= 'A' && c <= 'Z' ? (c - 'A') + 'a' : c); +} + +/** + * Converts the given string to its lowercase equivalent. + * This function is locale independent. It only converts uppercase + * characters in the standard 7-bit ASCII range. + * @param[in,out] str the string to convert to lowercase. + */ +void Downcase(std::string& str); + +/** + * Converts the given character to its uppercase equivalent. + * This function is locale independent. It only converts lowercase + * characters in the standard 7-bit ASCII range. + * @param[in] c the character to convert to uppercase. + * @return the uppercase equivalent of c; or the argument + * if no conversion is possible. + */ +constexpr unsigned char ToUpper(unsigned char c) +{ + return (c >= 'a' && c <= 'z' ? (c - 'a') + 'A' : c); +} + +/** + * Capitalizes the first character of the given string. + * This function is locale independent. It only capitalizes the + * first character of the argument if it has an uppercase equivalent + * in the standard 7-bit ASCII range. + * @param[in] str the string to capitalize. + * @return string with the first letter capitalized. + */ +std::string Capitalize(std::string str); + #endif // BITCOIN_UTILSTRENCODINGS_H diff --git a/src/validation.cpp b/src/validation.cpp index 3e51221a5e..7ec0c6a961 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -217,8 +217,8 @@ CCriticalSection cs_main; BlockMap& mapBlockIndex = g_chainstate.mapBlockIndex; CChain& chainActive = g_chainstate.chainActive; CBlockIndex *pindexBestHeader = nullptr; -CWaitableCriticalSection g_best_block_mutex; -CConditionVariable g_best_block_cv; +Mutex g_best_block_mutex; +std::condition_variable g_best_block_cv; uint256 g_best_block; int nScriptCheckThreads = 0; std::atomic_bool fImporting(false); @@ -421,7 +421,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool // lock on a mempool input, so we can use the return value of // CheckSequenceLocks to indicate the LockPoints validity int maxInputHeight = 0; - for (int height : prevheights) { + for (const int height : prevheights) { // Can ignore mempool inputs since we'll fail if they had non-zero locks if (height != tip->nHeight+1) { maxInputHeight = std::max(maxInputHeight, height); @@ -959,7 +959,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool bool validForFeeEstimation = !fReplacementTransaction && !bypass_limits && IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx); // Store transaction in memory - pool.addUnchecked(hash, entry, setAncestors, validForFeeEstimation); + pool.addUnchecked(entry, setAncestors, validForFeeEstimation); // trim mempool and check if tx was trimmed if (!bypass_limits) { @@ -2239,7 +2239,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar mempool.AddTransactionsUpdated(1); { - WaitableLock lock(g_best_block_mutex); + LOCK(g_best_block_mutex); g_best_block = pindexNew->GetBlockHash(); g_best_block_cv.notify_all(); } @@ -2448,7 +2448,7 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp if (!rv) { if (state.IsInvalid()) InvalidBlockFound(pindexNew, state); - return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); + return error("%s: ConnectBlock %s failed, %s", __func__, pindexNew->GetBlockHash().ToString(), FormatStateMessage(state)); } nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2; LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, nTimeConnectTotal * MILLI / nBlocksTotal); @@ -4291,7 +4291,7 @@ void UnloadBlockIndex() warningcache[b].clear(); } - for (BlockMap::value_type& entry : mapBlockIndex) { + for (const BlockMap::value_type& entry : mapBlockIndex) { delete entry.second; } mapBlockIndex.clear(); @@ -4492,7 +4492,7 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams) // Build forward-pointing map of the entire block tree. std::multimap<CBlockIndex*,CBlockIndex*> forward; - for (auto& entry : mapBlockIndex) { + for (const std::pair<const uint256, CBlockIndex*>& entry : mapBlockIndex) { forward.insert(std::make_pair(entry.second->pprev, entry.second)); } diff --git a/src/validation.h b/src/validation.h index c4c9b8b5ba..3df6456eca 100644 --- a/src/validation.h +++ b/src/validation.h @@ -151,8 +151,8 @@ extern BlockMap& mapBlockIndex; extern uint64_t nLastBlockTx; extern uint64_t nLastBlockWeight; extern const std::string strMessageMagic; -extern CWaitableCriticalSection g_best_block_mutex; -extern CConditionVariable g_best_block_cv; +extern Mutex g_best_block_mutex; +extern std::condition_variable g_best_block_cv; extern uint256 g_best_block; extern std::atomic_bool fImporting; extern std::atomic_bool fReindex; diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index 4fa9603011..729e4e39b0 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -311,7 +311,7 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) return false; fUseCrypto = true; - for (KeyMap::value_type& mKey : mapKeys) + for (const KeyMap::value_type& mKey : mapKeys) { const CKey &key = mKey.second; CPubKey vchPubKey = key.GetPubKey(); diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index d0fe51801e..dfd60ae5eb 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -72,7 +72,7 @@ BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& data database_filename = "wallet.dat"; } LOCK(cs_db); - // Note: An ununsed temporary BerkeleyEnvironment object may be created inside the + // Note: An unused temporary BerkeleyEnvironment object may be created inside the // emplace function if the key already exists. This is a little inefficient, // but not a big concern since the map will be changed in the future to hold // pointers instead of objects, anyway. @@ -503,7 +503,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo // be implemented, so no equality checks are needed at all. (Newer // versions of BDB have an set_lk_exclusive method for this // purpose, but the older version we use does not.) - for (auto& env : g_dbenvs) { + for (const auto& env : g_dbenvs) { CheckUniqueFileid(env.second, strFilename, *pdb_temp); } diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp index 2b8a0f6467..677bf74b5d 100644 --- a/src/wallet/feebumper.cpp +++ b/src/wallet/feebumper.cpp @@ -242,7 +242,7 @@ Result CommitTransaction(CWallet* wallet, const uint256& txid, CMutableTransacti CReserveKey reservekey(wallet); CValidationState state; - if (!wallet->CommitTransaction(tx, std::move(mapValue), oldWtx.vOrderForm, oldWtx.strFromAccount, reservekey, g_connman.get(), state)) { + if (!wallet->CommitTransaction(tx, std::move(mapValue), oldWtx.vOrderForm, reservekey, g_connman.get(), state)) { // NOTE: CommitTransaction never returns false, so this should never happen. errors.push_back(strprintf("The transaction was rejected: %s", FormatStateMessage(state))); return Result::WALLET_ERROR; diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index b9f267210e..b36287ff50 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -78,7 +78,7 @@ void WalletInit::AddWalletOptions() const gArgs.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)", false, OptionsCategory::WALLET); gArgs.AddArg("-walletrbf", strprintf("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)", DEFAULT_WALLET_RBF), false, OptionsCategory::WALLET); gArgs.AddArg("-zapwallettxes=<mode>", "Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup" - " (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)", false, OptionsCategory::WALLET); + " (1 = keep tx meta data e.g. payment request information, 2 = drop tx meta data)", false, OptionsCategory::WALLET); gArgs.AddArg("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE), true, OptionsCategory::WALLET_DEBUG_TEST); gArgs.AddArg("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET), true, OptionsCategory::WALLET_DEBUG_TEST); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 7cb41da39e..af36d321d5 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -41,7 +41,7 @@ int64_t static DecodeDumpTime(const std::string &str) { std::string static EncodeDumpString(const std::string &str) { std::stringstream ret; - for (unsigned char c : str) { + for (const unsigned char c : str) { if (c <= 32 || c >= 128 || c == '%') { ret << '%' << HexStr(&c, &c + 1); } else { @@ -1150,7 +1150,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) " \"keys\": [\"<key>\", ... ] , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n" " \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be treated as not incoming payments\n" " \"watchonly\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty\n" - " \"label\": <label> , (string, optional, default: '') Label to assign to the address (aka account name, for now), only allowed with internal=false\n" + " \"label\": <label> , (string, optional, default: '') Label to assign to the address, only allowed with internal=false\n" " }\n" " ,...\n" " ]\n" diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a7ec481646..e419f8d164 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -196,59 +196,6 @@ static UniValue getnewaddress(const JSONRPCRequest& request) return EncodeDestination(dest); } -CTxDestination GetLabelDestination(CWallet* const pwallet, const std::string& label, bool bForceNew=false) -{ - CTxDestination dest; - if (!pwallet->GetLabelDestination(dest, label, bForceNew)) { - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - } - - return dest; -} - -static UniValue getaccountaddress(const JSONRPCRequest& request) -{ - std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); - CWallet* const pwallet = wallet.get(); - - if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { - return NullUniValue; - } - - if (!IsDeprecatedRPCEnabled("accounts")) { - if (request.fHelp) { - throw std::runtime_error("getaccountaddress (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)"); - } - throw JSONRPCError(RPC_METHOD_DEPRECATED, "getaccountaddress is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts."); - } - - if (request.fHelp || request.params.size() != 1) - throw std::runtime_error( - "getaccountaddress \"account\"\n" - "\n\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n" - "\nArguments:\n" - "1. \"account\" (string, required) The account for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n" - "\nResult:\n" - "\"address\" (string) The account bitcoin address\n" - "\nExamples:\n" - + HelpExampleCli("getaccountaddress", "") - + HelpExampleCli("getaccountaddress", "\"\"") - + HelpExampleCli("getaccountaddress", "\"myaccount\"") - + HelpExampleRpc("getaccountaddress", "\"myaccount\"") - ); - - LOCK2(cs_main, pwallet->cs_wallet); - - // Parse the account first so we don't generate a key if there's an error - std::string account = LabelFromValue(request.params[0]); - - UniValue ret(UniValue::VSTR); - - ret = EncodeDestination(GetLabelDestination(pwallet, account)); - return ret; -} - - static UniValue getrawchangeaddress(const JSONRPCRequest& request) { std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); @@ -312,13 +259,6 @@ static UniValue setlabel(const JSONRPCRequest& request) return NullUniValue; } - if (!IsDeprecatedRPCEnabled("accounts") && request.strMethod == "setaccount") { - if (request.fHelp) { - throw std::runtime_error("setaccount (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)"); - } - throw JSONRPCError(RPC_METHOD_DEPRECATED, "setaccount is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts."); - } - if (request.fHelp || request.params.size() != 2) throw std::runtime_error( "setlabel \"address\" \"label\"\n" @@ -338,131 +278,19 @@ static UniValue setlabel(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); } - std::string old_label = pwallet->mapAddressBook[dest].name; std::string label = LabelFromValue(request.params[1]); if (IsMine(*pwallet, dest)) { pwallet->SetAddressBook(dest, label, "receive"); - if (request.strMethod == "setaccount" && old_label != label && dest == GetLabelDestination(pwallet, old_label)) { - // for setaccount, call GetLabelDestination so a new receive address is created for the old account - GetLabelDestination(pwallet, old_label, true); - } } else { pwallet->SetAddressBook(dest, label, "send"); } - // Detect when there are no addresses using this label. - // If so, delete the account record for it. Labels, unlike addresses, can be deleted, - // and if we wouldn't do this, the record would stick around forever. - bool found_address = false; - for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) { - if (item.second.name == label) { - found_address = true; - break; - } - } - if (!found_address) { - pwallet->DeleteLabel(old_label); - } - return NullUniValue; } -static UniValue getaccount(const JSONRPCRequest& request) -{ - std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); - CWallet* const pwallet = wallet.get(); - - if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { - return NullUniValue; - } - - if (!IsDeprecatedRPCEnabled("accounts")) { - if (request.fHelp) { - throw std::runtime_error("getaccount (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)"); - } - throw JSONRPCError(RPC_METHOD_DEPRECATED, "getaccount is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts."); - } - - if (request.fHelp || request.params.size() != 1) - throw std::runtime_error( - "getaccount \"address\"\n" - "\nDEPRECATED. Returns the account associated with the given address.\n" - "\nArguments:\n" - "1. \"address\" (string, required) The bitcoin address for account lookup.\n" - "\nResult:\n" - "\"accountname\" (string) the account address\n" - "\nExamples:\n" - + HelpExampleCli("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"") - + HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"") - ); - - LOCK2(cs_main, pwallet->cs_wallet); - - CTxDestination dest = DecodeDestination(request.params[0].get_str()); - if (!IsValidDestination(dest)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); - } - - std::string strAccount; - std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(dest); - if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) { - strAccount = (*mi).second.name; - } - return strAccount; -} - - -static UniValue getaddressesbyaccount(const JSONRPCRequest& request) -{ - std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); - CWallet* const pwallet = wallet.get(); - - if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { - return NullUniValue; - } - - if (!IsDeprecatedRPCEnabled("accounts")) { - if (request.fHelp) { - throw std::runtime_error("getaddressbyaccount (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)"); - } - throw JSONRPCError(RPC_METHOD_DEPRECATED, "getaddressesbyaccount is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts."); - } - - if (request.fHelp || request.params.size() != 1) - throw std::runtime_error( - "getaddressesbyaccount \"account\"\n" - "\nDEPRECATED. Returns the list of addresses for the given account.\n" - "\nArguments:\n" - "1. \"account\" (string, required) The account name.\n" - "\nResult:\n" - "[ (json array of string)\n" - " \"address\" (string) a bitcoin address associated with the given account\n" - " ,...\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("getaddressesbyaccount", "\"tabby\"") - + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"") - ); - - LOCK2(cs_main, pwallet->cs_wallet); - - std::string strAccount = LabelFromValue(request.params[0]); - - // Find all addresses that have the given account - UniValue ret(UniValue::VARR); - for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) { - const CTxDestination& dest = item.first; - const std::string& strName = item.second.name; - if (strName == strAccount) { - ret.push_back(EncodeDestination(dest)); - } - } - return ret; -} - -static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue, std::string fromAccount) +static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue) { CAmount curBalance = pwallet->GetBalance(); @@ -495,7 +323,7 @@ static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination & throw JSONRPCError(RPC_WALLET_ERROR, strError); } CValidationState state; - if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, std::move(fromAccount), reservekey, g_connman.get(), state)) { + if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, reservekey, g_connman.get(), state)) { strError = strprintf("Error: The transaction was rejected! Reason given: %s", FormatStateMessage(state)); throw JSONRPCError(RPC_WALLET_ERROR, strError); } @@ -587,7 +415,7 @@ static UniValue sendtoaddress(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); - CTransactionRef tx = SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue), {} /* fromAccount */); + CTransactionRef tx = SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue)); return tx->GetHash().GetHex(); } @@ -789,13 +617,6 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request) return NullUniValue; } - if (!IsDeprecatedRPCEnabled("accounts") && request.strMethod == "getreceivedbyaccount") { - if (request.fHelp) { - throw std::runtime_error("getreceivedbyaccount (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)"); - } - throw JSONRPCError(RPC_METHOD_DEPRECATED, "getreceivedbyaccount is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts."); - } - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( "getreceivedbylabel \"label\" ( minconf )\n" @@ -863,41 +684,16 @@ static UniValue getbalance(const JSONRPCRequest& request) if (request.fHelp || (request.params.size() > 3 )) throw std::runtime_error( - (IsDeprecatedRPCEnabled("accounts") ? std::string( - "getbalance ( \"account\" minconf include_watchonly )\n" - "\nIf account is not specified, returns the server's total available balance.\n" - "The available balance is what the wallet considers currently spendable, and is\n" - "thus affected by options which limit spendability such as -spendzeroconfchange.\n" - "If account is specified (DEPRECATED), returns the balance in the account.\n" - "Note that the account \"\" is not the same as leaving the parameter out.\n" - "The server total may be different to the balance in the default \"\" account.\n" - "\nArguments:\n" - "1. \"account\" (string, optional) DEPRECATED. This argument will be removed in V0.18. \n" - " To use this deprecated argument, start bitcoind with -deprecatedrpc=accounts. The account string may be given as a\n" - " specific account name to find the balance associated with wallet keys in\n" - " a named account, or as the empty string (\"\") to find the balance\n" - " associated with wallet keys not in any named account, or as \"*\" to find\n" - " the balance associated with all wallet keys regardless of account.\n" - " When this option is specified, it calculates the balance in a different\n" - " way than when it is not specified, and which can count spends twice when\n" - " there are conflicting pending transactions (such as those created by\n" - " the bumpfee command), temporarily resulting in low or even negative\n" - " balances. In general, account balance calculation is not considered\n" - " reliable and has resulted in confusing outcomes, so it is recommended to\n" - " avoid passing this argument.\n" - "2. minconf (numeric, optional) Only include transactions confirmed at least this many times. \n" - " The default is 1 if an account is provided or 0 if no account is provided\n") - : std::string( "getbalance ( \"(dummy)\" minconf include_watchonly )\n" "\nReturns the total available balance.\n" "The available balance is what the wallet considers currently spendable, and is\n" "thus affected by options which limit spendability such as -spendzeroconfchange.\n" "\nArguments:\n" "1. (dummy) (string, optional) Remains for backward compatibility. Must be excluded or set to \"*\".\n" - "2. minconf (numeric, optional, default=0) Only include transactions confirmed at least this many times.\n")) + + "2. minconf (numeric, optional, default=0) Only include transactions confirmed at least this many times.\n" "3. include_watchonly (bool, optional, default=false) Also include balance in watch-only addresses (see 'importaddress')\n" "\nResult:\n" - "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n" + "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this wallet.\n" "\nExamples:\n" "\nThe total amount in the wallet with 1 or more confirmations\n" + HelpExampleCli("getbalance", "") + @@ -913,13 +709,12 @@ static UniValue getbalance(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - const UniValue& account_value = request.params[0]; + const UniValue& dummy_value = request.params[0]; + if (!dummy_value.isNull() && dummy_value.get_str() != "*") { + throw JSONRPCError(RPC_METHOD_DEPRECATED, "dummy first argument must be excluded or set to \"*\"."); + } int min_depth = 0; - if (IsDeprecatedRPCEnabled("accounts") && !account_value.isNull()) { - // Default min_depth to 1 when an account is provided. - min_depth = 1; - } if (!request.params[1].isNull()) { min_depth = request.params[1].get_int(); } @@ -929,18 +724,6 @@ static UniValue getbalance(const JSONRPCRequest& request) filter = filter | ISMINE_WATCH_ONLY; } - if (!account_value.isNull()) { - - const std::string& account_param = account_value.get_str(); - const std::string* account = account_param != "*" ? &account_param : nullptr; - - if (!IsDeprecatedRPCEnabled("accounts") && account_param != "*") { - throw JSONRPCError(RPC_METHOD_DEPRECATED, "dummy first argument must be excluded or set to \"*\"."); - } else if (IsDeprecatedRPCEnabled("accounts")) { - return ValueFromAmount(pwallet->GetLegacyBalance(filter, min_depth, account)); - } - } - return ValueFromAmount(pwallet->GetBalance(filter, min_depth)); } @@ -968,148 +751,6 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request) } -static UniValue movecmd(const JSONRPCRequest& request) -{ - std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); - CWallet* const pwallet = wallet.get(); - - if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { - return NullUniValue; - } - - if (!IsDeprecatedRPCEnabled("accounts")) { - if (request.fHelp) { - throw std::runtime_error("move (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)"); - } - throw JSONRPCError(RPC_METHOD_DEPRECATED, "move is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts."); - } - - if (request.fHelp || request.params.size() < 3 || request.params.size() > 5) - throw std::runtime_error( - "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n" - "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n" - "\nArguments:\n" - "1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n" - "2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n" - "3. amount (numeric) Quantity of " + CURRENCY_UNIT + " to move between accounts.\n" - "4. (dummy) (numeric, optional) Ignored. Remains for backward compatibility.\n" - "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n" - "\nResult:\n" - "true|false (boolean) true if successful.\n" - "\nExamples:\n" - "\nMove 0.01 " + CURRENCY_UNIT + " from the default account to the account named tabby\n" - + HelpExampleCli("move", "\"\" \"tabby\" 0.01") + - "\nMove 0.01 " + CURRENCY_UNIT + " timotei to akiko with a comment and funds have 6 confirmations\n" - + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") + - "\nAs a json rpc call\n" - + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"") - ); - - LOCK2(cs_main, pwallet->cs_wallet); - - std::string strFrom = LabelFromValue(request.params[0]); - std::string strTo = LabelFromValue(request.params[1]); - CAmount nAmount = AmountFromValue(request.params[2]); - if (nAmount <= 0) - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); - if (!request.params[3].isNull()) - // unused parameter, used to be nMinDepth, keep type-checking it though - (void)request.params[3].get_int(); - std::string strComment; - if (!request.params[4].isNull()) - strComment = request.params[4].get_str(); - - if (!pwallet->AccountMove(strFrom, strTo, nAmount, strComment)) { - throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); - } - - return true; -} - - -static UniValue sendfrom(const JSONRPCRequest& request) -{ - std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); - CWallet* const pwallet = wallet.get(); - - if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { - return NullUniValue; - } - - if (!IsDeprecatedRPCEnabled("accounts")) { - if (request.fHelp) { - throw std::runtime_error("sendfrom (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)"); - } - throw JSONRPCError(RPC_METHOD_DEPRECATED, "sendfrom is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts."); - } - - - if (request.fHelp || request.params.size() < 3 || request.params.size() > 6) - throw std::runtime_error( - "sendfrom \"fromaccount\" \"toaddress\" amount ( minconf \"comment\" \"comment_to\" )\n" - "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address." - + HelpRequiringPassphrase(pwallet) + "\n" - "\nArguments:\n" - "1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n" - " Specifying an account does not influence coin selection, but it does associate the newly created\n" - " transaction with the account, so the account's balance computation and transaction history can reflect\n" - " the spend.\n" - "2. \"toaddress\" (string, required) The bitcoin address to send funds to.\n" - "3. amount (numeric or string, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n" - "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n" - "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n" - " This is not part of the transaction, just kept in your wallet.\n" - "6. \"comment_to\" (string, optional) An optional comment to store the name of the person or organization \n" - " to which you're sending the transaction. This is not part of the transaction, \n" - " it is just kept in your wallet.\n" - "\nResult:\n" - "\"txid\" (string) The transaction id.\n" - "\nExamples:\n" - "\nSend 0.01 " + CURRENCY_UNIT + " from the default account to the address, must have at least 1 confirmation\n" - + HelpExampleCli("sendfrom", "\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") + - "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n" - + HelpExampleCli("sendfrom", "\"tabby\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") + - "\nAs a json rpc call\n" - + HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"") - ); - - // Make sure the results are valid at least up to the most recent block - // the user could have gotten from another RPC command prior to now - pwallet->BlockUntilSyncedToCurrentChain(); - - LOCK2(cs_main, pwallet->cs_wallet); - - std::string strAccount = LabelFromValue(request.params[0]); - CTxDestination dest = DecodeDestination(request.params[1].get_str()); - if (!IsValidDestination(dest)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); - } - CAmount nAmount = AmountFromValue(request.params[2]); - if (nAmount <= 0) - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); - int nMinDepth = 1; - if (!request.params[3].isNull()) - nMinDepth = request.params[3].get_int(); - - mapValue_t mapValue; - if (!request.params[4].isNull() && !request.params[4].get_str().empty()) - mapValue["comment"] = request.params[4].get_str(); - if (!request.params[5].isNull() && !request.params[5].get_str().empty()) - mapValue["to"] = request.params[5].get_str(); - - EnsureWalletIsUnlocked(pwallet); - - // Check funds - CAmount nBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount); - if (nAmount > nBalance) - throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); - - CCoinControl no_coin_control; // This is a deprecated API - CTransactionRef tx = SendMoney(pwallet, dest, nAmount, false, no_coin_control, std::move(mapValue), std::move(strAccount)); - return tx->GetHash().GetHex(); -} - - static UniValue sendmany(const JSONRPCRequest& request) { std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); @@ -1119,12 +760,10 @@ static UniValue sendmany(const JSONRPCRequest& request) return NullUniValue; } - std::string help_text; - if (!IsDeprecatedRPCEnabled("accounts")) { - help_text = "sendmany \"\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] replaceable conf_target \"estimate_mode\")\n" + if (request.fHelp || request.params.size() < 2 || request.params.size() > 8) + throw std::runtime_error( + "sendmany \"\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] replaceable conf_target \"estimate_mode\")\n" "\nSend multiple times. Amounts are double-precision floating point numbers.\n" - "Note that the \"fromaccount\" argument has been removed in V0.17. To use this RPC with a \"fromaccount\" argument, restart\n" - "bitcoind with -deprecatedrpc=accounts\n" + HelpRequiringPassphrase(pwallet) + "\n" "\nArguments:\n" "1. \"dummy\" (string, required) Must be set to \"\" for backwards compatibility.\n" @@ -1160,49 +799,8 @@ static UniValue sendmany(const JSONRPCRequest& request) "\nSend two amounts to two different addresses, subtract fee from amount:\n" + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") + "\nAs a json rpc call\n" - + HelpExampleRpc("sendmany", "\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\""); - } else { - help_text = "sendmany \"\" \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] replaceable conf_target \"estimate_mode\")\n" - "\nSend multiple times. Amounts are double-precision floating point numbers." - + HelpRequiringPassphrase(pwallet) + "\n" - "\nArguments:\n" - "1. \"fromaccount\" (string, required) DEPRECATED. The account to send the funds from. Should be \"\" for the default account\n" - "2. \"amounts\" (string, required) A json object with addresses and amounts\n" - " {\n" - " \"address\":amount (numeric or string) The bitcoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value\n" - " ,...\n" - " }\n" - "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n" - "4. \"comment\" (string, optional) A comment\n" - "5. subtractfeefrom (array, optional) A json array with addresses.\n" - " The fee will be equally deducted from the amount of each selected address.\n" - " Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" - " If no addresses are specified here, the sender pays the fee.\n" - " [\n" - " \"address\" (string) Subtract fee from this address\n" - " ,...\n" - " ]\n" - "6. replaceable (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees via BIP 125\n" - "7. conf_target (numeric, optional) Confirmation target (in blocks)\n" - "8. \"estimate_mode\" (string, optional, default=UNSET) The fee estimate mode, must be one of:\n" - " \"UNSET\"\n" - " \"ECONOMICAL\"\n" - " \"CONSERVATIVE\"\n" - "\nResult:\n" - "\"txid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n" - " the number of addresses.\n" - "\nExamples:\n" - "\nSend two amounts to two different addresses:\n" - + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") + - "\nSend two amounts to two different addresses setting the confirmation and comment:\n" - + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") + - "\nSend two amounts to two different addresses, subtract fee from amount:\n" - + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") + - "\nAs a json rpc call\n" - + HelpExampleRpc("sendmany", "\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\""); - } - - if (request.fHelp || request.params.size() < 2 || request.params.size() > 8) throw std::runtime_error(help_text); + + HelpExampleRpc("sendmany", "\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\"") + ); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1214,10 +812,9 @@ static UniValue sendmany(const JSONRPCRequest& request) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } - if (!IsDeprecatedRPCEnabled("accounts") && !request.params[0].get_str().empty()) { + if (!request.params[0].isNull() && !request.params[0].get_str().empty()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"\""); } - std::string strAccount = LabelFromValue(request.params[0]); UniValue sendTo = request.params[1].get_obj(); int nMinDepth = 1; if (!request.params[2].isNull()) @@ -1282,9 +879,7 @@ static UniValue sendmany(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); // Check funds - if (IsDeprecatedRPCEnabled("accounts") && totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount)) { - throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); - } else if (!IsDeprecatedRPCEnabled("accounts") && totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, nullptr)) { + if (totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth)) { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Wallet has insufficient funds"); } @@ -1301,7 +896,7 @@ static UniValue sendmany(const JSONRPCRequest& request) if (!fCreated) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); CValidationState state; - if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, std::move(strAccount), keyChange, g_connman.get(), state)) { + if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, keyChange, g_connman.get(), state)) { strFailReason = strprintf("Transaction commit failed:: %s", FormatStateMessage(state)); throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); } @@ -1635,7 +1230,6 @@ static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bo if(fIsWatchonly) obj.pushKV("involvesWatchonly", true); obj.pushKV("address", EncodeDestination(address)); - obj.pushKV("account", label); obj.pushKV("amount", ValueFromAmount(nAmount)); obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)); obj.pushKV("label", label); @@ -1661,7 +1255,6 @@ static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bo UniValue obj(UniValue::VOBJ); if (entry.second.fIsWatchonly) obj.pushKV("involvesWatchonly", true); - obj.pushKV("account", entry.first); obj.pushKV("amount", ValueFromAmount(nAmount)); obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)); obj.pushKV("label", entry.first); @@ -1695,7 +1288,6 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request) " {\n" " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n" " \"address\" : \"receivingaddress\", (string) The receiving address\n" - " \"account\" : \"accountname\", (string) DEPRECATED. Backwards compatible alias for label.\n" " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n" " \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n" " \"label\" : \"label\", (string) The label of the receiving address. The default label is \"\".\n" @@ -1732,13 +1324,6 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request) return NullUniValue; } - if (!IsDeprecatedRPCEnabled("accounts") && request.strMethod == "listreceivedbyaccount") { - if (request.fHelp) { - throw std::runtime_error("listreceivedbyaccount (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)"); - } - throw JSONRPCError(RPC_METHOD_DEPRECATED, "listreceivedbyaccount is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts."); - } - if (request.fHelp || request.params.size() > 3) throw std::runtime_error( "listreceivedbylabel ( minconf include_empty include_watchonly)\n" @@ -1752,7 +1337,6 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request) "[\n" " {\n" " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n" - " \"account\" : \"accountname\", (string) DEPRECATED. Backwards compatible alias for label.\n" " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this label\n" " \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n" " \"label\" : \"label\" (string) The label of the receiving address. The default label is \"\".\n" @@ -1787,26 +1371,23 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) * * @param pwallet The wallet. * @param wtx The wallet transaction. - * @param strAccount The account, if any, or "*" for all. * @param nMinDepth The minimum confirmation depth. * @param fLong Whether to include the JSON version of the transaction. * @param ret The UniValue into which the result is stored. * @param filter The "is mine" filter bool. */ -static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { CAmount nFee; - std::string strSentAccount; std::list<COutputEntry> listReceived; std::list<COutputEntry> listSent; - wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter); + wtx.GetAmounts(listReceived, listSent, nFee, filter); - bool fAllAccounts = (strAccount == std::string("*")); bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY); // Sent - if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) + if ((!listSent.empty() || nFee != 0)) { for (const COutputEntry& s : listSent) { @@ -1814,7 +1395,6 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const if (involvesWatchonly || (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY)) { entry.pushKV("involvesWatchonly", true); } - if (IsDeprecatedRPCEnabled("accounts")) entry.pushKV("account", strSentAccount); MaybePushAddress(entry, s.destination); entry.pushKV("category", "send"); entry.pushKV("amount", ValueFromAmount(-s.amount)); @@ -1835,61 +1415,40 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const { for (const COutputEntry& r : listReceived) { - std::string account; + std::string label; if (pwallet->mapAddressBook.count(r.destination)) { - account = pwallet->mapAddressBook[r.destination].name; + label = pwallet->mapAddressBook[r.destination].name; } - if (fAllAccounts || (account == strAccount)) + UniValue entry(UniValue::VOBJ); + if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) { + entry.pushKV("involvesWatchonly", true); + } + MaybePushAddress(entry, r.destination); + if (wtx.IsCoinBase()) { - UniValue entry(UniValue::VOBJ); - if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) { - entry.pushKV("involvesWatchonly", true); - } - if (IsDeprecatedRPCEnabled("accounts")) entry.pushKV("account", account); - MaybePushAddress(entry, r.destination); - if (wtx.IsCoinBase()) - { - if (wtx.GetDepthInMainChain() < 1) - entry.pushKV("category", "orphan"); - else if (wtx.IsImmatureCoinBase()) - entry.pushKV("category", "immature"); - else - entry.pushKV("category", "generate"); - } + if (wtx.GetDepthInMainChain() < 1) + entry.pushKV("category", "orphan"); + else if (wtx.IsImmatureCoinBase()) + entry.pushKV("category", "immature"); else - { - entry.pushKV("category", "receive"); - } - entry.pushKV("amount", ValueFromAmount(r.amount)); - if (pwallet->mapAddressBook.count(r.destination)) { - entry.pushKV("label", account); - } - entry.pushKV("vout", r.vout); - if (fLong) - WalletTxToJSON(wtx, entry); - ret.push_back(entry); + entry.pushKV("category", "generate"); + } + else + { + entry.pushKV("category", "receive"); + } + entry.pushKV("amount", ValueFromAmount(r.amount)); + if (pwallet->mapAddressBook.count(r.destination)) { + entry.pushKV("label", label); } + entry.pushKV("vout", r.vout); + if (fLong) + WalletTxToJSON(wtx, entry); + ret.push_back(entry); } } } -static void AcentryToJSON(const CAccountingEntry& acentry, const std::string& strAccount, UniValue& ret) -{ - bool fAllAccounts = (strAccount == std::string("*")); - - if (fAllAccounts || acentry.strAccount == strAccount) - { - UniValue entry(UniValue::VOBJ); - entry.pushKV("account", acentry.strAccount); - entry.pushKV("category", "move"); - entry.pushKV("time", acentry.nTime); - entry.pushKV("amount", ValueFromAmount(acentry.nCreditDebit)); - if (IsDeprecatedRPCEnabled("accounts")) entry.pushKV("otheraccount", acentry.strOtherAccount); - entry.pushKV("comment", acentry.strComment); - ret.push_back(entry); - } -} - UniValue listtransactions(const JSONRPCRequest& request) { std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); @@ -1899,12 +1458,10 @@ UniValue listtransactions(const JSONRPCRequest& request) return NullUniValue; } - std::string help_text {}; - if (!IsDeprecatedRPCEnabled("accounts")) { - help_text = "listtransactions (dummy count skip include_watchonly)\n" - "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n" - "Note that the \"account\" argument and \"otheraccount\" return value have been removed in V0.17. To use this RPC with an \"account\" argument, restart\n" - "bitcoind with -deprecatedrpc=accounts\n" + if (request.fHelp || request.params.size() > 4) + throw std::runtime_error( + "listtransactions (dummy count skip include_watchonly)\n" + "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n" "\nArguments:\n" "1. \"dummy\" (string, optional) If set, should be \"*\" for backwards compatibility.\n" "2. count (numeric, optional, default=10) The number of transactions to return\n" @@ -1944,77 +1501,15 @@ UniValue listtransactions(const JSONRPCRequest& request) "\nList transactions 100 to 120\n" + HelpExampleCli("listtransactions", "\"*\" 20 100") + "\nAs a json rpc call\n" - + HelpExampleRpc("listtransactions", "\"*\", 20, 100"); - } else { - help_text = "listtransactions ( \"account\" count skip include_watchonly)\n" - "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n" - "\nArguments:\n" - "1. \"account\" (string, optional) DEPRECATED. This argument will be removed in V0.18. The account name. Should be \"*\".\n" - "2. count (numeric, optional, default=10) The number of transactions to return\n" - "3. skip (numeric, optional, default=0) The number of transactions to skip\n" - "4. include_watchonly (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')\n" - "\nResult:\n" - "[\n" - " {\n" - " \"account\":\"accountname\", (string) DEPRECATED. This field will be removed in V0.18. The account name associated with the transaction. \n" - " It will be \"\" for the default account.\n" - " \"address\":\"address\", (string) The bitcoin address of the transaction. Not present for \n" - " move transactions (category = move).\n" - " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n" - " transaction between accounts, and not associated with an address,\n" - " transaction id or block. 'send' and 'receive' transactions are \n" - " associated with an address, transaction id and block details\n" - " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the\n" - " 'move' category for moves outbound. It is positive for the 'receive' category,\n" - " and for the 'move' category for inbound funds.\n" - " \"label\": \"label\", (string) A comment for the address/transaction, if any\n" - " \"vout\": n, (numeric) the vout value\n" - " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n" - " 'send' category of transactions.\n" - " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n" - " 'receive' category of transactions. Negative confirmations indicate the\n" - " transaction conflicts with the block chain\n" - " \"trusted\": xxx, (bool) Whether we consider the outputs of this unconfirmed transaction safe to spend.\n" - " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n" - " category of transactions.\n" - " \"blockindex\": n, (numeric) The index of the transaction in the block that includes it. Available for 'send' and 'receive'\n" - " category of transactions.\n" - " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n" - " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n" - " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n" - " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n" - " for 'send' and 'receive' category of transactions.\n" - " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n" - " \"otheraccount\": \"accountname\", (string) DEPRECATED. This field will be removed in V0.18. For the 'move' category of transactions, the account the funds came \n" - " from (for receiving funds, positive amounts), or went to (for sending funds,\n" - " negative amounts).\n" - " \"bip125-replaceable\": \"yes|no|unknown\", (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n" - " may be unknown for unconfirmed transactions not in the mempool\n" - " \"abandoned\": xxx (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n" - " 'send' category of transactions.\n" - " }\n" - "]\n" - - "\nExamples:\n" - "\nList the most recent 10 transactions in the systems\n" - + HelpExampleCli("listtransactions", "") + - "\nList transactions 100 to 120\n" - + HelpExampleCli("listtransactions", "\"*\" 20 100") + - "\nAs a json rpc call\n" - + HelpExampleRpc("listtransactions", "\"*\", 20, 100"); - } - if (request.fHelp || request.params.size() > 4) throw std::runtime_error(help_text); + + HelpExampleRpc("listtransactions", "\"*\", 20, 100") + ); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now pwallet->BlockUntilSyncedToCurrentChain(); - std::string strAccount = "*"; - if (!request.params[0].isNull()) { - strAccount = request.params[0].get_str(); - if (!IsDeprecatedRPCEnabled("accounts") && strAccount != "*") { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"*\""); - } + if (!request.params[0].isNull() && request.params[0].get_str() != "*") { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"*\""); } int nCount = 10; if (!request.params[1].isNull()) @@ -2042,14 +1537,8 @@ UniValue listtransactions(const JSONRPCRequest& request) // iterate backwards until we have nCount items to return: for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { - CWalletTx *const pwtx = (*it).second.first; - if (pwtx != nullptr) - ListTransactions(pwallet, *pwtx, strAccount, 0, true, ret, filter); - if (IsDeprecatedRPCEnabled("accounts")) { - CAccountingEntry *const pacentry = (*it).second.second; - if (pacentry != nullptr) AcentryToJSON(*pacentry, strAccount, ret); - } - + CWalletTx *const pwtx = (*it).second; + ListTransactions(pwallet, *pwtx, 0, true, ret, filter); if ((int)ret.size() >= (nCount+nFrom)) break; } } @@ -2080,101 +1569,6 @@ UniValue listtransactions(const JSONRPCRequest& request) return ret; } -static UniValue listaccounts(const JSONRPCRequest& request) -{ - std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); - CWallet* const pwallet = wallet.get(); - - if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { - return NullUniValue; - } - - if (!IsDeprecatedRPCEnabled("accounts")) { - if (request.fHelp) { - throw std::runtime_error("listaccounts (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)"); - } - throw JSONRPCError(RPC_METHOD_DEPRECATED, "listaccounts is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts."); - } - - if (request.fHelp || request.params.size() > 2) - throw std::runtime_error( - "listaccounts ( minconf include_watchonly)\n" - "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n" - "\nArguments:\n" - "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n" - "2. include_watchonly (bool, optional, default=false) Include balances in watch-only addresses (see 'importaddress')\n" - "\nResult:\n" - "{ (json object where keys are account names, and values are numeric balances\n" - " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n" - " ...\n" - "}\n" - "\nExamples:\n" - "\nList account balances where there at least 1 confirmation\n" - + HelpExampleCli("listaccounts", "") + - "\nList account balances including zero confirmation transactions\n" - + HelpExampleCli("listaccounts", "0") + - "\nList account balances for 6 or more confirmations\n" - + HelpExampleCli("listaccounts", "6") + - "\nAs json rpc call\n" - + HelpExampleRpc("listaccounts", "6") - ); - - // Make sure the results are valid at least up to the most recent block - // the user could have gotten from another RPC command prior to now - pwallet->BlockUntilSyncedToCurrentChain(); - - LOCK2(cs_main, pwallet->cs_wallet); - - int nMinDepth = 1; - if (!request.params[0].isNull()) - nMinDepth = request.params[0].get_int(); - isminefilter includeWatchonly = ISMINE_SPENDABLE; - if(!request.params[1].isNull()) - if(request.params[1].get_bool()) - includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY; - - std::map<std::string, CAmount> mapAccountBalances; - for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) { - if (IsMine(*pwallet, entry.first) & includeWatchonly) { // This address belongs to me - mapAccountBalances[entry.second.name] = 0; - } - } - - for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) { - const CWalletTx& wtx = pairWtx.second; - CAmount nFee; - std::string strSentAccount; - std::list<COutputEntry> listReceived; - std::list<COutputEntry> listSent; - int nDepth = wtx.GetDepthInMainChain(); - if (wtx.IsImmatureCoinBase() || nDepth < 0) - continue; - wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly); - mapAccountBalances[strSentAccount] -= nFee; - for (const COutputEntry& s : listSent) - mapAccountBalances[strSentAccount] -= s.amount; - if (nDepth >= nMinDepth) - { - for (const COutputEntry& r : listReceived) - if (pwallet->mapAddressBook.count(r.destination)) { - mapAccountBalances[pwallet->mapAddressBook[r.destination].name] += r.amount; - } - else - mapAccountBalances[""] += r.amount; - } - } - - const std::list<CAccountingEntry>& acentries = pwallet->laccentries; - for (const CAccountingEntry& entry : acentries) - mapAccountBalances[entry.strAccount] += entry.nCreditDebit; - - UniValue ret(UniValue::VOBJ); - for (const std::pair<const std::string, CAmount>& accountBalance : mapAccountBalances) { - ret.pushKV(accountBalance.first, ValueFromAmount(accountBalance.second)); - } - return ret; -} - static UniValue listsinceblock(const JSONRPCRequest& request) { std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); @@ -2199,7 +1593,6 @@ static UniValue listsinceblock(const JSONRPCRequest& request) "\nResult:\n" "{\n" " \"transactions\": [\n" - " \"account\":\"accountname\", (string) DEPRECATED. This field will be removed in V0.18. To see this deprecated field, start bitcoind with -deprecatedrpc=accounts. The account name associated with the transaction. Will be \"\" for the default account.\n" " \"address\":\"address\", (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n" " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n" " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the 'move' category for moves \n" @@ -2282,7 +1675,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request) CWalletTx tx = pairWtx.second; if (depth == -1 || tx.GetDepthInMainChain() < depth) { - ListTransactions(pwallet, tx, "*", 0, true, transactions, filter); + ListTransactions(pwallet, tx, 0, true, transactions, filter); } } @@ -2299,7 +1692,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request) if (it != pwallet->mapWallet.end()) { // We want all transactions regardless of confirmation count to appear here, // even negative confirmation ones, hence the big negative. - ListTransactions(pwallet, it->second, "*", -100000000, true, removed, filter); + ListTransactions(pwallet, it->second, -100000000, true, removed, filter); } } paltindex = paltindex->pprev; @@ -2348,7 +1741,6 @@ static UniValue gettransaction(const JSONRPCRequest& request) " may be unknown for unconfirmed transactions not in the mempool\n" " \"details\" : [\n" " {\n" - " \"account\" : \"accountname\", (string) DEPRECATED. This field will be removed in a V0.18. To see this deprecated field, start bitcoind with -deprecatedrpc=accounts. The account name involved in the transaction, can be \"\" for the default account.\n" " \"address\" : \"address\", (string) The bitcoin address involved in the transaction\n" " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n" " \"amount\" : x.xxx, (numeric) The amount in " + CURRENCY_UNIT + "\n" @@ -2403,7 +1795,7 @@ static UniValue gettransaction(const JSONRPCRequest& request) WalletTxToJSON(wtx, entry); UniValue details(UniValue::VARR); - ListTransactions(pwallet, wtx, "*", 0, false, details, filter); + ListTransactions(pwallet, wtx, 0, false, details, filter); entry.pushKV("details", details); std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags()); @@ -2945,7 +2337,7 @@ static UniValue listlockunspent(const JSONRPCRequest& request) UniValue ret(UniValue::VARR); - for (COutPoint &outpt : vOutpts) { + for (const COutPoint& outpt : vOutpts) { UniValue o(UniValue::VOBJ); o.pushKV("txid", outpt.hash.GetHex()); @@ -3326,7 +2718,6 @@ static UniValue listunspent(const JSONRPCRequest& request) " \"vout\" : n, (numeric) the vout value\n" " \"address\" : \"address\", (string) the bitcoin address\n" " \"label\" : \"label\", (string) The associated label, or \"\" for the default label\n" - " \"account\" : \"account\", (string) DEPRECATED. This field will be removed in V0.18. To see this deprecated field, start bitcoind with -deprecatedrpc=accounts. The associated account, or \"\" for the default account\n" " \"scriptPubKey\" : \"key\", (string) the script key\n" " \"amount\" : x.xxx, (numeric) the transaction output amount in " + CURRENCY_UNIT + "\n" " \"confirmations\" : n, (numeric) The number of confirmations\n" @@ -3434,9 +2825,6 @@ static UniValue listunspent(const JSONRPCRequest& request) auto i = pwallet->mapAddressBook.find(address); if (i != pwallet->mapAddressBook.end()) { entry.pushKV("label", i->second.name); - if (IsDeprecatedRPCEnabled("accounts")) { - entry.pushKV("account", i->second.name); - } } if (scriptPubKey.IsPayToScriptHash()) { @@ -4175,10 +3563,9 @@ UniValue getaddressinfo(const JSONRPCRequest& request) " ]\n" " \"sigsrequired\" : xxxxx (numeric, optional) Number of signatures required to spend multisig output (only if \"script\" is \"multisig\")\n" " \"pubkey\" : \"publickeyhex\", (string, optional) The hex value of the raw public key, for single-key addresses (possibly embedded in P2SH or P2WSH)\n" - " \"embedded\" : {...}, (object, optional) Information about the address embedded in P2SH or P2WSH, if relevant and known. It includes all getaddressinfo output fields for the embedded address, excluding metadata (\"timestamp\", \"hdkeypath\", \"hdseedid\") and relation to the wallet (\"ismine\", \"iswatchonly\", \"account\").\n" + " \"embedded\" : {...}, (object, optional) Information about the address embedded in P2SH or P2WSH, if relevant and known. It includes all getaddressinfo output fields for the embedded address, excluding metadata (\"timestamp\", \"hdkeypath\", \"hdseedid\") and relation to the wallet (\"ismine\", \"iswatchonly\").\n" " \"iscompressed\" : true|false, (boolean) If the address is compressed\n" - " \"label\" : \"label\" (string) The label associated with the address, \"\" is the default account\n" - " \"account\" : \"account\" (string) DEPRECATED. This field will be removed in V0.18. To see this deprecated field, start bitcoind with -deprecatedrpc=accounts. The account associated with the address, \"\" is the default account\n" + " \"label\" : \"label\" (string) The label associated with the address, \"\" is the default label\n" " \"timestamp\" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT)\n" " \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n" " \"hdseedid\" : \"<hash160>\" (string, optional) The Hash160 of the HD seed\n" @@ -4220,9 +3607,6 @@ UniValue getaddressinfo(const JSONRPCRequest& request) ret.pushKVs(detail); if (pwallet->mapAddressBook.count(dest)) { ret.pushKV("label", pwallet->mapAddressBook[dest].name); - if (IsDeprecatedRPCEnabled("accounts")) { - ret.pushKV("account", pwallet->mapAddressBook[dest].name); - } } const CKeyMetadata* meta = nullptr; CKeyID key_id = GetKeyForDestination(*pwallet, dest); @@ -4430,74 +3814,17 @@ UniValue sethdseed(const JSONRPCRequest& request) return NullUniValue; } -bool ParseHDKeypath(std::string keypath_str, std::vector<uint32_t>& keypath) -{ - std::stringstream ss(keypath_str); - std::string item; - bool first = true; - while (std::getline(ss, item, '/')) { - if (item.compare("m") == 0) { - if (first) { - first = false; - continue; - } - return false; - } - // Finds whether it is hardened - uint32_t path = 0; - size_t pos = item.find("'"); - if (pos != std::string::npos) { - // The hardened tick can only be in the last index of the string - if (pos != item.size() - 1) { - return false; - } - path |= 0x80000000; - item = item.substr(0, item.size() - 1); // Drop the last character which is the hardened tick - } - - // Ensure this is only numbers - if (item.find_first_not_of( "0123456789" ) != std::string::npos) { - return false; - } - uint32_t number; - if (!ParseUInt32(item, &number)) { - return false; - } - path |= number; - - keypath.push_back(path); - first = false; - } - return true; -} - -void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths) +void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, KeyOriginInfo>& hd_keypaths) { CPubKey vchPubKey; if (!pwallet->GetPubKey(keyID, vchPubKey)) { return; } - CKeyMetadata meta; - auto it = pwallet->mapKeyMetadata.find(keyID); - if (it != pwallet->mapKeyMetadata.end()) { - meta = it->second; + KeyOriginInfo info; + if (!pwallet->GetKeyOrigin(keyID, info)) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken"); } - std::vector<uint32_t> keypath; - if (!meta.hdKeypath.empty()) { - if (!ParseHDKeypath(meta.hdKeypath, keypath)) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken"); - } - // Get the proper master key id - CKey key; - pwallet->GetKey(meta.hd_seed_id, key); - CExtKey masterKey; - masterKey.SetSeed(key.begin(), key.size()); - // Add to map - keypath.insert(keypath.begin(), ReadLE32(masterKey.key.GetPubKey().GetID().begin())); - } else { // Single pubkeys get the master fingerprint of themselves - keypath.insert(keypath.begin(), ReadLE32(vchPubKey.GetID().begin())); - } - hd_keypaths.emplace(vchPubKey, keypath); + hd_keypaths.emplace(vchPubKey, std::move(info)); } bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const CTransaction* txConst, int sighash_type, bool sign, bool bip32derivs) @@ -4525,28 +3852,7 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Specified Sighash and sighash in PSBT do not match."); } - SignatureData sigdata; - if (sign) { - complete &= SignPSBTInput(*pwallet, *psbtx.tx, input, sigdata, i, sighash_type); - } else { - complete &= SignPSBTInput(PublicOnlySigningProvider(pwallet), *psbtx.tx, input, sigdata, i, sighash_type); - } - - if (it != pwallet->mapWallet.end()) { - // Drop the unnecessary UTXO if we added both from the wallet. - if (sigdata.witness) { - input.non_witness_utxo = nullptr; - } else { - input.witness_utxo.SetNull(); - } - } - - // Get public key paths - if (bip32derivs) { - for (const auto& pubkey_it : sigdata.misc_pubkeys) { - AddKeypathToMap(pwallet, pubkey_it.first, input.hd_keypaths); - } - } + complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, !bip32derivs), *psbtx.tx, input, i, sighash_type); } // Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change @@ -4559,15 +3865,8 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C psbt_out.FillSignatureData(sigdata); MutableTransactionSignatureCreator creator(psbtx.tx.get_ptr(), 0, out.nValue, 1); - ProduceSignature(*pwallet, creator, out.scriptPubKey, sigdata); + ProduceSignature(HidingSigningProvider(pwallet, true, !bip32derivs), creator, out.scriptPubKey, sigdata); psbt_out.FromSignatureData(sigdata); - - // Get public key paths - if (bip32derivs) { - for (const auto& pubkey_it : sigdata.misc_pubkeys) { - AddKeypathToMap(pwallet, pubkey_it.first, psbt_out.hd_keypaths); - } - } } return complete; } @@ -4741,7 +4040,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) const CTransaction txConst(*psbtx.tx); // Fill transaction with out data but don't sign - bool bip32derivs = request.params[4].isNull() ? false : request.params[5].get_bool(); + bool bip32derivs = request.params[4].isNull() ? false : request.params[4].get_bool(); FillPSBT(pwallet, psbtx, &txConst, 1, false, bip32derivs); // Serialize the PSBT @@ -4769,76 +4068,62 @@ UniValue importmulti(const JSONRPCRequest& request); static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- - { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} }, - { "wallet", "walletprocesspsbt", &walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} }, - { "wallet", "walletcreatefundedpsbt", &walletcreatefundedpsbt, {"inputs","outputs","locktime","options","bip32derivs"} }, + { "generating", "generate", &generate, {"nblocks","maxtries"} }, + { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} }, { "hidden", "resendwallettransactions", &resendwallettransactions, {} }, + { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} }, { "wallet", "abandontransaction", &abandontransaction, {"txid"} }, { "wallet", "abortrescan", &abortrescan, {} }, - { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label|account","address_type"} }, - { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} }, + { "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"} }, { "wallet", "dumpprivkey", &dumpprivkey, {"address"} }, { "wallet", "dumpwallet", &dumpwallet, {"filename"} }, { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} }, + { "wallet", "getaddressesbylabel", &getaddressesbylabel, {"label"} }, { "wallet", "getaddressinfo", &getaddressinfo, {"address"} }, - { "wallet", "getbalance", &getbalance, {"account|dummy","minconf","include_watchonly"} }, - { "wallet", "getnewaddress", &getnewaddress, {"label|account","address_type"} }, + { "wallet", "getbalance", &getbalance, {"dummy","minconf","include_watchonly"} }, + { "wallet", "getnewaddress", &getnewaddress, {"label","address_type"} }, { "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} }, { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} }, + { "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf"} }, { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} }, { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} }, { "wallet", "getwalletinfo", &getwalletinfo, {} }, + { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} }, { "wallet", "importmulti", &importmulti, {"requests","options"} }, { "wallet", "importprivkey", &importprivkey, {"privkey","label","rescan"} }, - { "wallet", "importwallet", &importwallet, {"filename"} }, - { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} }, { "wallet", "importprunedfunds", &importprunedfunds, {"rawtransaction","txoutproof"} }, { "wallet", "importpubkey", &importpubkey, {"pubkey","label","rescan"} }, + { "wallet", "importwallet", &importwallet, {"filename"} }, { "wallet", "keypoolrefill", &keypoolrefill, {"newsize"} }, { "wallet", "listaddressgroupings", &listaddressgroupings, {} }, + { "wallet", "listlabels", &listlabels, {"purpose"} }, { "wallet", "listlockunspent", &listlockunspent, {} }, { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} }, + { "wallet", "listreceivedbylabel", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, { "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} }, - { "wallet", "listtransactions", &listtransactions, {"account|dummy","count","skip","include_watchonly"} }, + { "wallet", "listtransactions", &listtransactions, {"dummy","count","skip","include_watchonly"} }, { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} }, { "wallet", "listwallets", &listwallets, {} }, { "wallet", "loadwallet", &loadwallet, {"filename"} }, { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} }, - { "wallet", "sendmany", &sendmany, {"fromaccount|dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} }, + { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} }, + { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} }, + { "wallet", "sendmany", &sendmany, {"dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} }, { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} }, + { "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} }, + { "wallet", "setlabel", &setlabel, {"address","label"} }, { "wallet", "settxfee", &settxfee, {"amount"} }, { "wallet", "signmessage", &signmessage, {"address","message"} }, { "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} }, { "wallet", "unloadwallet", &unloadwallet, {"wallet_name"} }, + { "wallet", "walletcreatefundedpsbt", &walletcreatefundedpsbt, {"inputs","outputs","locktime","options","bip32derivs"} }, { "wallet", "walletlock", &walletlock, {} }, - { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} }, { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} }, - { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} }, - { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} }, - { "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} }, - - /** Account functions (deprecated) */ - { "wallet", "getaccountaddress", &getaccountaddress, {"account"} }, - { "wallet", "getaccount", &getaccount, {"address"} }, - { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} }, - { "wallet", "getreceivedbyaccount", &getreceivedbylabel, {"account","minconf"} }, - { "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} }, - { "wallet", "listreceivedbyaccount", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, - { "wallet", "setaccount", &setlabel, {"address","account"} }, - { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} }, - { "wallet", "move", &movecmd, {"fromaccount","toaccount","amount","minconf","comment"} }, - - /** Label functions (to replace non-balance account functions) */ - { "wallet", "getaddressesbylabel", &getaddressesbylabel, {"label"} }, - { "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf"} }, - { "wallet", "listlabels", &listlabels, {"purpose"} }, - { "wallet", "listreceivedbylabel", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, - { "wallet", "setlabel", &setlabel, {"address","label"} }, - - { "generating", "generate", &generate, {"nblocks","maxtries"} }, + { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} }, + { "wallet", "walletprocesspsbt", &walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} }, }; void RegisterWalletRPCCommands(CRPCTable &t) diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp deleted file mode 100644 index 79060887be..0000000000 --- a/src/wallet/test/accounting_tests.cpp +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2012-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 <wallet/wallet.h> - -#include <wallet/test/wallet_test_fixture.h> - -#include <stdint.h> - -#include <boost/test/unit_test.hpp> - -BOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup) - -static void -GetResults(CWallet& wallet, std::map<CAmount, CAccountingEntry>& results) -{ - std::list<CAccountingEntry> aes; - - results.clear(); - BOOST_CHECK(wallet.ReorderTransactions() == DBErrors::LOAD_OK); - wallet.ListAccountCreditDebit("", aes); - for (CAccountingEntry& ae : aes) - { - results[ae.nOrderPos] = ae; - } -} - -BOOST_AUTO_TEST_CASE(acc_orderupgrade) -{ - std::vector<CWalletTx*> vpwtx; - CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef()); - CAccountingEntry ae; - std::map<CAmount, CAccountingEntry> results; - - LOCK(m_wallet.cs_wallet); - - ae.strAccount = ""; - ae.nCreditDebit = 1; - ae.nTime = 1333333333; - ae.strOtherAccount = "b"; - ae.strComment = ""; - m_wallet.AddAccountingEntry(ae); - - wtx.mapValue["comment"] = "z"; - m_wallet.AddToWallet(wtx); - vpwtx.push_back(&m_wallet.mapWallet.at(wtx.GetHash())); - vpwtx[0]->nTimeReceived = (unsigned int)1333333335; - vpwtx[0]->nOrderPos = -1; - - ae.nTime = 1333333336; - ae.strOtherAccount = "c"; - m_wallet.AddAccountingEntry(ae); - - GetResults(m_wallet, results); - - BOOST_CHECK(m_wallet.nOrderPosNext == 3); - BOOST_CHECK(2 == results.size()); - BOOST_CHECK(results[0].nTime == 1333333333); - BOOST_CHECK(results[0].strComment.empty()); - BOOST_CHECK(1 == vpwtx[0]->nOrderPos); - BOOST_CHECK(results[2].nTime == 1333333336); - BOOST_CHECK(results[2].strOtherAccount == "c"); - - - ae.nTime = 1333333330; - ae.strOtherAccount = "d"; - ae.nOrderPos = m_wallet.IncOrderPosNext(); - m_wallet.AddAccountingEntry(ae); - - GetResults(m_wallet, results); - - BOOST_CHECK(results.size() == 3); - BOOST_CHECK(m_wallet.nOrderPosNext == 4); - BOOST_CHECK(results[0].nTime == 1333333333); - BOOST_CHECK(1 == vpwtx[0]->nOrderPos); - BOOST_CHECK(results[2].nTime == 1333333336); - BOOST_CHECK(results[3].nTime == 1333333330); - BOOST_CHECK(results[3].strComment.empty()); - - - wtx.mapValue["comment"] = "y"; - { - CMutableTransaction tx(*wtx.tx); - ++tx.nLockTime; // Just to change the hash :) - wtx.SetTx(MakeTransactionRef(std::move(tx))); - } - m_wallet.AddToWallet(wtx); - vpwtx.push_back(&m_wallet.mapWallet.at(wtx.GetHash())); - vpwtx[1]->nTimeReceived = (unsigned int)1333333336; - - wtx.mapValue["comment"] = "x"; - { - CMutableTransaction tx(*wtx.tx); - ++tx.nLockTime; // Just to change the hash :) - wtx.SetTx(MakeTransactionRef(std::move(tx))); - } - m_wallet.AddToWallet(wtx); - vpwtx.push_back(&m_wallet.mapWallet.at(wtx.GetHash())); - vpwtx[2]->nTimeReceived = (unsigned int)1333333329; - vpwtx[2]->nOrderPos = -1; - - GetResults(m_wallet, results); - - BOOST_CHECK(results.size() == 3); - BOOST_CHECK(m_wallet.nOrderPosNext == 6); - BOOST_CHECK(0 == vpwtx[2]->nOrderPos); - BOOST_CHECK(results[1].nTime == 1333333333); - BOOST_CHECK(2 == vpwtx[0]->nOrderPos); - BOOST_CHECK(results[3].nTime == 1333333336); - BOOST_CHECK(results[4].nTime == 1333333330); - BOOST_CHECK(results[4].strComment.empty()); - BOOST_CHECK(5 == vpwtx[1]->nOrderPos); - - - ae.nTime = 1333333334; - ae.strOtherAccount = "e"; - ae.nOrderPos = -1; - m_wallet.AddAccountingEntry(ae); - - GetResults(m_wallet, results); - - BOOST_CHECK(results.size() == 4); - BOOST_CHECK(m_wallet.nOrderPosNext == 7); - BOOST_CHECK(0 == vpwtx[2]->nOrderPos); - BOOST_CHECK(results[1].nTime == 1333333333); - BOOST_CHECK(2 == vpwtx[0]->nOrderPos); - BOOST_CHECK(results[3].nTime == 1333333336); - BOOST_CHECK(results[3].strComment.empty()); - BOOST_CHECK(results[4].nTime == 1333333330); - BOOST_CHECK(results[4].strComment.empty()); - BOOST_CHECK(results[5].nTime == 1333333334); - BOOST_CHECK(6 == vpwtx[1]->nOrderPos); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp index 61c3fa94a6..526f2d983f 100644 --- a/src/wallet/test/psbt_wallet_tests.cpp +++ b/src/wallet/test/psbt_wallet_tests.cpp @@ -13,8 +13,6 @@ #include <test/test_bitcoin.h> #include <wallet/test/wallet_test_fixture.h> -extern bool ParseHDKeypath(std::string keypath_str, std::vector<uint32_t>& keypath); - BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup) BOOST_AUTO_TEST_CASE(psbt_updater_test) diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index f44311b0be..3a8e6f751a 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -297,7 +297,7 @@ public: CCoinControl dummy; BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, reservekey, fee, changePos, error, dummy)); CValidationState state; - BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, {}, reservekey, nullptr, state)); + BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservekey, nullptr, state)); CMutableTransaction blocktx; { LOCK(wallet->cs_wallet); @@ -320,7 +320,11 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) // Confirm ListCoins initially returns 1 coin grouped under coinbaseKey // address. - auto list = wallet->ListCoins(); + std::map<CTxDestination, std::vector<COutput>> list; + { + LOCK2(cs_main, wallet->cs_wallet); + list = wallet->ListCoins(); + } BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U); @@ -333,7 +337,10 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) // coinbaseKey pubkey, even though the change address has a different // pubkey. AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */}); - list = wallet->ListCoins(); + { + LOCK2(cs_main, wallet->cs_wallet); + list = wallet->ListCoins(); + } BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U); @@ -359,7 +366,10 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) } // Confirm ListCoins still returns same result as before, despite coins // being locked. - list = wallet->ListCoins(); + { + LOCK2(cs_main, wallet->cs_wallet); + list = wallet->ListCoins(); + } BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index d0857bcb72..e41f829f02 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -585,7 +585,6 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran // nTimeReceived not copied on purpose copyTo->nTimeSmart = copyFrom->nTimeSmart; copyTo->fFromMe = copyFrom->fFromMe; - copyTo->strFromAccount = copyFrom->strFromAccount; // nOrderPos not copied on purpose // cached members not copied on purpose } @@ -735,44 +734,30 @@ DBErrors CWallet::ReorderTransactions() // Old wallets didn't have any defined order for transactions // Probably a bad idea to change the output of this - // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap. - typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair; - typedef std::multimap<int64_t, TxPair > TxItems; + // First: get all CWalletTx into a sorted-by-time multimap. + typedef std::multimap<int64_t, CWalletTx*> TxItems; TxItems txByTime; for (auto& entry : mapWallet) { CWalletTx* wtx = &entry.second; - txByTime.insert(std::make_pair(wtx->nTimeReceived, TxPair(wtx, nullptr))); - } - std::list<CAccountingEntry> acentries; - batch.ListAccountCreditDebit("", acentries); - for (CAccountingEntry& entry : acentries) - { - txByTime.insert(std::make_pair(entry.nTime, TxPair(nullptr, &entry))); + txByTime.insert(std::make_pair(wtx->nTimeReceived, wtx)); } nOrderPosNext = 0; std::vector<int64_t> nOrderPosOffsets; for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it) { - CWalletTx *const pwtx = (*it).second.first; - CAccountingEntry *const pacentry = (*it).second.second; - int64_t& nOrderPos = (pwtx != nullptr) ? pwtx->nOrderPos : pacentry->nOrderPos; + CWalletTx *const pwtx = (*it).second; + int64_t& nOrderPos = pwtx->nOrderPos; if (nOrderPos == -1) { nOrderPos = nOrderPosNext++; nOrderPosOffsets.push_back(nOrderPos); - if (pwtx) - { - if (!batch.WriteTx(*pwtx)) - return DBErrors::LOAD_FAIL; - } - else - if (!batch.WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) - return DBErrors::LOAD_FAIL; + if (!batch.WriteTx(*pwtx)) + return DBErrors::LOAD_FAIL; } else { @@ -789,14 +774,8 @@ DBErrors CWallet::ReorderTransactions() continue; // Since we're changing the order, write it back - if (pwtx) - { - if (!batch.WriteTx(*pwtx)) - return DBErrors::LOAD_FAIL; - } - else - if (!batch.WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) - return DBErrors::LOAD_FAIL; + if (!batch.WriteTx(*pwtx)) + return DBErrors::LOAD_FAIL; } } batch.WriteOrderPosNext(nOrderPosNext); @@ -816,80 +795,6 @@ int64_t CWallet::IncOrderPosNext(WalletBatch *batch) return nRet; } -bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment) -{ - WalletBatch batch(*database); - if (!batch.TxnBegin()) - return false; - - int64_t nNow = GetAdjustedTime(); - - // Debit - CAccountingEntry debit; - debit.nOrderPos = IncOrderPosNext(&batch); - debit.strAccount = strFrom; - debit.nCreditDebit = -nAmount; - debit.nTime = nNow; - debit.strOtherAccount = strTo; - debit.strComment = strComment; - AddAccountingEntry(debit, &batch); - - // Credit - CAccountingEntry credit; - credit.nOrderPos = IncOrderPosNext(&batch); - credit.strAccount = strTo; - credit.nCreditDebit = nAmount; - credit.nTime = nNow; - credit.strOtherAccount = strFrom; - credit.strComment = strComment; - AddAccountingEntry(credit, &batch); - - if (!batch.TxnCommit()) - return false; - - return true; -} - -bool CWallet::GetLabelDestination(CTxDestination &dest, const std::string& label, bool bForceNew) -{ - WalletBatch batch(*database); - - CAccount account; - batch.ReadAccount(label, account); - - if (!bForceNew) { - if (!account.vchPubKey.IsValid()) - bForceNew = true; - else { - // Check if the current key has been used (TODO: check other addresses with the same key) - CScript scriptPubKey = GetScriptForDestination(GetDestinationForKey(account.vchPubKey, m_default_address_type)); - for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); - it != mapWallet.end() && account.vchPubKey.IsValid(); - ++it) - for (const CTxOut& txout : (*it).second.tx->vout) - if (txout.scriptPubKey == scriptPubKey) { - bForceNew = true; - break; - } - } - } - - // Generate a new key - if (bForceNew) { - if (!GetKeyFromPool(account.vchPubKey, false)) - return false; - - LearnRelatedScripts(account.vchPubKey, m_default_address_type); - dest = GetDestinationForKey(account.vchPubKey, m_default_address_type); - SetAddressBook(dest, label, "receive"); - batch.WriteAccount(label, account); - } else { - dest = GetDestinationForKey(account.vchPubKey, m_default_address_type); - } - - return true; -} - void CWallet::MarkDirty() { { @@ -944,7 +849,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) if (fInsertedNew) { wtx.nTimeReceived = GetAdjustedTime(); wtx.nOrderPos = IncOrderPosNext(&batch); - wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr))); + wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx)); wtx.nTimeSmart = ComputeTimeSmart(wtx); AddToSpends(hash); } @@ -1019,7 +924,7 @@ void CWallet::LoadToWallet(const CWalletTx& wtxIn) CWalletTx& wtx = ins.first->second; wtx.BindWallet(this); if (/* insertion took place */ ins.second) { - wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr))); + wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx)); } AddToSpends(hash); for (const CTxIn& txin : wtx.tx->vin) { @@ -1579,7 +1484,7 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wall // Look up the inputs. We should have already checked that this transaction // IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our // wallet, with a valid index into the vout array, and the ability to sign. - for (auto& input : tx.vin) { + for (const CTxIn& input : tx.vin) { const auto mi = wallet->mapWallet.find(input.prevout.hash); if (mi == wallet->mapWallet.end()) { return -1; @@ -1615,12 +1520,11 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet, } void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived, - std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const + std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const { nFee = 0; listReceived.clear(); listSent.clear(); - strSentAccount = strFromAccount; // Compute fee: CAmount nDebit = GetDebit(filter); @@ -1819,7 +1723,7 @@ void CWallet::ReacceptWalletTransactions() } // Try to add wallet transactions to memory pool - for (std::pair<const int64_t, CWalletTx*>& item : mapSorted) { + for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) { CWalletTx& wtx = *(item.second); CValidationState state; wtx.AcceptToMemoryPool(maxTxFee, state); @@ -2065,7 +1969,7 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CCon continue; mapSorted.insert(std::make_pair(wtx.nTimeReceived, &wtx)); } - for (std::pair<const unsigned int, CWalletTx*>& item : mapSorted) + for (const std::pair<const unsigned int, CWalletTx*>& item : mapSorted) { CWalletTx& wtx = *item.second; if (wtx.RelayWalletTransaction(connman)) @@ -2189,7 +2093,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const // wallet, and then subtracts the values of TxIns spending from the wallet. This // also has fewer restrictions on which unconfirmed transactions are considered // trusted. -CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) const +CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth) const { LOCK2(cs_main, cs_wallet); @@ -2208,21 +2112,17 @@ CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, cons for (const CTxOut& out : wtx.tx->vout) { if (outgoing && IsChange(out)) { debit -= out.nValue; - } else if (IsMine(out) & filter && depth >= minDepth && (!account || *account == GetLabelName(out.scriptPubKey))) { + } else if (IsMine(out) & filter && depth >= minDepth) { balance += out.nValue; } } // For outgoing txs, subtract amount debited. - if (outgoing && (!account || *account == wtx.strFromAccount)) { + if (outgoing) { balance -= debit; } } - if (account) { - balance += WalletBatch(*database).GetAccountCreditDebit(*account); - } - return balance; } @@ -2352,23 +2252,15 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const { - // TODO: Add AssertLockHeld(cs_wallet) here. - // - // Because the return value from this function contains pointers to - // CWalletTx objects, callers to this function really should acquire the - // cs_wallet lock before calling it. However, the current caller doesn't - // acquire this lock yet. There was an attempt to add the missing lock in - // https://github.com/bitcoin/bitcoin/pull/10340, but that change has been - // postponed until after https://github.com/bitcoin/bitcoin/pull/10244 to - // avoid adding some extra complexity to the Qt code. + AssertLockHeld(cs_main); + AssertLockHeld(cs_wallet); std::map<CTxDestination, std::vector<COutput>> result; std::vector<COutput> availableCoins; - LOCK2(cs_main, cs_wallet); AvailableCoins(availableCoins); - for (auto& coin : availableCoins) { + for (const COutput& coin : availableCoins) { CTxDestination address; if (coin.fSpendable && ExtractDestination(FindNonChangeParentOutput(*coin.tx->tx, coin.i).scriptPubKey, address)) { @@ -2378,7 +2270,7 @@ std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const std::vector<COutPoint> lockedCoins; ListLockedCoins(lockedCoins); - for (const auto& output : lockedCoins) { + for (const COutPoint& output : lockedCoins) { auto it = mapWallet.find(output.hash); if (it != mapWallet.end()) { int depth = it->second.GetDepthInMainChain(); @@ -3054,7 +2946,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac /** * Call after CreateTransaction unless you want to abort */ -bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, std::string fromAccount, CReserveKey& reservekey, CConnman* connman, CValidationState& state) +bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, CReserveKey& reservekey, CConnman* connman, CValidationState& state) { { LOCK2(cs_main, cs_wallet); @@ -3062,7 +2954,6 @@ bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve CWalletTx wtxNew(this, std::move(tx)); wtxNew.mapValue = std::move(mapValue); wtxNew.vOrderForm = std::move(orderForm); - wtxNew.strFromAccount = std::move(fromAccount); wtxNew.fTimeReceivedIsTxTime = true; wtxNew.fFromMe = true; @@ -3102,31 +2993,6 @@ bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve return true; } -void CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) { - WalletBatch batch(*database); - return batch.ListAccountCreditDebit(strAccount, entries); -} - -bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry) -{ - WalletBatch batch(*database); - - return AddAccountingEntry(acentry, &batch); -} - -bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, WalletBatch *batch) -{ - if (!batch->WriteAccountingEntry(++nAccountingEntryNumber, acentry)) { - return false; - } - - laccentries.push_back(acentry); - CAccountingEntry & entry = laccentries.back(); - wtxOrdered.insert(std::make_pair(entry.nOrderPos, TxPair(nullptr, &entry))); - - return true; -} - DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { LOCK2(cs_main, cs_wallet); @@ -3280,17 +3146,17 @@ bool CWallet::NewKeyPool() LOCK(cs_wallet); WalletBatch batch(*database); - for (int64_t nIndex : setInternalKeyPool) { + for (const int64_t nIndex : setInternalKeyPool) { batch.ErasePool(nIndex); } setInternalKeyPool.clear(); - for (int64_t nIndex : setExternalKeyPool) { + for (const int64_t nIndex : setExternalKeyPool) { batch.ErasePool(nIndex); } setExternalKeyPool.clear(); - for (int64_t nIndex : set_pre_split_keypool) { + for (const int64_t nIndex : set_pre_split_keypool) { batch.ErasePool(nIndex); } set_pre_split_keypool.clear(); @@ -3567,7 +3433,7 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() { bool any_mine = false; // group all input addresses with each other - for (CTxIn txin : pcoin->tx->vin) + for (const CTxIn& txin : pcoin->tx->vin) { CTxDestination address; if(!IsMine(txin)) /* If this input isn't mine, ignore it */ @@ -3581,7 +3447,7 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() // group change with input addresses if (any_mine) { - for (CTxOut txout : pcoin->tx->vout) + for (const CTxOut& txout : pcoin->tx->vout) if (IsChange(txout)) { CTxDestination txoutAddr; @@ -3617,7 +3483,7 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() // make a set of all the groups hit by this new group std::set< std::set<CTxDestination>* > hits; std::map< CTxDestination, std::set<CTxDestination>* >::iterator it; - for (CTxDestination address : _grouping) + for (const CTxDestination& address : _grouping) if ((it = setmap.find(address)) != setmap.end()) hits.insert((*it).second); @@ -3632,12 +3498,12 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() uniqueGroupings.insert(merged); // update setmap - for (CTxDestination element : *merged) + for (const CTxDestination& element : *merged) setmap[element] = merged; } std::set< std::set<CTxDestination> > ret; - for (std::set<CTxDestination>* uniqueGrouping : uniqueGroupings) + for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings) { ret.insert(*uniqueGrouping); delete uniqueGrouping; @@ -3660,12 +3526,6 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co return result; } -void CWallet::DeleteLabel(const std::string& label) -{ - WalletBatch batch(*database); - batch.EraseAccount(label); -} - bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal) { if (nIndex == -1) @@ -3856,19 +3716,14 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const int64_t latestTolerated = latestNow + 300; const TxItems& txOrdered = wtxOrdered; for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { - CWalletTx* const pwtx = it->second.first; + CWalletTx* const pwtx = it->second; if (pwtx == &wtx) { continue; } - CAccountingEntry* const pacentry = it->second.second; int64_t nSmartTime; - if (pwtx) { - nSmartTime = pwtx->nTimeSmart; - if (!nSmartTime) { - nSmartTime = pwtx->nTimeReceived; - } - } else { - nSmartTime = pacentry->nTime; + nSmartTime = pwtx->nTimeSmart; + if (!nSmartTime) { + nSmartTime = pwtx->nTimeReceived; } if (nSmartTime <= latestTolerated) { latestEntry = nSmartTime; @@ -4313,7 +4168,6 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name, copyTo->nTimeReceived = copyFrom->nTimeReceived; copyTo->nTimeSmart = copyFrom->nTimeSmart; copyTo->fFromMe = copyFrom->fFromMe; - copyTo->strFromAccount = copyFrom->strFromAccount; copyTo->nOrderPos = copyFrom->nOrderPos; batch.WriteTx(*copyTo); } @@ -4469,3 +4323,29 @@ std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outpu } return groups; } + +bool CWallet::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const +{ + CKeyMetadata meta; + { + LOCK(cs_wallet); + auto it = mapKeyMetadata.find(keyID); + if (it != mapKeyMetadata.end()) { + meta = it->second; + } + } + if (!meta.hdKeypath.empty()) { + if (!ParseHDKeypath(meta.hdKeypath, info.path)) return false; + // Get the proper master key id + CKey key; + GetKey(meta.hd_seed_id, key); + CExtKey masterKey; + masterKey.SetSeed(key.begin(), key.size()); + // Compute identifier + CKeyID masterid = masterKey.key.GetPubKey().GetID(); + std::copy(masterid.begin(), masterid.begin() + 4, info.fingerprint); + } else { // Single pubkeys get the master fingerprint of themselves + std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint); + } + return true; +} diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 51ac3df71e..da326517c0 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -302,7 +302,7 @@ public: * serialized in the wallet database: * * "comment", "to" - comment strings provided to sendtoaddress, - * sendfrom, sendmany wallet RPCs + * and sendmany wallet RPCs * "replaces_txid" - txid (as HexStr) of transaction replaced by * bumpfee on transaction created by bumpfee * "replaced_by_txid" - txid (as HexStr) of transaction created by @@ -340,9 +340,8 @@ public: * externally and came in through the network or sendrawtransaction RPC. */ char fFromMe; - std::string strFromAccount; int64_t nOrderPos; //!< position in ordered transaction list - std::multimap<int64_t, std::pair<CWalletTx*, CAccountingEntry*>>::const_iterator m_it_wtxOrdered; + std::multimap<int64_t, CWalletTx*>::const_iterator m_it_wtxOrdered; // memory only mutable bool fDebitCached; @@ -379,7 +378,6 @@ public: nTimeReceived = 0; nTimeSmart = 0; fFromMe = false; - strFromAccount.clear(); fDebitCached = false; fCreditCached = false; fImmatureCreditCached = false; @@ -408,7 +406,7 @@ public: char fSpent = false; mapValue_t mapValueCopy = mapValue; - mapValueCopy["fromaccount"] = strFromAccount; + mapValueCopy["fromaccount"] = ""; WriteOrderPos(nOrderPos, mapValueCopy); if (nTimeSmart) { mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart); @@ -429,7 +427,6 @@ public: std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev s >> vUnused >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> fSpent; - strFromAccount = std::move(mapValue["fromaccount"]); ReadOrderPos(nOrderPos, mapValue); nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0; @@ -474,7 +471,7 @@ public: } void GetAmounts(std::list<COutputEntry>& listReceived, - std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const; + std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const; bool IsFromMe(const isminefilter& filter) const { @@ -569,89 +566,6 @@ public: } }; -/** - * DEPRECATED Internal transfers. - * Database key is acentry<account><counter>. - */ -class CAccountingEntry -{ -public: - std::string strAccount; - CAmount nCreditDebit; - int64_t nTime; - std::string strOtherAccount; - std::string strComment; - mapValue_t mapValue; - int64_t nOrderPos; //!< position in ordered transaction list - uint64_t nEntryNo; - - CAccountingEntry() - { - SetNull(); - } - - void SetNull() - { - nCreditDebit = 0; - nTime = 0; - strAccount.clear(); - strOtherAccount.clear(); - strComment.clear(); - nOrderPos = -1; - nEntryNo = 0; - } - - template <typename Stream> - void Serialize(Stream& s) const { - int nVersion = s.GetVersion(); - if (!(s.GetType() & SER_GETHASH)) { - s << nVersion; - } - //! Note: strAccount is serialized as part of the key, not here. - s << nCreditDebit << nTime << strOtherAccount; - - mapValue_t mapValueCopy = mapValue; - WriteOrderPos(nOrderPos, mapValueCopy); - - std::string strCommentCopy = strComment; - if (!mapValueCopy.empty() || !_ssExtra.empty()) { - CDataStream ss(s.GetType(), s.GetVersion()); - ss.insert(ss.begin(), '\0'); - ss << mapValueCopy; - ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end()); - strCommentCopy.append(ss.str()); - } - s << strCommentCopy; - } - - template <typename Stream> - void Unserialize(Stream& s) { - int nVersion = s.GetVersion(); - if (!(s.GetType() & SER_GETHASH)) { - s >> nVersion; - } - //! Note: strAccount is serialized as part of the key, not here. - s >> nCreditDebit >> nTime >> LIMITED_STRING(strOtherAccount, 65536) >> LIMITED_STRING(strComment, 65536); - - size_t nSepPos = strComment.find("\0", 0, 1); - mapValue.clear(); - if (std::string::npos != nSepPos) { - CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), s.GetType(), s.GetVersion()); - ss >> mapValue; - _ssExtra = std::vector<char>(ss.begin(), ss.end()); - } - ReadOrderPos(nOrderPos, mapValue); - if (std::string::npos != nSepPos) { - strComment.erase(nSepPos); - } - - mapValue.erase("n"); - } - -private: - std::vector<char> _ssExtra; -}; - struct CoinSelectionParams { bool use_bnb = true; @@ -826,10 +740,8 @@ public: } std::map<uint256, CWalletTx> mapWallet; - std::list<CAccountingEntry> laccentries; - typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair; - typedef std::multimap<int64_t, TxPair > TxItems; + typedef std::multimap<int64_t, CWalletTx*> TxItems; TxItems wtxOrdered; int64_t nOrderPosNext = 0; @@ -852,7 +764,7 @@ public: /** * Return list of available coins and locked coins grouped by non-change output address. */ - std::map<CTxDestination, std::vector<COutput>> ListCoins() const; + std::map<CTxDestination, std::vector<COutput>> ListCoins() const EXCLUSIVE_LOCKS_REQUIRED(cs_main, cs_wallet); /** * Find non-change parent output. @@ -941,8 +853,6 @@ public: */ int64_t IncOrderPosNext(WalletBatch *batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); DBErrors ReorderTransactions(); - bool AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment = "") EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - bool GetLabelDestination(CTxDestination &dest, const std::string& label, bool bForceNew = false); void MarkDirty(); bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true); @@ -962,7 +872,7 @@ public: CAmount GetImmatureBalance() const; CAmount GetUnconfirmedWatchOnlyBalance() const; CAmount GetImmatureWatchOnlyBalance() const; - CAmount GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) const; + CAmount GetLegacyBalance(const isminefilter& filter, int minDepth) const; CAmount GetAvailableBalance(const CCoinControl* coinControl = nullptr) const; OutputType TransactionChangeType(OutputType change_type, const std::vector<CRecipient>& vecSend); @@ -981,11 +891,8 @@ public: */ bool CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign = true); - bool CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, std::string fromAccount, CReserveKey& reservekey, CConnman* connman, CValidationState& state); + bool CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, CReserveKey& reservekey, CConnman* connman, CValidationState& state); - void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries); - bool AddAccountingEntry(const CAccountingEntry&); - bool AddAccountingEntry(const CAccountingEntry&, WalletBatch *batch); bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts, bool use_max_sig = false) const { std::vector<CTxOut> v_txouts(txouts.size()); @@ -999,7 +906,7 @@ public: unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET}; bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE}; bool m_signal_rbf{DEFAULT_WALLET_RBF}; - bool m_allow_fallback_fee{true}; //<! will be defined via chainparams + bool m_allow_fallback_fee{true}; //!< will be defined via chainparams CFeeRate m_min_fee{DEFAULT_TRANSACTION_MINFEE}; //!< Override with -mintxfee /** * If fee estimation does not have enough data to provide estimates, use this fee instead. @@ -1044,7 +951,6 @@ public: std::map<CTxDestination, CAmount> GetAddressBalances() EXCLUSIVE_LOCKS_REQUIRED(cs_main); std::set<CTxDestination> GetLabelAddresses(const std::string& label) const; - void DeleteLabel(const std::string& label); isminetype IsMine(const CTxIn& txin) const; /** @@ -1218,6 +1124,8 @@ public: LogPrintf(("%s " + fmt).c_str(), GetDisplayName(), parameters...); }; + /** Implement lookup of key origin information through wallet key metadata. */ + bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; }; /** A key allocated from the key pool. */ @@ -1251,37 +1159,6 @@ public: void KeepScript() override { KeepKey(); } }; - -/** - * DEPRECATED Account information. - * Stored in wallet with key "acc"+string account name. - */ -class CAccount -{ -public: - CPubKey vchPubKey; - - CAccount() - { - SetNull(); - } - - void SetNull() - { - vchPubKey = CPubKey(); - } - - ADD_SERIALIZE_METHODS; - - template <typename Stream, typename Operation> - inline void SerializationOp(Stream& s, Operation ser_action) { - int nVersion = s.GetVersion(); - if (!(s.GetType() & SER_GETHASH)) - READWRITE(nVersion); - READWRITE(vchPubKey); - } -}; - /** RAII object to check and reserve a wallet rescan */ class WalletRescanReserver { diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 1b787be198..5e85151358 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -17,6 +17,7 @@ #include <wallet/wallet.h> #include <atomic> +#include <string> #include <boost/thread.hpp> @@ -150,82 +151,6 @@ bool WalletBatch::WriteMinVersion(int nVersion) return WriteIC(std::string("minversion"), nVersion); } -bool WalletBatch::ReadAccount(const std::string& strAccount, CAccount& account) -{ - account.SetNull(); - return m_batch.Read(std::make_pair(std::string("acc"), strAccount), account); -} - -bool WalletBatch::WriteAccount(const std::string& strAccount, const CAccount& account) -{ - return WriteIC(std::make_pair(std::string("acc"), strAccount), account); -} - -bool WalletBatch::EraseAccount(const std::string& strAccount) -{ - return EraseIC(std::make_pair(std::string("acc"), strAccount)); -} - -bool WalletBatch::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry) -{ - return WriteIC(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry); -} - -CAmount WalletBatch::GetAccountCreditDebit(const std::string& strAccount) -{ - std::list<CAccountingEntry> entries; - ListAccountCreditDebit(strAccount, entries); - - CAmount nCreditDebit = 0; - for (const CAccountingEntry& entry : entries) - nCreditDebit += entry.nCreditDebit; - - return nCreditDebit; -} - -void WalletBatch::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) -{ - bool fAllAccounts = (strAccount == "*"); - - Dbc* pcursor = m_batch.GetCursor(); - if (!pcursor) - throw std::runtime_error(std::string(__func__) + ": cannot create DB cursor"); - bool setRange = true; - while (true) - { - // Read next record - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - if (setRange) - ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? std::string("") : strAccount), uint64_t(0))); - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); - setRange = false; - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - { - pcursor->close(); - throw std::runtime_error(std::string(__func__) + ": error scanning DB"); - } - - // Unserialize - std::string strType; - ssKey >> strType; - if (strType != "acentry") - break; - CAccountingEntry acentry; - ssKey >> acentry.strAccount; - if (!fAllAccounts && acentry.strAccount != strAccount) - break; - - ssValue >> acentry; - ssKey >> acentry.nEntryNo; - entries.push_back(acentry); - } - - pcursor->close(); -} - class CWalletScanState { public: unsigned int nKeys; @@ -284,9 +209,10 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { char fTmp; char fUnused; - ssValue >> fTmp >> fUnused >> wtx.strFromAccount; - strErr = strprintf("LoadWallet() upgrading tx ver=%d %d '%s' %s", - wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount, hash.ToString()); + std::string unused_string; + ssValue >> fTmp >> fUnused >> unused_string; + strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s", + wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString()); wtx.fTimeReceivedIsTxTime = fTmp; } else @@ -302,24 +228,6 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, pwallet->LoadToWallet(wtx); } - else if (strType == "acentry") - { - std::string strAccount; - ssKey >> strAccount; - uint64_t nNumber; - ssKey >> nNumber; - if (nNumber > pwallet->nAccountingEntryNumber) { - pwallet->nAccountingEntryNumber = nNumber; - } - - if (!wss.fAnyUnordered) - { - CAccountingEntry acentry; - ssValue >> acentry; - if (acentry.nOrderPos == -1) - wss.fAnyUnordered = true; - } - } else if (strType == "watchs") { wss.nWatchKeys++; @@ -510,7 +418,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, return false; } } else if (strType != "bestblock" && strType != "bestblock_nomerkle" && - strType != "minversion") { + strType != "minversion" && strType != "acentry") { wss.m_unknown_records++; } } catch (...) @@ -612,7 +520,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta) pwallet->UpdateTimeFirstKey(1); - for (uint256 hash : wss.vWalletUpgrade) + for (const uint256& hash : wss.vWalletUpgrade) WriteTx(pwallet->mapWallet.at(hash)); // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: @@ -625,12 +533,6 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) if (wss.fAnyUnordered) result = pwallet->ReorderTransactions(); - pwallet->laccentries.clear(); - ListAccountCreditDebit("*", pwallet->laccentries); - for (CAccountingEntry& entry : pwallet->laccentries) { - pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair(nullptr, &entry))); - } - return result; } @@ -709,7 +611,7 @@ DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<u // erase each matching wallet TX bool delerror = false; std::vector<uint256>::iterator it = vTxHashIn.begin(); - for (uint256 hash : vTxHash) { + for (const uint256& hash : vTxHash) { while (it < vTxHashIn.end() && (*it) < hash) { it++; } @@ -740,7 +642,7 @@ DBErrors WalletBatch::ZapWalletTx(std::vector<CWalletTx>& vWtx) return err; // erase each wallet TX - for (uint256& hash : vTxHash) { + for (const uint256& hash : vTxHash) { if (!EraseTx(hash)) return DBErrors::CORRUPT; } diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 0e6cb1bba4..5584407a56 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -31,8 +31,6 @@ static const bool DEFAULT_FLUSHWALLET = true; -class CAccount; -class CAccountingEntry; struct CBlockLocator; class CKeyPool; class CMasterKey; @@ -199,21 +197,11 @@ public: bool WriteMinVersion(int nVersion); - /// This writes directly to the database, and will not update the CWallet's cached accounting entries! - /// Use wallet.AddAccountingEntry instead, to write *and* update its caches. - bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry); - bool ReadAccount(const std::string& strAccount, CAccount& account); - bool WriteAccount(const std::string& strAccount, const CAccount& account); - bool EraseAccount(const std::string& strAccount); - /// Write destination data key,value tuple to database bool WriteDestData(const std::string &address, const std::string &key, const std::string &value); /// Erase destination data tuple from wallet database bool EraseDestData(const std::string &address, const std::string &key); - CAmount GetAccountCreditDebit(const std::string& strAccount); - void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries); - DBErrors LoadWallet(CWallet* pwallet); DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx); DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx); |