aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build_msvc/README.md6
-rw-r--r--contrib/verify-commits/trusted-keys1
-rw-r--r--doc/release-notes.md6
-rw-r--r--src/bitcoin-cli.cpp78
-rw-r--r--src/init.cpp8
-rw-r--r--src/miner.cpp5
-rw-r--r--src/miner.h3
-rw-r--r--src/net_processing.cpp41
-rw-r--r--src/qt/clientmodel.cpp2
-rw-r--r--src/qt/forms/debugwindow.ui6
-rw-r--r--src/qt/guiutil.cpp7
-rw-r--r--src/rest.cpp41
-rw-r--r--src/rpc/blockchain.cpp251
-rw-r--r--src/rpc/blockchain.h11
-rw-r--r--src/rpc/mining.cpp111
-rw-r--r--src/rpc/misc.cpp4
-rw-r--r--src/rpc/net.cpp42
-rw-r--r--src/rpc/rawtransaction.cpp88
-rw-r--r--src/rpc/server.cpp2
-rw-r--r--src/rpc/util.cpp33
-rw-r--r--src/rpc/util.h4
-rw-r--r--src/script/descriptor.cpp189
-rw-r--r--src/test/data/tx_invalid.json42
-rw-r--r--src/test/data/tx_valid.json4
-rw-r--r--src/test/dbwrapper_tests.cpp18
-rw-r--r--src/test/denialofservice_tests.cpp4
-rw-r--r--src/test/descriptor_tests.cpp12
-rw-r--r--src/test/flatfile_tests.cpp8
-rw-r--r--src/test/fs_tests.cpp2
-rw-r--r--src/test/getarg_tests.cpp120
-rw-r--r--src/test/net_tests.cpp3
-rw-r--r--src/test/settings_tests.cpp2
-rw-r--r--src/test/transaction_tests.cpp67
-rw-r--r--src/test/util/setup_common.cpp11
-rw-r--r--src/test/util/setup_common.h2
-rw-r--r--src/test/util_tests.cpp43
-rw-r--r--src/test/versionbits_tests.cpp64
-rw-r--r--src/util/system.cpp164
-rw-r--r--src/util/system.h28
-rw-r--r--src/validation.cpp6
-rw-r--r--src/wallet/rpcdump.cpp34
-rw-r--r--src/wallet/rpcwallet.cpp226
-rwxr-xr-xtest/functional/feature_csv_activation.py4
-rwxr-xr-xtest/functional/rpc_blockchain.py3
-rwxr-xr-xtest/functional/wallet_basic.py2
45 files changed, 1028 insertions, 780 deletions
diff --git a/build_msvc/README.md b/build_msvc/README.md
index 87ea556a23..5ce0f6cde4 100644
--- a/build_msvc/README.md
+++ b/build_msvc/README.md
@@ -27,7 +27,11 @@ Options for installing the dependencies in a Visual Studio compatible manner are
- Download the source code, build each dependency, add the required include paths, link libraries and binary tools to the Visual Studio project files.
- Use [nuget](https://www.nuget.org/) packages with the understanding that any binary files have been compiled by an untrusted third party.
-The [external dependencies](https://github.com/bitcoin/bitcoin/blob/master/doc/dependencies.md) required for building are listed in the `build_msvc/vcpkg.json` file. The `msbuild` project files are configured to automatically install the `vcpkg` dependencies.
+The [external dependencies](https://github.com/bitcoin/bitcoin/blob/master/doc/dependencies.md) required for building are listed in the `build_msvc/vcpkg.json` file. To ensure `msbuild` project files automatically install the `vcpkg` dependencies use:
+
+```
+vcpkg integrate install
+```
Qt
---------------------
diff --git a/contrib/verify-commits/trusted-keys b/contrib/verify-commits/trusted-keys
index 27fede6277..c14f90b04b 100644
--- a/contrib/verify-commits/trusted-keys
+++ b/contrib/verify-commits/trusted-keys
@@ -4,3 +4,4 @@
B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B
CA03882CB1FC067B5D3ACFE4D300116E1C875A3D
E777299FC265DD04793070EB944D35F9AC3DB76A
+D1DBF2C4B96F2DEBF4C16654410108112E7EA81F
diff --git a/doc/release-notes.md b/doc/release-notes.md
index fced86254a..874b919f08 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -136,6 +136,12 @@ Changes to Wallet or GUI related settings can be found in the GUI or Wallet sect
Tools and Utilities
-------------------
+- A new CLI `-addrinfo` command returns the number of addresses known to the
+ node per network type (including Tor v2 versus v3) and total. This can be
+ useful to see if the node knows enough addresses in a network to use options
+ like `-onlynet=<network>` or to upgrade to current and future Tor releases
+ that support Tor v3 addresses only. (#21595)
+
Wallet
------
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 4f3d7a4ffe..4a4710ea3a 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -42,6 +42,7 @@ static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
static const bool DEFAULT_NAMED=false;
static const int CONTINUE_EXECUTION=-1;
+static constexpr int8_t UNKNOWN_NETWORK{-1};
/** Default number of blocks to generate for RPC generatetoaddress. */
static const std::string DEFAULT_NBLOCKS = "1";
@@ -59,6 +60,7 @@ static void SetupCliArgs(ArgsManager& argsman)
argsman.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-generate", strprintf("Generate blocks immediately, equivalent to RPC getnewaddress 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: bitcoin-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-addrinfo", "Get the number of addresses known to the node, per network and total.", 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). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -228,6 +230,60 @@ public:
virtual UniValue ProcessReply(const UniValue &batch_in) = 0;
};
+/** Process addrinfo requests */
+class AddrinfoRequestHandler : public BaseRequestHandler
+{
+private:
+ static constexpr std::array m_networks{"ipv4", "ipv6", "torv2", "torv3", "i2p"};
+ int8_t NetworkStringToId(const std::string& str) const
+ {
+ for (size_t i = 0; i < m_networks.size(); ++i) {
+ if (str == m_networks.at(i)) return i;
+ }
+ return UNKNOWN_NETWORK;
+ }
+
+public:
+ UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
+ {
+ if (!args.empty()) {
+ throw std::runtime_error("-addrinfo takes no arguments");
+ }
+ UniValue params{RPCConvertValues("getnodeaddresses", std::vector<std::string>{{"0"}})};
+ return JSONRPCRequestObj("getnodeaddresses", params, 1);
+ }
+
+ UniValue ProcessReply(const UniValue& reply) override
+ {
+ if (!reply["error"].isNull()) return reply;
+ const std::vector<UniValue>& nodes{reply["result"].getValues()};
+ if (!nodes.empty() && nodes.at(0)["network"].isNull()) {
+ throw std::runtime_error("-addrinfo requires bitcoind server to be running v22.0 and up");
+ }
+ // Count the number of peers we know by network, including torv2 versus torv3.
+ std::array<uint64_t, m_networks.size()> counts{{}};
+ for (const UniValue& node : nodes) {
+ std::string network_name{node["network"].get_str()};
+ if (network_name == "onion") {
+ network_name = node["address"].get_str().size() > 22 ? "torv3" : "torv2";
+ }
+ const int8_t network_id{NetworkStringToId(network_name)};
+ if (network_id == UNKNOWN_NETWORK) continue;
+ ++counts.at(network_id);
+ }
+ // Prepare result to return to user.
+ UniValue result{UniValue::VOBJ}, addresses{UniValue::VOBJ};
+ uint64_t total{0}; // Total address count
+ for (size_t i = 0; i < m_networks.size(); ++i) {
+ addresses.pushKV(m_networks.at(i), counts.at(i));
+ total += counts.at(i);
+ }
+ addresses.pushKV("total", total);
+ result.pushKV("addresses_known", addresses);
+ return JSONRPCReplyObj(result, NullUniValue, 1);
+ }
+};
+
/** Process getinfo requests */
class GetinfoRequestHandler: public BaseRequestHandler
{
@@ -299,16 +355,14 @@ public:
class NetinfoRequestHandler : public BaseRequestHandler
{
private:
- static constexpr int8_t UNKNOWN_NETWORK{-1};
- static constexpr uint8_t m_networks_size{4};
static constexpr uint8_t MAX_DETAIL_LEVEL{4};
- const std::array<std::string, m_networks_size> m_networks{{"ipv4", "ipv6", "onion", "i2p"}};
- std::array<std::array<uint16_t, m_networks_size + 1>, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total)
+ static constexpr std::array m_networks{"ipv4", "ipv6", "onion", "i2p"};
+ std::array<std::array<uint16_t, m_networks.size() + 1>, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total)
uint8_t m_block_relay_peers_count{0};
uint8_t m_manual_peers_count{0};
int8_t NetworkStringToId(const std::string& str) const
{
- for (uint8_t i = 0; i < m_networks_size; ++i) {
+ for (size_t i = 0; i < m_networks.size(); ++i) {
if (str == m_networks.at(i)) return i;
}
return UNKNOWN_NETWORK;
@@ -405,10 +459,10 @@ public:
const bool is_outbound{!peer["inbound"].get_bool()};
const bool is_block_relay{!peer["relaytxes"].get_bool()};
const std::string conn_type{peer["connection_type"].get_str()};
- ++m_counts.at(is_outbound).at(network_id); // in/out by network
- ++m_counts.at(is_outbound).at(m_networks_size); // in/out overall
- ++m_counts.at(2).at(network_id); // total by network
- ++m_counts.at(2).at(m_networks_size); // total overall
+ ++m_counts.at(is_outbound).at(network_id); // in/out by network
+ ++m_counts.at(is_outbound).at(m_networks.size()); // in/out overall
+ ++m_counts.at(2).at(network_id); // total by network
+ ++m_counts.at(2).at(m_networks.size()); // total overall
if (conn_type == "block-relay-only") ++m_block_relay_peers_count;
if (conn_type == "manual") ++m_manual_peers_count;
if (DetailsRequested()) {
@@ -478,11 +532,11 @@ public:
if (any_i2p_peers) result += " i2p";
result += " total block";
if (m_manual_peers_count) result += " manual";
- const std::array<std::string, 3> rows{{"in", "out", "total"}};
+ const std::array rows{"in", "out", "total"};
for (uint8_t i = 0; i < 3; ++i) {
result += strprintf("\n%-5s %5i %5i %5i", rows.at(i), m_counts.at(i).at(0), m_counts.at(i).at(1), m_counts.at(i).at(2)); // ipv4/ipv6/onion peers counts
if (any_i2p_peers) result += strprintf(" %5i", m_counts.at(i).at(3)); // i2p peers count
- result += strprintf(" %5i", m_counts.at(i).at(m_networks_size)); // total peers count
+ result += strprintf(" %5i", m_counts.at(i).at(m_networks.size())); // total peers count
if (i == 1) { // the outbound row has two extra columns for block relay and manual peer counts
result += strprintf(" %5i", m_block_relay_peers_count);
if (m_manual_peers_count) result += strprintf(" %5i", m_manual_peers_count);
@@ -914,6 +968,8 @@ static int CommandLineRPC(int argc, char *argv[])
} else {
ParseError(error, strPrint, nRet);
}
+ } else if (gArgs.GetBoolArg("-addrinfo", false)) {
+ rh.reset(new AddrinfoRequestHandler());
} else {
rh.reset(new DefaultRequestHandler());
if (args.size() < 1) {
diff --git a/src/init.cpp b/src/init.cpp
index 07e882c9df..741e70f748 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -637,7 +637,7 @@ static void CleanupBlockRevFiles()
// Remove the rev files immediately and insert the blk file paths into an
// ordered map keyed by block file index.
LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
- fs::path blocksdir = GetBlocksDir();
+ fs::path blocksdir = gArgs.GetBlocksDirPath();
for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {
if (fs::is_regular_file(*it) &&
it->path().filename().string().length() == 12 &&
@@ -919,7 +919,7 @@ bool AppInitParameterInteraction(const ArgsManager& args)
InitWarning(warnings);
}
- if (!fs::is_directory(GetBlocksDir())) {
+ if (!fs::is_directory(gArgs.GetBlocksDirPath())) {
return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), args.GetArg("-blocksdir", "")));
}
@@ -1759,8 +1759,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
InitError(strprintf(_("Error: Disk space is low for %s"), GetDataDir()));
return false;
}
- if (!CheckDiskSpace(GetBlocksDir())) {
- InitError(strprintf(_("Error: Disk space is low for %s"), GetBlocksDir()));
+ if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) {
+ InitError(strprintf(_("Error: Disk space is low for %s"), gArgs.GetBlocksDirPath()));
return false;
}
diff --git a/src/miner.cpp b/src/miner.cpp
index 8a9406f810..3bc7fdd458 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -39,13 +39,14 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
return nNewTime - nOldTime;
}
-void RegenerateCommitments(CBlock& block, BlockManager& blockman)
+void RegenerateCommitments(CBlock& block, CBlockIndex* prev_block)
{
CMutableTransaction tx{*block.vtx.at(0)};
tx.vout.erase(tx.vout.begin() + GetWitnessCommitmentIndex(block));
block.vtx.at(0) = MakeTransactionRef(tx);
- GenerateCoinbaseCommitment(block, WITH_LOCK(::cs_main, assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman)); return blockman.LookupBlockIndex(block.hashPrevBlock)), Params().GetConsensus());
+ WITH_LOCK(::cs_main, assert(g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock) == prev_block));
+ GenerateCoinbaseCommitment(block, prev_block, Params().GetConsensus());
block.hashMerkleRoot = BlockMerkleRoot(block);
}
diff --git a/src/miner.h b/src/miner.h
index c400c90f6c..becf362b79 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -202,8 +202,7 @@ private:
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
-// TODO just accept a CBlockIndex*
/** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */
-void RegenerateCommitments(CBlock& block, BlockManager& blockman);
+void RegenerateCommitments(CBlock& block, CBlockIndex* prev_block);
#endif // BITCOIN_MINER_H
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index a5bcf9eaa8..b3927b5ec5 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -451,6 +451,8 @@ private:
void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc) EXCLUSIVE_LOCKS_REQUIRED(peer.m_getdata_requests_mutex) LOCKS_EXCLUDED(::cs_main);
+ void ProcessBlock(CNode& pfrom, const std::shared_ptr<const CBlock>& pblock, bool fForceProcessing);
+
/** Relay map (txid or wtxid -> CTransactionRef) */
typedef std::map<uint256, CTransactionRef> MapRelay;
MapRelay mapRelay GUARDED_BY(cs_main);
@@ -2309,6 +2311,18 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv)
m_connman.PushMessage(&peer, std::move(msg));
}
+void PeerManagerImpl::ProcessBlock(CNode& pfrom, const std::shared_ptr<const CBlock>& pblock, bool fForceProcessing)
+{
+ bool fNewBlock = false;
+ m_chainman.ProcessNewBlock(m_chainparams, pblock, fForceProcessing, &fNewBlock);
+ if (fNewBlock) {
+ pfrom.nLastBlockTime = GetTime();
+ } else {
+ LOCK(cs_main);
+ mapBlockSource.erase(pblock->GetHash());
+ }
+}
+
void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
const std::chrono::microseconds time_received,
const std::atomic<bool>& interruptMsgProc)
@@ -3390,7 +3404,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
LOCK(cs_main);
mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom.GetId(), false));
}
- bool fNewBlock = false;
// Setting fForceProcessing to true means that we bypass some of
// our anti-DoS protections in AcceptBlock, which filters
// unrequested blocks that might be trying to waste our resources
@@ -3400,13 +3413,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// we have a chain with at least nMinimumChainWork), and we ignore
// compact blocks with less work than our tip, it is safe to treat
// reconstructed compact blocks as having been requested.
- m_chainman.ProcessNewBlock(m_chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
- if (fNewBlock) {
- pfrom.nLastBlockTime = GetTime();
- } else {
- LOCK(cs_main);
- mapBlockSource.erase(pblock->GetHash());
- }
+ ProcessBlock(pfrom, pblock, /*fForceProcessing=*/true);
LOCK(cs_main); // hold cs_main for CBlockIndex::IsValid()
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) {
// Clear download state for this block, which is in
@@ -3483,20 +3490,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
} // Don't hold cs_main when we call into ProcessNewBlock
if (fBlockRead) {
- bool fNewBlock = false;
// Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
// even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
// This bypasses some anti-DoS logic in AcceptBlock (eg to prevent
// disk-space attacks), but this should be safe due to the
// protections in the compact block handler -- see related comment
// in compact block optimistic reconstruction handling.
- m_chainman.ProcessNewBlock(m_chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
- if (fNewBlock) {
- pfrom.nLastBlockTime = GetTime();
- } else {
- LOCK(cs_main);
- mapBlockSource.erase(pblock->GetHash());
- }
+ ProcessBlock(pfrom, pblock, /*fForceProcessing=*/true);
}
return;
}
@@ -3551,14 +3551,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// cs_main in ProcessNewBlock is fine.
mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
}
- bool fNewBlock = false;
- m_chainman.ProcessNewBlock(m_chainparams, pblock, forceProcessing, &fNewBlock);
- if (fNewBlock) {
- pfrom.nLastBlockTime = GetTime();
- } else {
- LOCK(cs_main);
- mapBlockSource.erase(pblock->GetHash());
- }
+ ProcessBlock(pfrom, pblock, forceProcessing);
return;
}
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index b244bc94f2..f2c555de52 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -216,7 +216,7 @@ QString ClientModel::dataDir() const
QString ClientModel::blocksDir() const
{
- return GUIUtil::boostPathToQString(GetBlocksDir());
+ return GUIUtil::boostPathToQString(gArgs.GetBlocksDirPath());
}
void ClientModel::updateBanlist()
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index e45cafe48a..13687a6510 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -923,9 +923,15 @@
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
+ <property name="textElideMode">
+ <enum>Qt::ElideMiddle</enum>
+ </property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
<attribute name="horizontalHeaderHighlightSections">
<bool>false</bool>
</attribute>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 0e91f9f385..d10bf9f9ae 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -630,8 +630,11 @@ bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
void setClipboard(const QString& str)
{
- QApplication::clipboard()->setText(str, QClipboard::Clipboard);
- QApplication::clipboard()->setText(str, QClipboard::Selection);
+ QClipboard* clipboard = QApplication::clipboard();
+ clipboard->setText(str, QClipboard::Clipboard);
+ if (clipboard->supportsSelection()) {
+ clipboard->setText(str, QClipboard::Selection);
+ }
}
fs::path qstringToBoostPath(const QString &path)
diff --git a/src/rest.cpp b/src/rest.cpp
index 9d4ac55bbe..d41f374c49 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -181,14 +181,16 @@ static bool rest_headers(const std::any& context,
std::vector<const CBlockIndex *> headers;
headers.reserve(count);
{
+ ChainstateManager& chainman = EnsureAnyChainman(context);
LOCK(cs_main);
- tip = ::ChainActive().Tip();
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash);
- while (pindex != nullptr && ::ChainActive().Contains(pindex)) {
+ CChain& active_chain = chainman.ActiveChain();
+ tip = active_chain.Tip();
+ const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
+ while (pindex != nullptr && active_chain.Contains(pindex)) {
headers.push_back(pindex);
if (headers.size() == (unsigned long)count)
break;
- pindex = ::ChainActive().Next(pindex);
+ pindex = active_chain.Next(pindex);
}
}
@@ -232,7 +234,8 @@ static bool rest_headers(const std::any& context,
}
}
-static bool rest_block(HTTPRequest* req,
+static bool rest_block(const std::any& context,
+ HTTPRequest* req,
const std::string& strURIPart,
bool showTxDetails)
{
@@ -249,9 +252,10 @@ static bool rest_block(HTTPRequest* req,
CBlockIndex* pblockindex = nullptr;
CBlockIndex* tip = nullptr;
{
+ ChainstateManager& chainman = EnsureAnyChainman(context);
LOCK(cs_main);
- tip = ::ChainActive().Tip();
- pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash);
+ tip = chainman.ActiveChain().Tip();
+ pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
if (!pblockindex) {
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
}
@@ -298,12 +302,12 @@ static bool rest_block(HTTPRequest* req,
static bool rest_block_extended(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
- return rest_block(req, strURIPart, true);
+ return rest_block(context, req, strURIPart, true);
}
static bool rest_block_notxdetails(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
- return rest_block(req, strURIPart, false);
+ return rest_block(context, req, strURIPart, false);
}
// A bit of a hack - dependency on a function defined in rpc/blockchain.cpp
@@ -537,6 +541,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
std::string bitmapStringRepresentation;
std::vector<bool> hits;
bitmap.resize((vOutPoints.size() + 7) / 8);
+ ChainstateManager& chainman = EnsureAnyChainman(context);
{
auto process_utxos = [&vOutPoints, &outs, &hits](const CCoinsView& view, const CTxMemPool& mempool) {
for (const COutPoint& vOutPoint : vOutPoints) {
@@ -552,12 +557,12 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
if (!mempool) return false;
// use db+mempool as cache backend in case user likes to query mempool
LOCK2(cs_main, mempool->cs);
- CCoinsViewCache& viewChain = ::ChainstateActive().CoinsTip();
+ CCoinsViewCache& viewChain = chainman.ActiveChainstate().CoinsTip();
CCoinsViewMemPool viewMempool(&viewChain, *mempool);
process_utxos(viewMempool, *mempool);
} else {
LOCK(cs_main); // no need to lock mempool!
- process_utxos(::ChainstateActive().CoinsTip(), CTxMemPool());
+ process_utxos(chainman.ActiveChainstate().CoinsTip(), CTxMemPool());
}
for (size_t i = 0; i < hits.size(); ++i) {
@@ -572,7 +577,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
// serialize data
// use exact same output as mentioned in Bip64
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
- ssGetUTXOResponse << ::ChainActive().Height() << ::ChainActive().Tip()->GetBlockHash() << bitmap << outs;
+ ssGetUTXOResponse << chainman.ActiveChain().Height() << chainman.ActiveChain().Tip()->GetBlockHash() << bitmap << outs;
std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
req->WriteHeader("Content-Type", "application/octet-stream");
@@ -582,7 +587,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
case RetFormat::HEX: {
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
- ssGetUTXOResponse << ::ChainActive().Height() << ::ChainActive().Tip()->GetBlockHash() << bitmap << outs;
+ ssGetUTXOResponse << chainman.ActiveChain().Height() << chainman.ActiveChain().Tip()->GetBlockHash() << bitmap << outs;
std::string strHex = HexStr(ssGetUTXOResponse) + "\n";
req->WriteHeader("Content-Type", "text/plain");
@@ -595,8 +600,8 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
// pack in some essentials
// use more or less the same output as mentioned in Bip64
- objGetUTXOResponse.pushKV("chainHeight", ::ChainActive().Height());
- objGetUTXOResponse.pushKV("chaintipHash", ::ChainActive().Tip()->GetBlockHash().GetHex());
+ objGetUTXOResponse.pushKV("chainHeight", chainman.ActiveChain().Height());
+ objGetUTXOResponse.pushKV("chaintipHash", chainman.ActiveChain().Tip()->GetBlockHash().GetHex());
objGetUTXOResponse.pushKV("bitmap", bitmapStringRepresentation);
UniValue utxos(UniValue::VARR);
@@ -639,11 +644,13 @@ static bool rest_blockhash_by_height(const std::any& context, HTTPRequest* req,
CBlockIndex* pblockindex = nullptr;
{
+ ChainstateManager& chainman = EnsureAnyChainman(context);
LOCK(cs_main);
- if (blockheight > ::ChainActive().Height()) {
+ const CChain& active_chain = chainman.ActiveChain();
+ if (blockheight > active_chain.Height()) {
return RESTERR(req, HTTP_NOT_FOUND, "Block height out of range");
}
- pblockindex = ::ChainActive()[blockheight];
+ pblockindex = active_chain[blockheight];
}
switch (rf) {
case RetFormat::BINARY: {
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index f27e9af0d9..e7fd97ee1f 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -56,7 +56,7 @@ static Mutex cs_blockchange;
static std::condition_variable cond_blockchange;
static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange);
-NodeContext& EnsureNodeContext(const std::any& context)
+NodeContext& EnsureAnyNodeContext(const std::any& context)
{
auto node_context = util::AnyPtr<NodeContext>(context);
if (!node_context) {
@@ -65,33 +65,46 @@ NodeContext& EnsureNodeContext(const std::any& context)
return *node_context;
}
-CTxMemPool& EnsureMemPool(const std::any& context)
+CTxMemPool& EnsureMemPool(const NodeContext& node)
{
- const NodeContext& node = EnsureNodeContext(context);
if (!node.mempool) {
throw JSONRPCError(RPC_CLIENT_MEMPOOL_DISABLED, "Mempool disabled or instance not found");
}
return *node.mempool;
}
-ChainstateManager& EnsureChainman(const std::any& context)
+CTxMemPool& EnsureAnyMemPool(const std::any& context)
+{
+ return EnsureMemPool(EnsureAnyNodeContext(context));
+}
+
+ChainstateManager& EnsureChainman(const NodeContext& node)
{
- const NodeContext& node = EnsureNodeContext(context);
if (!node.chainman) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Node chainman not found");
}
+ WITH_LOCK(::cs_main, CHECK_NONFATAL(std::addressof(g_chainman) == std::addressof(*node.chainman)));
return *node.chainman;
}
-CBlockPolicyEstimator& EnsureFeeEstimator(const std::any& context)
+ChainstateManager& EnsureAnyChainman(const std::any& context)
+{
+ return EnsureChainman(EnsureAnyNodeContext(context));
+}
+
+CBlockPolicyEstimator& EnsureFeeEstimator(const NodeContext& node)
{
- NodeContext& node = EnsureNodeContext(context);
if (!node.fee_estimator) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Fee estimation disabled");
}
return *node.fee_estimator;
}
+CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context)
+{
+ return EnsureFeeEstimator(EnsureAnyNodeContext(context));
+}
+
/* Calculate the difficulty for a given block index.
*/
double GetDifficulty(const CBlockIndex* blockindex)
@@ -198,8 +211,9 @@ static RPCHelpMan getblockcount()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- return ::ChainActive().Height();
+ return chainman.ActiveChain().Height();
},
};
}
@@ -217,8 +231,9 @@ static RPCHelpMan getbestblockhash()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- return ::ChainActive().Tip()->GetBlockHash().GetHex();
+ return chainman.ActiveChain().Tip()->GetBlockHash().GetHex();
},
};
}
@@ -239,7 +254,7 @@ static RPCHelpMan waitfornewblock()
"\nWaits for a specific new block and returns useful info about it.\n"
"\nReturns the current block on timeout or exit.\n",
{
- {"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
+ {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -282,7 +297,7 @@ static RPCHelpMan waitforblock()
"\nReturns the current block on timeout or exit.\n",
{
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."},
- {"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
+ {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -329,7 +344,7 @@ static RPCHelpMan waitforblockheight()
"\nReturns the current block on timeout or exit.\n",
{
{"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "Block height to wait for."},
- {"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
+ {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -398,8 +413,9 @@ static RPCHelpMan getdifficulty()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- return GetDifficulty(::ChainActive().Tip());
+ return GetDifficulty(chainman.ActiveChain().Tip());
},
};
}
@@ -542,8 +558,8 @@ static RPCHelpMan getrawmempool()
"\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
"\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n",
{
- {"verbose", RPCArg::Type::BOOL, /* default */ "false", "True for a json object, false for array of transaction ids"},
- {"mempool_sequence", RPCArg::Type::BOOL, /* default */ "false", "If verbose=false, returns a json object with transaction list and mempool sequence number attached."},
+ {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
+ {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false}, "If verbose=false, returns a json object with transaction list and mempool sequence number attached."},
},
{
RPCResult{"for verbose = false",
@@ -581,7 +597,7 @@ static RPCHelpMan getrawmempool()
include_mempool_sequence = request.params[1].get_bool();
}
- return MempoolToJSON(EnsureMemPool(request.context), fVerbose, include_mempool_sequence);
+ return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose, include_mempool_sequence);
},
};
}
@@ -592,7 +608,7 @@ static RPCHelpMan getmempoolancestors()
"\nIf txid is in the mempool, returns all in-mempool ancestors.\n",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
- {"verbose", RPCArg::Type::BOOL, /* default */ "false", "True for a json object, false for array of transaction ids"},
+ {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
},
{
RPCResult{"for verbose = false",
@@ -616,7 +632,7 @@ static RPCHelpMan getmempoolancestors()
uint256 hash = ParseHashV(request.params[0], "parameter 1");
- const CTxMemPool& mempool = EnsureMemPool(request.context);
+ const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
LOCK(mempool.cs);
CTxMemPool::txiter it = mempool.mapTx.find(hash);
@@ -656,7 +672,7 @@ static RPCHelpMan getmempooldescendants()
"\nIf txid is in the mempool, returns all in-mempool descendants.\n",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
- {"verbose", RPCArg::Type::BOOL, /* default */ "false", "True for a json object, false for array of transaction ids"},
+ {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
},
{
RPCResult{"for verbose = false",
@@ -680,7 +696,7 @@ static RPCHelpMan getmempooldescendants()
uint256 hash = ParseHashV(request.params[0], "parameter 1");
- const CTxMemPool& mempool = EnsureMemPool(request.context);
+ const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
LOCK(mempool.cs);
CTxMemPool::txiter it = mempool.mapTx.find(hash);
@@ -732,7 +748,7 @@ static RPCHelpMan getmempoolentry()
{
uint256 hash = ParseHashV(request.params[0], "parameter 1");
- const CTxMemPool& mempool = EnsureMemPool(request.context);
+ const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
LOCK(mempool.cs);
CTxMemPool::txiter it = mempool.mapTx.find(hash);
@@ -763,13 +779,15 @@ static RPCHelpMan getblockhash()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
+ const CChain& active_chain = chainman.ActiveChain();
int nHeight = request.params[0].get_int();
- if (nHeight < 0 || nHeight > ::ChainActive().Height())
+ if (nHeight < 0 || nHeight > active_chain.Height())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
- CBlockIndex* pblockindex = ::ChainActive()[nHeight];
+ CBlockIndex* pblockindex = active_chain[nHeight];
return pblockindex->GetBlockHash().GetHex();
},
};
@@ -782,7 +800,7 @@ static RPCHelpMan getblockheader()
"If verbose is true, returns an Object with information about blockheader <hash>.\n",
{
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
- {"verbose", RPCArg::Type::BOOL, /* default */ "true", "true for a json object, false for the hex-encoded data"},
+ {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true}, "true for a json object, false for the hex-encoded data"},
},
{
RPCResult{"for verbose = true",
@@ -822,9 +840,10 @@ static RPCHelpMan getblockheader()
const CBlockIndex* pblockindex;
const CBlockIndex* tip;
{
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash);
- tip = ::ChainActive().Tip();
+ pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
+ tip = chainman.ActiveChain().Tip();
}
if (!pblockindex) {
@@ -883,7 +902,7 @@ static RPCHelpMan getblock()
"If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n",
{
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
- {"verbosity|verbose", RPCArg::Type::NUM, /* default */ "1", "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"},
+ {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"},
},
{
RPCResult{"for verbosity = 0",
@@ -936,19 +955,21 @@ static RPCHelpMan getblock()
int verbosity = 1;
if (!request.params[1].isNull()) {
- if(request.params[1].isNum())
- verbosity = request.params[1].get_int();
- else
+ if (request.params[1].isBool()) {
verbosity = request.params[1].get_bool() ? 1 : 0;
+ } else {
+ verbosity = request.params[1].get_int();
+ }
}
CBlock block;
const CBlockIndex* pblockindex;
const CBlockIndex* tip;
{
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash);
- tip = ::ChainActive().Tip();
+ pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
+ tip = chainman.ActiveChain().Tip();
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
@@ -988,7 +1009,10 @@ static RPCHelpMan pruneblockchain()
if (!fPruneMode)
throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
+ CChainState& active_chainstate = chainman.ActiveChainstate();
+ CChain& active_chain = active_chainstate.m_chain;
int heightParam = request.params[0].get_int();
if (heightParam < 0)
@@ -998,7 +1022,7 @@ static RPCHelpMan pruneblockchain()
// too low to be a block time (corresponds to timestamp from Sep 2001).
if (heightParam > 1000000000) {
// Add a 2 hour buffer to include blocks which might have had old timestamps
- CBlockIndex* pindex = ::ChainActive().FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
+ CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
if (!pindex) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
}
@@ -1006,7 +1030,7 @@ static RPCHelpMan pruneblockchain()
}
unsigned int height = (unsigned int) heightParam;
- unsigned int chainHeight = (unsigned int) ::ChainActive().Height();
+ unsigned int chainHeight = (unsigned int) active_chain.Height();
if (chainHeight < Params().PruneAfterHeight())
throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
else if (height > chainHeight)
@@ -1016,8 +1040,8 @@ static RPCHelpMan pruneblockchain()
height = chainHeight - MIN_BLOCKS_TO_KEEP;
}
- PruneBlockFilesManual(::ChainstateActive(), height);
- const CBlockIndex* block = ::ChainActive().Tip();
+ PruneBlockFilesManual(active_chainstate, height);
+ const CBlockIndex* block = active_chain.Tip();
CHECK_NONFATAL(block);
while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
block = block->pprev;
@@ -1046,7 +1070,7 @@ static RPCHelpMan gettxoutsetinfo()
"\nReturns statistics about the unspent transaction output set.\n"
"Note this call may take some time.\n",
{
- {"hash_type", RPCArg::Type::STR, /* default */ "hash_serialized_2", "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'muhash', 'none'."},
+ {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized_2"}, "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'muhash', 'none'."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -1070,13 +1094,21 @@ static RPCHelpMan gettxoutsetinfo()
UniValue ret(UniValue::VOBJ);
CCoinsStats stats;
- ::ChainstateActive().ForceFlushStateToDisk();
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ ChainstateManager& chainman = EnsureChainman(node);
+ CChainState& active_chainstate = chainman.ActiveChainstate();
+ active_chainstate.ForceFlushStateToDisk();
const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())};
- CCoinsView* coins_view = WITH_LOCK(::cs_main, return &::ChainstateActive().CoinsDB());
- NodeContext& node = EnsureNodeContext(request.context);
- if (GetUTXOStats(coins_view, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)), stats, hash_type, node.rpc_interruption_point)) {
+ CCoinsView* coins_view;
+ BlockManager* blockman;
+ {
+ LOCK(::cs_main);
+ coins_view = &active_chainstate.CoinsDB();
+ blockman = &active_chainstate.m_blockman;
+ }
+ if (GetUTXOStats(coins_view, *blockman, stats, hash_type, node.rpc_interruption_point)) {
ret.pushKV("height", (int64_t)stats.nHeight);
ret.pushKV("bestblock", stats.hashBlock.GetHex());
ret.pushKV("transactions", (int64_t)stats.nTransactions);
@@ -1105,7 +1137,7 @@ static RPCHelpMan gettxout()
{
{"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
{"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
- {"include_mempool", RPCArg::Type::BOOL, /* default */ "true", "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."},
+ {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."},
},
{
RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "", ""},
@@ -1135,6 +1167,8 @@ static RPCHelpMan gettxout()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ ChainstateManager& chainman = EnsureChainman(node);
LOCK(cs_main);
UniValue ret(UniValue::VOBJ);
@@ -1147,10 +1181,11 @@ static RPCHelpMan gettxout()
fMempool = request.params[2].get_bool();
Coin coin;
- CCoinsViewCache* coins_view = &::ChainstateActive().CoinsTip();
+ CChainState& active_chainstate = chainman.ActiveChainstate();
+ CCoinsViewCache* coins_view = &active_chainstate.CoinsTip();
if (fMempool) {
- const CTxMemPool& mempool = EnsureMemPool(request.context);
+ const CTxMemPool& mempool = EnsureMemPool(node);
LOCK(mempool.cs);
CCoinsViewMemPool view(coins_view, mempool);
if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
@@ -1162,7 +1197,7 @@ static RPCHelpMan gettxout()
}
}
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(coins_view->GetBestBlock());
+ const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(coins_view->GetBestBlock());
ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
if (coin.nHeight == MEMPOOL_HEIGHT) {
ret.pushKV("confirmations", 0);
@@ -1185,9 +1220,9 @@ static RPCHelpMan verifychain()
return RPCHelpMan{"verifychain",
"\nVerifies blockchain database.\n",
{
- {"checklevel", RPCArg::Type::NUM, /* default */ strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL),
+ {"checklevel", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
strprintf("How thorough the block verification is:\n - %s", Join(CHECKLEVEL_DOC, "\n- "))},
- {"nblocks", RPCArg::Type::NUM, /* default */ strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS), "The number of blocks to check."},
+ {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS)}, "The number of blocks to check."},
},
RPCResult{
RPCResult::Type::BOOL, "", "Verified or not"},
@@ -1200,39 +1235,41 @@ static RPCHelpMan verifychain()
const int check_level(request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].get_int());
const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].get_int()};
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- return CVerifyDB().VerifyDB(Params(), ::ChainstateActive(), &::ChainstateActive().CoinsTip(), check_level, check_depth);
+ CChainState& active_chainstate = chainman.ActiveChainstate();
+ return CVerifyDB().VerifyDB(Params(), active_chainstate, &active_chainstate.CoinsTip(), check_level, check_depth);
},
};
}
-static void BuriedForkDescPushBack(UniValue& softforks, const std::string &name, int height) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static void BuriedForkDescPushBack(UniValue& softforks, const std::string &name, int softfork_height, int tip_height) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
// For buried deployments.
// A buried deployment is one where the height of the activation has been hardcoded into
// the client implementation long after the consensus change has activated. See BIP 90.
// Buried deployments with activation height value of
// std::numeric_limits<int>::max() are disabled and thus hidden.
- if (height == std::numeric_limits<int>::max()) return;
+ if (softfork_height == std::numeric_limits<int>::max()) return;
UniValue rv(UniValue::VOBJ);
rv.pushKV("type", "buried");
// getblockchaininfo reports the softfork as active from when the chain height is
// one below the activation height
- rv.pushKV("active", ::ChainActive().Tip()->nHeight + 1 >= height);
- rv.pushKV("height", height);
+ rv.pushKV("active", tip_height + 1 >= softfork_height);
+ rv.pushKV("height", softfork_height);
softforks.pushKV(name, rv);
}
-static void BIP9SoftForkDescPushBack(UniValue& softforks, const std::string &name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static void BIP9SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue& softforks, const std::string &name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
// For BIP9 deployments.
// Deployments that are never active are hidden.
if (consensusParams.vDeployments[id].nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) return;
UniValue bip9(UniValue::VOBJ);
- const ThresholdState thresholdState = VersionBitsState(::ChainActive().Tip(), consensusParams, id, versionbitscache);
+ const ThresholdState thresholdState = VersionBitsState(active_chain_tip, consensusParams, id, versionbitscache);
switch (thresholdState) {
case ThresholdState::DEFINED: bip9.pushKV("status", "defined"); break;
case ThresholdState::STARTED: bip9.pushKV("status", "started"); break;
@@ -1246,12 +1283,12 @@ static void BIP9SoftForkDescPushBack(UniValue& softforks, const std::string &nam
}
bip9.pushKV("start_time", consensusParams.vDeployments[id].nStartTime);
bip9.pushKV("timeout", consensusParams.vDeployments[id].nTimeout);
- int64_t since_height = VersionBitsStateSinceHeight(::ChainActive().Tip(), consensusParams, id, versionbitscache);
+ int64_t since_height = VersionBitsStateSinceHeight(active_chain_tip, consensusParams, id, versionbitscache);
bip9.pushKV("since", since_height);
if (ThresholdState::STARTED == thresholdState)
{
UniValue statsUV(UniValue::VOBJ);
- BIP9Stats statsStruct = VersionBitsStatistics(::ChainActive().Tip(), consensusParams, id);
+ BIP9Stats statsStruct = VersionBitsStatistics(active_chain_tip, consensusParams, id);
statsUV.pushKV("period", statsStruct.period);
statsUV.pushKV("threshold", statsStruct.threshold);
statsUV.pushKV("elapsed", statsStruct.elapsed);
@@ -1328,18 +1365,22 @@ RPCHelpMan getblockchaininfo()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
+ CChainState& active_chainstate = chainman.ActiveChainstate();
- const CBlockIndex* tip = ::ChainActive().Tip();
+ const CBlockIndex* tip = active_chainstate.m_chain.Tip();
+ CHECK_NONFATAL(tip);
+ const int height = tip->nHeight;
UniValue obj(UniValue::VOBJ);
obj.pushKV("chain", Params().NetworkIDString());
- obj.pushKV("blocks", (int)::ChainActive().Height());
+ obj.pushKV("blocks", height);
obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1);
obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
obj.pushKV("difficulty", (double)GetDifficulty(tip));
obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
- obj.pushKV("initialblockdownload", ::ChainstateActive().IsInitialBlockDownload());
+ obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload());
obj.pushKV("chainwork", tip->nChainWork.GetHex());
obj.pushKV("size_on_disk", CalculateCurrentUsage());
obj.pushKV("pruned", fPruneMode);
@@ -1362,13 +1403,13 @@ RPCHelpMan getblockchaininfo()
const Consensus::Params& consensusParams = Params().GetConsensus();
UniValue softforks(UniValue::VOBJ);
- BuriedForkDescPushBack(softforks, "bip34", consensusParams.BIP34Height);
- BuriedForkDescPushBack(softforks, "bip66", consensusParams.BIP66Height);
- BuriedForkDescPushBack(softforks, "bip65", consensusParams.BIP65Height);
- BuriedForkDescPushBack(softforks, "csv", consensusParams.CSVHeight);
- BuriedForkDescPushBack(softforks, "segwit", consensusParams.SegwitHeight);
- BIP9SoftForkDescPushBack(softforks, "testdummy", consensusParams, Consensus::DEPLOYMENT_TESTDUMMY);
- BIP9SoftForkDescPushBack(softforks, "taproot", consensusParams, Consensus::DEPLOYMENT_TAPROOT);
+ BuriedForkDescPushBack(softforks, "bip34", consensusParams.BIP34Height, height);
+ BuriedForkDescPushBack(softforks, "bip66", consensusParams.BIP66Height, height);
+ BuriedForkDescPushBack(softforks, "bip65", consensusParams.BIP65Height, height);
+ BuriedForkDescPushBack(softforks, "csv", consensusParams.CSVHeight, height);
+ BuriedForkDescPushBack(softforks, "segwit", consensusParams.SegwitHeight, height);
+ BIP9SoftForkDescPushBack(tip, softforks, "testdummy", consensusParams, Consensus::DEPLOYMENT_TESTDUMMY);
+ BIP9SoftForkDescPushBack(tip, softforks, "taproot", consensusParams, Consensus::DEPLOYMENT_TAPROOT);
obj.pushKV("softforks", softforks);
obj.pushKV("warnings", GetWarnings(false).original);
@@ -1419,8 +1460,9 @@ static RPCHelpMan getchaintips()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- ChainstateManager& chainman = EnsureChainman(request.context);
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
+ CChain& active_chain = chainman.ActiveChain();
/*
* Idea: The set of chain tips is the active chain tip, plus orphan blocks which do not have another orphan building off of them.
@@ -1434,7 +1476,7 @@ static RPCHelpMan getchaintips()
std::set<const CBlockIndex*> setPrevs;
for (const std::pair<const uint256, CBlockIndex*>& item : chainman.BlockIndex()) {
- if (!chainman.ActiveChain().Contains(item.second)) {
+ if (!active_chain.Contains(item.second)) {
setOrphans.insert(item.second);
setPrevs.insert(item.second->pprev);
}
@@ -1447,7 +1489,7 @@ static RPCHelpMan getchaintips()
}
// Always report the currently active tip.
- setTips.insert(chainman.ActiveChain().Tip());
+ setTips.insert(active_chain.Tip());
/* Construct the output array. */
UniValue res(UniValue::VARR);
@@ -1456,11 +1498,11 @@ static RPCHelpMan getchaintips()
obj.pushKV("height", block->nHeight);
obj.pushKV("hash", block->phashBlock->GetHex());
- const int branchLen = block->nHeight - chainman.ActiveChain().FindFork(block)->nHeight;
+ const int branchLen = block->nHeight - active_chain.FindFork(block)->nHeight;
obj.pushKV("branchlen", branchLen);
std::string status;
- if (chainman.ActiveChain().Contains(block)) {
+ if (active_chain.Contains(block)) {
// This block is part of the currently active chain.
status = "active";
} else if (block->nStatus & BLOCK_FAILED_MASK) {
@@ -1531,7 +1573,7 @@ static RPCHelpMan getmempoolinfo()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- return MempoolInfoToJSON(EnsureMemPool(request.context));
+ return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
},
};
}
@@ -1555,16 +1597,17 @@ static RPCHelpMan preciousblock()
uint256 hash(ParseHashV(request.params[0], "blockhash"));
CBlockIndex* pblockindex;
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
{
LOCK(cs_main);
- pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash);
+ pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
}
BlockValidationState state;
- ::ChainstateActive().PreciousBlock(state, Params(), pblockindex);
+ chainman.ActiveChainstate().PreciousBlock(state, Params(), pblockindex);
if (!state.IsValid()) {
throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
@@ -1592,18 +1635,19 @@ static RPCHelpMan invalidateblock()
uint256 hash(ParseHashV(request.params[0], "blockhash"));
BlockValidationState state;
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
CBlockIndex* pblockindex;
{
LOCK(cs_main);
- pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash);
+ pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
}
- ::ChainstateActive().InvalidateBlock(state, Params(), pblockindex);
+ chainman.ActiveChainstate().InvalidateBlock(state, Params(), pblockindex);
if (state.IsValid()) {
- ::ChainstateActive().ActivateBestChain(state, Params());
+ chainman.ActiveChainstate().ActivateBestChain(state, Params());
}
if (!state.IsValid()) {
@@ -1630,20 +1674,21 @@ static RPCHelpMan reconsiderblock()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
uint256 hash(ParseHashV(request.params[0], "blockhash"));
{
LOCK(cs_main);
- CBlockIndex* pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash);
+ CBlockIndex* pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
- ::ChainstateActive().ResetBlockFailureFlags(pblockindex);
+ chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
}
BlockValidationState state;
- ::ChainstateActive().ActivateBestChain(state, Params());
+ chainman.ActiveChainstate().ActivateBestChain(state, Params());
if (!state.IsValid()) {
throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
@@ -1659,8 +1704,8 @@ static RPCHelpMan getchaintxstats()
return RPCHelpMan{"getchaintxstats",
"\nCompute statistics about the total number and rate of transactions in the chain.\n",
{
- {"nblocks", RPCArg::Type::NUM, /* default */ "one month", "Size of the window in number of blocks"},
- {"blockhash", RPCArg::Type::STR_HEX, /* default */ "chain tip", "The hash of the block that ends the window."},
+ {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"}, "Size of the window in number of blocks"},
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"chain tip"}, "The hash of the block that ends the window."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -1680,20 +1725,21 @@ static RPCHelpMan getchaintxstats()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
const CBlockIndex* pindex;
int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month
if (request.params[1].isNull()) {
LOCK(cs_main);
- pindex = ::ChainActive().Tip();
+ pindex = chainman.ActiveChain().Tip();
} else {
uint256 hash(ParseHashV(request.params[1], "blockhash"));
LOCK(cs_main);
- pindex = g_chainman.m_blockman.LookupBlockIndex(hash);
+ pindex = chainman.m_blockman.LookupBlockIndex(hash);
if (!pindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
- if (!::ChainActive().Contains(pindex)) {
+ if (!chainman.ActiveChain().Contains(pindex)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
}
}
@@ -1806,7 +1852,7 @@ static RPCHelpMan getblockstats()
"It won't work for some heights with pruning.\n",
{
{"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", "", {"", "string or numeric"}},
- {"stats", RPCArg::Type::ARR, /* default */ "all values", "Values to plot (see result below)",
+ {"stats", RPCArg::Type::ARR, RPCArg::DefaultHint{"all values"}, "Values to plot (see result below)",
{
{"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
{"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
@@ -1861,12 +1907,14 @@ static RPCHelpMan getblockstats()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
+ CChain& active_chain = chainman.ActiveChain();
CBlockIndex* pindex;
if (request.params[0].isNum()) {
const int height = request.params[0].get_int();
- const int current_tip = ::ChainActive().Height();
+ const int current_tip = active_chain.Height();
if (height < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height));
}
@@ -1874,14 +1922,14 @@ static RPCHelpMan getblockstats()
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip));
}
- pindex = ::ChainActive()[height];
+ pindex = active_chain[height];
} else {
const uint256 hash(ParseHashV(request.params[0], "hash_or_height"));
- pindex = g_chainman.m_blockman.LookupBlockIndex(hash);
+ pindex = chainman.m_blockman.LookupBlockIndex(hash);
if (!pindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
- if (!::ChainActive().Contains(pindex)) {
+ if (!active_chain.Contains(pindex)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Block is not in chain %s", Params().NetworkIDString()));
}
}
@@ -2072,7 +2120,7 @@ static RPCHelpMan savemempool()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- const CTxMemPool& mempool = EnsureMemPool(request.context);
+ const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
if (!mempool.IsLoaded()) {
throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
@@ -2173,7 +2221,7 @@ static RPCHelpMan scantxoutset()
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
{
{"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
- {"range", RPCArg::Type::RANGE, /* default */ "1000", "The range of HD chain indexes to explore (either end or [begin,end])"},
+ {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "The range of HD chain indexes to explore (either end or [begin,end])"},
}},
},
"[scanobjects,...]"},
@@ -2262,15 +2310,17 @@ static RPCHelpMan scantxoutset()
int64_t count = 0;
std::unique_ptr<CCoinsViewCursor> pcursor;
CBlockIndex* tip;
+ NodeContext& node = EnsureAnyNodeContext(request.context);
{
+ ChainstateManager& chainman = EnsureChainman(node);
LOCK(cs_main);
- ::ChainstateActive().ForceFlushStateToDisk();
- pcursor = std::unique_ptr<CCoinsViewCursor>(::ChainstateActive().CoinsDB().Cursor());
+ CChainState& active_chainstate = chainman.ActiveChainstate();
+ active_chainstate.ForceFlushStateToDisk();
+ pcursor = std::unique_ptr<CCoinsViewCursor>(active_chainstate.CoinsDB().Cursor());
CHECK_NONFATAL(pcursor);
- tip = ::ChainActive().Tip();
+ tip = active_chainstate.m_chain.Tip();
CHECK_NONFATAL(tip);
}
- NodeContext& node = EnsureNodeContext(request.context);
bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
result.pushKV("success", res);
result.pushKV("txouts", count);
@@ -2310,7 +2360,7 @@ static RPCHelpMan getblockfilter()
"\nRetrieve a BIP 157 content filter for a particular block.\n",
{
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hash of the block"},
- {"filtertype", RPCArg::Type::STR, /*default*/ "basic", "The type name of the filter"},
+ {"filtertype", RPCArg::Type::STR, RPCArg::Default{"basic"}, "The type name of the filter"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -2343,8 +2393,9 @@ static RPCHelpMan getblockfilter()
const CBlockIndex* block_index;
bool block_was_connected;
{
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- block_index = g_chainman.m_blockman.LookupBlockIndex(block_hash);
+ block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
if (!block_index) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
@@ -2427,7 +2478,7 @@ static RPCHelpMan dumptxoutset()
FILE* file{fsbridge::fopen(temppath, "wb")};
CAutoFile afile{file, SER_DISK, CLIENT_VERSION};
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
UniValue result = CreateUTXOSnapshot(node, node.chainman->ActiveChainstate(), afile);
fs::rename(temppath, path);
@@ -2465,7 +2516,7 @@ UniValue CreateUTXOSnapshot(NodeContext& node, CChainState& chainstate, CAutoFil
}
pcursor = std::unique_ptr<CCoinsViewCursor>(chainstate.CoinsDB().Cursor());
- tip = g_chainman.m_blockman.LookupBlockIndex(stats.hashBlock);
+ tip = chainstate.m_blockman.LookupBlockIndex(stats.hashBlock);
CHECK_NONFATAL(tip);
}
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index cd04c9a10f..ffb6f03b47 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -56,10 +56,13 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES],
void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr);
-NodeContext& EnsureNodeContext(const std::any& context);
-CTxMemPool& EnsureMemPool(const std::any& context);
-ChainstateManager& EnsureChainman(const std::any& context);
-CBlockPolicyEstimator& EnsureFeeEstimator(const std::any& context);
+NodeContext& EnsureAnyNodeContext(const std::any& context);
+CTxMemPool& EnsureMemPool(const NodeContext& node);
+CTxMemPool& EnsureAnyMemPool(const std::any& context);
+ChainstateManager& EnsureChainman(const NodeContext& node);
+ChainstateManager& EnsureAnyChainman(const std::any& context);
+CBlockPolicyEstimator& EnsureFeeEstimator(const NodeContext& node);
+CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context);
/**
* Helper to create UTXO snapshots given a chainstate and a file handle.
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 72ad0df199..32318dd484 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -44,11 +44,12 @@
* or from the last difficulty change if 'lookup' is nonpositive.
* If 'height' is nonnegative, compute the estimate at the time when a given block was found.
*/
-static UniValue GetNetworkHashPS(int lookup, int height) {
- CBlockIndex *pb = ::ChainActive().Tip();
+static UniValue GetNetworkHashPS(int lookup, int height, const CChain& active_chain) {
+ const CBlockIndex* pb = active_chain.Tip();
- if (height >= 0 && height < ::ChainActive().Height())
- pb = ::ChainActive()[height];
+ if (height >= 0 && height < active_chain.Height()) {
+ pb = active_chain[height];
+ }
if (pb == nullptr || !pb->nHeight)
return 0;
@@ -61,7 +62,7 @@ static UniValue GetNetworkHashPS(int lookup, int height) {
if (lookup > pb->nHeight)
lookup = pb->nHeight;
- CBlockIndex *pb0 = pb;
+ const CBlockIndex* pb0 = pb;
int64_t minTime = pb0->GetBlockTime();
int64_t maxTime = minTime;
for (int i = 0; i < lookup; i++) {
@@ -88,8 +89,8 @@ static RPCHelpMan getnetworkhashps()
"Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n"
"Pass in [height] to estimate the network speed at the time when a certain block was found.\n",
{
- {"nblocks", RPCArg::Type::NUM, /* default */ "120", "The number of blocks, or -1 for blocks since last difficulty change."},
- {"height", RPCArg::Type::NUM, /* default */ "-1", "To estimate at the time of the given height."},
+ {"nblocks", RPCArg::Type::NUM, RPCArg::Default{120}, "The number of blocks, or -1 for blocks since last difficulty change."},
+ {"height", RPCArg::Type::NUM, RPCArg::Default{-1}, "To estimate at the time of the given height."},
},
RPCResult{
RPCResult::Type::NUM, "", "Hashes per second estimated"},
@@ -99,8 +100,9 @@ static RPCHelpMan getnetworkhashps()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1);
+ return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1, chainman.ActiveChain());
},
};
}
@@ -111,7 +113,8 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t&
{
LOCK(cs_main);
- IncrementExtraNonce(&block, ::ChainActive().Tip(), extra_nonce);
+ CHECK_NONFATAL(std::addressof(::ChainActive()) == std::addressof(chainman.ActiveChain()));
+ IncrementExtraNonce(&block, chainman.ActiveChain().Tip(), extra_nonce);
}
CChainParams chainparams(Params());
@@ -143,7 +146,8 @@ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& me
{ // Don't keep cs_main locked
LOCK(cs_main);
- nHeight = ::ChainActive().Height();
+ CHECK_NONFATAL(std::addressof(::ChainActive()) == std::addressof(chainman.ActiveChain()));
+ nHeight = chainman.ActiveChain().Height();
nHeightEnd = nHeight+nGenerate;
}
unsigned int nExtraNonce = 0;
@@ -210,7 +214,7 @@ static RPCHelpMan generatetodescriptor()
{
{"num_blocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."},
{"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor to send the newly generated bitcoin to."},
- {"maxtries", RPCArg::Type::NUM, /* default */ ToString(DEFAULT_MAX_TRIES), "How many iterations to try."},
+ {"maxtries", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_MAX_TRIES}, "How many iterations to try."},
},
RPCResult{
RPCResult::Type::ARR, "", "hashes of blocks generated",
@@ -231,8 +235,9 @@ static RPCHelpMan generatetodescriptor()
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
}
- const CTxMemPool& mempool = EnsureMemPool(request.context);
- ChainstateManager& chainman = EnsureChainman(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ const CTxMemPool& mempool = EnsureMemPool(node);
+ ChainstateManager& chainman = EnsureChainman(node);
return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries);
},
@@ -253,7 +258,7 @@ static RPCHelpMan generatetoaddress()
{
{"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."},
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The address to send the newly generated bitcoin to."},
- {"maxtries", RPCArg::Type::NUM, /* default */ ToString(DEFAULT_MAX_TRIES), "How many iterations to try."},
+ {"maxtries", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_MAX_TRIES}, "How many iterations to try."},
},
RPCResult{
RPCResult::Type::ARR, "", "hashes of blocks generated",
@@ -276,8 +281,9 @@ static RPCHelpMan generatetoaddress()
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
}
- const CTxMemPool& mempool = EnsureMemPool(request.context);
- ChainstateManager& chainman = EnsureChainman(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ const CTxMemPool& mempool = EnsureMemPool(node);
+ ChainstateManager& chainman = EnsureChainman(node);
CScript coinbase_script = GetScriptForDestination(destination);
@@ -325,7 +331,8 @@ static RPCHelpMan generateblock()
coinbase_script = GetScriptForDestination(destination);
}
- const CTxMemPool& mempool = EnsureMemPool(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ const CTxMemPool& mempool = EnsureMemPool(node);
std::vector<CTransactionRef> txs;
const auto raw_txs_or_txids = request.params[1].get_array();
@@ -354,11 +361,12 @@ static RPCHelpMan generateblock()
CChainParams chainparams(Params());
CBlock block;
+ ChainstateManager& chainman = EnsureChainman(node);
{
LOCK(cs_main);
CTxMemPool empty_mempool;
- std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(::ChainstateActive(), empty_mempool, chainparams).CreateNewBlock(coinbase_script));
+ std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(chainman.ActiveChainstate(), empty_mempool, chainparams).CreateNewBlock(coinbase_script));
if (!blocktemplate) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
}
@@ -369,13 +377,14 @@ static RPCHelpMan generateblock()
// Add transactions
block.vtx.insert(block.vtx.end(), txs.begin(), txs.end());
- RegenerateCommitments(block, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)));
+ CBlockIndex* prev_block = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock));
+ RegenerateCommitments(block, prev_block);
{
LOCK(cs_main);
BlockValidationState state;
- if (!TestBlockValidity(state, chainparams, ::ChainstateActive(), block, g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) {
+ if (!TestBlockValidity(state, chainparams, chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) {
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.ToString()));
}
}
@@ -384,7 +393,7 @@ static RPCHelpMan generateblock()
uint64_t max_tries{DEFAULT_MAX_TRIES};
unsigned int extra_nonce{0};
- if (!GenerateBlock(EnsureChainman(request.context), block, max_tries, extra_nonce, block_hash) || block_hash.IsNull()) {
+ if (!GenerateBlock(chainman, block, max_tries, extra_nonce, block_hash) || block_hash.IsNull()) {
throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
}
@@ -418,14 +427,17 @@ static RPCHelpMan getmininginfo()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ const CTxMemPool& mempool = EnsureMemPool(node);
+ ChainstateManager& chainman = EnsureChainman(node);
LOCK(cs_main);
- const CTxMemPool& mempool = EnsureMemPool(request.context);
+ const CChain& active_chain = chainman.ActiveChain();
UniValue obj(UniValue::VOBJ);
- obj.pushKV("blocks", (int)::ChainActive().Height());
+ obj.pushKV("blocks", active_chain.Height());
if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
- obj.pushKV("difficulty", (double)GetDifficulty(::ChainActive().Tip()));
+ obj.pushKV("difficulty", (double)GetDifficulty(active_chain.Tip()));
obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request));
obj.pushKV("pooledtx", (uint64_t)mempool.size());
obj.pushKV("chain", Params().NetworkIDString());
@@ -467,7 +479,7 @@ static RPCHelpMan prioritisetransaction()
throw JSONRPCError(RPC_INVALID_PARAMETER, "Priority is no longer supported, dummy argument to prioritisetransaction must be 0.");
}
- EnsureMemPool(request.context).PrioritiseTransaction(hash, nAmount);
+ EnsureAnyMemPool(request.context).PrioritiseTransaction(hash, nAmount);
return true;
},
};
@@ -513,7 +525,7 @@ static RPCHelpMan getblocktemplate()
" https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
" https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n",
{
- {"template_request", RPCArg::Type::OBJ, "{}", "Format of the template",
+ {"template_request", RPCArg::Type::OBJ, RPCArg::Default{UniValue::VOBJ}, "Format of the template",
{
{"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
{"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings",
@@ -588,12 +600,16 @@ static RPCHelpMan getblocktemplate()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ ChainstateManager& chainman = EnsureChainman(node);
LOCK(cs_main);
std::string strMode = "template";
UniValue lpval = NullUniValue;
std::set<std::string> setClientRules;
int64_t nMaxVersionPreVB = -1;
+ CChainState& active_chainstate = chainman.ActiveChainstate();
+ CChain& active_chain = active_chainstate.m_chain;
if (!request.params[0].isNull())
{
const UniValue& oparam = request.params[0].get_obj();
@@ -619,7 +635,7 @@ static RPCHelpMan getblocktemplate()
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
uint256 hash = block.GetHash();
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash);
+ const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
if (pindex) {
if (pindex->IsValid(BLOCK_VALID_SCRIPTS))
return "duplicate";
@@ -628,12 +644,12 @@ static RPCHelpMan getblocktemplate()
return "duplicate-inconclusive";
}
- CBlockIndex* const pindexPrev = ::ChainActive().Tip();
+ CBlockIndex* const pindexPrev = active_chain.Tip();
// TestBlockValidity only supports blocks built on the current Tip
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
return "inconclusive-not-best-prevblk";
BlockValidationState state;
- TestBlockValidity(state, Params(), ::ChainstateActive(), block, pindexPrev, false, true);
+ TestBlockValidity(state, Params(), active_chainstate, block, pindexPrev, false, true);
return BIP22ValidationResult(state);
}
@@ -655,7 +671,6 @@ static RPCHelpMan getblocktemplate()
if (strMode != "template")
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
- NodeContext& node = EnsureNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -664,13 +679,13 @@ static RPCHelpMan getblocktemplate()
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
}
- if (::ChainstateActive().IsInitialBlockDownload()) {
+ if (active_chainstate.IsInitialBlockDownload()) {
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
}
}
static unsigned int nTransactionsUpdatedLast;
- const CTxMemPool& mempool = EnsureMemPool(request.context);
+ const CTxMemPool& mempool = EnsureMemPool(node);
if (!lpval.isNull())
{
@@ -690,7 +705,7 @@ static RPCHelpMan getblocktemplate()
else
{
// NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier
- hashWatchedChain = ::ChainActive().Tip()->GetBlockHash();
+ hashWatchedChain = active_chain.Tip()->GetBlockHash();
nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
}
@@ -735,7 +750,7 @@ static RPCHelpMan getblocktemplate()
static CBlockIndex* pindexPrev;
static int64_t nStart;
static std::unique_ptr<CBlockTemplate> pblocktemplate;
- if (pindexPrev != ::ChainActive().Tip() ||
+ if (pindexPrev != active_chain.Tip() ||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5))
{
// Clear pindexPrev so future calls make a new block, despite any failures from here on
@@ -743,12 +758,12 @@ static RPCHelpMan getblocktemplate()
// Store the pindexBest used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
- CBlockIndex* pindexPrevNew = ::ChainActive().Tip();
+ CBlockIndex* pindexPrevNew = active_chain.Tip();
nStart = GetTime();
// Create new block
CScript scriptDummy = CScript() << OP_TRUE;
- pblocktemplate = BlockAssembler(::ChainstateActive(), mempool, Params()).CreateNewBlock(scriptDummy);
+ pblocktemplate = BlockAssembler(active_chainstate, mempool, Params()).CreateNewBlock(scriptDummy);
if (!pblocktemplate)
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
@@ -884,7 +899,7 @@ static RPCHelpMan getblocktemplate()
result.pushKV("transactions", transactions);
result.pushKV("coinbaseaux", aux);
result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue);
- result.pushKV("longpollid", ::ChainActive().Tip()->GetBlockHash().GetHex() + ToString(nTransactionsUpdatedLast));
+ result.pushKV("longpollid", active_chain.Tip()->GetBlockHash().GetHex() + ToString(nTransactionsUpdatedLast));
result.pushKV("target", hashTarget.GetHex());
result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1);
result.pushKV("mutable", aMutable);
@@ -945,7 +960,7 @@ static RPCHelpMan submitblock()
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n",
{
{"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded block data to submit"},
- {"dummy", RPCArg::Type::STR, /* default */ "ignored", "dummy value, for compatibility with BIP22. This value is ignored."},
+ {"dummy", RPCArg::Type::STR, RPCArg::DefaultHint{"ignored"}, "dummy value, for compatibility with BIP22. This value is ignored."},
},
{
RPCResult{"If the block was accepted", RPCResult::Type::NONE, "", ""},
@@ -967,10 +982,11 @@ static RPCHelpMan submitblock()
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block does not start with a coinbase");
}
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
uint256 hash = block.GetHash();
{
LOCK(cs_main);
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash);
+ const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
if (pindex) {
if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
return "duplicate";
@@ -983,7 +999,7 @@ static RPCHelpMan submitblock()
{
LOCK(cs_main);
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock);
+ const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock);
if (pindex) {
UpdateUncommittedBlockStructures(block, pindex, Params().GetConsensus());
}
@@ -992,7 +1008,7 @@ static RPCHelpMan submitblock()
bool new_block;
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
RegisterSharedValidationInterface(sc);
- bool accepted = EnsureChainman(request.context).ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block);
+ bool accepted = chainman.ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block);
UnregisterSharedValidationInterface(sc);
if (!new_block && accepted) {
return "duplicate";
@@ -1025,15 +1041,16 @@ static RPCHelpMan submitheader()
if (!DecodeHexBlockHeader(h, request.params[0].get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block header decode failed");
}
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
{
LOCK(cs_main);
- if (!g_chainman.m_blockman.LookupBlockIndex(h.hashPrevBlock)) {
+ if (!chainman.m_blockman.LookupBlockIndex(h.hashPrevBlock)) {
throw JSONRPCError(RPC_VERIFY_ERROR, "Must submit previous header (" + h.hashPrevBlock.GetHex() + ") first");
}
}
BlockValidationState state;
- EnsureChainman(request.context).ProcessNewBlockHeaders({h}, state, Params());
+ chainman.ProcessNewBlockHeaders({h}, state, Params());
if (state.IsValid()) return NullUniValue;
if (state.IsError()) {
throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
@@ -1052,7 +1069,7 @@ static RPCHelpMan estimatesmartfee()
"in BIP 141 (witness data is discounted).\n",
{
{"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "conservative", "The fee estimate mode.\n"
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"conservative"}, "The fee estimate mode.\n"
" Whether to return a more conservative estimate which also satisfies\n"
" a longer history. A conservative estimate potentially returns a\n"
" higher feerate and is more likely to be sufficient for the desired\n"
@@ -1082,7 +1099,7 @@ static RPCHelpMan estimatesmartfee()
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
- CBlockPolicyEstimator& fee_estimator = EnsureFeeEstimator(request.context);
+ CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
@@ -1123,7 +1140,7 @@ static RPCHelpMan estimaterawfee()
"defined in BIP 141 (witness data is discounted).\n",
{
{"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
- {"threshold", RPCArg::Type::NUM, /* default */ "0.95", "The proportion of transactions in a given feerate range that must have been\n"
+ {"threshold", RPCArg::Type::NUM, RPCArg::Default{0.95}, "The proportion of transactions in a given feerate range that must have been\n"
" confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n"
" lower buckets."},
},
@@ -1170,7 +1187,7 @@ static RPCHelpMan estimaterawfee()
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
- CBlockPolicyEstimator& fee_estimator = EnsureFeeEstimator(request.context);
+ CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 8e98919391..00a06260ea 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -90,7 +90,7 @@ static RPCHelpMan createmultisig()
{
{"key", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The hex-encoded public key"},
}},
- {"address_type", RPCArg::Type::STR, /* default */ "legacy", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"address_type", RPCArg::Type::STR, RPCArg::Default{"legacy"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -475,7 +475,7 @@ static RPCHelpMan getmemoryinfo()
return RPCHelpMan{"getmemoryinfo",
"Returns an object containing information about memory usage.\n",
{
- {"mode", RPCArg::Type::STR, /* default */ "\"stats\"", "determines what kind of information is returned.\n"
+ {"mode", RPCArg::Type::STR, RPCArg::Default{"stats"}, "determines what kind of information is returned.\n"
" - \"stats\" returns general statistics about memory usage in the daemon.\n"
" - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+)."},
},
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 337f861903..be068edf68 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -53,7 +53,7 @@ static RPCHelpMan getconnectioncount()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -76,7 +76,7 @@ static RPCHelpMan ping()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if (!node.peerman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
@@ -165,7 +165,7 @@ static RPCHelpMan getpeerinfo()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.connman || !node.peerman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
@@ -285,7 +285,7 @@ static RPCHelpMan addnode()
self.ToString());
}
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -350,7 +350,7 @@ static RPCHelpMan addconnection()
throw JSONRPCError(RPC_INVALID_PARAMETER, self.ToString());
}
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if (!node.connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled.");
}
@@ -376,8 +376,8 @@ static RPCHelpMan disconnectnode()
"\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n"
"\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n",
{
- {"address", RPCArg::Type::STR, /* default */ "fallback to nodeid", "The IP address/port of the node"},
- {"nodeid", RPCArg::Type::NUM, /* default */ "fallback to address", "The node ID (see getpeerinfo for node IDs)"},
+ {"address", RPCArg::Type::STR, RPCArg::DefaultHint{"fallback to nodeid"}, "The IP address/port of the node"},
+ {"nodeid", RPCArg::Type::NUM, RPCArg::DefaultHint{"fallback to address"}, "The node ID (see getpeerinfo for node IDs)"},
},
RPCResult{RPCResult::Type::NONE, "", ""},
RPCExamples{
@@ -388,7 +388,7 @@ static RPCHelpMan disconnectnode()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -422,7 +422,7 @@ static RPCHelpMan getaddednodeinfo()
"\nReturns information about the given added node, or all added nodes\n"
"(note that onetry addnodes are not listed here)\n",
{
- {"node", RPCArg::Type::STR, /* default */ "all nodes", "If provided, return information about this specific node, otherwise all nodes are returned."},
+ {"node", RPCArg::Type::STR, RPCArg::DefaultHint{"all nodes"}, "If provided, return information about this specific node, otherwise all nodes are returned."},
},
RPCResult{
RPCResult::Type::ARR, "", "",
@@ -448,7 +448,7 @@ static RPCHelpMan getaddednodeinfo()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -519,7 +519,7 @@ static RPCHelpMan getnettotals()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -618,7 +618,7 @@ static RPCHelpMan getnetworkinfo()
obj.pushKV("version", CLIENT_VERSION);
obj.pushKV("subversion", strSubVersion);
obj.pushKV("protocolversion",PROTOCOL_VERSION);
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if (node.connman) {
ServiceFlags services = node.connman->GetLocalServices();
obj.pushKV("localservices", strprintf("%016x", services));
@@ -663,8 +663,8 @@ static RPCHelpMan setban()
{
{"subnet", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)"},
{"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'add' to add an IP/Subnet to the list, 'remove' to remove an IP/Subnet from the list"},
- {"bantime", RPCArg::Type::NUM, /* default */ "0", "time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)"},
- {"absolute", RPCArg::Type::BOOL, /* default */ "false", "If set, the bantime must be an absolute timestamp expressed in " + UNIX_EPOCH_TIME},
+ {"bantime", RPCArg::Type::NUM, RPCArg::Default{0}, "time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)"},
+ {"absolute", RPCArg::Type::BOOL, RPCArg::Default{false}, "If set, the bantime must be an absolute timestamp expressed in " + UNIX_EPOCH_TIME},
},
RPCResult{RPCResult::Type::NONE, "", ""},
RPCExamples{
@@ -680,7 +680,7 @@ static RPCHelpMan setban()
if (strCommand != "add" && strCommand != "remove") {
throw std::runtime_error(help.ToString());
}
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if (!node.banman) {
throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
}
@@ -762,7 +762,7 @@ static RPCHelpMan listbanned()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.banman) {
throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
}
@@ -802,7 +802,7 @@ static RPCHelpMan clearbanned()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if (!node.banman) {
throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
}
@@ -825,7 +825,7 @@ static RPCHelpMan setnetworkactive()
RPCExamples{""},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if (!node.connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
@@ -842,7 +842,7 @@ static RPCHelpMan getnodeaddresses()
return RPCHelpMan{"getnodeaddresses",
"\nReturn known addresses, which can potentially be used to find new nodes in the network.\n",
{
- {"count", RPCArg::Type::NUM, /* default */ "1", "The maximum number of addresses to return. Specify 0 to return all known addresses."},
+ {"count", RPCArg::Type::NUM, RPCArg::Default{1}, "The maximum number of addresses to return. Specify 0 to return all known addresses."},
},
RPCResult{
RPCResult::Type::ARR, "", "",
@@ -863,7 +863,7 @@ static RPCHelpMan getnodeaddresses()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if (!node.connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
@@ -909,7 +909,7 @@ static RPCHelpMan addpeeraddress()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
if (!node.addrman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Address manager functionality missing or disabled");
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 527e9be87c..16ca3bb47d 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -41,7 +41,7 @@
#include <univalue.h>
-static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
+static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, CChainState& active_chainstate)
{
// Call into TxToUniv() in bitcoin-common to decode the transaction hex.
//
@@ -54,10 +54,10 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue&
LOCK(cs_main);
entry.pushKV("blockhash", hashBlock.GetHex());
- CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hashBlock);
+ CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(hashBlock);
if (pindex) {
- if (::ChainActive().Contains(pindex)) {
- entry.pushKV("confirmations", 1 + ::ChainActive().Height() - pindex->nHeight);
+ if (active_chainstate.m_chain.Contains(pindex)) {
+ entry.pushKV("confirmations", 1 + active_chainstate.m_chain.Height() - pindex->nHeight);
entry.pushKV("time", pindex->GetBlockTime());
entry.pushKV("blocktime", pindex->GetBlockTime());
}
@@ -85,7 +85,7 @@ static RPCHelpMan getrawtransaction()
"If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
- {"verbose", RPCArg::Type::BOOL, /* default */ "false", "If false, return a string, otherwise return a json object"},
+ {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If false, return a string, otherwise return a json object"},
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "The block in which to look for the transaction"},
},
{
@@ -158,7 +158,8 @@ static RPCHelpMan getrawtransaction()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- const NodeContext& node = EnsureNodeContext(request.context);
+ const NodeContext& node = EnsureAnyNodeContext(request.context);
+ ChainstateManager& chainman = EnsureChainman(node);
bool in_active_chain = true;
uint256 hash = ParseHashV(request.params[0], "parameter 1");
@@ -179,11 +180,11 @@ static RPCHelpMan getrawtransaction()
LOCK(cs_main);
uint256 blockhash = ParseHashV(request.params[2], "parameter 3");
- blockindex = g_chainman.m_blockman.LookupBlockIndex(blockhash);
+ blockindex = chainman.m_blockman.LookupBlockIndex(blockhash);
if (!blockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found");
}
- in_active_chain = ::ChainActive().Contains(blockindex);
+ in_active_chain = chainman.ActiveChain().Contains(blockindex);
}
bool f_txindex_ready = false;
@@ -216,7 +217,7 @@ static RPCHelpMan getrawtransaction()
UniValue result(UniValue::VOBJ);
if (blockindex) result.pushKV("in_active_chain", in_active_chain);
- TxToJSON(*tx, hash_block, result);
+ TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
return result;
},
};
@@ -258,21 +259,23 @@ static RPCHelpMan gettxoutproof()
CBlockIndex* pblockindex = nullptr;
uint256 hashBlock;
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
if (!request.params[1].isNull()) {
LOCK(cs_main);
hashBlock = ParseHashV(request.params[1], "blockhash");
- pblockindex = g_chainman.m_blockman.LookupBlockIndex(hashBlock);
+ pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
} else {
LOCK(cs_main);
+ CChainState& active_chainstate = chainman.ActiveChainstate();
// Loop through txids and try to find which block they're in. Exit loop once a block is found.
for (const auto& tx : setTxids) {
- const Coin& coin = AccessByTxid(::ChainstateActive().CoinsTip(), tx);
+ const Coin& coin = AccessByTxid(active_chainstate.CoinsTip(), tx);
if (!coin.IsSpent()) {
- pblockindex = ::ChainActive()[coin.nHeight];
+ pblockindex = active_chainstate.m_chain[coin.nHeight];
break;
}
}
@@ -291,7 +294,7 @@ static RPCHelpMan gettxoutproof()
if (!tx || hashBlock.IsNull()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
}
- pblockindex = g_chainman.m_blockman.LookupBlockIndex(hashBlock);
+ pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock);
if (!pblockindex) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt");
}
@@ -349,10 +352,11 @@ static RPCHelpMan verifytxoutproof()
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot)
return res;
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash());
- if (!pindex || !::ChainActive().Contains(pindex) || pindex->nTx == 0) {
+ const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash());
+ if (!pindex || !chainman.ActiveChain().Contains(pindex) || pindex->nTx == 0) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
}
@@ -383,7 +387,7 @@ static RPCHelpMan createrawtransaction()
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
{"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
- {"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"},
+ {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'replaceable' and 'locktime' arguments"}, "The sequence number"},
},
},
},
@@ -405,8 +409,8 @@ static RPCHelpMan createrawtransaction()
},
},
},
- {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
- {"replaceable", RPCArg::Type::BOOL, /* default */ "false", "Marks this transaction as BIP125-replaceable.\n"
+ {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
+ {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{false}, "Marks this transaction as BIP125-replaceable.\n"
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
},
RPCResult{
@@ -445,7 +449,7 @@ static RPCHelpMan decoderawtransaction()
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"},
- {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
+ {"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n"
"If iswitness is not present, heuristic tests will be used in decoding.\n"
"If true, only witness deserialization will be tried.\n"
"If false, only non-witness deserialization will be tried.\n"
@@ -676,10 +680,11 @@ static RPCHelpMan combinerawtransaction()
CCoinsView viewDummy;
CCoinsViewCache view(&viewDummy);
{
- const CTxMemPool& mempool = EnsureMemPool(request.context);
- LOCK(cs_main);
- LOCK(mempool.cs);
- CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip();
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ const CTxMemPool& mempool = EnsureMemPool(node);
+ ChainstateManager& chainman = EnsureChainman(node);
+ LOCK2(cs_main, mempool.cs);
+ CCoinsViewCache &viewChain = chainman.ActiveChainstate().CoinsTip();
CCoinsViewMemPool viewMempool(&viewChain, mempool);
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
@@ -747,7 +752,7 @@ static RPCHelpMan signrawtransactionwithkey()
},
},
},
- {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type. Must be one of:\n"
+ {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"ALL"}, "The signature hash type. Must be one of:\n"
" \"ALL\"\n"
" \"NONE\"\n"
" \"SINGLE\"\n"
@@ -803,7 +808,7 @@ static RPCHelpMan signrawtransactionwithkey()
for (const CTxIn& txin : mtx.vin) {
coins[txin.prevout]; // Create empty map entry keyed by prevout.
}
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
FindCoins(node, coins);
// Parse the prevtxs array
@@ -827,7 +832,7 @@ static RPCHelpMan sendrawtransaction()
"\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
- {"maxfeerate", RPCArg::Type::AMOUNT, /* default */ FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK()),
+ {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
"Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
"/kB.\nSet to 0 to accept any fee rate.\n"},
},
@@ -866,7 +871,7 @@ static RPCHelpMan sendrawtransaction()
std::string err_string;
AssertLockNotHeld(cs_main);
- NodeContext& node = EnsureNodeContext(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /*relay*/ true, /*wait_callback*/ true);
if (TransactionError::OK != err) {
throw JSONRPCTransactionError(err, err_string);
@@ -890,7 +895,7 @@ static RPCHelpMan testmempoolaccept()
{"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
},
},
- {"maxfeerate", RPCArg::Type::AMOUNT, /* default */ FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK()), "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kB\n"},
+ {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())}, "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kB\n"},
},
RPCResult{
RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n"
@@ -941,7 +946,9 @@ static RPCHelpMan testmempoolaccept()
DEFAULT_MAX_RAW_TX_FEE_RATE :
CFeeRate(AmountFromValue(request.params[1]));
- CTxMemPool& mempool = EnsureMemPool(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+
+ CTxMemPool& mempool = EnsureMemPool(node);
int64_t virtual_size = GetVirtualTransactionSize(*tx);
CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
@@ -950,7 +957,8 @@ static RPCHelpMan testmempoolaccept()
result_0.pushKV("txid", tx->GetHash().GetHex());
result_0.pushKV("wtxid", tx->GetWitnessHash().GetHex());
- const MempoolAcceptResult accept_result = WITH_LOCK(cs_main, return AcceptToMemoryPool(::ChainstateActive(), mempool, std::move(tx),
+ ChainstateManager& chainman = EnsureChainman(node);
+ const MempoolAcceptResult accept_result = WITH_LOCK(cs_main, return AcceptToMemoryPool(chainman.ActiveChainstate(), mempool, std::move(tx),
false /* bypass_limits */, /* test_accept */ true));
// Only return the fee and vsize if the transaction would pass ATMP.
@@ -1354,7 +1362,7 @@ static RPCHelpMan finalizepsbt()
"Implements the Finalizer and Extractor roles.\n",
{
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},
- {"extract", RPCArg::Type::BOOL, /* default */ "true", "If true and the transaction is complete,\n"
+ {"extract", RPCArg::Type::BOOL, RPCArg::Default{true}, "If true and the transaction is complete,\n"
" extract and return the complete transaction in normal network serialization instead of the PSBT."},
},
RPCResult{
@@ -1416,7 +1424,7 @@ static RPCHelpMan createpsbt()
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
{"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
- {"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"},
+ {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'replaceable' and 'locktime' arguments"}, "The sequence number"},
},
},
},
@@ -1438,8 +1446,8 @@ static RPCHelpMan createpsbt()
},
},
},
- {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
- {"replaceable", RPCArg::Type::BOOL, /* default */ "false", "Marks this transaction as BIP125 replaceable.\n"
+ {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
+ {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{false}, "Marks this transaction as BIP125 replaceable.\n"
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
},
RPCResult{
@@ -1491,9 +1499,9 @@ static RPCHelpMan converttopsbt()
"createpsbt and walletcreatefundedpsbt should be used for new applications.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of a raw transaction"},
- {"permitsigdata", RPCArg::Type::BOOL, /* default */ "false", "If true, any signatures in the input will be discarded and conversion\n"
+ {"permitsigdata", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, any signatures in the input will be discarded and conversion\n"
" will continue. If false, RPC will fail if any signatures are present."},
- {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
+ {"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n"
"If iswitness is not present, heuristic tests will be used in decoding.\n"
"If true, only witness deserialization will be tried.\n"
"If false, only non-witness deserialization will be tried.\n"
@@ -1563,7 +1571,7 @@ static RPCHelpMan utxoupdatepsbt()
{"", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with an output descriptor and extra information", {
{"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
- {"range", RPCArg::Type::RANGE, "1000", "Up to what index HD chains should be explored (either end or [begin,end])"},
+ {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "Up to what index HD chains should be explored (either end or [begin,end])"},
}},
}},
},
@@ -1599,9 +1607,11 @@ static RPCHelpMan utxoupdatepsbt()
CCoinsView viewDummy;
CCoinsViewCache view(&viewDummy);
{
- const CTxMemPool& mempool = EnsureMemPool(request.context);
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ const CTxMemPool& mempool = EnsureMemPool(node);
+ ChainstateManager& chainman = EnsureChainman(node);
LOCK2(cs_main, mempool.cs);
- CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip();
+ CCoinsViewCache &viewChain = chainman.ActiveChainstate().CoinsTip();
CCoinsViewMemPool viewMempool(&viewChain, mempool);
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 5d816ba5bb..cf80b08b96 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -135,7 +135,7 @@ static RPCHelpMan help()
return RPCHelpMan{"help",
"\nList all commands, or get help for a specified command.\n",
{
- {"command", RPCArg::Type::STR, /* default */ "all commands", "The command to get help on"},
+ {"command", RPCArg::Type::STR, RPCArg::DefaultHint{"all commands"}, "The command to get help on"},
},
{
RPCResult{RPCResult::Type::STR, "", "The help text"},
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index ba3105ca01..df3ee9f007 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -498,6 +498,33 @@ RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RP
for (const std::string& name : names) {
CHECK_NONFATAL(named_args.insert(name).second);
}
+ // Default value type should match argument type only when defined
+ if (arg.m_fallback.index() == 2) {
+ const RPCArg::Type type = arg.m_type;
+ switch (std::get<RPCArg::Default>(arg.m_fallback).getType()) {
+ case UniValue::VOBJ:
+ CHECK_NONFATAL(type == RPCArg::Type::OBJ);
+ break;
+ case UniValue::VARR:
+ CHECK_NONFATAL(type == RPCArg::Type::ARR);
+ break;
+ case UniValue::VSTR:
+ CHECK_NONFATAL(type == RPCArg::Type::STR || type == RPCArg::Type::STR_HEX || type == RPCArg::Type::AMOUNT);
+ break;
+ case UniValue::VNUM:
+ CHECK_NONFATAL(type == RPCArg::Type::NUM || type == RPCArg::Type::AMOUNT || type == RPCArg::Type::RANGE);
+ break;
+ case UniValue::VBOOL:
+ CHECK_NONFATAL(type == RPCArg::Type::BOOL);
+ break;
+ case UniValue::VNULL:
+ // Null values are accepted in all arguments
+ break;
+ default:
+ CHECK_NONFATAL(false);
+ break;
+ }
+ }
}
}
@@ -646,7 +673,7 @@ std::string RPCArg::GetName() const
bool RPCArg::IsOptional() const
{
- if (m_fallback.index() == 1) {
+ if (m_fallback.index() != 0) {
return true;
} else {
return RPCArg::Optional::NO != std::get<RPCArg::Optional>(m_fallback);
@@ -694,7 +721,9 @@ std::string RPCArg::ToDescriptionString() const
} // no default case, so the compiler can warn about missing cases
}
if (m_fallback.index() == 1) {
- ret += ", optional, default=" + std::get<std::string>(m_fallback);
+ ret += ", optional, default=" + std::get<RPCArg::DefaultHint>(m_fallback);
+ } else if (m_fallback.index() == 2) {
+ ret += ", optional, default=" + std::get<RPCArg::Default>(m_fallback).write();
} else {
switch (std::get<RPCArg::Optional>(m_fallback)) {
case RPCArg::Optional::OMITTED: {
diff --git a/src/rpc/util.h b/src/rpc/util.h
index 6e783e19fb..8ec18b2f35 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -145,7 +145,9 @@ struct RPCArg {
*/
OMITTED,
};
- using Fallback = std::variant<Optional, /* default value for optional args */ std::string>;
+ using DefaultHint = std::string;
+ using Default = UniValue;
+ using Fallback = std::variant<Optional, /* hint for default value */ DefaultHint, /* default constant value */ Default>;
const std::string m_names; //!< The name of the arg (can be empty for inner args, can contain multiple aliases separated by | for named request arguments)
const Type m_type;
const bool m_hidden;
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 30399dca51..f1433553bc 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -481,34 +481,35 @@ class DescriptorImpl : public Descriptor
const std::string m_name;
protected:
- //! The sub-descriptor argument (nullptr for everything but SH and WSH).
+ //! The sub-descriptor arguments (empty for everything but SH and WSH).
//! In doc/descriptors.m this is referred to as SCRIPT expressions sh(SCRIPT)
//! and wsh(SCRIPT), and distinct from KEY expressions and ADDR expressions.
- const std::unique_ptr<DescriptorImpl> m_subdescriptor_arg;
+ //! Subdescriptors can only ever generate a single script.
+ const std::vector<std::unique_ptr<DescriptorImpl>> m_subdescriptor_args;
//! Return a serialization of anything except pubkey and script arguments, to be prepended to those.
virtual std::string ToStringExtra() const { return ""; }
/** A helper function to construct the scripts for this descriptor.
*
- * This function is invoked once for every CScript produced by evaluating
- * m_subdescriptor_arg, or just once in case m_subdescriptor_arg is nullptr.
-
+ * This function is invoked once by ExpandHelper.
+ *
* @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 evaluations of m_subdescriptor_args (one for each m_subdescriptor_args element).
* @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.
+ * The origin info of the provided pubkeys is automatically added.
* @return A vector with scriptPubKeys for this descriptor.
*/
- virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, const CScript* script, FlatSigningProvider& out) const = 0;
+ virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, Span<const CScript> scripts, FlatSigningProvider& out) const = 0;
public:
- DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::unique_ptr<DescriptorImpl> script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_arg(std::move(script)) {}
+ DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args() {}
+ DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::unique_ptr<DescriptorImpl> script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args(Vector(std::move(script))) {}
bool IsSolvable() const override
{
- if (m_subdescriptor_arg) {
- if (!m_subdescriptor_arg->IsSolvable()) return false;
+ for (const auto& arg : m_subdescriptor_args) {
+ if (!arg->IsSolvable()) return false;
}
return true;
}
@@ -518,12 +519,24 @@ public:
for (const auto& pubkey : m_pubkey_args) {
if (pubkey->IsRange()) return true;
}
- if (m_subdescriptor_arg) {
- if (m_subdescriptor_arg->IsRange()) return true;
+ for (const auto& arg : m_subdescriptor_args) {
+ if (arg->IsRange()) return true;
}
return false;
}
+ virtual bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, bool priv, bool normalized) const
+ {
+ size_t pos = 0;
+ for (const auto& scriptarg : m_subdescriptor_args) {
+ if (pos++) ret += ",";
+ std::string tmp;
+ if (!scriptarg->ToStringHelper(arg, tmp, priv, normalized)) return false;
+ ret += std::move(tmp);
+ }
+ return true;
+ }
+
bool ToStringHelper(const SigningProvider* arg, std::string& out, bool priv, bool normalized) const
{
std::string extra = ToStringExtra();
@@ -541,13 +554,10 @@ public:
}
ret += std::move(tmp);
}
- if (m_subdescriptor_arg) {
- if (pos++) ret += ",";
- std::string tmp;
- if (!m_subdescriptor_arg->ToStringHelper(arg, tmp, priv, normalized)) return false;
- ret += std::move(tmp);
- }
- out = std::move(ret) + ")";
+ std::string subscript;
+ if (!ToStringSubScriptHelper(arg, subscript, priv, normalized)) return false;
+ if (pos && subscript.size()) ret += ',';
+ out = std::move(ret) + std::move(subscript) + ")";
return true;
}
@@ -577,17 +587,20 @@ public:
std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
entries.reserve(m_pubkey_args.size());
- // Construct temporary data in `entries` and `subscripts`, to avoid producing output in case of failure.
+ // Construct temporary data in `entries`, `subscripts`, and `subprovider` to avoid producing output in case of failure.
for (const auto& p : m_pubkey_args) {
entries.emplace_back();
if (!p->GetPubKey(pos, arg, entries.back().first, entries.back().second, read_cache, write_cache)) return false;
}
std::vector<CScript> subscripts;
- if (m_subdescriptor_arg) {
- FlatSigningProvider subprovider;
- if (!m_subdescriptor_arg->ExpandHelper(pos, arg, read_cache, subscripts, subprovider, write_cache)) return false;
- out = Merge(out, subprovider);
+ FlatSigningProvider subprovider;
+ for (const auto& subarg : m_subdescriptor_args) {
+ std::vector<CScript> outscripts;
+ if (!subarg->ExpandHelper(pos, arg, read_cache, outscripts, subprovider, write_cache)) return false;
+ assert(outscripts.size() == 1);
+ subscripts.emplace_back(std::move(outscripts[0]));
}
+ out = Merge(std::move(out), std::move(subprovider));
std::vector<CPubKey> pubkeys;
pubkeys.reserve(entries.size());
@@ -595,17 +608,8 @@ public:
pubkeys.push_back(entry.first);
out.origins.emplace(entry.first.GetID(), std::make_pair<CPubKey, KeyOriginInfo>(CPubKey(entry.first), std::move(entry.second)));
}
- if (m_subdescriptor_arg) {
- for (const auto& subscript : subscripts) {
- out.scripts.emplace(CScriptID(subscript), subscript);
- std::vector<CScript> addscripts = MakeScripts(pubkeys, &subscript, out);
- for (auto& addscript : addscripts) {
- output_scripts.push_back(std::move(addscript));
- }
- }
- } else {
- output_scripts = MakeScripts(pubkeys, nullptr, out);
- }
+
+ output_scripts = MakeScripts(pubkeys, MakeSpan(subscripts), out);
return true;
}
@@ -626,10 +630,8 @@ public:
if (!p->GetPrivKey(pos, provider, key)) continue;
out.keys.emplace(key.GetPubKey().GetID(), key);
}
- if (m_subdescriptor_arg) {
- FlatSigningProvider subprovider;
- m_subdescriptor_arg->ExpandPrivate(pos, provider, subprovider);
- out = Merge(out, subprovider);
+ for (const auto& arg : m_subdescriptor_args) {
+ arg->ExpandPrivate(pos, provider, out);
}
}
@@ -642,9 +644,9 @@ class AddressDescriptor final : public DescriptorImpl
const CTxDestination m_destination;
protected:
std::string ToStringExtra() const override { return EncodeDestination(m_destination); }
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
public:
- AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
+ AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, "addr"), m_destination(std::move(destination)) {}
bool IsSolvable() const final { return false; }
std::optional<OutputType> GetOutputType() const override
@@ -668,9 +670,9 @@ class RawDescriptor final : public DescriptorImpl
const CScript m_script;
protected:
std::string ToStringExtra() const override { return HexStr(m_script); }
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(m_script); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return Vector(m_script); }
public:
- RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
+ RawDescriptor(CScript script) : DescriptorImpl({}, "raw"), m_script(std::move(script)) {}
bool IsSolvable() const final { return false; }
std::optional<OutputType> GetOutputType() const override
@@ -694,9 +696,9 @@ public:
class PKDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); }
public:
- PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pk") {}
+ PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pk") {}
bool IsSingleType() const final { return true; }
};
@@ -704,14 +706,14 @@ public:
class PKHDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
{
CKeyID id = keys[0].GetID();
out.pubkeys.emplace(id, keys[0]);
return Vector(GetScriptForDestination(PKHash(id)));
}
public:
- PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pkh") {}
+ PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pkh") {}
std::optional<OutputType> GetOutputType() const override { return OutputType::LEGACY; }
bool IsSingleType() const final { return true; }
};
@@ -720,14 +722,14 @@ public:
class WPKHDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
{
CKeyID id = keys[0].GetID();
out.pubkeys.emplace(id, keys[0]);
return Vector(GetScriptForDestination(WitnessV0KeyHash(id)));
}
public:
- WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "wpkh") {}
+ WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "wpkh") {}
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
bool IsSingleType() const final { return true; }
};
@@ -736,7 +738,7 @@ public:
class ComboDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
{
std::vector<CScript> ret;
CKeyID id = keys[0].GetID();
@@ -752,7 +754,7 @@ protected:
return ret;
}
public:
- ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "combo") {}
+ ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "combo") {}
bool IsSingleType() const final { return false; }
};
@@ -763,7 +765,7 @@ class MultisigDescriptor final : public DescriptorImpl
const bool m_sorted;
protected:
std::string ToStringExtra() const override { return strprintf("%i", m_threshold); }
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override {
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override {
if (m_sorted) {
std::vector<CPubKey> sorted_keys(keys);
std::sort(sorted_keys.begin(), sorted_keys.end());
@@ -772,7 +774,7 @@ protected:
return Vector(GetScriptForMultisig(m_threshold, keys));
}
public:
- MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), {}, sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {}
+ MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {}
bool IsSingleType() const final { return true; }
};
@@ -780,14 +782,19 @@ public:
class SHDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(ScriptHash(*script))); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript> scripts, FlatSigningProvider& out) const override
+ {
+ auto ret = Vector(GetScriptForDestination(ScriptHash(scripts[0])));
+ if (ret.size()) out.scripts.emplace(CScriptID(scripts[0]), scripts[0]);
+ return ret;
+ }
public:
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
std::optional<OutputType> GetOutputType() const override
{
- assert(m_subdescriptor_arg);
- if (m_subdescriptor_arg->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT;
+ assert(m_subdescriptor_args.size() == 1);
+ if (m_subdescriptor_args[0]->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT;
return OutputType::LEGACY;
}
bool IsSingleType() const final { return true; }
@@ -797,7 +804,12 @@ public:
class WSHDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(WitnessV0ScriptHash(*script))); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript> scripts, FlatSigningProvider& out) const override
+ {
+ auto ret = Vector(GetScriptForDestination(WitnessV0ScriptHash(scripts[0])));
+ if (ret.size()) out.scripts.emplace(CScriptID(scripts[0]), scripts[0]);
+ return ret;
+ }
public:
WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {}
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
@@ -809,9 +821,10 @@ public:
////////////////////////////////////////////////////////////////////////////
enum class ParseScriptContext {
- TOP,
- P2SH,
- P2WSH,
+ TOP, //!< Top-level context (script goes directly in scriptPubKey)
+ P2SH, //!< Inside sh() (script becomes P2SH redeemScript)
+ P2WPKH, //!< Inside wpkh() (no script, pubkey only)
+ P2WSH, //!< Inside wsh() (script becomes v0 witness script)
};
/** Parse a key path, being passed a split list of elements (the first element is ignored). */
@@ -838,10 +851,11 @@ enum class ParseScriptContext {
}
/** Parse a public key that excludes origin information. */
-std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error)
+std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
{
using namespace spanparsing;
+ bool permit_uncompressed = ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH;
auto split = Split(sp, '/');
std::string str(split[0].begin(), split[0].end());
if (str.size() == 0) {
@@ -899,7 +913,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
}
/** Parse a public key including origin information (if enabled). */
-std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error)
+std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
{
using namespace spanparsing;
@@ -908,7 +922,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c
error = "Multiple ']' characters found for a single pubkey";
return nullptr;
}
- if (origin_split.size() == 1) return ParsePubkeyInner(key_exp_index, origin_split[0], permit_uncompressed, out, error);
+ if (origin_split.size() == 1) return ParsePubkeyInner(key_exp_index, origin_split[0], ctx, out, error);
if (origin_split[0].empty() || origin_split[0][0] != '[') {
error = strprintf("Key origin start '[ character expected but not found, got '%c' instead",
origin_split[0].empty() ? /** empty, implies split char */ ']' : origin_split[0][0]);
@@ -930,34 +944,37 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c
assert(fpr_bytes.size() == 4);
std::copy(fpr_bytes.begin(), fpr_bytes.end(), info.fingerprint);
if (!ParseKeyPath(slash_split, info.path, error)) return nullptr;
- auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], permit_uncompressed, out, error);
+ auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], ctx, out, error);
if (!provider) return nullptr;
return std::make_unique<OriginPubkeyProvider>(key_exp_index, std::move(info), std::move(provider));
}
/** Parse a script in a particular context. */
-std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
+std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
{
using namespace spanparsing;
auto expr = Expr(sp);
bool sorted_multi = false;
if (Func("pk", expr)) {
- auto pubkey = ParsePubkey(key_exp_index, expr, ctx != ParseScriptContext::P2WSH, out, error);
+ auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error);
if (!pubkey) return nullptr;
+ ++key_exp_index;
return std::make_unique<PKDescriptor>(std::move(pubkey));
}
if (Func("pkh", expr)) {
- auto pubkey = ParsePubkey(key_exp_index, expr, ctx != ParseScriptContext::P2WSH, out, error);
+ auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error);
if (!pubkey) return nullptr;
+ ++key_exp_index;
return std::make_unique<PKHDescriptor>(std::move(pubkey));
}
if (ctx == ParseScriptContext::TOP && Func("combo", expr)) {
- auto pubkey = ParsePubkey(key_exp_index, expr, true, out, error);
+ auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error);
if (!pubkey) return nullptr;
+ ++key_exp_index;
return std::make_unique<ComboDescriptor>(std::move(pubkey));
- } else if (ctx != ParseScriptContext::TOP && Func("combo", expr)) {
- error = "Cannot have combo in non-top level";
+ } else if (Func("combo", expr)) {
+ error = "Can only have combo() at top level";
return nullptr;
}
if ((sorted_multi = Func("sortedmulti", expr)) || Func("multi", expr)) {
@@ -975,7 +992,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
return nullptr;
}
auto arg = Expr(expr);
- auto pk = ParsePubkey(key_exp_index, arg, ctx != ParseScriptContext::P2WSH, out, error);
+ auto pk = ParsePubkey(key_exp_index, arg, ctx, out, error);
if (!pk) return nullptr;
script_size += pk->GetSize() + 1;
providers.emplace_back(std::move(pk));
@@ -1005,28 +1022,29 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
}
return std::make_unique<MultisigDescriptor>(thres, std::move(providers), sorted_multi);
}
- if (ctx != ParseScriptContext::P2WSH && Func("wpkh", expr)) {
- auto pubkey = ParsePubkey(key_exp_index, expr, false, out, error);
+ if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wpkh", expr)) {
+ auto pubkey = ParsePubkey(key_exp_index, expr, ParseScriptContext::P2WPKH, out, error);
if (!pubkey) return nullptr;
+ key_exp_index++;
return std::make_unique<WPKHDescriptor>(std::move(pubkey));
- } else if (ctx == ParseScriptContext::P2WSH && Func("wpkh", expr)) {
- error = "Cannot have wpkh within wsh";
+ } else if (Func("wpkh", expr)) {
+ error = "Can only have wpkh() at top level or inside sh()";
return nullptr;
}
if (ctx == ParseScriptContext::TOP && Func("sh", expr)) {
auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2SH, out, error);
if (!desc || expr.size()) return nullptr;
return std::make_unique<SHDescriptor>(std::move(desc));
- } else if (ctx != ParseScriptContext::TOP && Func("sh", expr)) {
- error = "Cannot have sh in non-top level";
+ } else if (Func("sh", expr)) {
+ error = "Can only have sh() at top level";
return nullptr;
}
- if (ctx != ParseScriptContext::P2WSH && Func("wsh", expr)) {
+ if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wsh", expr)) {
auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2WSH, out, error);
if (!desc || expr.size()) return nullptr;
return std::make_unique<WSHDescriptor>(std::move(desc));
- } else if (ctx == ParseScriptContext::P2WSH && Func("wsh", expr)) {
- error = "Cannot have wsh within wsh";
+ } else if (Func("wsh", expr)) {
+ error = "Can only have wsh() at top level or inside sh()";
return nullptr;
}
if (ctx == ParseScriptContext::TOP && Func("addr", expr)) {
@@ -1036,6 +1054,9 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
return nullptr;
}
return std::make_unique<AddressDescriptor>(std::move(dest));
+ } else if (Func("addr", expr)) {
+ error = "Can only have addr() at top level";
+ return nullptr;
}
if (ctx == ParseScriptContext::TOP && Func("raw", expr)) {
std::string str(expr.begin(), expr.end());
@@ -1045,6 +1066,9 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
}
auto bytes = ParseHex(str);
return std::make_unique<RawDescriptor>(CScript(bytes.begin(), bytes.end()));
+ } else if (Func("raw", expr)) {
+ error = "Can only have raw() at top level";
+ return nullptr;
}
if (ctx == ParseScriptContext::P2SH) {
error = "A function is needed within P2SH";
@@ -1174,7 +1198,8 @@ std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProv
{
Span<const char> sp{descriptor};
if (!CheckChecksum(sp, require_checksum, error)) return nullptr;
- auto ret = ParseScript(0, sp, ParseScriptContext::TOP, out, error);
+ uint32_t key_exp_index = 0;
+ auto ret = ParseScript(key_exp_index, sp, ParseScriptContext::TOP, out, error);
if (sp.size() == 0 && ret) return std::unique_ptr<Descriptor>(std::move(ret));
return nullptr;
}
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index c394356798..41bebab2a0 100644
--- a/src/test/data/tx_invalid.json
+++ b/src/test/data/tx_invalid.json
@@ -124,15 +124,15 @@
["CHECKLOCKTIMEVERIFY tests"],
["By-height locks, with argument just beyond tx nLockTime"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKLOCKTIMEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKLOCKTIMEVERIFY"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d", "CHECKLOCKTIMEVERIFY"],
["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 CHECKLOCKTIMEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 CHECKLOCKTIMEVERIFY"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "CHECKLOCKTIMEVERIFY"],
["Argument missing"],
@@ -142,11 +142,11 @@
"010000000100010000000000000000000000000000000000000000000000000000000000000000000001b1010000000100000000000000000000000000", "CHECKLOCKTIMEVERIFY"],
["Argument negative with by-blockheight nLockTime=0"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKLOCKTIMEVERIFY"],
["Argument negative with by-blocktime nLockTime=500,000,000"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "CHECKLOCKTIMEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b1010000000100000000000000000002000000", "CHECKLOCKTIMEVERIFY"],
@@ -167,19 +167,19 @@
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "CHECKLOCKTIMEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b100000000010000000000000000000065cd1d", "NONE"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "CHECKLOCKTIMEVERIFY"],
["Argument 2^32 with nLockTime=2^32-1"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x050000000001 CHECKLOCKTIMEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x050000000001 CHECKLOCKTIMEVERIFY"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "CHECKLOCKTIMEVERIFY"],
["Same, but with nLockTime=2^31-1"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKLOCKTIMEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKLOCKTIMEVERIFY"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f", "CHECKLOCKTIMEVERIFY"],
["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"],
@@ -201,15 +201,15 @@
["CHECKSEQUENCEVERIFY tests"],
["By-height locks, with argument just beyond txin.nSequence"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKSEQUENCEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKSEQUENCEVERIFY"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
["By-time locks, with argument just beyond txin.nSequence (but within numerical boundaries)"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 CHECKSEQUENCEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 CHECKSEQUENCEVERIFY"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
["Argument missing"],
@@ -217,21 +217,21 @@
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
["Argument negative with by-blockheight txin.nSequence=0"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKSEQUENCEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKSEQUENCEVERIFY"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
["Argument negative with by-blocktime txin.nSequence=CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKSEQUENCEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKSEQUENCEVERIFY"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
["Argument/tx height/time mismatch, both versions"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 CHECKSEQUENCEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 CHECKSEQUENCEVERIFY"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"],
@@ -249,7 +249,7 @@
["Failure due to insufficient tx.nVersion (<2)"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "CHECKSEQUENCEVERIFY"],
["Unknown witness program version (with DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)"],
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index 2727af5abd..b874f6f26c 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -62,10 +62,6 @@
["c76168ef1a272a4f176e55e73157ecfce040cfad16a5272f6296eb7089dca846", 1, "DUP HASH160 0x14 0x34fea2c5a75414fd945273ae2d029ce1f28dafcf EQUALVERIFY CHECKSIG"]],
"010000000390d31c6107013d754529d8818eff285fe40a3e7635f6930fec5d12eb02107a43010000006b483045022100f40815ae3c81a0dd851cc8d376d6fd226c88416671346a9033468cca2cdcc6c202204f764623903e6c4bed1b734b75d82c40f1725e4471a55ad4f51218f86130ac038321033d710ab45bb54ac99618ad23b3c1da661631aa25f23bfe9d22b41876f1d46e4effffffff3ff04a68e22bdd52e7c8cb848156d2d158bd5515b3c50adabc87d0ca2cd3482d010000006a4730440220598d263c107004008e9e26baa1e770be30fd31ee55ded1898f7c00da05a75977022045536bead322ca246779698b9c3df3003377090f41afeca7fb2ce9e328ec4af2832102b738b531def73020bd637f32935924cc88549c8206976226d968edd3a42fc2d7ffffffff46a8dc8970eb96622f27a516adcf40e0fcec5731e7556e174f2a271aef6861c7010000006b483045022100c5b90a777a9fdc90c208dbef7290d1fc1be651f47151ee4ccff646872a454cf90220640cfbc4550446968fbbe9d12528f3adf7d87b31541569c59e790db8a220482583210391332546e22bbe8fe3af54addfad6f8b83d05fa4f5e047593d4c07ae938795beffffffff028036be26000000001976a914ddfb29efad43a667465ac59ff14dc6442a1adfca88ac3d5cba01000000001976a914b64dde7a505a13ca986c40e86e984a8dc81368b688ac00000000", "NONE"],
-["An invalid P2SH Transaction"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
-"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "P2SH,CLEANSTACK,WITNESS"],
-
["A valid P2SH Transaction using the standard transaction type put forth in BIP 16"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", "LOW_S"],
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index a6080ad3dd..b5f3bb2fa4 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -26,7 +26,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false");
+ fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'k';
uint256 in = InsecureRand256();
@@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_basic_data)
{
// Perform tests both obfuscated and non-obfuscated.
for (bool obfuscate : {false, true}) {
- fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_1_obfuscate_true" : "dbwrapper_1_obfuscate_false");
+ fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_1_obfuscate_true" : "dbwrapper_1_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), false, true, obfuscate);
uint256 res;
@@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false");
+ fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'i';
@@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false");
+ fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
// The two keys are intentionally chosen for ordering
@@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
{
// We're going to share this fs::path between two wrappers
- fs::path ph = GetDataDir() / "existing_data_no_obfuscate";
+ fs::path ph = m_args.GetDataDirPath() / "existing_data_no_obfuscate";
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
@@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
BOOST_AUTO_TEST_CASE(existing_data_reindex)
{
// We're going to share this fs::path between two wrappers
- fs::path ph = GetDataDir() / "existing_data_reindex";
+ fs::path ph = m_args.GetDataDirPath() / "existing_data_reindex";
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
@@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_AUTO_TEST_CASE(iterator_ordering)
{
- fs::path ph = GetDataDir() / "iterator_ordering";
+ fs::path ph = m_args.GetDataDirPath() / "iterator_ordering";
CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<256; ++x) {
uint8_t key = x;
@@ -358,7 +358,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
{
char buf[10];
- fs::path ph = GetDataDir() / "iterator_string_ordering";
+ fs::path ph = m_args.GetDataDirPath() / "iterator_string_ordering";
CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<10; ++x) {
for (int y = 0; y < 10; y++) {
@@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(unicodepath)
// On Windows this test will fail if the directory is created using
// the ANSI CreateDirectoryA call and the code page isn't UTF8.
// It will succeed if created with CreateDirectoryW.
- fs::path ph = GetDataDir() / "test_runner_₿_🏃_20191128_104644";
+ fs::path ph = m_args.GetDataDirPath() / "test_runner_₿_🏃_20191128_104644";
CDBWrapper dbw(ph, (1 << 20));
fs::path lockPath = ph / "LOCK";
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 599e628685..ddf0e0ca90 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -208,7 +208,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
BOOST_AUTO_TEST_CASE(peer_discouragement)
{
const CChainParams& chainparams = Params();
- auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ auto banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = std::make_unique<CConnmanTest>(0x1337, 0x1337, *m_node.addrman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(),
*m_node.scheduler, *m_node.chainman, *m_node.mempool, false);
@@ -302,7 +302,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
BOOST_AUTO_TEST_CASE(DoS_bantime)
{
const CChainParams& chainparams = Params();
- auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ auto banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(),
*m_node.scheduler, *m_node.chainman, *m_node.mempool, false);
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index aecf955fee..ea41a03728 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -24,7 +24,7 @@ void CheckUnparsable(const std::string& prv, const std::string& pub, const std::
auto parse_pub = Parse(pub, keys_pub, error);
BOOST_CHECK_MESSAGE(!parse_priv, prv);
BOOST_CHECK_MESSAGE(!parse_pub, pub);
- BOOST_CHECK(error == expected_error);
+ BOOST_CHECK_EQUAL(error, expected_error);
}
constexpr int DEFAULT = 0;
@@ -355,12 +355,12 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
// Check for invalid nesting of structures
CheckUnparsable("sh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "A function is needed within P2SH"); // P2SH needs a script, not a key
- CheckUnparsable("sh(combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Cannot have combo in non-top level"); // Old must be top level
+ CheckUnparsable("sh(combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Can only have combo() at top level"); // Old must be top level
CheckUnparsable("wsh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wsh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "A function is needed within P2WSH"); // P2WSH needs a script, not a key
- CheckUnparsable("wsh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Cannot have wpkh within wsh"); // Cannot embed witness inside witness
- CheckUnparsable("wsh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Cannot have sh in non-top level"); // Cannot embed P2SH inside P2WSH
- CheckUnparsable("sh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Cannot have sh in non-top level"); // Cannot embed P2SH inside P2SH
- CheckUnparsable("wsh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Cannot have wsh within wsh"); // Cannot embed P2WSH inside P2WSH
+ CheckUnparsable("wsh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Can only have wpkh() at top level or inside sh()"); // Cannot embed witness inside witness
+ CheckUnparsable("wsh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have sh() at top level"); // Cannot embed P2SH inside P2WSH
+ CheckUnparsable("sh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have sh() at top level"); // Cannot embed P2SH inside P2SH
+ CheckUnparsable("wsh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have wsh() at top level or inside sh()"); // Cannot embed P2WSH inside P2WSH
// Checksums
Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp
index 0c5c19113d..9194ed8130 100644
--- a/src/test/flatfile_tests.cpp
+++ b/src/test/flatfile_tests.cpp
@@ -14,7 +14,7 @@ BOOST_FIXTURE_TEST_SUITE(flatfile_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(flatfile_filename)
{
- const auto data_dir = GetDataDir();
+ const auto data_dir = m_args.GetDataDirPath();
FlatFilePos pos(456, 789);
@@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(flatfile_filename)
BOOST_AUTO_TEST_CASE(flatfile_open)
{
- const auto data_dir = GetDataDir();
+ const auto data_dir = m_args.GetDataDirPath();
FlatFileSeq seq(data_dir, "a", 16 * 1024);
std::string line1("A purely peer-to-peer version of electronic cash would allow online "
@@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE(flatfile_open)
BOOST_AUTO_TEST_CASE(flatfile_allocate)
{
- const auto data_dir = GetDataDir();
+ const auto data_dir = m_args.GetDataDirPath();
FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space;
@@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(flatfile_allocate)
BOOST_AUTO_TEST_CASE(flatfile_flush)
{
- const auto data_dir = GetDataDir();
+ const auto data_dir = m_args.GetDataDirPath();
FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space;
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index e52cd5230c..452bc06bbb 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -13,7 +13,7 @@ BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(fsbridge_fstream)
{
- fs::path tmpfolder = GetDataDir();
+ fs::path tmpfolder = m_args.GetDataDirPath();
// tmpfile1 should be the same as tmpfile2
fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃";
fs::path tmpfile2 = tmpfolder / "fs_tests_₿_🏃";
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 45c9b90ee9..2a217f3455 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -18,7 +18,7 @@ namespace getarg_tests{
protected:
void SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args);
void ResetArgs(const std::string& strArg);
- ArgsManager m_args;
+ ArgsManager m_local_args;
};
}
@@ -39,14 +39,14 @@ void LocalTestingSetup :: ResetArgs(const std::string& strArg)
vecChar.push_back(s.c_str());
std::string error;
- BOOST_CHECK(m_args.ParseParameters(vecChar.size(), vecChar.data(), error));
+ BOOST_CHECK(m_local_args.ParseParameters(vecChar.size(), vecChar.data(), error));
}
void LocalTestingSetup :: SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args)
{
- m_args.ClearArgs();
+ m_local_args.ClearArgs();
for (const auto& arg : args) {
- m_args.AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS);
+ m_local_args.AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS);
}
}
@@ -55,52 +55,52 @@ BOOST_AUTO_TEST_CASE(boolarg)
const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY);
SetupArgs({foo});
ResetArgs("-foo");
- BOOST_CHECK(m_args.GetBoolArg("-foo", false));
- BOOST_CHECK(m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(m_local_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(m_local_args.GetBoolArg("-foo", true));
- BOOST_CHECK(!m_args.GetBoolArg("-fo", false));
- BOOST_CHECK(m_args.GetBoolArg("-fo", true));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-fo", false));
+ BOOST_CHECK(m_local_args.GetBoolArg("-fo", true));
- BOOST_CHECK(!m_args.GetBoolArg("-fooo", false));
- BOOST_CHECK(m_args.GetBoolArg("-fooo", true));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-fooo", false));
+ BOOST_CHECK(m_local_args.GetBoolArg("-fooo", true));
ResetArgs("-foo=0");
- BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
- BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
ResetArgs("-foo=1");
- BOOST_CHECK(m_args.GetBoolArg("-foo", false));
- BOOST_CHECK(m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(m_local_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(m_local_args.GetBoolArg("-foo", true));
// New 0.6 feature: auto-map -nosomething to !-something:
ResetArgs("-nofoo");
- BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
- BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
ResetArgs("-nofoo=1");
- BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
- BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
ResetArgs("-foo -nofoo"); // -nofoo should win
- BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
- BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
ResetArgs("-foo=1 -nofoo=1"); // -nofoo should win
- BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
- BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
ResetArgs("-foo=0 -nofoo=0"); // -nofoo=0 should win
- BOOST_CHECK(m_args.GetBoolArg("-foo", false));
- BOOST_CHECK(m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(m_local_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(m_local_args.GetBoolArg("-foo", true));
// New 0.6 feature: treat -- same as -:
ResetArgs("--foo=1");
- BOOST_CHECK(m_args.GetBoolArg("-foo", false));
- BOOST_CHECK(m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(m_local_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(m_local_args.GetBoolArg("-foo", true));
ResetArgs("--nofoo=1");
- BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
- BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
}
@@ -110,24 +110,24 @@ BOOST_AUTO_TEST_CASE(stringarg)
const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
SetupArgs({foo, bar});
ResetArgs("");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "eleven");
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "");
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "eleven");
ResetArgs("-foo -bar");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "");
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "");
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "");
ResetArgs("-foo=");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "");
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "");
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "");
ResetArgs("-foo=11");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "11");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "11");
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "11");
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "11");
ResetArgs("-foo=eleven");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "eleven");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "eleven");
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "eleven");
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "eleven");
}
@@ -137,20 +137,20 @@ BOOST_AUTO_TEST_CASE(intarg)
const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
SetupArgs({foo, bar});
ResetArgs("");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 11), 11);
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 0), 0);
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 11), 11);
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 0), 0);
ResetArgs("-foo -bar");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 11), 0);
- BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 0);
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 11), 0);
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 0);
ResetArgs("-foo=11 -bar=12");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 0), 11);
- BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 12);
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 0), 11);
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 12);
ResetArgs("-foo=NaN -bar=NotANumber");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 1), 0);
- BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 0);
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 1), 0);
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 0);
}
BOOST_AUTO_TEST_CASE(doubledash)
@@ -159,11 +159,11 @@ BOOST_AUTO_TEST_CASE(doubledash)
const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
SetupArgs({foo, bar});
ResetArgs("--foo");
- BOOST_CHECK_EQUAL(m_args.GetBoolArg("-foo", false), true);
+ BOOST_CHECK_EQUAL(m_local_args.GetBoolArg("-foo", false), true);
ResetArgs("--foo=verbose --bar=1");
- BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "verbose");
- BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 0), 1);
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "verbose");
+ BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 0), 1);
}
BOOST_AUTO_TEST_CASE(boolargno)
@@ -172,24 +172,24 @@ BOOST_AUTO_TEST_CASE(boolargno)
const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
SetupArgs({foo, bar});
ResetArgs("-nofoo");
- BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
- BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
ResetArgs("-nofoo=1");
- BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
- BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
ResetArgs("-nofoo=0");
- BOOST_CHECK(m_args.GetBoolArg("-foo", true));
- BOOST_CHECK(m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(m_local_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(m_local_args.GetBoolArg("-foo", false));
ResetArgs("-foo --nofoo"); // --nofoo should win
- BOOST_CHECK(!m_args.GetBoolArg("-foo", true));
- BOOST_CHECK(!m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
ResetArgs("-nofoo -foo"); // foo always wins:
- BOOST_CHECK(m_args.GetBoolArg("-foo", true));
- BOOST_CHECK(m_args.GetBoolArg("-foo", false));
+ BOOST_CHECK(m_local_args.GetBoolArg("-foo", true));
+ BOOST_CHECK(m_local_args.GetBoolArg("-foo", false));
}
BOOST_AUTO_TEST_CASE(logargs)
@@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(logargs)
});
// Log the arguments
- m_args.LogArgs();
+ m_local_args.LogArgs();
LogInstance().DeleteCallback(print_connection);
// Check that what should appear does, and what shouldn't doesn't.
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 8eab26f3d5..1c397481dc 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -307,9 +307,6 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_REQUIRE(addr.IsValid());
BOOST_REQUIRE(addr.IsIPv6());
BOOST_CHECK(!addr.IsBindAny());
- const std::string addr_str{addr.ToString()};
- BOOST_CHECK(addr_str == scoped_addr || addr_str == "fe80:0:0:0:0:0:0:1");
- // The fallback case "fe80:0:0:0:0:0:0:1" is needed for macOS 10.14/10.15 and (probably) later.
// Test that the delimiter "%" and default zone id of 0 can be omitted for the default scope.
BOOST_REQUIRE(LookupHost(link_local + "%0", addr, false));
BOOST_REQUIRE(addr.IsValid());
diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp
index 548fd020a6..f5ae9f86d1 100644
--- a/src/test/settings_tests.cpp
+++ b/src/test/settings_tests.cpp
@@ -45,7 +45,7 @@ BOOST_FIXTURE_TEST_SUITE(settings_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(ReadWrite)
{
- fs::path path = GetDataDir() / "settings.json";
+ fs::path path = m_args.GetDataDirPath() / "settings.json";
WriteText(path, R"({
"string": "string",
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index aaa6caa4f1..9bbf9567f5 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -20,6 +20,7 @@
#include <script/signingprovider.h>
#include <script/standard.h>
#include <streams.h>
+#include <test/util/script.h>
#include <test/util/transaction_utils.h>
#include <util/strencodings.h>
#include <util/string.h>
@@ -59,6 +60,9 @@ static std::map<std::string, unsigned int> mapFlagNames = {
{std::string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE},
{std::string("CONST_SCRIPTCODE"), (unsigned int)SCRIPT_VERIFY_CONST_SCRIPTCODE},
{std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT},
+ {std::string("DISCOURAGE_UPGRADABLE_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE},
+ {std::string("DISCOURAGE_OP_SUCCESS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS},
+ {std::string("DISCOURAGE_UPGRADABLE_TAPROOT_VERSION"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION},
};
unsigned int ParseScriptFlags(std::string strFlags)
@@ -78,6 +82,16 @@ unsigned int ParseScriptFlags(std::string strFlags)
return flags;
}
+// Check that all flags in STANDARD_SCRIPT_VERIFY_FLAGS are present in mapFlagNames.
+bool CheckMapFlagNames()
+{
+ unsigned int standard_flags_missing{STANDARD_SCRIPT_VERIFY_FLAGS};
+ for (const auto& pair : mapFlagNames) {
+ standard_flags_missing &= ~(pair.second);
+ }
+ return standard_flags_missing == 0;
+}
+
std::string FormatScriptFlags(unsigned int flags)
{
if (flags == 0) {
@@ -139,6 +153,7 @@ unsigned int TrimFlags(unsigned int flags)
// CLEANSTACK requires WITNESS (and transitively CLEANSTACK requires P2SH)
if (!(flags & SCRIPT_VERIFY_WITNESS)) flags &= ~(unsigned int)SCRIPT_VERIFY_CLEANSTACK;
+ Assert(IsValidFlagCombination(flags));
return flags;
}
@@ -149,17 +164,21 @@ unsigned int FillFlags(unsigned int flags)
// WITNESS implies P2SH (and transitively CLEANSTACK implies P2SH)
if (flags & SCRIPT_VERIFY_WITNESS) flags |= SCRIPT_VERIFY_P2SH;
+ Assert(IsValidFlagCombination(flags));
return flags;
}
-// Return valid flags that are all except one flag for each flag
-std::vector<unsigned int> ExcludeIndividualFlags(unsigned int flags)
+// Exclude each possible script verify flag from flags. Returns a set of these flag combinations
+// that are valid and without duplicates. For example: if flags=1111 and the 4 possible flags are
+// 0001, 0010, 0100, and 1000, this should return the set {0111, 1011, 1101, 1110}.
+// Assumes that mapFlagNames contains all script verify flags.
+std::set<unsigned int> ExcludeIndividualFlags(unsigned int flags)
{
- std::vector<unsigned int> flags_combos;
- for (unsigned int i = 0; i < mapFlagNames.size(); ++i) {
- const unsigned int flags_excluding_i = TrimFlags(flags & ~(1U << i));
- if (flags != flags_excluding_i && std::find(flags_combos.begin(), flags_combos.end(), flags_excluding_i) != flags_combos.end()) {
- flags_combos.push_back(flags_excluding_i);
+ std::set<unsigned int> flags_combos;
+ for (const auto& pair : mapFlagNames) {
+ const unsigned int flags_excluding_one = TrimFlags(flags & ~(pair.second));
+ if (flags != flags_excluding_one) {
+ flags_combos.insert(flags_excluding_one);
}
}
return flags_combos;
@@ -169,6 +188,7 @@ BOOST_FIXTURE_TEST_SUITE(transaction_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(tx_valid)
{
+ BOOST_CHECK_MESSAGE(CheckMapFlagNames(), "mapFlagNames is missing a script verification flag");
// Read tests from test/data/tx_valid.json
UniValue tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
@@ -228,16 +248,15 @@ BOOST_AUTO_TEST_CASE(tx_valid)
BOOST_ERROR("Bad test flags: " << strTest);
}
- if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, ~verify_flags, txdata, strTest, /* expect_valid */ true)) {
- BOOST_ERROR("Tx unexpectedly failed: " << strTest);
- }
+ BOOST_CHECK_MESSAGE(CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, ~verify_flags, txdata, strTest, /* expect_valid */ true),
+ "Tx unexpectedly failed: " << strTest);
// Backwards compatibility of script verification flags: Removing any flag(s) should not invalidate a valid transaction
- for (size_t i = 0; i < mapFlagNames.size(); ++i) {
+ for (const auto& [name, flag] : mapFlagNames) {
// Removing individual flags
- unsigned int flags = TrimFlags(~(verify_flags | (1U << i)));
+ unsigned int flags = TrimFlags(~(verify_flags | flag));
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /* expect_valid */ true)) {
- BOOST_ERROR("Tx unexpectedly failed with flag " << ToString(i) << " unset: " << strTest);
+ BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest);
}
// Removing random combinations of flags
flags = TrimFlags(~(verify_flags | (unsigned int)InsecureRandBits(mapFlagNames.size())));
@@ -247,7 +266,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
}
// Check that flags are maximal: transaction should fail if any unset flags are set.
- for (auto flags_excluding_one: ExcludeIndividualFlags(verify_flags)) {
+ for (auto flags_excluding_one : ExcludeIndividualFlags(verify_flags)) {
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, ~flags_excluding_one, txdata, strTest, /* expect_valid */ false)) {
BOOST_ERROR("Too many flags unset: " << strTest);
}
@@ -314,27 +333,31 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
PrecomputedTransactionData txdata(tx);
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
- // Not using FillFlags() in the main test, in order to detect invalid verifyFlags combination
- if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, verify_flags, txdata, strTest, /* expect_valid */ false)) {
- BOOST_ERROR("Tx unexpectedly passed: " << strTest);
+ // Check that the test gives a valid combination of flags (otherwise VerifyScript will throw). Don't edit the flags.
+ if (verify_flags != FillFlags(verify_flags)) {
+ BOOST_ERROR("Bad test flags: " << strTest);
}
+ // Not using FillFlags() in the main test, in order to detect invalid verifyFlags combination
+ BOOST_CHECK_MESSAGE(CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, verify_flags, txdata, strTest, /* expect_valid */ false),
+ "Tx unexpectedly passed: " << strTest);
+
// Backwards compatibility of script verification flags: Adding any flag(s) should not validate an invalid transaction
- for (size_t i = 0; i < mapFlagNames.size(); i++) {
- unsigned int flags = FillFlags(verify_flags | (1U << i));
+ for (const auto& [name, flag] : mapFlagNames) {
+ unsigned int flags = FillFlags(verify_flags | flag);
// Adding individual flags
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /* expect_valid */ false)) {
- BOOST_ERROR("Tx unexpectedly passed with flag " << ToString(i) << " set: " << strTest);
+ BOOST_ERROR("Tx unexpectedly passed with flag " << name << " set: " << strTest);
}
// Adding random combinations of flags
flags = FillFlags(verify_flags | (unsigned int)InsecureRandBits(mapFlagNames.size()));
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /* expect_valid */ false)) {
- BOOST_ERROR("Tx unexpectedly passed with random flags " << ToString(flags) << ": " << strTest);
+ BOOST_ERROR("Tx unexpectedly passed with random flags " << name << ": " << strTest);
}
}
// Check that flags are minimal: transaction should succeed if any set flags are unset.
- for (auto flags_excluding_one: ExcludeIndividualFlags(verify_flags)) {
+ for (auto flags_excluding_one : ExcludeIndividualFlags(verify_flags)) {
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags_excluding_one, txdata, strTest, /* expect_valid */ true)) {
BOOST_ERROR("Too many flags set: " << strTest);
}
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index d644dd2327..ffc5115145 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -71,7 +71,8 @@ std::ostream& operator<<(std::ostream& os, const uint256& num)
}
BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::vector<const char*>& extra_args)
- : m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME / g_insecure_rand_ctx_temp_path.rand256().ToString()}
+ : m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME / g_insecure_rand_ctx_temp_path.rand256().ToString()},
+ m_args{}
{
const std::vector<const char*> arguments = Cat(
{
@@ -87,8 +88,9 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
extra_args);
util::ThreadRename("test");
fs::create_directories(m_path_root);
+ m_args.ForceSetArg("-datadir", m_path_root.string());
gArgs.ForceSetArg("-datadir", m_path_root.string());
- ClearDatadirCache();
+ gArgs.ClearPathCache();
{
SetupServerArgs(m_node);
std::string error;
@@ -191,7 +193,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
}
m_node.addrman = std::make_unique<CAddrMan>();
- m_node.banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests.
m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman,
m_node.banman.get(), *m_node.scheduler, *m_node.chainman,
@@ -242,7 +244,8 @@ CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransa
for (const CMutableTransaction& tx : txns) {
block.vtx.push_back(MakeTransactionRef(tx));
}
- RegenerateCommitments(block, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)));
+ CBlockIndex* prev_block = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock));
+ RegenerateCommitments(block, prev_block);
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index a32f1f3805..b19dd75765 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -8,6 +8,7 @@
#include <chainparamsbase.h>
#include <fs.h>
#include <key.h>
+#include <util/system.h>
#include <node/context.h>
#include <pubkey.h>
#include <random.h>
@@ -80,6 +81,7 @@ struct BasicTestingSetup {
~BasicTestingSetup();
const fs::path m_path_root;
+ ArgsManager m_args;
};
/** Testing setup that performs all steps up until right before
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index a1ac9ead69..04b908829b 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -49,24 +49,27 @@ BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(util_datadir)
{
- ClearDatadirCache();
- const fs::path dd_norm = GetDataDir();
+ // Use local args variable instead of m_args to avoid making assumptions about test setup
+ ArgsManager args;
+ args.ForceSetArg("-datadir", m_path_root.string());
- gArgs.ForceSetArg("-datadir", dd_norm.string() + "/");
- ClearDatadirCache();
- BOOST_CHECK_EQUAL(dd_norm, GetDataDir());
+ const fs::path dd_norm = args.GetDataDirPath();
- gArgs.ForceSetArg("-datadir", dd_norm.string() + "/.");
- ClearDatadirCache();
- BOOST_CHECK_EQUAL(dd_norm, GetDataDir());
+ args.ForceSetArg("-datadir", dd_norm.string() + "/");
+ args.ClearPathCache();
+ BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath());
- gArgs.ForceSetArg("-datadir", dd_norm.string() + "/./");
- ClearDatadirCache();
- BOOST_CHECK_EQUAL(dd_norm, GetDataDir());
+ args.ForceSetArg("-datadir", dd_norm.string() + "/.");
+ args.ClearPathCache();
+ BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath());
- gArgs.ForceSetArg("-datadir", dd_norm.string() + "/.//");
- ClearDatadirCache();
- BOOST_CHECK_EQUAL(dd_norm, GetDataDir());
+ args.ForceSetArg("-datadir", dd_norm.string() + "/./");
+ args.ClearPathCache();
+ BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath());
+
+ args.ForceSetArg("-datadir", dd_norm.string() + "/.//");
+ args.ClearPathCache();
+ BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath());
}
BOOST_AUTO_TEST_CASE(util_check)
@@ -1143,21 +1146,23 @@ BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
{
// Test writing setting.
TestArgsManager args1;
+ args1.ForceSetArg("-datadir", m_path_root.string());
args1.LockSettings([&](util::Settings& settings) { settings.rw_settings["name"] = "value"; });
args1.WriteSettingsFile();
// Test reading setting.
TestArgsManager args2;
+ args2.ForceSetArg("-datadir", m_path_root.string());
args2.ReadSettingsFile();
args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); });
// Test error logging, and remove previously written setting.
{
ASSERT_DEBUG_LOG("Failed renaming settings file");
- fs::remove(GetDataDir() / "settings.json");
- fs::create_directory(GetDataDir() / "settings.json");
+ fs::remove(args1.GetDataDirPath() / "settings.json");
+ fs::create_directory(args1.GetDataDirPath() / "settings.json");
args2.WriteSettingsFile();
- fs::remove(GetDataDir() / "settings.json");
+ fs::remove(args1.GetDataDirPath() / "settings.json");
}
}
@@ -1796,7 +1801,7 @@ static constexpr char ExitCommand = 'X';
BOOST_AUTO_TEST_CASE(test_LockDirectory)
{
- fs::path dirname = GetDataDir() / "lock_dir";
+ fs::path dirname = m_args.GetDataDirPath() / "lock_dir";
const std::string lockname = ".lock";
#ifndef WIN32
// Revert SIGCHLD to default, otherwise boost.test will catch and fail on
@@ -1885,7 +1890,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
BOOST_AUTO_TEST_CASE(test_DirIsWritable)
{
// Should be able to write to the data dir.
- fs::path tmpdirname = GetDataDir();
+ fs::path tmpdirname = m_args.GetDataDirPath();
BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true);
// Should not be able to write to a non-existent dir.
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index 05838ec19a..304cd8feb0 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -81,11 +81,9 @@ class VersionBitsTester
TestNeverActiveConditionChecker checker_never[CHECKERS];
// Test counter (to identify failures)
- int num;
+ int num{1000};
public:
- VersionBitsTester() : num(1000) {}
-
VersionBitsTester& Reset() {
// Have each group of tests be counted by the 1000s part, starting at 1000
num = num - (num % 1000) + 1000;
@@ -257,39 +255,6 @@ BOOST_AUTO_TEST_CASE(versionbits_test)
}
}
-BOOST_AUTO_TEST_CASE(versionbits_sanity)
-{
- // Sanity checks of version bit deployments
- const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
- const Consensus::Params &mainnetParams = chainParams->GetConsensus();
- for (int i=0; i<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
- uint32_t bitmask = VersionBitsMask(mainnetParams, static_cast<Consensus::DeploymentPos>(i));
- // Make sure that no deployment tries to set an invalid bit.
- BOOST_CHECK_EQUAL(bitmask & ~(uint32_t)VERSIONBITS_TOP_MASK, bitmask);
-
- // Check min_activation_height is on a retarget boundary
- BOOST_CHECK_EQUAL(mainnetParams.vDeployments[i].min_activation_height % mainnetParams.nMinerConfirmationWindow, 0);
- // Check min_activation_height is 0 for ALWAYS_ACTIVE and never active deployments
- if (mainnetParams.vDeployments[i].nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE || mainnetParams.vDeployments[i].nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) {
- BOOST_CHECK_EQUAL(mainnetParams.vDeployments[i].min_activation_height, 0);
- }
-
- // Verify that the deployment windows of different deployment using the
- // same bit are disjoint.
- // This test may need modification at such time as a new deployment
- // is proposed that reuses the bit of an activated soft fork, before the
- // end time of that soft fork. (Alternatively, the end time of that
- // activated soft fork could be later changed to be earlier to avoid
- // overlap.)
- for (int j=i+1; j<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; j++) {
- if (VersionBitsMask(mainnetParams, static_cast<Consensus::DeploymentPos>(j)) == bitmask) {
- BOOST_CHECK(mainnetParams.vDeployments[j].nStartTime > mainnetParams.vDeployments[i].nTimeout ||
- mainnetParams.vDeployments[i].nStartTime > mainnetParams.vDeployments[j].nTimeout);
- }
- }
- }
-}
-
/** Check that ComputeBlockVersion will set the appropriate bit correctly */
static void check_computeblockversion(const Consensus::Params& params, Consensus::DeploymentPos dep)
{
@@ -305,16 +270,25 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus
BOOST_CHECK_EQUAL(ComputeBlockVersion(nullptr, params), VERSIONBITS_TOP_BITS);
// always/never active deployments shouldn't need to be tested further
- if (nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE) return;
- if (nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) return;
+ if (nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE ||
+ nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE)
+ {
+ BOOST_CHECK_EQUAL(min_activation_height, 0);
+ return;
+ }
BOOST_REQUIRE(nStartTime < nTimeout);
BOOST_REQUIRE(nStartTime >= 0);
BOOST_REQUIRE(nTimeout <= std::numeric_limits<uint32_t>::max() || nTimeout == Consensus::BIP9Deployment::NO_TIMEOUT);
BOOST_REQUIRE(0 <= bit && bit < 32);
+ // Make sure that no deployment tries to set an invalid bit.
BOOST_REQUIRE(((1 << bit) & VERSIONBITS_TOP_MASK) == 0);
BOOST_REQUIRE(min_activation_height >= 0);
- BOOST_REQUIRE_EQUAL(min_activation_height % params.nMinerConfirmationWindow, 0);
+ // Check min_activation_height is on a retarget boundary
+ BOOST_REQUIRE_EQUAL(min_activation_height % params.nMinerConfirmationWindow, 0U);
+
+ const uint32_t bitmask{VersionBitsMask(params, dep)};
+ BOOST_CHECK_EQUAL(bitmask, uint32_t{1} << bit);
// In the first chain, test that the bit is set by CBV until it has failed.
// In the second chain, test the bit is set by CBV while STARTED and
@@ -443,8 +417,18 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// ACTIVE and FAILED states in roughly the way we expect
for (const auto& chain_name : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET, CBaseChainParams::REGTEST}) {
const auto chainParams = CreateChainParams(*m_node.args, chain_name);
+ uint32_t chain_all_vbits{0};
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++i) {
- check_computeblockversion(chainParams->GetConsensus(), static_cast<Consensus::DeploymentPos>(i));
+ const auto dep = static_cast<Consensus::DeploymentPos>(i);
+ // Check that no bits are re-used (within the same chain). This is
+ // disallowed because the transition to FAILED (on timeout) does
+ // not take precedence over STARTED/LOCKED_IN. So all softforks on
+ // the same bit might overlap, even when non-overlapping start-end
+ // times are picked.
+ const uint32_t dep_mask{VersionBitsMask(chainParams->GetConsensus(), dep)};
+ BOOST_CHECK(!(chain_all_vbits & dep_mask));
+ chain_all_vbits |= dep_mask;
+ check_computeblockversion(chainParams->GetConsensus(), dep);
}
}
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 0b83a76504..9b3bd46b38 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -235,6 +235,19 @@ static bool CheckValid(const std::string& key, const util::SettingsValue& val, u
return true;
}
+namespace {
+fs::path StripRedundantLastElementsOfPath(const fs::path& path)
+{
+ auto result = path;
+ while (result.filename().string() == ".") {
+ result = result.parent_path();
+ }
+
+ assert(fs::equivalent(result, path));
+ return result;
+}
+} // namespace
+
// Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to
// #include class definitions for all members.
// For example, m_settings has an internal dependency on univalue.
@@ -375,6 +388,72 @@ std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) co
return std::nullopt;
}
+const fs::path& ArgsManager::GetBlocksDirPath()
+{
+ LOCK(cs_args);
+ fs::path& path = m_cached_blocks_path;
+
+ // Cache the path to avoid calling fs::create_directories on every call of
+ // this function
+ if (!path.empty()) return path;
+
+ if (IsArgSet("-blocksdir")) {
+ path = fs::system_complete(GetArg("-blocksdir", ""));
+ if (!fs::is_directory(path)) {
+ path = "";
+ return path;
+ }
+ } else {
+ path = GetDataDirPath(false);
+ }
+
+ path /= BaseParams().DataDir();
+ path /= "blocks";
+ fs::create_directories(path);
+ path = StripRedundantLastElementsOfPath(path);
+ return path;
+}
+
+const fs::path& ArgsManager::GetDataDirPath(bool net_specific) const
+{
+ LOCK(cs_args);
+ fs::path& path = net_specific ? m_cached_network_datadir_path : m_cached_datadir_path;
+
+ // Cache the path to avoid calling fs::create_directories on every call of
+ // this function
+ if (!path.empty()) return path;
+
+ std::string datadir = GetArg("-datadir", "");
+ if (!datadir.empty()) {
+ path = fs::system_complete(datadir);
+ if (!fs::is_directory(path)) {
+ path = "";
+ return path;
+ }
+ } else {
+ path = GetDefaultDataDir();
+ }
+ if (net_specific)
+ path /= BaseParams().DataDir();
+
+ if (fs::create_directories(path)) {
+ // This is the first run, create wallets subdirectory too
+ fs::create_directories(path / "wallets");
+ }
+
+ path = StripRedundantLastElementsOfPath(path);
+ return path;
+}
+
+void ArgsManager::ClearPathCache()
+{
+ LOCK(cs_args);
+
+ m_cached_datadir_path = fs::path();
+ m_cached_network_datadir_path = fs::path();
+ m_cached_blocks_path = fs::path();
+}
+
std::optional<const ArgsManager::Command> ArgsManager::GetCommand() const
{
Command ret;
@@ -434,7 +513,7 @@ bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const
}
if (filepath) {
std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME);
- *filepath = fsbridge::AbsPathJoin(GetDataDir(/* net_specific= */ true), temp ? settings + ".tmp" : settings);
+ *filepath = fsbridge::AbsPathJoin(GetDataDirPath(/* net_specific= */ true), temp ? settings + ".tmp" : settings);
}
return true;
}
@@ -723,79 +802,9 @@ fs::path GetDefaultDataDir()
#endif
}
-namespace {
-fs::path StripRedundantLastElementsOfPath(const fs::path& path)
-{
- auto result = path;
- while (result.filename().string() == ".") {
- result = result.parent_path();
- }
-
- assert(fs::equivalent(result, path));
- return result;
-}
-} // namespace
-
-static fs::path g_blocks_path_cache_net_specific;
-static fs::path pathCached;
-static fs::path pathCachedNetSpecific;
-static RecursiveMutex csPathCached;
-
-const fs::path &GetBlocksDir()
-{
- LOCK(csPathCached);
- fs::path &path = g_blocks_path_cache_net_specific;
-
- // Cache the path to avoid calling fs::create_directories on every call of
- // this function
- if (!path.empty()) return path;
-
- if (gArgs.IsArgSet("-blocksdir")) {
- path = fs::system_complete(gArgs.GetArg("-blocksdir", ""));
- if (!fs::is_directory(path)) {
- path = "";
- return path;
- }
- } else {
- path = GetDataDir(false);
- }
-
- path /= BaseParams().DataDir();
- path /= "blocks";
- fs::create_directories(path);
- path = StripRedundantLastElementsOfPath(path);
- return path;
-}
-
const fs::path &GetDataDir(bool fNetSpecific)
{
- LOCK(csPathCached);
- fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
-
- // Cache the path to avoid calling fs::create_directories on every call of
- // this function
- if (!path.empty()) return path;
-
- std::string datadir = gArgs.GetArg("-datadir", "");
- if (!datadir.empty()) {
- path = fs::system_complete(datadir);
- if (!fs::is_directory(path)) {
- path = "";
- return path;
- }
- } else {
- path = GetDefaultDataDir();
- }
- if (fNetSpecific)
- path /= BaseParams().DataDir();
-
- if (fs::create_directories(path)) {
- // This is the first run, create wallets subdirectory too
- fs::create_directories(path / "wallets");
- }
-
- path = StripRedundantLastElementsOfPath(path);
- return path;
+ return gArgs.GetDataDirPath(fNetSpecific);
}
bool CheckDataDirOption()
@@ -804,15 +813,6 @@ bool CheckDataDirOption()
return datadir.empty() || fs::is_directory(fs::system_complete(datadir));
}
-void ClearDatadirCache()
-{
- LOCK(csPathCached);
-
- pathCached = fs::path();
- pathCachedNetSpecific = fs::path();
- g_blocks_path_cache_net_specific = fs::path();
-}
-
fs::path GetConfigFile(const std::string& confPath)
{
return AbsPathForConfigVal(fs::path(confPath), false);
@@ -971,7 +971,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
}
// If datadir is changed in .conf file:
- ClearDatadirCache();
+ gArgs.ClearPathCache();
if (!CheckDataDirOption()) {
error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", ""));
return false;
diff --git a/src/util/system.h b/src/util/system.h
index 29657e56e2..61f862c93a 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -91,13 +91,9 @@ void ReleaseDirectoryLocks();
bool TryCreateDirectories(const fs::path& p);
fs::path GetDefaultDataDir();
-// The blocks directory is always net specific.
-const fs::path &GetBlocksDir();
const fs::path &GetDataDir(bool fNetSpecific = true);
// Return true if -datadir option points to a valid directory or is not specified.
bool CheckDataDirOption();
-/** Tests only */
-void ClearDatadirCache();
fs::path GetConfigFile(const std::string& confPath);
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
@@ -200,6 +196,9 @@ protected:
std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
bool m_accept_any_command GUARDED_BY(cs_args){true};
std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
+ fs::path m_cached_blocks_path GUARDED_BY(cs_args);
+ mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args);
+ mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args);
[[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false);
@@ -264,6 +263,27 @@ public:
std::optional<const Command> GetCommand() const;
/**
+ * Get blocks directory path
+ *
+ * @return Blocks path which is network specific
+ */
+ const fs::path& GetBlocksDirPath();
+
+ /**
+ * Get data directory path
+ *
+ * @param net_specific Append network identifier to the returned path
+ * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
+ * @post Returned directory path is created unless it is empty
+ */
+ const fs::path& GetDataDirPath(bool net_specific = true) const;
+
+ /**
+ * Clear cached directory paths
+ */
+ void ClearPathCache();
+
+ /**
* Return a vector of strings of the given argument
*
* @param strArg Argument to get (e.g. "-foo")
diff --git a/src/validation.cpp b/src/validation.cpp
index 332cb581b8..2bf505e26b 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2204,7 +2204,7 @@ bool CChainState::FlushStateToDisk(
// Write blocks and block index to disk.
if (fDoFullFlush || fPeriodicWrite) {
// Depend on nMinDiskSpace to ensure we can write block index
- if (!CheckDiskSpace(GetBlocksDir())) {
+ if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) {
return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
}
{
@@ -3890,12 +3890,12 @@ void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPr
static FlatFileSeq BlockFileSeq()
{
- return FlatFileSeq(GetBlocksDir(), "blk", gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE);
+ return FlatFileSeq(gArgs.GetBlocksDirPath(), "blk", gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE);
}
static FlatFileSeq UndoFileSeq()
{
- return FlatFileSeq(GetBlocksDir(), "rev", UNDOFILE_CHUNK_SIZE);
+ return FlatFileSeq(gArgs.GetBlocksDirPath(), "rev", UNDOFILE_CHUNK_SIZE);
}
FILE* OpenBlockFile(const FlatFilePos &pos, bool fReadOnly) {
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 769987ccf2..653dbdfc1d 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -100,8 +100,8 @@ RPCHelpMan importprivkey()
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key (see dumpprivkey)"},
- {"label", RPCArg::Type::STR, /* default */ "current label if address exists, otherwise \"\"", "An optional label"},
- {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"},
+ {"label", RPCArg::Type::STR, RPCArg::DefaultHint{"current label if address exists, otherwise \"\""}, "An optional label"},
+ {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Rescan the wallet for transactions"},
},
RPCResult{RPCResult::Type::NONE, "", ""},
RPCExamples{
@@ -232,9 +232,9 @@ RPCHelpMan importaddress()
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Bitcoin address (or hex-encoded script)"},
- {"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"},
- {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"},
- {"p2sh", RPCArg::Type::BOOL, /* default */ "false", "Add the P2SH version of the script as well"},
+ {"label", RPCArg::Type::STR, RPCArg::Default{""}, "An optional label"},
+ {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Rescan the wallet for transactions"},
+ {"p2sh", RPCArg::Type::BOOL, RPCArg::Default{false}, "Add the P2SH version of the script as well"},
},
RPCResult{RPCResult::Type::NONE, "", ""},
RPCExamples{
@@ -426,8 +426,8 @@ RPCHelpMan importpubkey()
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"pubkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The hex-encoded public key"},
- {"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"},
- {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"},
+ {"label", RPCArg::Type::STR, RPCArg::Default{""}, "An optional label"},
+ {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Rescan the wallet for transactions"},
},
RPCResult{RPCResult::Type::NONE, "", ""},
RPCExamples{
@@ -1279,28 +1279,28 @@ RPCHelpMan importmulti()
},
{"redeemscript", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Allowed only if the scriptPubKey is a P2SH or P2SH-P2WSH address/scriptPubKey"},
{"witnessscript", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Allowed only if the scriptPubKey is a P2SH-P2WSH or P2WSH address/scriptPubKey"},
- {"pubkeys", RPCArg::Type::ARR, /* default */ "empty array", "Array of strings giving pubkeys to import. They must occur in P2PKH or P2WPKH scripts. They are not required when the private key is also provided (see the \"keys\" argument).",
+ {"pubkeys", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Array of strings giving pubkeys to import. They must occur in P2PKH or P2WPKH scripts. They are not required when the private key is also provided (see the \"keys\" argument).",
{
{"pubKey", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""},
}
},
- {"keys", RPCArg::Type::ARR, /* default */ "empty array", "Array of strings giving private keys to import. The corresponding public keys must occur in the output or redeemscript.",
+ {"keys", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Array of strings giving private keys to import. The corresponding public keys must occur in the output or redeemscript.",
{
{"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""},
}
},
{"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in the form [begin,end]) to import"},
- {"internal", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be treated as not incoming payments (also known as change)"},
- {"watchonly", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be considered watchonly."},
- {"label", RPCArg::Type::STR, /* default */ "''", "Label to assign to the address, only allowed with internal=false"},
- {"keypool", RPCArg::Type::BOOL, /* default */ "false", "Stating whether imported public keys should be added to the keypool for when users request new addresses. Only allowed when wallet private keys are disabled"},
+ {"internal", RPCArg::Type::BOOL, RPCArg::Default{false}, "Stating whether matching outputs should be treated as not incoming payments (also known as change)"},
+ {"watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "Stating whether matching outputs should be considered watchonly."},
+ {"label", RPCArg::Type::STR, RPCArg::Default{""}, "Label to assign to the address, only allowed with internal=false"},
+ {"keypool", RPCArg::Type::BOOL, RPCArg::Default{false}, "Stating whether imported public keys should be added to the keypool for when users request new addresses. Only allowed when wallet private keys are disabled"},
},
},
},
"\"requests\""},
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
{
- {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Stating if should rescan the blockchain after all imports"},
+ {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Stating if should rescan the blockchain after all imports"},
},
"\"options\""},
},
@@ -1591,7 +1591,7 @@ RPCHelpMan importdescriptors()
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
{"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "Descriptor to import."},
- {"active", RPCArg::Type::BOOL, /* default */ "false", "Set this descriptor to be the active descriptor for the corresponding output type/externality"},
+ {"active", RPCArg::Type::BOOL, RPCArg::Default{false}, "Set this descriptor to be the active descriptor for the corresponding output type/externality"},
{"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in the form [begin,end]) to import"},
{"next_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If a ranged descriptor is set to active, this specifies the next index to generate addresses from"},
{"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, "Time from which to start rescanning the blockchain for this descriptor, in " + UNIX_EPOCH_TIME + "\n"
@@ -1601,8 +1601,8 @@ RPCHelpMan importdescriptors()
" of all descriptors being imported will be scanned.",
/* oneline_description */ "", {"timestamp | \"now\"", "integer / string"}
},
- {"internal", RPCArg::Type::BOOL, /* default */ "false", "Whether matching outputs should be treated as not incoming payments (e.g. change)"},
- {"label", RPCArg::Type::STR, /* default */ "''", "Label to assign to the address, only allowed with internal=false"},
+ {"internal", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether matching outputs should be treated as not incoming payments (e.g. change)"},
+ {"label", RPCArg::Type::STR, RPCArg::Default{""}, "Label to assign to the address, only allowed with internal=false"},
},
},
},
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 76460f106b..67d9d56133 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -237,8 +237,8 @@ static RPCHelpMan getnewaddress()
"If 'label' is specified, it is added to the address book \n"
"so payments received with the address will be associated with 'label'.\n",
{
- {"label", RPCArg::Type::STR, /* default */ "\"\"", "The label name for the address to be linked to. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."},
- {"address_type", RPCArg::Type::STR, /* default */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"label", RPCArg::Type::STR, RPCArg::Default{""}, "The label name for the address to be linked to. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."},
+ {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -addresstype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
},
RPCResult{
RPCResult::Type::STR, "address", "The new bitcoin address"
@@ -287,7 +287,7 @@ static RPCHelpMan getrawchangeaddress()
"\nReturns a new Bitcoin address, for receiving change.\n"
"This is for use with raw transactions, NOT normal use.\n",
{
- {"address_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
},
RPCResult{
RPCResult::Type::STR, "address", "The address"
@@ -439,16 +439,16 @@ static RPCHelpMan sendtoaddress()
{"comment_to", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment to store the name of the person or organization\n"
"to which you're sending the transaction. This is not part of the \n"
"transaction, just kept in your wallet."},
- {"subtractfeefromamount", RPCArg::Type::BOOL, /* default */ "false", "The fee will be deducted from the amount being sent.\n"
+ {"subtractfeefromamount", RPCArg::Type::BOOL, RPCArg::Default{false}, "The fee will be deducted from the amount being sent.\n"
"The recipient will receive less bitcoins than you enter in the amount field."},
- {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
- {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
+ {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
" \"" + FeeModes("\"\n\"") + "\""},
- {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
+ {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{true}, "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
"dirty if they have previously been used in a transaction."},
- {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
- {"verbose", RPCArg::Type::BOOL, /* default */ "false", "If true, return extra information about the transaction."},
+ {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
+ {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra information about the transaction."},
},
{
RPCResult{"if verbose is not set or set to false",
@@ -697,7 +697,7 @@ static RPCHelpMan getreceivedbyaddress()
"\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for transactions."},
- {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only include transactions confirmed at least this many times."},
+ {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "Only include transactions confirmed at least this many times."},
},
RPCResult{
RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received at this address."
@@ -735,7 +735,7 @@ static RPCHelpMan getreceivedbylabel()
"\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n",
{
{"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The selected label, may be the default label using \"\"."},
- {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only include transactions confirmed at least this many times."},
+ {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "Only include transactions confirmed at least this many times."},
},
RPCResult{
RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this label."
@@ -775,9 +775,9 @@ static RPCHelpMan getbalance()
"thus affected by options which limit spendability such as -spendzeroconfchange.\n",
{
{"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Remains for backward compatibility. Must be excluded or set to \"*\"."},
- {"minconf", RPCArg::Type::NUM, /* default */ "0", "Only include transactions confirmed at least this many times."},
- {"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."},
+ {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "Only include transactions confirmed at least this many times."},
+ {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also include balance in watch-only addresses (see 'importaddress')"},
+ {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::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."},
},
RPCResult{
RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this wallet."
@@ -868,12 +868,12 @@ static RPCHelpMan sendmany()
{"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Subtract fee from this address"},
},
},
- {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
- {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
+ {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
" \"" + FeeModes("\"\n\"") + "\""},
- {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
- {"verbose", RPCArg::Type::BOOL, /* default */ "false", "If true, return extra infomration about the transaction."},
+ {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
+ {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra infomration about the transaction."},
},
{
RPCResult{"if verbose is not set or set to false",
@@ -956,7 +956,7 @@ static RPCHelpMan addmultisigaddress()
},
},
{"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A label to assign the addresses to."},
- {"address_type", RPCArg::Type::STR, /* default */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -addresstype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -1185,9 +1185,9 @@ static RPCHelpMan listreceivedbyaddress()
return RPCHelpMan{"listreceivedbyaddress",
"\nList balances by receiving address.\n",
{
- {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."},
- {"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include addresses that haven't received any payments."},
- {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses (see 'importaddress')"},
+ {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
+ {"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include addresses that haven't received any payments."},
+ {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see 'importaddress')"},
{"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If present, only return information on this address."},
},
RPCResult{
@@ -1234,9 +1234,9 @@ static RPCHelpMan listreceivedbylabel()
return RPCHelpMan{"listreceivedbylabel",
"\nList received transactions by label.\n",
{
- {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."},
- {"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include labels that haven't received any payments."},
- {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses (see 'importaddress')"},
+ {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
+ {"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include labels that haven't received any payments."},
+ {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see 'importaddress')"},
},
RPCResult{
RPCResult::Type::ARR, "", "",
@@ -1396,9 +1396,9 @@ static RPCHelpMan listtransactions()
{
{"label|dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, should be a valid label name to return only incoming transactions\n"
"with the specified label, or \"*\" to disable filtering and return all transactions."},
- {"count", RPCArg::Type::NUM, /* default */ "10", "The number of transactions to return"},
- {"skip", RPCArg::Type::NUM, /* default */ "0", "The number of transactions to skip"},
- {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Include transactions to watch-only addresses (see 'importaddress')"},
+ {"count", RPCArg::Type::NUM, RPCArg::Default{10}, "The number of transactions to return"},
+ {"skip", RPCArg::Type::NUM, RPCArg::Default{0}, "The number of transactions to skip"},
+ {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"},
},
RPCResult{
RPCResult::Type::ARR, "", "",
@@ -1507,9 +1507,9 @@ static RPCHelpMan listsinceblock()
"Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n",
{
{"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, the block hash to list transactions since, otherwise list all transactions."},
- {"target_confirmations", RPCArg::Type::NUM, /* default */ "1", "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
- {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Include transactions to watch-only addresses (see 'importaddress')"},
- {"include_removed", RPCArg::Type::BOOL, /* default */ "true", "Show transactions that were removed due to a reorg in the \"removed\" array\n"
+ {"target_confirmations", RPCArg::Type::NUM, RPCArg::Default{1}, "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
+ {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"},
+ {"include_removed", RPCArg::Type::BOOL, RPCArg::Default{true}, "Show transactions that were removed due to a reorg in the \"removed\" array\n"
"(not guaranteed to work on pruned nodes)"},
},
RPCResult{
@@ -1645,9 +1645,9 @@ static RPCHelpMan gettransaction()
"\nGet detailed information about in-wallet transaction <txid>\n",
{
{"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
- {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false",
+ {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"},
"Whether to include watch-only addresses in balance calculation and details[]"},
- {"verbose", RPCArg::Type::BOOL, /* default */ "false",
+ {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
"Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)"},
},
RPCResult{
@@ -1832,7 +1832,7 @@ static RPCHelpMan keypoolrefill()
"\nFills the keypool."+
HELP_REQUIRING_PASSPHRASE,
{
- {"newsize", RPCArg::Type::NUM, /* default */ "100", "The new keypool size"},
+ {"newsize", RPCArg::Type::NUM, RPCArg::Default{100}, "The new keypool size"},
},
RPCResult{RPCResult::Type::NONE, "", ""},
RPCExamples{
@@ -2124,7 +2124,7 @@ static RPCHelpMan lockunspent()
"Also see the listunspent call\n",
{
{"unlock", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Whether to unlock (true) or lock (false) the specified transactions"},
- {"transactions", RPCArg::Type::ARR, /* default */ "empty array", "The transaction outputs and within each, the txid (string) vout (numeric).",
+ {"transactions", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The transaction outputs and within each, the txid (string) vout (numeric).",
{
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
@@ -2567,7 +2567,7 @@ static RPCHelpMan loadwallet()
"\napplied to the new wallet (eg -rescan, etc).\n",
{
{"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."},
- {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
+ {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Default{UniValue::VNULL}, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -2630,7 +2630,7 @@ static RPCHelpMan setwalletflag()
"\nChange the state of the given wallet flag for a wallet.\n",
{
{"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
- {"value", RPCArg::Type::BOOL, /* default */ "true", "The new state."},
+ {"value", RPCArg::Type::BOOL, RPCArg::Default{true}, "The new state."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -2693,13 +2693,13 @@ static RPCHelpMan createwallet()
"\nCreates and loads a new wallet.\n",
{
{"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."},
- {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
- {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
+ {"disable_private_keys", RPCArg::Type::BOOL, RPCArg::Default{false}, "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
+ {"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
- {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "false", "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
- {"descriptors", RPCArg::Type::BOOL, /* default */ "false", "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation"},
- {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
- {"external_signer", RPCArg::Type::BOOL, /* default */ "false", "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."},
+ {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{false}, "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
+ {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation"},
+ {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Default{UniValue::VNULL}, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
+ {"external_signer", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -2788,8 +2788,8 @@ static RPCHelpMan unloadwallet()
"Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n"
"Specifying the wallet name on a wallet endpoint is invalid.",
{
- {"wallet_name", RPCArg::Type::STR, /* default */ "the wallet name from the RPC endpoint", "The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."},
- {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
+ {"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."},
+ {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Default{UniValue::VNULL}, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
},
RPCResult{RPCResult::Type::OBJ, "", "", {
{RPCResult::Type::STR, "warning", "Warning message if wallet was not unloaded cleanly."},
@@ -2840,21 +2840,21 @@ static RPCHelpMan listunspent()
"with between minconf and maxconf (inclusive) confirmations.\n"
"Optionally filter to only include txouts paid to specified addresses.\n",
{
- {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum confirmations to filter"},
- {"maxconf", RPCArg::Type::NUM, /* default */ "9999999", "The maximum confirmations to filter"},
- {"addresses", RPCArg::Type::ARR, /* default */ "empty array", "The bitcoin addresses to filter",
+ {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum confirmations to filter"},
+ {"maxconf", RPCArg::Type::NUM, RPCArg::Default{9999999}, "The maximum confirmations to filter"},
+ {"addresses", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The bitcoin addresses to filter",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address"},
},
},
- {"include_unsafe", RPCArg::Type::BOOL, /* default */ "true", "Include outputs that are not safe to spend\n"
+ {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include outputs that are not safe to spend\n"
"See description of \"safe\" attribute below."},
{"query_options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "JSON with query options",
{
- {"minimumAmount", RPCArg::Type::AMOUNT, /* default */ "0", "Minimum value of each UTXO in " + CURRENCY_UNIT + ""},
- {"maximumAmount", RPCArg::Type::AMOUNT, /* default */ "unlimited", "Maximum value of each UTXO in " + CURRENCY_UNIT + ""},
- {"maximumCount", RPCArg::Type::NUM, /* default */ "unlimited", "Maximum number of UTXOs"},
- {"minimumSumAmount", RPCArg::Type::AMOUNT, /* default */ "unlimited", "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""},
+ {"minimumAmount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(0)}, "Minimum value of each UTXO in " + CURRENCY_UNIT + ""},
+ {"maximumAmount", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"unlimited"}, "Maximum value of each UTXO in " + CURRENCY_UNIT + ""},
+ {"maximumCount", RPCArg::Type::NUM, RPCArg::DefaultHint{"unlimited"}, "Maximum number of UTXOs"},
+ {"minimumSumAmount", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"unlimited"}, "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""},
},
"query_options"},
},
@@ -3204,17 +3204,17 @@ static RPCHelpMan fundrawtransaction()
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
{
- {"add_inputs", RPCArg::Type::BOOL, /* default */ "true", "For a transaction with existing inputs, automatically include more if they are not enough."},
- {"changeAddress", RPCArg::Type::STR, /* default */ "pool address", "The bitcoin address to receive the change"},
- {"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
- {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
- {"includeWatching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only.\n"
+ {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."},
+ {"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
+ {"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
+ {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
"e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
- {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
- {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
- {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
- {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "The integers.\n"
+ {"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
+ {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
+ {"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
+ {"subtractFeeFromOutputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The integers.\n"
"The fee will be equally deducted from the amount of each specified output.\n"
"Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
"If no outputs are specified here, the sender pays the fee.",
@@ -3222,14 +3222,14 @@ static RPCHelpMan fundrawtransaction()
{"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
},
},
- {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
+ {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n"
"Allows this transaction to be replaced by a transaction with higher fees"},
- {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
" \"" + FeeModes("\"\n\"") + "\""},
},
"options"},
- {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
+ {"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n"
"If iswitness is not present, heuristic tests will be used in decoding.\n"
"If true, only witness deserialization will be tried.\n"
"If false, only non-witness deserialization will be tried.\n"
@@ -3310,7 +3310,7 @@ RPCHelpMan signrawtransactionwithwallet()
},
},
},
- {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type. Must be one of\n"
+ {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"ALL"}, "The signature hash type. Must be one of\n"
" \"ALL\"\n"
" \"NONE\"\n"
" \"SINGLE\"\n"
@@ -3402,19 +3402,19 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"},
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
{
- {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks\n"},
- {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation",
+ {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks\n"},
+ {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"},
"\nSpecify a fee rate in " + CURRENCY_ATOM + "/vB instead of relying on the built-in fee estimator.\n"
"Must be at least " + incremental_fee + " higher than the current transaction fee rate.\n"
"WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB.\n"},
- {"replaceable", RPCArg::Type::BOOL, /* default */ "true", "Whether the new transaction should still be\n"
+ {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether the new transaction should still be\n"
"marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n"
"be left unchanged from the original. If false, any input sequence numbers in the\n"
"original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
"so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
"still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
"are replaceable).\n"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
"\"" + FeeModes("\"\n\"") + "\""},
},
"options"},
@@ -3564,7 +3564,7 @@ static RPCHelpMan rescanblockchain()
"\nRescan the local blockchain for wallet related transactions.\n"
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
- {"start_height", RPCArg::Type::NUM, /* default */ "0", "block height where the rescan should start"},
+ {"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "block height where the rescan should start"},
{"stop_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "the last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call."},
},
RPCResult{
@@ -4023,35 +4023,35 @@ static RPCHelpMan send()
},
},
},
- {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
" \"" + FeeModes("\"\n\"") + "\""},
- {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
+ {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
{
- {"add_inputs", RPCArg::Type::BOOL, /* default */ "false", "If inputs are specified, automatically include more if they are not enough."},
- {"add_to_wallet", RPCArg::Type::BOOL, /* default */ "true", "When false, returns a serialized transaction which will not be added to the wallet or broadcast"},
- {"change_address", RPCArg::Type::STR_HEX, /* default */ "pool address", "The bitcoin address to receive the change"},
- {"change_position", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
- {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
- {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."},
+ {"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns a serialized transaction which will not be added to the wallet or broadcast"},
+ {"change_address", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
+ {"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
+ {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
" \"" + FeeModes("\"\n\"") + "\""},
- {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
- {"include_watching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only.\n"
+ {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
+ {"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
"e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
- {"inputs", RPCArg::Type::ARR, /* default */ "empty array", "Specify inputs instead of adding them automatically. A JSON array of JSON objects",
+ {"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Specify inputs instead of adding them automatically. A JSON array of JSON objects",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
{"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
{"sequence", RPCArg::Type::NUM, RPCArg::Optional::NO, "The sequence number"},
},
},
- {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
- {"lock_unspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
- {"psbt", RPCArg::Type::BOOL, /* default */ "automatic", "Always return a PSBT, implies add_to_wallet=false."},
- {"subtract_fee_from_outputs", RPCArg::Type::ARR, /* default */ "empty array", "Outputs to subtract the fee from, specified as integer indices.\n"
+ {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
+ {"lock_unspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
+ {"psbt", RPCArg::Type::BOOL, RPCArg::DefaultHint{"automatic"}, "Always return a PSBT, implies add_to_wallet=false."},
+ {"subtract_fee_from_outputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Outputs to subtract the fee from, specified as integer indices.\n"
"The fee will be equally deducted from the amount of each specified output.\n"
"Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
"If no outputs are specified here, the sender pays the fee.",
@@ -4059,7 +4059,7 @@ static RPCHelpMan send()
{"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
},
},
- {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
+ {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n"
"Allows this transaction to be replaced by a transaction with higher fees"},
},
"options"},
@@ -4207,11 +4207,11 @@ static RPCHelpMan sethdseed()
"\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." +
HELP_REQUIRING_PASSPHRASE,
{
- {"newkeypool", RPCArg::Type::BOOL, /* default */ "true", "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
+ {"newkeypool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
"If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
"If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
"keypool will be used until it has been depleted."},
- {"seed", RPCArg::Type::STR, /* default */ "random seed", "The WIF private key to use as the new HD seed.\n"
+ {"seed", RPCArg::Type::STR, RPCArg::DefaultHint{"random seed"}, "The WIF private key to use as the new HD seed.\n"
"The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"},
},
RPCResult{RPCResult::Type::NONE, "", ""},
@@ -4278,15 +4278,15 @@ static RPCHelpMan walletprocesspsbt()
HELP_REQUIRING_PASSPHRASE,
{
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction base64 string"},
- {"sign", RPCArg::Type::BOOL, /* default */ "true", "Also sign the transaction when updating"},
- {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type to sign with if not specified by the PSBT. Must be one of\n"
+ {"sign", RPCArg::Type::BOOL, RPCArg::Default{true}, "Also sign the transaction when updating"},
+ {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"ALL"}, "The signature hash type to sign with if not specified by the PSBT. Must be one of\n"
" \"ALL\"\n"
" \"NONE\"\n"
" \"SINGLE\"\n"
" \"ALL|ANYONECANPAY\"\n"
" \"NONE|ANYONECANPAY\"\n"
" \"SINGLE|ANYONECANPAY\""},
- {"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"},
+ {"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -4347,7 +4347,7 @@ static RPCHelpMan walletcreatefundedpsbt()
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
{"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
- {"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'locktime' and 'options.replaceable' arguments", "The sequence number"},
+ {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'locktime' and 'options.replaceable' arguments"}, "The sequence number"},
},
},
},
@@ -4369,18 +4369,18 @@ static RPCHelpMan walletcreatefundedpsbt()
},
},
},
- {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
+ {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
{
- {"add_inputs", RPCArg::Type::BOOL, /* default */ "false", "If inputs are specified, automatically include more if they are not enough."},
- {"changeAddress", RPCArg::Type::STR_HEX, /* default */ "pool address", "The bitcoin address to receive the change"},
- {"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
- {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
- {"includeWatching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only"},
- {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
- {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
- {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
- {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "The outputs to subtract the fee from.\n"
+ {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."},
+ {"changeAddress", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
+ {"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
+ {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only"},
+ {"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
+ {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
+ {"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
+ {"subtractFeeFromOutputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The outputs to subtract the fee from.\n"
"The fee will be equally deducted from the amount of each specified output.\n"
"Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
"If no outputs are specified here, the sender pays the fee.",
@@ -4388,14 +4388,14 @@ static RPCHelpMan walletcreatefundedpsbt()
{"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
},
},
- {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
+ {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n"
"Allows this transaction to be replaced by a transaction with higher fees"},
- {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
" \"" + FeeModes("\"\n\"") + "\""},
},
"options"},
- {"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"},
+ {"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -4468,7 +4468,7 @@ static RPCHelpMan upgradewallet()
"\nUpgrade the wallet. Upgrades to the latest version if no version number is specified.\n"
"New keys may be generated and a new wallet backup will need to be made.",
{
- {"version", RPCArg::Type::NUM, /* default */ strprintf("%d", FEATURE_LATEST), "The version number to upgrade to. Default is the latest wallet version."}
+ {"version", RPCArg::Type::NUM, RPCArg::Default{FEATURE_LATEST}, "The version number to upgrade to. Default is the latest wallet version."}
},
RPCResult{
RPCResult::Type::OBJ, "", "",
diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py
index 46ba18b9b5..8fa3f52de8 100755
--- a/test/functional/feature_csv_activation.py
+++ b/test/functional/feature_csv_activation.py
@@ -9,8 +9,8 @@ BIP 68 - nSequence relative lock times
BIP 112 - CHECKSEQUENCEVERIFY
BIP 113 - MedianTimePast semantics for nLockTime
-mine 82 blocks whose coinbases will be used to generate inputs for our tests
-mine 345 blocks and seed block chain with the 82 inputs will use for our tests at height 427
+mine 83 blocks whose coinbases will be used to generate inputs for our tests
+mine 344 blocks and seed block chain with the 83 inputs used for our tests at height 427
mine 2 blocks and verify soft fork not yet activated
mine 1 block and test that soft fork is activated (rules enforced for next block)
Test BIP 113 is enforced
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index 821409ccc1..ac53a280b4 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -410,6 +410,9 @@ class BlockchainTest(BitcoinTestFramework):
self.log.info("Test that getblock with verbosity 2 still works with pruned Undo data")
datadir = get_datadir_path(self.options.tmpdir, 0)
+ self.log.info("Test that getblock with invalid verbosity type returns proper error message")
+ assert_raises_rpc_error(-1, "JSON value is not an integer as expected", node.getblock, blockhash, "2")
+
def move_block_file(old, new):
old_path = os.path.join(datadir, self.chain, 'blocks', old)
new_path = os.path.join(datadir, self.chain, 'blocks', new)
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index dc6f8ed9c4..46eecae611 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -95,6 +95,8 @@ class WalletTest(BitcoinTestFramework):
# but invisible if you include mempool
txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False)
assert_equal(txout['value'], 50)
+ txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index) # by default include_mempool=True
+ assert txout is None
txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True)
assert txout is None
# new utxo from mempool should be invisible if you exclude mempool