Skip to content
Bitcoin Roots

v31.1-roots.1 · Commit 3: [PATCH 03/17] feat(policy): preserve cluster accounting and repair dynamic dust

src/init.cpp

Before: src/init.cpp · After: src/init.cpp

File metadata
index ac87cf0a531d0b7d931d635cc72f5fb69b82a436..fed689af2441e05abd49f8e96f3ee94a83640d49 100644

Download original patch · Release notes

Diff rows 1–79 of 79. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.

src/init.cpp CHANGED
@@ -670,24 +670,24 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
670
  SetupChainParamsBaseOptions(argsman);
671
 
672
  argsman.AddArg("-acceptunknownwitness", strprintf("Relay transactions sending to unknown or future witness script versions (default: %u)", DEFAULT_ACCEPTUNKNOWNWITNESS) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
673
- argsman.AddArg("-dustdynamic=<value>", "Staged parsing only; enforcement is deferred to L8 graph policy. See doc/feature-contracts/policy-parsing.md for accepted grammar.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
674
  argsman.AddArg("-bytespersigopstrict", strprintf("Minimum bytes per sigop in transactions we relay and mine (integer 0 to 4294967295; default: %u)", DEFAULT_BYTES_PER_SIGOP_STRICT), ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
675
- argsman.AddArg("-datacarriercost=<value>", "Staged parsing only; enforcement is deferred to L8 graph policy. See doc/feature-contracts/policy-parsing.md for accepted grammar.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
676
  argsman.AddArg("-datacarrierfullcount", strprintf("Apply datacarriersize limit to all known data-carrier methods (default: %u)", DEFAULT_DATACARRIER_FULLCOUNT) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION | (DEFAULT_DATACARRIER_FULLCOUNT ? uint32_t{ArgsManager::DEBUG_ONLY} : 0), OptionsCategory::NODE_RELAY);
677
  argsman.AddArg("-permitbaredatacarrier", strprintf("Relay transactions with data carrier outputs and no monetary outputs (default: %u)", DEFAULT_PERMITBAREDATACARRIER) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
678
  argsman.AddArg("-acceptnonstddatacarrier", strprintf("Relay nonstandard data carrier outputs (default: %u)", DEFAULT_ACCEPT_NON_STD_DATACARRIER) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
679
  argsman.AddArg("-permitephemeral", "Permit ephemeral policy exceptions: send, dust, anchor, reject, or 0, optionally prefixed with '-'. Tokens are separated by ',' or '+'; 0 disables all, empty or 1 enables all (default: anchor only)", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
680
- argsman.AddArg("-subdustfeepenalty=<value>", "Staged parsing only; enforcement is deferred to L8 graph policy. See doc/feature-contracts/policy-parsing.md for accepted grammar.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
681
  argsman.AddArg("-maxscriptsize=<n>", strprintf("Maximum size of scripts (including the witness stack) we relay and mine (integer 0 to 4294967295; default: %s)", DEFAULT_SCRIPT_SIZE_POLICY_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
682
  argsman.AddArg("-maxtxlegacysigops", strprintf("Maximum legacy sigops in transactions we relay and mine (integer 0 to 4294967295; default: %s)", MAX_TX_LEGACY_SIGOPS), ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
683
- argsman.AddArg("-mempoolreplacement=<value>", "Staged parsing only; enforcement is deferred to L8 graph policy. See doc/feature-contracts/policy-parsing.md for accepted grammar.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
684
- argsman.AddArg("-mempoolfullrbf", "Staged legacy alias; replacement enforcement is deferred to L8 graph policy.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
685
- argsman.AddArg("-mempooltruc=<value>", "Staged parsing only; enforcement is deferred to L8 graph policy. See doc/feature-contracts/policy-parsing.md for accepted grammar.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
686
  argsman.AddArg("-minrelaycoinblocks=<n>", strprintf("Minimum coin blocks a transaction must spend to be relayed (integer 0 to 9223372036854775807; default: %s)", 0), ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
687
  argsman.AddArg("-minrelaymaturity=<n>", strprintf("Minimum input maturity before relay (integer 0 to 2147483647; default: %s)", 0), ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
688
  argsman.AddArg("-permitbareanchor", strprintf("Relay transactions that only have ephemeral anchor outputs (default: %u)", DEFAULT_PERMITBAREANCHOR) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
689
  argsman.AddArg("-permitbarepubkey", strprintf("Relay legacy pubkey outputs (default: %u)", DEFAULT_PERMIT_BAREPUBKEY) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
690
- argsman.AddArg("-spkreuse=<value>", "Staged parsing only; enforcement is deferred to L8 graph policy. See doc/feature-contracts/policy-parsing.md for accepted grammar.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
691
  argsman.AddArg("-rejecttokens", strprintf("Refuse to relay or mine transactions involving non-bitcoin tokens (default: %u)", DEFAULT_REJECT_TOKENS) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
692
  argsman.AddArg("-rejectparasites", strprintf("Refuse to relay or mine parasitic overlay protocols (default: %u)", DEFAULT_REJECT_PARASITES) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
693
  argsman.AddArg("-blockmaxsize=<value>", "Staged parsing only; enforcement is deferred to L9 mining. See doc/feature-contracts/policy-parsing.md for accepted grammar.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
@@ -942,7 +942,7 @@ bool AppInitBasicSetup(const ArgsManager& args, std::atomic<int>& exit_status)
942
  bool AppInitParameterInteraction(const ArgsManager& args)
943
  {
944
  if (auto result = ValidateRootsPolicyOptions(args); !result) return InitError(util::ErrorString(result));
945
- for (const char* option : {"-datacarriercost", "-subdustfeepenalty", "-mempoolreplacement", "-mempoolfullrbf", "-mempooltruc", "-spkreuse", "-dustdynamic", "-blockmaxsize", "-blockprioritysize"}) {
946
  if (args.IsArgSet(option)) {
947
  InitWarning(Untranslated(strprintf("%s is parsed but not enforced in this staged candidate; graph policy and mining implementations are pending.", option)));
948
  }
@@ -1181,6 +1181,9 @@ bool AppInitParameterInteraction(const ArgsManager& args)
1181
  if (!mempool_result) {
1182
  return InitError(util::ErrorString(mempool_result));
1183
  }
 
 
 
1184
  }
1185
 
1186
  return true;
@@ -1919,6 +1922,31 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1919
  return true;
1920
  }
1921
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1922
  ChainstateManager& chainman = *Assert(node.chainman);
1923
  auto& kernel_notifications{*Assert(node.notifications)};
1924
 
 
670
  SetupChainParamsBaseOptions(argsman);
671
 
672
  argsman.AddArg("-acceptunknownwitness", strprintf("Relay transactions sending to unknown or future witness script versions (default: %u)", DEFAULT_ACCEPTUNKNOWNWITNESS) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
673
+ argsman.AddArg("-dustdynamic=<value>", "Update the dust rate every 15 minutes using off, [multiplier*]target:blocks, or [multiplier*]mempool:kvB (default: off). Multiplier defaults to 3; the configured dustrelayfee is the floor and fallback when no estimate is available.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
674
  argsman.AddArg("-bytespersigopstrict", strprintf("Minimum bytes per sigop in transactions we relay and mine (integer 0 to 4294967295; default: %u)", DEFAULT_BYTES_PER_SIGOP_STRICT), ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
675
+ argsman.AddArg("-datacarriercost=<value>", "Treat data carrier bytes as at least N vbytes each (0 to 1073741823.75, exact hundredths; rounded up to quarter-vbytes; default: 1). Only local policy size changes.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
676
  argsman.AddArg("-datacarrierfullcount", strprintf("Apply datacarriersize limit to all known data-carrier methods (default: %u)", DEFAULT_DATACARRIER_FULLCOUNT) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION | (DEFAULT_DATACARRIER_FULLCOUNT ? uint32_t{ArgsManager::DEBUG_ONLY} : 0), OptionsCategory::NODE_RELAY);
677
  argsman.AddArg("-permitbaredatacarrier", strprintf("Relay transactions with data carrier outputs and no monetary outputs (default: %u)", DEFAULT_PERMITBAREDATACARRIER) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
678
  argsman.AddArg("-acceptnonstddatacarrier", strprintf("Relay nonstandard data carrier outputs (default: %u)", DEFAULT_ACCEPT_NON_STD_DATACARRIER) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
679
  argsman.AddArg("-permitephemeral", "Permit ephemeral policy exceptions: send, dust, anchor, reject, or 0, optionally prefixed with '-'. Tokens are separated by ',' or '+'; 0 disables all, empty or 1 enables all (default: anchor only)", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
680
+ argsman.AddArg("-subdustfeepenalty=<value>", "Subtract sub-dust output deficits from modified policy fees (default: 1). Values: 0 or 1; no value means 1. Actual fees and consensus validity are unchanged.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
681
  argsman.AddArg("-maxscriptsize=<n>", strprintf("Maximum size of scripts (including the witness stack) we relay and mine (integer 0 to 4294967295; default: %s)", DEFAULT_SCRIPT_SIZE_POLICY_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
682
  argsman.AddArg("-maxtxlegacysigops", strprintf("Maximum legacy sigops in transactions we relay and mine (integer 0 to 4294967295; default: %s)", MAX_TX_LEGACY_SIGOPS), ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
683
+ argsman.AddArg("-mempoolreplacement=<value>", "Set RBF policy: 0 disables, fee,optin honors signaling or TRUC/v3 replaceability, and fee,-optin enables full RBF. Tokens are separated by ',' or '+'; empty or 1 enables fee-based replacement (default: fee,-optin).", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
684
+ argsman.AddArg("-mempoolfullrbf", "Legacy RBF alias: accept replacement without requiring signaling (default: 1). Explicit optin or replacement disabling overrides this alias.", ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
685
+ argsman.AddArg("-mempooltruc=<value>", "Set TRUC policy: reject, accept, enforce/optin, or -enforce/-optin. Tokens are separated by ',' or '+'; 0 rejects, empty or 1 enforces (default: enforce).", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
686
  argsman.AddArg("-minrelaycoinblocks=<n>", strprintf("Minimum coin blocks a transaction must spend to be relayed (integer 0 to 9223372036854775807; default: %s)", 0), ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
687
  argsman.AddArg("-minrelaymaturity=<n>", strprintf("Minimum input maturity before relay (integer 0 to 2147483647; default: %s)", 0), ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
688
  argsman.AddArg("-permitbareanchor", strprintf("Relay transactions that only have ephemeral anchor outputs (default: %u)", DEFAULT_PERMITBAREANCHOR) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
689
  argsman.AddArg("-permitbarepubkey", strprintf("Relay legacy pubkey outputs (default: %u)", DEFAULT_PERMIT_BAREPUBKEY) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
690
+ argsman.AddArg("-spkreuse=<value>", "Set local script reuse policy: allow or conflict; empty/1 aliases allow, 0 aliases conflict (default: allow).", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
691
  argsman.AddArg("-rejecttokens", strprintf("Refuse to relay or mine transactions involving non-bitcoin tokens (default: %u)", DEFAULT_REJECT_TOKENS) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
692
  argsman.AddArg("-rejectparasites", strprintf("Refuse to relay or mine parasitic overlay protocols (default: %u)", DEFAULT_REJECT_PARASITES) + " Values: 0 or 1; no value means 1.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION, OptionsCategory::NODE_RELAY);
693
  argsman.AddArg("-blockmaxsize=<value>", "Staged parsing only; enforcement is deferred to L9 mining. See doc/feature-contracts/policy-parsing.md for accepted grammar.", ArgsManager::ALLOW_ANY | ArgsManager::STRICT_NEGATION | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
 
942
  bool AppInitParameterInteraction(const ArgsManager& args)
943
  {
944
  if (auto result = ValidateRootsPolicyOptions(args); !result) return InitError(util::ErrorString(result));
945
+ for (const char* option : {"-blockmaxsize", "-blockprioritysize"}) {
946
  if (args.IsArgSet(option)) {
947
  InitWarning(Untranslated(strprintf("%s is parsed but not enforced in this staged candidate; graph policy and mining implementations are pending.", option)));
948
  }
 
1181
  if (!mempool_result) {
1182
  return InitError(util::ErrorString(mempool_result));
1183
  }
1184
+ if (mempool_opts.rbf_policy == RBFPolicy::Never && args.GetBoolArg("-mempoolfullrbf", false)) {
1185
+ InitWarning(_("False mempoolreplacement option contradicts true mempoolfullrbf; disallowing all RBF"));
1186
+ }
1187
  }
1188
 
1189
  return true;
 
1922
  return true;
1923
  }
1924
 
1925
+ // Register only after the final successful load: InitAndLoadChainstate may
1926
+ // destroy a failed attempt's mempool. Shutdown stops and joins the scheduler
1927
+ // before destroying the final mempool/estimator. Capture their node owner,
1928
+ // never a mempool pointer from a constructor or a retry attempt.
1929
+ if (status == ChainstateLoadStatus::SUCCESS && node.mempool->m_opts.dust_relay_target != 0) {
1930
+ const auto target{node.mempool->m_opts.dust_relay_target};
1931
+ if (target < 0 && node.fee_estimator && static_cast<unsigned>(-target) > node.fee_estimator->HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE)) {
1932
+ return InitError(_("Dynamic dust target exceeds the initialized fee estimator horizon"));
1933
+ }
1934
+ const auto update_dust = [&node] {
1935
+ if (ShutdownRequested(node)) return;
1936
+ const auto target{node.mempool->m_opts.dust_relay_target};
1937
+ std::optional<CFeeRate> estimate;
1938
+ if (target > 0) {
1939
+ estimate = node.mempool->EstimateDustFromMempool(target);
1940
+ } else if (node.fee_estimator) {
1941
+ estimate = node.fee_estimator->estimateRawFee(-target, 0.8, FeeEstimateHorizon::LONG_HALFLIFE);
1942
+ }
1943
+ node.mempool->UpdateDynamicDustFee(estimate);
1944
+ };
1945
+ update_dust();
1946
+ scheduler.scheduleEvery(update_dust, std::chrono::minutes{15});
1947
+ LogInfo("Dynamic dust updates scheduled after chainstate load");
1948
+ }
1949
+
1950
  ChainstateManager& chainman = *Assert(node.chainman);
1951
  auto& kernel_notifications{*Assert(node.notifications)};
1952