diff --git a/depends/README.md b/depends/README.md
index d60166634ff0e..a2a7b749c25e3 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -89,44 +89,28 @@ For linux S390X cross compilation:
pkg_add bash gtar
### Dependency Options
+
The following can be set when running make: `make FOO=bar`
-
-- SOURCES_PATH
-- downloaded sources will be placed here
-- BASE_CACHE
-- built packages will be placed here
-- SDK_PATH
-- Path where sdk's can be found (used by macOS)
-- FALLBACK_DOWNLOAD_PATH
-- If a source file can't be fetched, try here before giving up
-- NO_QT
-- Don't download/build/cache qt and its dependencies
-- NO_QR
-- Don't download/build/cache packages needed for enabling qrencode
-- NO_ZMQ
-- Don't download/build/cache packages needed for enabling zeromq
-- NO_WALLET
-- Don't download/build/cache libs needed to enable the wallet
-- NO_BDB
-- Don't download/build/cache BerkeleyDB
-- NO_SQLITE
-- Don't download/build/cache SQLite
-- NO_UPNP
-- Don't download/build/cache packages needed for enabling upnp
-- NO_NATPMP
-- Don't download/build/cache packages needed for enabling NAT-PMP
-- DEBUG
-- disable some optimizations and enable more runtime checking
-- HOST_ID_SALT
-- Optional salt to use when generating host package ids
-- BUILD_ID_SALT
-- Optional salt to use when generating build package ids
-- FORCE_USE_SYSTEM_CLANG
-- (EXPERTS ONLY) When cross-compiling for macOS, use Clang found in the
-system's
$PATH
rather than the default prebuilt release of Clang
-from llvm.org. Clang 8 or later is required.
-
+- `SOURCES_PATH`: Downloaded sources will be placed here
+- `BASE_CACHE`: Built packages will be placed here
+- `SDK_PATH`: Path where SDKs can be found (used by macOS)
+- `FALLBACK_DOWNLOAD_PATH`: If a source file can't be fetched, try here before giving up
+- `NO_QT`: Don't download/build/cache Qt and its dependencies
+- `NO_QR`: Don't download/build/cache packages needed for enabling qrencode
+- `NO_ZMQ`: Don't download/build/cache packages needed for enabling ZeroMQ
+- `NO_WALLET`: Don't download/build/cache libs needed to enable the wallet
+- `NO_BDB`: Don't download/build/cache BerkeleyDB
+- `NO_SQLITE`: Don't download/build/cache SQLite
+- `NO_UPNP`: Don't download/build/cache packages needed for enabling UPnP
+- `NO_NATPMP`: Don't download/build/cache packages needed for enabling NAT-PMP
+- `DEBUG`: Disable some optimizations and enable more runtime checking
+- `HOST_ID_SALT`: Optional salt to use when generating host package ids
+- `BUILD_ID_SALT`: Optional salt to use when generating build package ids
+- `FORCE_USE_SYSTEM_CLANG`: (EXPERTS ONLY) When cross-compiling for macOS, use Clang found in the
+ system's `$PATH` rather than the default prebuilt release of Clang
+ from llvm.org. Clang 8 or later is required.
+
If some packages are not built, for example `make NO_WALLET=1`, the appropriate
options will be passed to Dash Core's configure. In this case, `--disable-wallet`.
diff --git a/doc/fuzzing.md b/doc/fuzzing.md
index 4ebbbdc934d38..859c3c04b77dd 100644
--- a/doc/fuzzing.md
+++ b/doc/fuzzing.md
@@ -128,33 +128,32 @@ Full configure that was tested on macOS Catalina with `brew` installed `llvm`:
Read the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html) for more information. This [libFuzzer tutorial](https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md) might also be of interest.
-# Fuzzing Dash Core using american fuzzy lop (`afl-fuzz`)
+# Fuzzing Dash Core using afl++
## Quickstart guide
-To quickly get started fuzzing Dash Core using [`afl-fuzz`](https://github.com/google/afl):
+To quickly get started fuzzing Dash Core using [afl++](https://github.com/AFLplusplus/AFLplusplus):
```sh
$ git clone https://github.com/dashpay/dash
$ cd dash/
-$ git clone https://github.com/google/afl
-$ make -C afl/
-$ make -C afl/llvm_mode/
+$ git clone https://github.com/AFLplusplus/AFLplusplus
+$ make -C AFLplusplus/ source-only
$ ./autogen.sh
-# It is possible to compile with afl-gcc and afl-g++ instead of afl-clang. However, running afl-fuzz
-# may require more memory via the -m flag.
-$ CC=$(pwd)/afl/afl-clang-fast CXX=$(pwd)/afl/afl-clang-fast++ ./configure --enable-fuzz --enable-c++17
+# If afl-clang-lto is not available, see
+# https://github.com/AFLplusplus/AFLplusplus#a-selecting-the-best-afl-compiler-for-instrumenting-the-target
+$ CC=$(pwd)/AFLplusplus/afl-clang-lto CXX=$(pwd)/AFLplusplus/afl-clang-lto++ ./configure --enable-fuzz --enable-c++17
$ make
# For macOS you may need to ignore x86 compilation checks when running "make". If so,
# try compiling using: AFL_NO_X86=1 make
$ mkdir -p inputs/ outputs/
$ echo A > inputs/thin-air-input
-$ FUZZ=bech32 afl/afl-fuzz -i inputs/ -o outputs/ -- src/test/fuzz/fuzz
+$ FUZZ=bech32 AFLplusplus/afl-fuzz -i inputs/ -o outputs/ -- src/test/fuzz/fuzz
# You may have to change a few kernel parameters to test optimally - afl-fuzz
# will print an error and suggestion if so.
```
-Read the [`afl-fuzz` documentation](https://github.com/google/afl) for more information.
+Read the [afl++ documentation](https://github.com/AFLplusplus/AFLplusplus) for more information.
# Fuzzing Dash Core using Honggfuzz
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index bd3ef610dfc59..d237006c8b965 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -56,7 +56,7 @@ static void SetupCliArgs(ArgsManager& argsman)
argsman.AddArg("-datadir=", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-generate", strprintf("Generate blocks immediately, equivalent to RPC generatenewaddress followed by RPC generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: dash-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0).", ArgsManager::ALLOW_INT, OptionsCategory::OPTIONS);
+ argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-rpcclienttimeout=", strprintf("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)", DEFAULT_HTTP_CLIENT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-rpcconnect=", strprintf("Send commands to node running on (default: %s)", DEFAULT_RPCCONNECT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -312,7 +312,8 @@ class NetinfoRequestHandler : public BaseRequestHandler
}
return UNKNOWN_NETWORK;
}
- uint8_t m_details_level{0}; //!< Optional user-supplied arg to set dashboard details level
+ uint8_t m_details_level{0}; //!< Optional user-supplied arg to set dashboard details level
+ bool m_is_help_requested{false}; //!< Optional user-supplied arg to print help documentation
bool DetailsRequested() const { return m_details_level > 0 && m_details_level < 5; }
bool IsAddressSelected() const { return m_details_level == 2 || m_details_level == 4; }
bool IsVersionSelected() const { return m_details_level == 3 || m_details_level == 4; }
@@ -344,6 +345,62 @@ class NetinfoRequestHandler : public BaseRequestHandler
if (gArgs.GetChainName() == CBaseChainParams::REGTEST) return " regtest";
return "";
}
+ const UniValue NetinfoHelp()
+ {
+ return std::string{
+ "-netinfo level|\"help\" \n\n"
+ "Returns a network peer connections dashboard with information from the remote server.\n"
+ "Under the hood, -netinfo fetches the data by calling getpeerinfo and getnetworkinfo.\n"
+ "An optional integer argument from 0 to 4 can be passed for different peers listings.\n"
+ "Pass \"help\" to see this detailed help documentation.\n"
+ "If more than one argument is passed, only the first one is read and parsed.\n"
+ "Suggestion: use with the Linux watch(1) command for a live dashboard; see example below.\n\n"
+ "Arguments:\n"
+ "1. level (integer 0-4, optional) Specify the info level of the peers dashboard (default 0):\n"
+ " 0 - Connection counts and local addresses\n"
+ " 1 - Like 0 but with a peers listing (without address or version columns)\n"
+ " 2 - Like 1 but with an address column\n"
+ " 3 - Like 1 but with a version column\n"
+ " 4 - Like 1 but with both address and version columns\n"
+ "2. help (string \"help\", optional) Print this help documentation instead of the dashboard.\n\n"
+ "Result:\n\n"
+ "* The peers listing in levels 1-4 displays all of the peers sorted by direction and minimum ping time:\n\n"
+ " Column Description\n"
+ " ------ -----------\n"
+ " <-> Direction\n"
+ " \"in\" - inbound connections are those initiated by the peer\n"
+ " \"out\" - outbound connections are those initiated by us\n"
+ " type Type of peer connection\n"
+ " \"full\" - full relay, the default\n"
+ " \"block\" - block relay; like full relay but does not relay transactions or addresses\n"
+ " net Network the peer connected through (\"ipv4\", \"ipv6\", \"onion\", \"i2p\", or \"cjdns\")\n"
+ " mping Minimum observed ping time, in milliseconds (ms)\n"
+ " ping Last observed ping time, in milliseconds (ms)\n"
+ " send Time since last message sent to the peer, in seconds\n"
+ " recv Time since last message received from the peer, in seconds\n"
+ " txn Time since last novel transaction received from the peer and accepted into our mempool, in minutes\n"
+ " blk Time since last novel block passing initial validity checks received from the peer, in minutes\n"
+ " age Duration of connection to the peer, in minutes\n"
+ " asmap Mapped AS (Autonomous System) number in the BGP route to the peer, used for diversifying\n"
+ " peer selection (only displayed if the -asmap config option is set)\n"
+ " id Peer index, in increasing order of peer connections since node startup\n"
+ " address IP address and port of the peer\n"
+ " version Peer version and subversion concatenated, e.g. \"70016/Satoshi:21.0.0/\"\n\n"
+ "* The connection counts table displays the number of peers by direction, network, and the totals\n"
+ " for each, as well as a column for block relay peers.\n\n"
+ "* The local addresses table lists each local address broadcast by the node, the port, and the score.\n\n"
+ "Examples:\n\n"
+ "Connection counts and local addresses only\n"
+ "> dash-cli -netinfo\n\n"
+ "Compact peers listing\n"
+ "> dash-cli -netinfo 1\n\n"
+ "Full dashboard\n"
+ "> dash-cli -netinfo 4\n\n"
+ "Full live dashboard, adjust --interval or --no-title as needed (Linux)\n"
+ "> watch --interval 1 --no-title dash-cli -netinfo 4\n\n"
+ "See this help\n"
+ "> dash-cli -netinfo help\n"};
+ }
const int64_t m_time_now{GetSystemTimeInSeconds()};
public:
@@ -356,6 +413,10 @@ class NetinfoRequestHandler : public BaseRequestHandler
uint8_t n{0};
if (ParseUInt8(args.at(0), &n)) {
m_details_level = n;
+ } else if (args.at(0) == "help") {
+ m_is_help_requested = true;
+ } else {
+ throw std::runtime_error(strprintf("invalid -netinfo argument: %s", args.at(0)));
}
}
UniValue result(UniValue::VARR);
@@ -366,6 +427,9 @@ class NetinfoRequestHandler : public BaseRequestHandler
UniValue ProcessReply(const UniValue& batch_in) override
{
+ if (m_is_help_requested) {
+ return JSONRPCReplyObj(NetinfoHelp(), NullUniValue, 1);
+ }
const std::vector batch{JSONRPCProcessBatchReply(batch_in)};
if (!batch[ID_PEERINFO]["error"].isNull()) return batch[ID_PEERINFO];
if (!batch[ID_NETWORKINFO]["error"].isNull()) return batch[ID_NETWORKINFO];
@@ -417,7 +481,7 @@ class NetinfoRequestHandler : public BaseRequestHandler
// Report detailed peer connections list sorted by direction and minimum ping time.
if (DetailsRequested() && !m_peers.empty()) {
std::sort(m_peers.begin(), m_peers.end());
- result += "Peer connections sorted by direction and min ping\n<-> relay net mping ping send recv txn blk uptime ";
+ result += "<-> relay net mping ping send recv txn blk uptime ";
if (m_is_asmap_on) result += " asmap ";
result += strprintf("%*s %-*s%s\n", m_max_id_length, "id", IsAddressSelected() ? m_max_addr_length : 0, IsAddressSelected() ? "address" : "", IsVersionSelected() ? "version" : "");
for (const Peer& peer : m_peers) {
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 03058e6498934..fd5677efe59cb 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -129,7 +129,7 @@ std::optional CChainParams::GetLLMQ(Consensus::LLMQType l
}
/**
- * Main network
+ * Main network on which people trade goods and services.
*/
class CMainParams : public CChainParams {
public:
@@ -325,7 +325,7 @@ class CMainParams : public CChainParams {
};
/**
- * Testnet (v3)
+ * Testnet (v3): public test network which is reset from time to time.
*/
class CTestNetParams : public CChainParams {
public:
@@ -496,7 +496,7 @@ class CTestNetParams : public CChainParams {
};
/**
- * Devnet
+ * Devnet: The Development network intended for developers use.
*/
class CDevNetParams : public CChainParams {
public:
@@ -731,7 +731,8 @@ class CDevNetParams : public CChainParams {
};
/**
- * Regression test
+ * Regression test: intended for private networks only. Has minimal difficulty to ensure that
+ * blocks can be found instantly.
*/
class CRegTestParams : public CChainParams {
public:
diff --git a/src/chainparams.h b/src/chainparams.h
index e5e6ec0347508..7e2d93586ad2d 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -65,10 +65,7 @@ struct ChainTxData {
/**
* CChainParams defines various tweakable parameters of a given instance of the
- * Dash system. There are three: the main network on which people trade goods
- * and services, the public test network which gets reset from time to time and
- * a regression test mode which is intended for private networks only. It has
- * minimal difficulty to ensure that blocks can be found instantly.
+ * Dash system.
*/
class CChainParams
{
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index a1c6d24db6c7b..865c75ad7b3fb 100755
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -574,7 +574,7 @@ struct CNodeState {
* - its connection type is IsBlockOnlyConn() == false
* - it gave us a valid connecting header
* - we haven't reached MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT yet
- * - it has a better chain than we have
+ * - its chain tip has at least as much work as ours
*
* CHAIN_SYNC_TIMEOUT: if a peer's best known block has less work than our tip,
* set a timeout CHAIN_SYNC_TIMEOUT seconds in the future:
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index ae540d66b5dc5..57ea467642548 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -421,7 +421,7 @@ class DescriptorImpl : public Descriptor
* m_subdescriptor_arg, or just once in case m_subdescriptor_arg is nullptr.
* @param pubkeys The evaluations of the m_pubkey_args field.
- * @param script The evaluation of m_subdescriptor_arg (or nullptr when m_subdescriptor_arg is nullptr).
+ * @param scripts The evaluation of m_subdescriptor_arg (or nullptr when m_subdescriptor_arg is nullptr).
* @param out A FlatSigningProvider to put scripts or public keys in that are necessary to the solver.
* The script arguments to this function are automatically added, as is the origin info of the provided pubkeys.
* @return A vector with scriptPubKeys for this descriptor.
diff --git a/src/validation.cpp b/src/validation.cpp
index 5bc1e91996a24..be691495ed31f 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -740,7 +740,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
}
- // Bring the best block into scope
+ // This is const, but calls into the back end CoinsViews. The CCoinsViewDB at the bottom of the
+ // hierarchy brings the best block into scope. See CCoinsViewDB::GetBestBlock().
m_view.GetBestBlock();
// we have all inputs cached now, so switch back to dummy (to protect
@@ -990,9 +991,9 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
if (!res || test_accept) {
if (!res) LogPrint(BCLog::MEMPOOL, "%s: %s %s (%s)\n", __func__, tx->GetHash().ToString(), state.GetRejectReason(), state.GetDebugMessage());
- // Remove coins that were not present in the coins cache before calling ATMPW;
- // this is to prevent memory DoS in case we receive a large number of
- // invalid transactions that attempt to overrun the in-memory coins cache
+ // Remove coins that were not present in the coins cache before calling;
+ // AcceptSingleTransaction(); this is to prevent memory DoS in case we receive a large
+ // number of invalid transactions that attempt to overrun the in-memory coins cache
// (`CCoinsViewCache::cacheCoins`).
for (const COutPoint& hashTx : coins_to_uncache)
@@ -2716,7 +2717,6 @@ void CChainState::UpdateTip(const CBlockIndex* pindexNew)
assert(std::addressof(::ChainstateActive()) == std::addressof(*this));
if (!this->IsInitialBlockDownload())
{
- int nUpgraded = 0;
const CBlockIndex* pindex = pindexNew;
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
WarningBitsConditionChecker checker(bit);
@@ -2730,16 +2730,6 @@ void CChainState::UpdateTip(const CBlockIndex* pindexNew)
}
}
}
- // Check the version of the last 100 blocks to see if we need to upgrade:
- for (int i = 0; i < 100 && pindex != nullptr; i++)
- {
- int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, m_params.GetConsensus());
- if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0)
- ++nUpgraded;
- pindex = pindex->pprev;
- }
- if (nUpgraded > 0)
- AppendWarning(warningMessages, strprintf(_("%d of last 100 blocks have unexpected version").translated, nUpgraded));
}
assert(std::addressof(::ChainstateActive()) == std::addressof(*this));
LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo) evodb_cache=%.1fMiB%s\n", __func__,
@@ -4259,8 +4249,11 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s
// Therefore, the following critical section must include the CheckBlock() call as well.
LOCK(cs_main);
- // Ensure that CheckBlock() passes before calling AcceptBlock, as
- // belt-and-suspenders.
+ // Skipping AcceptBlock() for CheckBlock() failures means that we will never mark a block as invalid if
+ // CheckBlock() fails. This is protective against consensus failure if there are any unknown forms of block
+ // malleability that cause CheckBlock() to fail; see e.g. CVE-2012-2459 and
+ // https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-February/016697.html. Because CheckBlock() is
+ // not very expensive, the anti-DoS benefits of caching failure (of a definitely-invalid block) are not substantial.
bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus());
if (ret) {
// Store to disk
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 87a8747fbf380..83c160b3ee42c 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -54,7 +54,7 @@ const WalletInitInterface& g_wallet_init_interface = WalletInit();
void WalletInit::AddWalletOptions(ArgsManager& argsman) const
{
- argsman.AddArg("-avoidpartialspends", strprintf("Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u (always enabled for wallets with \"avoid_reuse\" enabled))", DEFAULT_AVOIDPARTIALSPENDS), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
+ argsman.AddArg("-avoidpartialspends", strprintf("Group outputs by address, selecting many (possibly all) or none, instead of selecting on a per-output basis. Privacy is improved as addresses are mostly swept with fewer transactions and outputs are aggregated in clean change addresses. It may result in higher fees due to less optimal coin selection caused by this added limitation and possibly a larger-than-necessary number of inputs being used. Always enabled for wallets with \"avoid_reuse\" enabled, otherwise default: %u.", DEFAULT_AVOIDPARTIALSPENDS), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-createwalletbackups=", strprintf("Number of automatic wallet backups (default: %u)", nWalletBackups), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
#if HAVE_SYSTEM
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 9b663d3f2c6dd..e8602e3248031 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -789,7 +789,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
{"minconf", RPCArg::Type::NUM, /* default */ "0", "Only include transactions confirmed at least this many times."},
{"addlocked", RPCArg::Type::BOOL, /* default */ "false", "Whether to include transactions locked via InstantSend in the wallet's balance."},
{"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also include balance in watch-only addresses (see 'importaddress')"},
- {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."},
+ {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction. If true, this also activates avoidpartialspends, grouping outputs by their addresses."},
},
RPCResult{
RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this wallet."
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index bb9520d58cb87..74a4080191668 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -66,7 +66,7 @@ const std::map WALLET_FLAG_CAVEATS{
},
};
-static const size_t OUTPUT_GROUP_MAX_ENTRIES = 10;
+static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100};
RecursiveMutex cs_wallets;
static std::vector> vpwallets GUARDED_BY(cs_wallets);
@@ -2871,7 +2871,7 @@ bool CWallet::SelectCoins(const std::vector& vAvailableCoins, const CAm
// form groups from remaining coins; note that preset coins will not
// automatically have their associated (same address) coins included
if (coin_control.m_avoid_partial_spends && vCoins.size() > OUTPUT_GROUP_MAX_ENTRIES) {
- // Cases where we have 11+ outputs all pointing to the same destination may result in
+ // Cases where we have 101+ outputs all pointing to the same destination may result in
// privacy leaks as they will potentially be deterministically sorted. We solve that by
// explicitly shuffling the outputs before processing
Shuffle(vCoins.begin(), vCoins.end(), FastRandomContext());
diff --git a/test/functional/README.md b/test/functional/README.md
index 60867ac62cd94..11485ed03acd6 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -61,10 +61,13 @@ don't have test cases for.
- Avoid stop-starting the nodes multiple times during the test if possible. A
stop-start takes several seconds, so doing it several times blows up the
runtime of the test.
-- Set the `self.setup_clean_chain` variable in `set_test_params()` to control whether
- or not to use the cached data directories. The cached data directories
- contain a 200-block pre-mined blockchain and wallets for four nodes. Each node
- has 25 mature blocks (25x500=12500 DASH) in its wallet.
+- Set the `self.setup_clean_chain` variable in `set_test_params()` to `True` to
+ initialize an empty blockchain and start from the Genesis block, rather than
+ load a premined blockchain from cache with the default value of `False`. The
+ cached data directories contain a 200-block pre-mined blockchain with the
+ spendable mining rewards being split between four nodes. Each node has 25
+ mature block subsidies (25x500=12500 DASH) in its wallet. Using them is much more
+ efficient than mining blocks in your test.
- When calling RPCs with lots of arguments, consider using named keyword
arguments instead of positional arguments to make the intent of the call
clear to readers.
diff --git a/test/functional/example_test.py b/test/functional/example_test.py
index a9bda99198126..8a3e3d7f60799 100755
--- a/test/functional/example_test.py
+++ b/test/functional/example_test.py
@@ -77,6 +77,9 @@ def set_test_params(self):
"""Override test parameters for your individual test.
This method must be overridden and num_nodes must be explicitly set."""
+ # By default every test loads a pre-mined chain of 200 blocks from cache.
+ # Set setup_clean_chain to True to skip this and start from the Genesis
+ # block.
self.setup_clean_chain = True
self.num_nodes = 3
# Use self.extra_args to change command-line arguments for the nodes
diff --git a/test/functional/feature_asmap.py b/test/functional/feature_asmap.py
index 60c4dd16323b1..0eb998fab7469 100755
--- a/test/functional/feature_asmap.py
+++ b/test/functional/feature_asmap.py
@@ -36,7 +36,6 @@ def expected_messages(filename):
class AsmapTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 1
def test_without_asmap_arg(self):
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index e80c8eae48f62..de35e4bcec35f 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -49,7 +49,6 @@
class ChainstateWriteCrashTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
- self.setup_clean_chain = False
self.rpc_timeout = 480
self.supports_cli = False
diff --git a/test/functional/feature_includeconf.py b/test/functional/feature_includeconf.py
index 879bb54a94a6e..7e705516fbfb6 100755
--- a/test/functional/feature_includeconf.py
+++ b/test/functional/feature_includeconf.py
@@ -20,7 +20,6 @@
class IncludeConfTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 1
def setup_chain(self):
diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py
index 1f0012d95f6c0..48c17fb7714a0 100755
--- a/test/functional/p2p_addr_relay.py
+++ b/test/functional/p2p_addr_relay.py
@@ -40,7 +40,6 @@ def on_addr(self, message):
class AddrTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 1
def run_test(self):
diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py
index f0e716e84f353..4bab19388142f 100755
--- a/test/functional/p2p_blocksonly.py
+++ b/test/functional/p2p_blocksonly.py
@@ -12,7 +12,6 @@
class P2PBlocksOnly(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 1
self.extra_args = [["-blocksonly"]]
diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py
index f00e91f3cc37a..f5daa890922ac 100755
--- a/test/functional/p2p_filter.py
+++ b/test/functional/p2p_filter.py
@@ -54,7 +54,6 @@ def on_tx(self, message):
class FilterTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 1
self.extra_args = [[
'-peerbloomfilters',
diff --git a/test/functional/p2p_getaddr_caching.py b/test/functional/p2p_getaddr_caching.py
index cad2e7550660e..a2cb488001adf 100755
--- a/test/functional/p2p_getaddr_caching.py
+++ b/test/functional/p2p_getaddr_caching.py
@@ -39,7 +39,6 @@ def addr_received(self):
class AddrTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 1
def run_test(self):
diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py
index 15770819c9f27..9229a62d46e0a 100755
--- a/test/functional/p2p_invalid_locator.py
+++ b/test/functional/p2p_invalid_locator.py
@@ -13,7 +13,6 @@
class InvalidLocatorTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.setup_clean_chain = False
def run_test(self):
node = self.nodes[0] # convenience reference to the node
diff --git a/test/functional/p2p_tx_download.py b/test/functional/p2p_tx_download.py
index 8d2963f5293d3..bd0ce10622a5b 100755
--- a/test/functional/p2p_tx_download.py
+++ b/test/functional/p2p_tx_download.py
@@ -52,7 +52,6 @@ def on_getdata(self, message):
class TxDownloadTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 2
def test_tx_requests(self):
diff --git a/test/functional/rpc_estimatefee.py b/test/functional/rpc_estimatefee.py
index 14a04aa1cff56..faba579e5729b 100755
--- a/test/functional/rpc_estimatefee.py
+++ b/test/functional/rpc_estimatefee.py
@@ -14,7 +14,6 @@
class EstimateFeeTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 1
def run_test(self):
diff --git a/test/functional/rpc_getaddressinfo_label_deprecation.py b/test/functional/rpc_getaddressinfo_label_deprecation.py
index 5e739ebede51a..a173771940418 100755
--- a/test/functional/rpc_getaddressinfo_label_deprecation.py
+++ b/test/functional/rpc_getaddressinfo_label_deprecation.py
@@ -12,7 +12,6 @@
class GetAddressInfoLabelDeprecationTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.setup_clean_chain = False
# Start node[0] with -deprecatedrpc=label, and node[1] without.
self.extra_args = [["-deprecatedrpc=label"], []]
diff --git a/test/functional/rpc_getaddressinfo_labels_purpose_deprecation.py b/test/functional/rpc_getaddressinfo_labels_purpose_deprecation.py
index 903f5536b91cc..3c1eea7fbeb81 100755
--- a/test/functional/rpc_getaddressinfo_labels_purpose_deprecation.py
+++ b/test/functional/rpc_getaddressinfo_labels_purpose_deprecation.py
@@ -16,7 +16,6 @@
class GetAddressInfoLabelsPurposeDeprecationTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.setup_clean_chain = False
# Start node[0] with -deprecatedrpc=labelspurpose and node[1] without.
self.extra_args = [["-deprecatedrpc=labelspurpose"], []]
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index d0037580bb2e8..24e9b0dbe7cfd 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -21,7 +21,6 @@
class PSBTTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 3
# TODO: remove -txindex. Currently required for getrawtransaction call.
self.extra_args = [
diff --git a/test/functional/test-shell.md b/test/functional/test-shell.md
index f6ea9ef68277f..b8e899d6758f7 100644
--- a/test/functional/test-shell.md
+++ b/test/functional/test-shell.md
@@ -178,7 +178,7 @@ can be called after the TestShell is shut down.
| `num_nodes` | `1` | Sets the number of initialized bitcoind processes. |
| `perf` | False | Profiles running nodes with `perf` for the duration of the test if set to `True`. |
| `rpc_timeout` | `60` | Sets the RPC server timeout for the underlying bitcoind processes. |
-| `setup_clean_chain` | `False` | Initializes an empty blockchain by default. A 199-block-long chain is initialized if set to `True`. |
+| `setup_clean_chain` | `False` | A 200-block-long chain is initialized from cache by default. Instead, `setup_clean_chain` initializes an empty blockchain if set to `True`. |
| `randomseed` | Random Integer | `TestShell.options.randomseed` is a member of `TestShell` which can be accessed during a test to seed a random generator. User can override default with a constant value for reproducible test runs. |
| `supports_cli` | `False` | Whether the bitcoin-cli utility is compiled and available for the test. |
| `tmpdir` | `"/var/folders/.../"` | Sets directory for test logs. Will be deleted upon a successful test run unless `nocleanup` is set to `True` |
diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py
index bff24f772d0d9..b5fb557c5c29b 100755
--- a/test/functional/wallet_avoidreuse.py
+++ b/test/functional/wallet_avoidreuse.py
@@ -48,30 +48,29 @@ def count_unspent(node):
r["reused"]["supported"] = supports_reused
return r
-def assert_unspent(node, total_count=None, total_sum=None, reused_supported=None, reused_count=None, reused_sum=None):
+def assert_unspent(node, total_count=None, total_sum=None, reused_supported=None, reused_count=None, reused_sum=None, margin=0.001):
'''Make assertions about a node's unspent output statistics'''
stats = count_unspent(node)
if total_count is not None:
assert_equal(stats["total"]["count"], total_count)
if total_sum is not None:
- assert_approx(stats["total"]["sum"], total_sum, 0.001)
+ assert_approx(stats["total"]["sum"], total_sum, margin)
if reused_supported is not None:
assert_equal(stats["reused"]["supported"], reused_supported)
if reused_count is not None:
assert_equal(stats["reused"]["count"], reused_count)
if reused_sum is not None:
- assert_approx(stats["reused"]["sum"], reused_sum, 0.001)
+ assert_approx(stats["reused"]["sum"], reused_sum, margin)
-def assert_balances(node, mine):
+def assert_balances(node, mine, margin=0.001):
'''Make assertions about a node's getbalances output'''
got = node.getbalances()["mine"]
for k,v in mine.items():
- assert_approx(got[k], v, 0.001)
+ assert_approx(got[k], v, margin)
class AvoidReuseTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 2
# This test isn't testing txn relay/timing, so set whitelist on the
# peers for instant txn relay. This speeds up the test run time 2-3x.
@@ -290,7 +289,7 @@ def test_getbalances_used(self):
ret_addr = self.nodes[0].getnewaddress()
# send multiple transactions, reusing one address
- for _ in range(11):
+ for _ in range(101):
self.nodes[0].sendtoaddress(new_addr, 1)
self.nodes[0].generate(1)
@@ -302,14 +301,14 @@ def test_getbalances_used(self):
# getbalances and listunspent should show the remaining outputs
# in the reused address as used/reused
- assert_unspent(self.nodes[1], total_count=2, total_sum=6, reused_count=1, reused_sum=1)
- assert_balances(self.nodes[1], mine={"used": 1, "trusted": 5})
+ assert_unspent(self.nodes[1], total_count=2, total_sum=96, reused_count=1, reused_sum=1, margin=0.01)
+ assert_balances(self.nodes[1], mine={"used": 1, "trusted": 95}, margin=0.01)
def test_full_destination_group_is_preferred(self):
'''
- Test the case where [1] only has 11 outputs of 1 BTC in the same reused
+ Test the case where [1] only has 101 outputs of 1 BTC in the same reused
address and tries to send a small payment of 0.5 BTC. The wallet
- should use 10 outputs from the reused address as inputs and not a
+ should use 100 outputs from the reused address as inputs and not a
single 1 BTC input, in order to join several outputs from the reused
address.
'''
@@ -321,8 +320,8 @@ def test_full_destination_group_is_preferred(self):
new_addr = self.nodes[1].getnewaddress()
ret_addr = self.nodes[0].getnewaddress()
- # Send 11 outputs of 1 BTC to the same, reused address in the wallet
- for _ in range(11):
+ # Send 101 outputs of 1 BTC to the same, reused address in the wallet
+ for _ in range(101):
self.nodes[0].sendtoaddress(new_addr, 1)
self.nodes[0].generate(1)
@@ -333,14 +332,14 @@ def test_full_destination_group_is_preferred(self):
txid = self.nodes[1].sendtoaddress(address=ret_addr, amount=0.5)
inputs = self.nodes[1].getrawtransaction(txid, 1)["vin"]
- # The transaction should use 10 inputs exactly
- assert_equal(len(inputs), 10)
+ # The transaction should use 100 inputs exactly
+ assert_equal(len(inputs), 100)
def test_all_destination_groups_are_used(self):
'''
- Test the case where [1] only has 22 outputs of 1 BTC in the same reused
- address and tries to send a payment of 20.5 BTC. The wallet
- should use all 22 outputs from the reused address as inputs.
+ Test the case where [1] only has 202 outputs of 1 BTC in the same reused
+ address and tries to send a payment of 200.5 BTC. The wallet
+ should use all 202 outputs from the reused address as inputs.
'''
self.log.info("Test that all destination groups are used")
@@ -350,20 +349,20 @@ def test_all_destination_groups_are_used(self):
new_addr = self.nodes[1].getnewaddress()
ret_addr = self.nodes[0].getnewaddress()
- # Send 22 outputs of 1 BTC to the same, reused address in the wallet
- for _ in range(22):
+ # Send 202 outputs of 1 BTC to the same, reused address in the wallet
+ for _ in range(202):
self.nodes[0].sendtoaddress(new_addr, 1)
self.nodes[0].generate(1)
self.sync_all()
# Sending a transaction that needs to use the full groups
- # of 10 inputs but also the incomplete group of 2 inputs.
- txid = self.nodes[1].sendtoaddress(address=ret_addr, amount=20.5)
+ # of 100 inputs but also the incomplete group of 2 inputs.
+ txid = self.nodes[1].sendtoaddress(address=ret_addr, amount=200.5)
inputs = self.nodes[1].getrawtransaction(txid, 1)["vin"]
- # The transaction should use 22 inputs exactly
- assert_equal(len(inputs), 22)
+ # The transaction should use 202 inputs exactly
+ assert_equal(len(inputs), 202)
if __name__ == '__main__':
diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py
index 834dfc2ec4bb0..29693bf81d7f1 100755
--- a/test/functional/wallet_create_tx.py
+++ b/test/functional/wallet_create_tx.py
@@ -12,7 +12,6 @@
class CreateTxWalletTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 1
def skip_test_if_missing_module(self):
diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py
index df1d9082e22ca..54dac62bfae1d 100755
--- a/test/functional/wallet_createwallet.py
+++ b/test/functional/wallet_createwallet.py
@@ -13,7 +13,6 @@
class CreateWalletTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 1
def skip_test_if_missing_module(self):
diff --git a/test/functional/wallet_watchonly.py b/test/functional/wallet_watchonly.py
index 36d9118749f5c..2b91edf22fcfd 100755
--- a/test/functional/wallet_watchonly.py
+++ b/test/functional/wallet_watchonly.py
@@ -15,7 +15,6 @@
class CreateWalletWatchonlyTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = False
self.num_nodes = 1
self.supports_cli = True