Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ci/dash/lint-tidy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ iwyu_tool.py \
"src/random.cpp" \
"src/rpc/fees.cpp" \
"src/rpc/signmessage.cpp" \
"src/test/fuzz/string.cpp" \
"src/test/fuzz/txorphan.cpp" \
"src/util/bip32.cpp" \
"src/util/bytevectorhash.cpp" \
Expand Down
8 changes: 6 additions & 2 deletions doc/REST-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,15 @@ Returns various information about the transaction mempool.
Only supports JSON as output format.
Refer to the `getmempoolinfo` RPC help for details.

`GET /rest/mempool/contents.json`
`GET /rest/mempool/contents.json?verbose=<true|false>&mempool_sequence=<false|true>`

Returns the transactions in the mempool.
Only supports JSON as output format.
Refer to the `getrawmempool` RPC help for details.
Refer to the `getrawmempool` RPC help for details. Defaults to setting
`verbose=true` and `mempool_sequence=false`.

*Query parameters for `verbose` and `mempool_sequence` available in 25.0 and up.*

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 Nitpick: Remove Bitcoin Core release number from Dash REST docs

This note was copied from the Bitcoin Core backport and says the new verbose and mempool_sequence query parameters are available in 25.0 and up. This is Dash Core documentation, and this PR is based on a Dash tree reporting version 23.1.5 in configure.ac, so the Bitcoin Core release number is misleading for Dash users trying to determine which Dash release contains /rest/mempool/contents.json?verbose=...&mempool_sequence=.... Adapt the sentence to the Dash release that will ship this backport, or remove the version-specific sentence.

source: ['codex']



Risks
-------------
Expand Down
4 changes: 2 additions & 2 deletions doc/developer-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ code.
- Align pointers and references to the left i.e. use `type& var` and not `type &var`.
- Use a named cast or functional cast, not a C-Style cast. When casting
between integer types, use functional casts such as `int(x)` or `int{x}`
instead of `(int) x`. When casting between more complex types, use static_cast.
Use reinterpret_cast and const_cast as appropriate.
instead of `(int) x`. When casting between more complex types, use `static_cast`.
Use `reinterpret_cast` and `const_cast` as appropriate.
- Prefer [`list initialization ({})`](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-list) where possible.
For example `int x{0};` instead of `int x = 0;` or `int x(0);`

Expand Down
9 changes: 5 additions & 4 deletions src/.clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ misc-unused-using-decls,
modernize-use-default-member-init,
modernize-use-emplace,
modernize-use-nullptr,
performance-for-range-copy,
performance-move-const-arg,
performance-no-automatic-move,
performance-unnecessary-copy-initialization,
performance-*,
-performance-inefficient-string-concatenation,
-performance-no-int-to-ptr,
-performance-noexcept-move-constructor,
-performance-unnecessary-value-param,
readability-const-return-type,
readability-redundant-declaration,
readability-redundant-string-init,
Expand Down
4 changes: 1 addition & 3 deletions src/bench/lockedpool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ static void BenchLockedPool(benchmark::Bench& bench)
const size_t synth_size = 1024*1024;
Arena b(synth_base, synth_size, 16);

