Bitcoin Core  0.20.99
P2P Digital Currency
settings.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <util/settings.h>
6 
7 #include <univalue.h>
8 
9 namespace util {
10 namespace {
11 
12 enum class Source {
13  FORCED,
14  COMMAND_LINE,
15  CONFIG_FILE_NETWORK_SECTION,
16  CONFIG_FILE_DEFAULT_SECTION
17 };
18 
24 template <typename Fn>
25 static void MergeSettings(const Settings& settings, const std::string& section, const std::string& name, Fn&& fn)
26 {
27  // Merge in the forced settings
28  if (auto* value = FindKey(settings.forced_settings, name)) {
29  fn(SettingsSpan(*value), Source::FORCED);
30  }
31  // Merge in the command-line options
32  if (auto* values = FindKey(settings.command_line_options, name)) {
33  fn(SettingsSpan(*values), Source::COMMAND_LINE);
34  }
35  // Merge in the network-specific section of the config file
36  if (!section.empty()) {
37  if (auto* map = FindKey(settings.ro_config, section)) {
38  if (auto* values = FindKey(*map, name)) {
39  fn(SettingsSpan(*values), Source::CONFIG_FILE_NETWORK_SECTION);
40  }
41  }
42  }
43  // Merge in the default section of the config file
44  if (auto* map = FindKey(settings.ro_config, "")) {
45  if (auto* values = FindKey(*map, name)) {
46  fn(SettingsSpan(*values), Source::CONFIG_FILE_DEFAULT_SECTION);
47  }
48  }
49 }
50 } // namespace
51 
53  const std::string& section,
54  const std::string& name,
55  bool ignore_default_section_config,
56  bool get_chain_name)
57 {
58  SettingsValue result;
59  bool done = false; // Done merging any more settings sources.
60  MergeSettings(settings, section, name, [&](SettingsSpan span, Source source) {
61  // Weird behavior preserved for backwards compatibility: Apply negated
62  // setting even if non-negated setting would be ignored. A negated
63  // value in the default section is applied to network specific options,
64  // even though normal non-negated values there would be ignored.
65  const bool never_ignore_negated_setting = span.last_negated();
66 
67  // Weird behavior preserved for backwards compatibility: Take first
68  // assigned value instead of last. In general, later settings take
69  // precedence over early settings, but for backwards compatibility in
70  // the config file the precedence is reversed for all settings except
71  // chain name settings.
72  const bool reverse_precedence =
73  (source == Source::CONFIG_FILE_NETWORK_SECTION || source == Source::CONFIG_FILE_DEFAULT_SECTION) &&
74  !get_chain_name;
75 
76  // Weird behavior preserved for backwards compatibility: Negated
77  // -regtest and -testnet arguments which you would expect to override
78  // values set in the configuration file are currently accepted but
79  // silently ignored. It would be better to apply these just like other
80  // negated values, or at least warn they are ignored.
81  const bool skip_negated_command_line = get_chain_name;
82 
83  if (done) return;
84 
85  // Ignore settings in default config section if requested.
86  if (ignore_default_section_config && source == Source::CONFIG_FILE_DEFAULT_SECTION &&
87  !never_ignore_negated_setting) {
88  return;
89  }
90 
91  // Skip negated command line settings.
92  if (skip_negated_command_line && span.last_negated()) return;
93 
94  if (!span.empty()) {
95  result = reverse_precedence ? span.begin()[0] : span.end()[-1];
96  done = true;
97  } else if (span.last_negated()) {
98  result = false;
99  done = true;
100  }
101  });
102  return result;
103 }
104 
105 std::vector<SettingsValue> GetSettingsList(const Settings& settings,
106  const std::string& section,
107  const std::string& name,
108  bool ignore_default_section_config)
109 {
110  std::vector<SettingsValue> result;
111  bool done = false; // Done merging any more settings sources.
112  bool prev_negated_empty = false;
113  MergeSettings(settings, section, name, [&](SettingsSpan span, Source source) {
114  // Weird behavior preserved for backwards compatibility: Apply config
115  // file settings even if negated on command line. Negating a setting on
116  // command line will ignore earlier settings on the command line and
117  // ignore settings in the config file, unless the negated command line
118  // value is followed by non-negated value, in which case config file
119  // settings will be brought back from the dead (but earlier command
120  // line settings will still be ignored).
121  const bool add_zombie_config_values =
122  (source == Source::CONFIG_FILE_NETWORK_SECTION || source == Source::CONFIG_FILE_DEFAULT_SECTION) &&
123  !prev_negated_empty;
124 
125  // Ignore settings in default config section if requested.
126  if (ignore_default_section_config && source == Source::CONFIG_FILE_DEFAULT_SECTION) return;
127 
128  // Add new settings to the result if isn't already complete, or if the
129  // values are zombies.
130  if (!done || add_zombie_config_values) {
131  for (const auto& value : span) {
132  if (value.isArray()) {
133  result.insert(result.end(), value.getValues().begin(), value.getValues().end());
134  } else {
135  result.push_back(value);
136  }
137  }
138  }
139 
140  // If a setting was negated, or if a setting was forced, set
141  // done to true to ignore any later lower priority settings.
142  done |= span.negated() > 0 || source == Source::FORCED;
143 
144  // Update the negated and empty state used for the zombie values check.
145  prev_negated_empty |= span.last_negated() && result.empty();
146  });
147  return result;
148 }
149 
150 bool OnlyHasDefaultSectionSetting(const Settings& settings, const std::string& section, const std::string& name)
151 {
152  bool has_default_section_setting = false;
153  bool has_other_setting = false;
154  MergeSettings(settings, section, name, [&](SettingsSpan span, Source source) {
155  if (span.empty()) return;
156  else if (source == Source::CONFIG_FILE_DEFAULT_SECTION) has_default_section_setting = true;
157  else has_other_setting = true;
158  });
159  // If a value is set in the default section and not explicitly overwritten by the
160  // user on the command line or in a different section, then we want to enable
161  // warnings about the value being ignored.
162  return has_default_section_setting && !has_other_setting;
163 }
164 
165 SettingsSpan::SettingsSpan(const std::vector<SettingsValue>& vec) noexcept : SettingsSpan(vec.data(), vec.size()) {}
166 const SettingsValue* SettingsSpan::begin() const { return data + negated(); }
167 const SettingsValue* SettingsSpan::end() const { return data + size; }
168 bool SettingsSpan::empty() const { return size == 0 || last_negated(); }
169 bool SettingsSpan::last_negated() const { return size > 0 && data[size - 1].isFalse(); }
170 size_t SettingsSpan::negated() const
171 {
172  for (size_t i = size; i > 0; --i) {
173  if (data[i - 1].isFalse()) return i; // Return number of negated values (position of last false value)
174  }
175  return 0;
176 }
177 
178 } // namespace util
Stored bitcoin settings.
Definition: settings.h:29
bool OnlyHasDefaultSectionSetting(const Settings &settings, const std::string &section, const std::string &name)
Return true if a setting is set in the default config file section, and not overridden by a higher pr...
Definition: settings.cpp:150
Definition: httprpc.h:8
size_t negated() const
Number of negated values.
Definition: settings.cpp:170
SettingsValue GetSetting(const Settings &settings, const std::string &section, const std::string &name, bool ignore_default_section_config, bool get_chain_name)
Get settings value from combined sources: forced settings, command line arguments and the read-only c...
Definition: settings.cpp:52
const SettingsValue * end() const
Pointer to end of values.
Definition: settings.cpp:167
bool last_negated() const
True if the last value is negated.
Definition: settings.cpp:169
auto FindKey(Map &&map, Key &&key) -> decltype(&map.at(key))
Map lookup helper.
Definition: settings.h:86
bool done
std::vector< SettingsValue > GetSettingsList(const Settings &settings, const std::string &section, const std::string &name, bool ignore_default_section_config)
Get combined setting value similar to GetSetting(), except if setting was specified multiple times...
Definition: settings.cpp:105
const char * source
Definition: rpcconsole.cpp:50
bool empty() const
True if there are any non-negated values.
Definition: settings.cpp:168
const char * name
Definition: rest.cpp:41
std::map< std::string, std::vector< SettingsValue > > command_line_options
Map of setting name to list of command line values.
Definition: settings.h:33
const SettingsValue * begin() const
Pointer to first non-negated value.
Definition: settings.cpp:166
Accessor for list of settings that skips negated values when iterated over.
Definition: settings.h:69
SettingsSpan()=default
std::map< std::string, std::map< std::string, std::vector< SettingsValue > > > ro_config
Map of config section name and setting name to list of config file values.
Definition: settings.h:35
std::map< std::string, SettingsValue > forced_settings
Map of setting name to forced setting value.
Definition: settings.h:31