Skip to content

Commit 8a59be4

Browse files
committed
Merge branch 'truc_opts-28+knots' into permitbarepubkey-28+knots
2 parents 07ed462 + 0b272c3 commit 8a59be4

25 files changed

+763
-70
lines changed

configure.ac

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,21 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]],
927927
[ AC_MSG_RESULT([no])]
928928
)
929929

930+
AC_MSG_CHECKING(for compatible sysinfo call)
931+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/sysinfo.h>]],
932+
[[
933+
struct sysinfo info;
934+
int rv = sysinfo(&info);
935+
unsigned long test = info.freeram + info.bufferram + info.mem_unit;
936+
]])],
937+
[
938+
AC_MSG_RESULT(yes);
939+
AC_DEFINE(HAVE_LINUX_SYSINFO, 1, [Define this symbol if you have a Linux-compatible sysinfo call])
940+
],[
941+
AC_MSG_RESULT(no)
942+
]
943+
)
944+
930945
dnl Check for posix_fallocate
931946
AC_MSG_CHECKING([for posix_fallocate])
932947
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[

src/bitcoin-cli.cpp

Lines changed: 62 additions & 21 deletions
Large diffs are not rendered by default.

src/common/system.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
#include <malloc.h>
2323
#endif
2424

25+
#ifdef HAVE_LINUX_SYSINFO
26+
#include <sys/sysinfo.h>
27+
#endif
28+
2529
#include <cstdlib>
2630
#include <locale>
2731
#include <stdexcept>
@@ -110,3 +114,39 @@ int64_t GetStartupTime()
110114
{
111115
return nStartupTime;
112116
}
117+
118+
size_t g_low_memory_threshold = 10 * 1024 * 1024 /* 10 MB */;
119+
120+
bool SystemNeedsMemoryReleased()
121+
{
122+
if (g_low_memory_threshold <= 0) {
123+
// Intentionally bypass other metrics when disabled entirely
124+
return false;
125+
}
126+
#ifdef WIN32
127+
MEMORYSTATUSEX mem_status;
128+
mem_status.dwLength = sizeof(mem_status);
129+
if (GlobalMemoryStatusEx(&mem_status)) {
130+
if (mem_status.dwMemoryLoad >= 99 ||
131+
mem_status.ullAvailPhys < g_low_memory_threshold ||
132+
mem_status.ullAvailVirtual < g_low_memory_threshold) {
133+
LogPrintf("%s: YES: %s%% memory load; %s available physical memory; %s available virtual memory\n", __func__, int(mem_status.dwMemoryLoad), size_t(mem_status.ullAvailPhys), size_t(mem_status.ullAvailVirtual));
134+
return true;
135+
}
136+
}
137+
#endif
138+
#ifdef HAVE_LINUX_SYSINFO
139+
struct sysinfo sys_info;
140+
if (!sysinfo(&sys_info)) {
141+
// Explicitly 64-bit in case of 32-bit userspace on 64-bit kernel
142+
const uint64_t free_ram = uint64_t(sys_info.freeram) * sys_info.mem_unit;
143+
const uint64_t buffer_ram = uint64_t(sys_info.bufferram) * sys_info.mem_unit;
144+
if (free_ram + buffer_ram < g_low_memory_threshold) {
145+
LogPrintf("%s: YES: %s free RAM + %s buffer RAM\n", __func__, free_ram, buffer_ram);
146+
return true;
147+
}
148+
}
149+
#endif
150+
// NOTE: sysconf(_SC_AVPHYS_PAGES) doesn't account for caches on at least Linux, so not safe to use here
151+
return false;
152+
}

src/common/system.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ std::string ShellEscape(const std::string& arg);
2323
void runCommand(const std::string& strCommand);
2424
#endif
2525

26+
extern size_t g_low_memory_threshold;
27+
28+
bool SystemNeedsMemoryReleased();
29+
2630
/**
2731
* Return the number of cores available on the current system.
2832
* @note This does count virtual cores, such as those provided by HyperThreading.

src/init.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ void SetupServerArgs(ArgsManager& argsman)
492492
argsman.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
493493
argsman.AddArg("-allowignoredconf", strprintf("For backwards compatibility, treat an unused %s file in the datadir as a warning, not an error.", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
494494
argsman.AddArg("-loadblock=<file>", "Imports blocks from external file on startup", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
495+
argsman.AddArg("-lowmem=<n>", strprintf("If system available memory falls below <n> MiB, flush caches (0 to disable, default: %s)", g_low_memory_threshold / 1024 / 1024), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
495496
argsman.AddArg("-maxmempool=<n>", strprintf("Keep the transaction memory pool below <n> megabytes (default: %u)", DEFAULT_MAX_MEMPOOL_SIZE_MB), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
496497
argsman.AddArg("-maxorphantx=<n>", strprintf("Keep at most <n> unconnectable transactions in memory (default: %u)", DEFAULT_MAX_ORPHAN_TRANSACTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
497498
argsman.AddArg("-mempoolexpiry=<n>", strprintf("Do not keep transactions in the mempool longer than <n> hours (default: %u)", DEFAULT_MEMPOOL_EXPIRY_HOURS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -647,7 +648,9 @@ void SetupServerArgs(ArgsManager& argsman)
647648
"is of this size or less (default: %u)",
648649
MAX_OP_RETURN_RELAY),
649650
ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
650-
argsman.AddArg("-mempoolfullrbf", strprintf("(DEPRECATED) Accept transaction replace-by-fee without requiring replaceability signaling (default: %u)", DEFAULT_MEMPOOL_FULL_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
651+
argsman.AddArg("-mempoolfullrbf", strprintf("Accept transaction replace-by-fee without requiring replaceability signaling (default: %u)", (DEFAULT_MEMPOOL_RBF_POLICY == RBFPolicy::Always)), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
652+
argsman.AddArg("-mempoolreplacement", strprintf("Set to 0 to disable RBF entirely, \"fee,optin\" to honour RBF opt-out signal, or \"fee,-optin\" to always RBF aka full RBF (default: %s)", "fee,-optin"), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
653+
argsman.AddArg("-mempooltruc", strprintf("Behaviour for transactions requesting TRUC limits: \"reject\" the transactions entirely, \"accept\" them just like any other, or \"enforce\" to impose their requested restrictions (default: %s)", "enforce"), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
651654
argsman.AddArg("-permitbaremultisig", strprintf("Relay transactions creating non-P2SH multisig outputs (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY,
652655
OptionsCategory::NODE_RELAY);
653656
argsman.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)",
@@ -1540,6 +1543,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
15401543
bool do_reindex{args.GetBoolArg("-reindex", false)};
15411544
const bool do_reindex_chainstate{args.GetBoolArg("-reindex-chainstate", false)};
15421545

1546+
if (gArgs.IsArgSet("-lowmem")) {
1547+
g_low_memory_threshold = gArgs.GetIntArg("-lowmem", 0 /* not used */) * 1024 * 1024;
1548+
}
1549+
if (g_low_memory_threshold > 0) {
1550+
LogPrintf("* Flushing caches if available system memory drops below %s MiB\n", g_low_memory_threshold / 1024 / 1024);
1551+
}
1552+
1553+
if (mempool_opts.rbf_policy == RBFPolicy::Always) {
1554+
nLocalServices = ServiceFlags(nLocalServices | NODE_REPLACE_BY_FEE);
1555+
}
1556+
15431557
for (bool fLoaded = false; !fLoaded && !ShutdownRequested(node);) {
15441558
bilingual_str mempool_error;
15451559
node.mempool = std::make_unique<CTxMemPool>(mempool_opts, mempool_error);

src/kernel/mempool_options.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,19 @@
1515

1616
class ValidationSignals;
1717

18+
enum class RBFPolicy { Never, OptIn, Always };
19+
enum class TRUCPolicy { Reject, Accept, Enforce };
20+
1821
/** Default for -maxmempool, maximum megabytes of mempool memory usage */
1922
static constexpr unsigned int DEFAULT_MAX_MEMPOOL_SIZE_MB{300};
2023
/** Default for -maxmempool when blocksonly is set */
2124
static constexpr unsigned int DEFAULT_BLOCKSONLY_MAX_MEMPOOL_SIZE_MB{5};
2225
/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */
2326
static constexpr unsigned int DEFAULT_MEMPOOL_EXPIRY_HOURS{336};
24-
/** Default for -mempoolfullrbf, if the transaction replaceability signaling is ignored */
25-
static constexpr bool DEFAULT_MEMPOOL_FULL_RBF{true};
27+
/** Default for -mempoolreplacement; must update docs in init.cpp manually */
28+
static constexpr RBFPolicy DEFAULT_MEMPOOL_RBF_POLICY{RBFPolicy::Always};
29+
/** Default for -mempooltruc; must update docs in init.cpp manually */
30+
static constexpr TRUCPolicy DEFAULT_MEMPOOL_TRUC_POLICY{TRUCPolicy::Enforce};
2631
/** Whether to fall back to legacy V1 serialization when writing mempool.dat */
2732
static constexpr bool DEFAULT_PERSIST_V1_DAT{false};
2833
/** Default for -acceptnonstdtxn */
@@ -55,7 +60,8 @@ struct MemPoolOptions {
5560
std::optional<unsigned> max_datacarrier_bytes{DEFAULT_ACCEPT_DATACARRIER ? std::optional{MAX_OP_RETURN_RELAY} : std::nullopt};
5661
bool permit_bare_multisig{DEFAULT_PERMIT_BAREMULTISIG};
5762
bool require_standard{true};
58-
bool full_rbf{DEFAULT_MEMPOOL_FULL_RBF};
63+
RBFPolicy rbf_policy{DEFAULT_MEMPOOL_RBF_POLICY};
64+
TRUCPolicy truc_policy{DEFAULT_MEMPOOL_TRUC_POLICY};
5965
bool persist_v1_dat{DEFAULT_PERSIST_V1_DAT};
6066
MemPoolLimits limits{};
6167

src/node/mempool_args.cpp

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
#include <consensus/amount.h>
1313
#include <kernel/chainparams.h>
1414
#include <logging.h>
15+
#include <node/interface_ui.h>
1516
#include <policy/feerate.h>
1617
#include <policy/policy.h>
1718
#include <tinyformat.h>
1819
#include <util/moneystr.h>
20+
#include <util/string.h>
1921
#include <util/translation.h>
2022

2123
#include <chrono>
@@ -92,9 +94,86 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& argsman, const CChainP
9294
return util::Error{strprintf(Untranslated("acceptnonstdtxn is not currently supported for %s chain"), chainparams.GetChainTypeString())};
9395
}
9496

95-
mempool_opts.full_rbf = argsman.GetBoolArg("-mempoolfullrbf", mempool_opts.full_rbf);
96-
if (!mempool_opts.full_rbf) {
97-
LogInfo("Warning: mempoolfullrbf=0 set but deprecated and will be removed in a future release\n");
97+
if (argsman.IsArgSet("-mempoolreplacement") || argsman.IsArgSet("-mempoolfullrbf")) {
98+
// Generally, mempoolreplacement overrides mempoolfullrbf, but the latter is used to infer intent in some cases
99+
std::optional<bool> optin_flag;
100+
bool fee_flag{false};
101+
if (argsman.GetBoolArg("-mempoolreplacement", false)) {
102+
fee_flag = true;
103+
} else {
104+
for (auto& opt : util::SplitString(argsman.GetArg("-mempoolreplacement", ""), ",+")) {
105+
if (opt == "optin") {
106+
optin_flag = true;
107+
} else if (opt == "-optin") {
108+
optin_flag = false;
109+
} else if (opt == "fee") {
110+
fee_flag = true;
111+
}
112+
}
113+
}
114+
if (optin_flag.value_or(false)) {
115+
// "optin" is explicitly specified
116+
mempool_opts.rbf_policy = RBFPolicy::OptIn;
117+
} else if (argsman.GetBoolArg("-mempoolfullrbf", false)) {
118+
const bool mempoolreplacement_false{argsman.IsArgSet("-mempoolreplacement") && !(fee_flag || optin_flag.has_value())};
119+
if (mempoolreplacement_false) {
120+
// This is a contradiction, but override rather than error
121+
InitWarning(_("False mempoolreplacement option contradicts true mempoolfullrbf; disallowing all RBF"));
122+
mempool_opts.rbf_policy = RBFPolicy::Never;
123+
} else {
124+
mempool_opts.rbf_policy = RBFPolicy::Always;
125+
}
126+
} else if (!optin_flag.value_or(true)) {
127+
// "-optin" is explicitly specified
128+
mempool_opts.rbf_policy = fee_flag ? RBFPolicy::Always : RBFPolicy::Never;
129+
} else if (fee_flag) {
130+
// Just "fee" by itself
131+
if (!argsman.GetBoolArg("-mempoolfullrbf", true)) {
132+
mempool_opts.rbf_policy = RBFPolicy::OptIn;
133+
} else {
134+
// Fallback to default, unless it's been changed to Never
135+
if (mempool_opts.rbf_policy == RBFPolicy::Never) {
136+
mempool_opts.rbf_policy = RBFPolicy::Always;
137+
}
138+
}
139+
} else if (!argsman.IsArgSet("-mempoolreplacement")) {
140+
// mempoolfullrbf is always explicitly false here
141+
// Fallback to default, as long as it isn't Always
142+
if (mempool_opts.rbf_policy == RBFPolicy::Always) {
143+
mempool_opts.rbf_policy = RBFPolicy::OptIn;
144+
}
145+
} else {
146+
// mempoolreplacement is explicitly false here
147+
mempool_opts.rbf_policy = RBFPolicy::Never;
148+
}
149+
}
150+
151+
if (argsman.IsArgSet("-mempooltruc")) {
152+
std::optional<bool> accept_flag, enforce_flag;
153+
if (argsman.GetBoolArg("-mempooltruc", false)) {
154+
enforce_flag = true;
155+
}
156+
for (auto& opt : util::SplitString(argsman.GetArg("-mempooltruc", ""), ",+")) {
157+
if (opt == "optin" || opt == "enforce") {
158+
enforce_flag = true;
159+
} else if (opt == "-optin" || opt == "-enforce") {
160+
enforce_flag = false;
161+
} else if (opt == "accept") {
162+
accept_flag = true;
163+
} else if (opt == "reject" || opt == "0") {
164+
accept_flag = false;
165+
}
166+
}
167+
168+
if (accept_flag && !*accept_flag) { // reject
169+
mempool_opts.truc_policy = TRUCPolicy::Reject;
170+
} else if (enforce_flag && *enforce_flag) { // enforce
171+
mempool_opts.truc_policy = TRUCPolicy::Enforce;
172+
} else if ((!accept_flag) && !enforce_flag) {
173+
// nothing specified, leave at default
174+
} else { // accept or -enforce
175+
mempool_opts.truc_policy = TRUCPolicy::Accept;
176+
}
98177
}
99178

100179
mempool_opts.persist_v1_dat = argsman.GetBoolArg("-persistmempoolv1", mempool_opts.persist_v1_dat);

src/protocol.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static std::string serviceFlagToStr(size_t bit)
9999
case NODE_COMPACT_FILTERS: return "COMPACT_FILTERS";
100100
case NODE_NETWORK_LIMITED: return "NETWORK_LIMITED";
101101
case NODE_P2P_V2: return "P2P_V2";
102+
case NODE_REPLACE_BY_FEE: return "REPLACE_BY_FEE?";
102103
// Not using default, so we get warned when a case is missing
103104
}
104105

src/protocol.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,8 @@ enum ServiceFlags : uint64_t {
336336
// collisions and other cases where nodes may be advertising a service they
337337
// do not actually support. Other service bits should be allocated via the
338338
// BIP process.
339+
340+
NODE_REPLACE_BY_FEE = (1 << 26),
339341
};
340342

341343
/**

src/rest.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <validation.h>
3434

3535
#include <any>
36+
#include <optional>
3637
#include <vector>
3738

3839
#include <univalue.h>
@@ -650,8 +651,8 @@ static bool rest_mempool(const std::any& context, HTTPRequest* req, const std::s
650651

651652
std::string param;
652653
const RESTResponseFormat rf = ParseDataFormat(param, str_uri_part);
653-
if (param != "contents" && param != "info") {
654-
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/mempool/<info|contents>.json");
654+
if (param != "contents" && param != "info" && param != "info/with_fee_histogram") {
655+
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/mempool/<info|info/with_fee_histogram|contents>.json");
655656
}
656657

657658
const CTxMemPool* mempool = GetMemPool(context, req);
@@ -685,8 +686,10 @@ static bool rest_mempool(const std::any& context, HTTPRequest* req, const std::s
685686
return RESTERR(req, HTTP_BAD_REQUEST, "Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")");
686687
}
687688
str_json = MempoolToJSON(*mempool, verbose, mempool_sequence).write() + "\n";
689+
} else if (param == "info/with_fee_histogram") {
690+
str_json = MempoolInfoToJSON(*mempool, MempoolInfoToJSON_const_histogram_floors).write() + "\n";
688691
} else {
689-
str_json = MempoolInfoToJSON(*mempool).write() + "\n";
692+
str_json = MempoolInfoToJSON(*mempool, std::nullopt).write() + "\n";
690693
}
691694

692695
req->WriteHeader("Content-Type", "application/json");

0 commit comments

Comments
 (0)