std::vector<void*> addr;
for (int x=0; x<ASIZE; ++x)
addr.push_back(nullptr);
std::vector<void*> addr{ASIZE, nullptr};
uint32_t s = 0x12345678;
bench.run([&] {
int idx = s & (addr.size() - 1);
Expand Down
1 change: 1 addition & 0 deletions src/bitcoin-cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,7 @@ static void ParseGetInfoResult(UniValue& result)
}

std::vector<std::string> formatted_proxies;
formatted_proxies.reserve(ordered_proxies.size());
for (const std::string& proxy : ordered_proxies) {
formatted_proxies.emplace_back(strprintf("%s (%s)", proxy, Join(proxy_networks.find(proxy)->second, ", ")));
}
Expand Down
1 change: 1 addition & 0 deletions src/bitcoin-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ static int Grind(const std::vector<std::string>& args, std::string& strPrint)

std::vector<std::thread> threads;
int n_tasks = std::max(1u, std::thread::hardware_concurrency());
threads.reserve(n_tasks);
for (int i = 0; i < n_tasks; ++i) {
threads.emplace_back(grind_task, nBits, header, i, n_tasks, std::ref(found), std::ref(proposed_nonce));
}
Expand Down
3 changes: 3 additions & 0 deletions src/httpserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,9 @@ std::optional<std::string> HTTPRequest::GetQueryParameter(const std::string& key
std::optional<std::string> GetQueryParameterFromUri(const char* uri, const std::string& key)
{
evhttp_uri* uri_parsed{evhttp_uri_parse(uri)};
if (!uri_parsed) {
throw std::runtime_error("URI parsing failed, it likely contained RFC 3986 invalid characters");
}
const char* query{evhttp_uri_get_query(uri_parsed)};
std::optional<std::string> result;

Expand Down
1 change: 1 addition & 0 deletions src/node/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,7 @@ class NodeImpl : public Node
if (command == "") return {};
ExternalSigner::Enumerate(command, signers, Params().NetworkIDString());
std::vector<std::unique_ptr<interfaces::ExternalSigner>> result;
result.reserve(signers.size());
for (auto& signer : signers) {
result.emplace_back(std::make_unique<ExternalSignerImpl>(std::move(signer)));
}
Expand Down
4 changes: 2 additions & 2 deletions src/qt/trafficgraphwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ void TrafficGraphWidget::paintEvent(QPaintEvent *)
painter.drawLine(XMARGIN, YMARGIN + h, width() - XMARGIN, YMARGIN + h);

// decide what order of magnitude we are
int base = floor(log10(fMax));
float val = pow(10.0f, base);
int base = std::floor(std::log10(fMax));
float val = std::pow(10.0f, base);
float val2 = val;

const QString units = tr("kB/s");
Expand Down
37 changes: 34 additions & 3 deletions src/rest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,11 @@ static bool rest_headers(const CoreContext& context,
} else if (path.size() == 1) {
// new path with query parameter: /rest/headers/<hash>?count=<count>
hashStr = path[0];
raw_count = req->GetQueryParameter("count").value_or("5");
try {
raw_count = req->GetQueryParameter("count").value_or("5");
} catch (const std::runtime_error& e) {
return RESTERR(req, HTTP_BAD_REQUEST, e.what());
}
} else {
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/headers/<hash>.<ext>?count=<count>");
}
Expand Down Expand Up @@ -403,7 +407,11 @@ static bool rest_filter_header(const CoreContext& context, HTTPRequest* req, con
} else if (uri_parts.size() == 2) {
// new path with query parameter: /rest/blockfilterheaders/<filtertype>/<blockhash>?count=<count>
raw_blockhash = uri_parts[1];
raw_count = req->GetQueryParameter("count").value_or("5");
try {
raw_count = req->GetQueryParameter("count").value_or("5");
} catch (const std::runtime_error& e) {
return RESTERR(req, HTTP_BAD_REQUEST, e.what());
}
} else {
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<blockhash>.<ext>?count=<count>");
}
Expand Down Expand Up @@ -645,7 +653,30 @@ static bool rest_mempool(const CoreContext& context, HTTPRequest* req, const std

std::string str_json;
if (param == "contents") {
str_json = MempoolToJSON(*mempool, llmq_ctx->isman.get(), true).write() + "\n";
std::string raw_verbose;
try {
raw_verbose = req->GetQueryParameter("verbose").value_or("true");
} catch (const std::runtime_error& e) {
return RESTERR(req, HTTP_BAD_REQUEST, e.what());
}
if (raw_verbose != "true" && raw_verbose != "false") {
return RESTERR(req, HTTP_BAD_REQUEST, "The \"verbose\" query parameter must be either \"true\" or \"false\".");
}
std::string raw_mempool_sequence;
try {
raw_mempool_sequence = req->GetQueryParameter("mempool_sequence").value_or("false");
} catch (const std::runtime_error& e) {
return RESTERR(req, HTTP_BAD_REQUEST, e.what());
}
if (raw_mempool_sequence != "true" && raw_mempool_sequence != "false") {
return RESTERR(req, HTTP_BAD_REQUEST, "The \"mempool_sequence\" query parameter must be either \"true\" or \"false\".");
}
const bool verbose{raw_verbose == "true"};
const bool mempool_sequence{raw_mempool_sequence == "true"};
if (verbose && mempool_sequence) {
return RESTERR(req, HTTP_BAD_REQUEST, "Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")");
}
str_json = MempoolToJSON(*mempool, llmq_ctx->isman.get(), verbose, mempool_sequence).write() + "\n";
} else {
str_json = MempoolInfoToJSON(*mempool, *llmq_ctx->isman).write() + "\n";
}
Expand Down
2 changes: 2 additions & 0 deletions src/rpc/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
std::string category;
std::set<intptr_t> setDone;
std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
vCommands.reserve(mapCommands.size());

for (const auto& entry : mapCommands)
vCommands.emplace_back(entry.second.front()->category + entry.first, entry.second.front());
Expand Down Expand Up @@ -540,6 +541,7 @@ static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& req
std::vector<std::string> CRPCTable::listCommands() const
{
std::vector<std::string> commandList;
commandList.reserve(mapCommands.size());
for (const auto& i : mapCommands) commandList.emplace_back(i.first);
return commandList;
}
Expand Down
5 changes: 3 additions & 2 deletions src/rpc/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ bool RPCHelpMan::IsValidNumArgs(size_t num_args) const
std::vector<std::string> RPCHelpMan::GetArgNames() const
{
std::vector<std::string> ret;
ret.reserve(m_args.size());
for (const auto& arg : m_args) {
ret.emplace_back(arg.m_names);
}
Expand Down Expand Up @@ -671,12 +672,12 @@ UniValue RPCHelpMan::GetArgMap() const

std::string RPCArg::GetFirstName() const
{
return m_names.substr(0, m_names.find("|"));
return m_names.substr(0, m_names.find('|'));
}

std::string RPCArg::GetName() const
{
CHECK_NONFATAL(std::string::npos == m_names.find("|"));
CHECK_NONFATAL(std::string::npos == m_names.find('|'));
return m_names;
}

Expand Down
1 change: 1 addition & 0 deletions src/test/allocator_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ BOOST_AUTO_TEST_CASE(arena_tests)
b.walk();
#endif
// Sweeping allocate all memory
addr.reserve(2048);
for (int x=0; x<1024; ++x)
addr.push_back(b.alloc(1024));
BOOST_CHECK(b.stats().free == 0);
Expand Down
158 changes: 4 additions & 154 deletions src/test/fuzz/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
#include <blockfilter.h>
#include <clientversion.h>
#include <common/url.h>
#include <logging.h>
#include <netaddress.h>
#include <netbase.h>
#include <rpc/client.h>
#include <rpc/request.h>
Expand All @@ -26,107 +24,16 @@
#include <util/string.h>
#include <util/system.h>
#include <util/translation.h>
#include <version.h>

#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <ios>
#include <stdexcept>
#include <string>
#include <vector>

namespace {
bool LegacyParsePrechecks(const std::string& str)
{
if (str.empty()) // No empty string allowed
return false;
if (str.size() >= 1 && (IsSpace(str[0]) || IsSpace(str[str.size() - 1]))) // No padding allowed
return false;
if (!ContainsNoNUL(str)) // No embedded NUL characters allowed
return false;
return true;
}

bool LegacyParseInt32(const std::string& str, int32_t* out)
{
if (!LegacyParsePrechecks(str))
return false;
char* endp = nullptr;
errno = 0; // strtol will not set errno if valid
long int n = strtol(str.c_str(), &endp, 10);
if (out) *out = (int32_t)n;
// Note that strtol returns a *long int*, so even if strtol doesn't report an over/underflow
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
// platforms the size of these types may be different.
return endp && *endp == 0 && !errno &&
n >= std::numeric_limits<int32_t>::min() &&
n <= std::numeric_limits<int32_t>::max();
}

bool LegacyParseInt64(const std::string& str, int64_t* out)
{
if (!LegacyParsePrechecks(str))
return false;
char* endp = nullptr;
errno = 0; // strtoll will not set errno if valid
long long int n = strtoll(str.c_str(), &endp, 10);
if (out) *out = (int64_t)n;
// Note that strtoll returns a *long long int*, so even if strtol doesn't report an over/underflow
// we still have to check that the returned value is within the range of an *int64_t*.
return endp && *endp == 0 && !errno &&
n >= std::numeric_limits<int64_t>::min() &&
n <= std::numeric_limits<int64_t>::max();
}

bool LegacyParseUInt32(const std::string& str, uint32_t* out)
{
if (!LegacyParsePrechecks(str))
return false;
if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoul accepts these by default if they fit in the range
return false;
char* endp = nullptr;
errno = 0; // strtoul will not set errno if valid
unsigned long int n = strtoul(str.c_str(), &endp, 10);
if (out) *out = (uint32_t)n;
// Note that strtoul returns a *unsigned long int*, so even if it doesn't report an over/underflow
// we still have to check that the returned value is within the range of an *uint32_t*. On 64-bit
// platforms the size of these types may be different.
return endp && *endp == 0 && !errno &&
n <= std::numeric_limits<uint32_t>::max();
}

bool LegacyParseUInt8(const std::string& str, uint8_t* out)
{
uint32_t u32;
if (!LegacyParseUInt32(str, &u32) || u32 > std::numeric_limits<uint8_t>::max()) {
return false;
}
if (out != nullptr) {
*out = static_cast<uint8_t>(u32);
}
return true;
}

bool LegacyParseUInt64(const std::string& str, uint64_t* out)
{
if (!LegacyParsePrechecks(str))
return false;
if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoull accepts these by default if they fit in the range
return false;
char* endp = nullptr;
errno = 0; // strtoull will not set errno if valid
unsigned long long int n = strtoull(str.c_str(), &endp, 10);
if (out) *out = (uint64_t)n;
// Note that strtoull returns a *unsigned long long int*, so even if it doesn't report an over/underflow
// we still have to check that the returned value is within the range of an *uint64_t*.
return endp && *endp == 0 && !errno &&
n <= std::numeric_limits<uint64_t>::max();
}

// For backwards compatibility checking.
int64_t atoi64_legacy(const std::string& str)
{
return strtoll(str.c_str(), nullptr, 10);
}
}; // namespace
enum class FeeEstimateMode;

FUZZ_TARGET(string)
{
Expand Down Expand Up @@ -229,61 +136,4 @@ FUZZ_TARGET(string)
const bilingual_str bs2{random_string_2, random_string_1};
(void)(bs1 + bs2);
}
{
int32_t i32;
int64_t i64;
uint32_t u32;
uint64_t u64;
uint8_t u8;
const bool ok_i32 = ParseInt32(random_string_1, &i32);
const bool ok_i64 = ParseInt64(random_string_1, &i64);
const bool ok_u32 = ParseUInt32(random_string_1, &u32);
const bool ok_u64 = ParseUInt64(random_string_1, &u64);
const bool ok_u8 = ParseUInt8(random_string_1, &u8);

int32_t i32_legacy;
int64_t i64_legacy;
uint32_t u32_legacy;
uint64_t u64_legacy;
uint8_t u8_legacy;
const bool ok_i32_legacy = LegacyParseInt32(random_string_1, &i32_legacy);
const bool ok_i64_legacy = LegacyParseInt64(random_string_1, &i64_legacy);
const bool ok_u32_legacy = LegacyParseUInt32(random_string_1, &u32_legacy);
const bool ok_u64_legacy = LegacyParseUInt64(random_string_1, &u64_legacy);
const bool ok_u8_legacy = LegacyParseUInt8(random_string_1, &u8_legacy);

assert(ok_i32 == ok_i32_legacy);
assert(ok_i64 == ok_i64_legacy);
assert(ok_u32 == ok_u32_legacy);
assert(ok_u64 == ok_u64_legacy);
assert(ok_u8 == ok_u8_legacy);

if (ok_i32) {
assert(i32 == i32_legacy);
}
if (ok_i64) {
assert(i64 == i64_legacy);
}
if (ok_u32) {
assert(u32 == u32_legacy);
}
if (ok_u64) {
assert(u64 == u64_legacy);
}
if (ok_u8) {
assert(u8 == u8_legacy);
}
}

{
const int locale_independent_atoi_result = LocaleIndependentAtoi<int>(random_string_1);
const int64_t atoi64_result = atoi64_legacy(random_string_1);
assert(locale_independent_atoi_result == std::clamp<int64_t>(atoi64_result, std::numeric_limits<int>::min(), std::numeric_limits<int>::max()));
}

{
const int64_t atoi64_result = atoi64_legacy(random_string_1);
const int64_t locale_independent_atoi_result = LocaleIndependentAtoi<int64_t>(random_string_1);
assert(atoi64_result == locale_independent_atoi_result);
}
}
Loading
Loading