@@ -96,3 +96,140 @@ UniValue listsettings(const UniValue& params, bool fHelp)
96
96
return gArgs .OutputArgs ();
97
97
}
98
98
99
+ UniValue changesettings (const UniValue& params, bool fHelp )
100
+ {
101
+ if (fHelp || params.size () < 1 )
102
+ {
103
+ throw runtime_error (
104
+ " changesettings <name=value> [name=value] ... [name=value]\n "
105
+ " \n "
106
+ " name=value: name and value pair for setting to store/change (1st mandatory, 2nd+ optional).\n "
107
+ " \n "
108
+ " Note that the settings should be done in the same format as config file entries.\n "
109
+ " \n "
110
+ " Example:"
111
+ " changesettings enable enablestakesplit=1 stakingefficiency=98 minstakesplitvalue=800\n "
112
+ );
113
+ }
114
+
115
+ // -------- name ------------ value - value_changed - immediate_effect
116
+ std::map<std::string, std::tuple<std::string, bool , bool >> valid_settings;
117
+
118
+ UniValue result (UniValue::VOBJ);
119
+ UniValue settings_stored_with_no_state_change (UniValue::VARR);
120
+ UniValue settings_immediate (UniValue::VARR);
121
+ UniValue settings_applied_requiring_restart (UniValue::VARR);
122
+ // UniValue invalid_settings_ignored(UniValue::VARR);
123
+
124
+ // Validation
125
+ for (unsigned int i = 0 ; i < params.size (); ++i)
126
+ {
127
+ std::string param = params[i].get_str ();
128
+
129
+ if (param.size () > 0 && param[0 ] == ' -' )
130
+ {
131
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Incorrectly formatted setting change: " + param);
132
+ }
133
+
134
+ std::string::size_type pos;
135
+ std::string name;
136
+ std::string value;
137
+
138
+ if ((pos = param.find (' =' )) != std::string::npos)
139
+ {
140
+ name = param.substr (0 , pos);
141
+ value = param.substr (pos + 1 );
142
+ }
143
+ else
144
+ {
145
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Incorrectly formatted setting change: " + param);
146
+ }
147
+
148
+ std::optional<unsigned int > flags = gArgs .GetArgFlags (' -' + name);
149
+
150
+ if (!flags)
151
+ {
152
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid setting: " + param);
153
+ }
154
+
155
+ // TODO: Record explicit default state for settings.
156
+ // This currently has a problem that I am not sure yet how to solve. Settings that are defaulted to true, unless
157
+ // they are set to the contrary, such as -staking, will falsely indicate a change because the defaulted state is
158
+ // not explicitly stored for comparison. After there is an explicit entry defined in the settings file, it works
159
+ // correctly.
160
+
161
+ // Also, the overloading of GetArg is NOT helpful here...
162
+ std::string current_value;
163
+
164
+ // It is either a string or a number.... One of these will succeed.
165
+ try
166
+ {
167
+ current_value = gArgs .GetArg (name, " never_used_default" );
168
+ }
169
+ catch (std::exception & e)
170
+ {
171
+ // If it is a number convert back to a string.
172
+ current_value = ToString (gArgs .GetArg (name, 1 ));
173
+ }
174
+
175
+ bool value_changed = (current_value != value);
176
+ bool immediate_effect = *flags & ArgsManager::IMMEDIATE_EFFECT;
177
+
178
+ auto insert_pair = valid_settings.insert (std::make_pair (
179
+ name, std::make_tuple (value, value_changed, immediate_effect)));
180
+
181
+ if (!insert_pair.second )
182
+ {
183
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " changesettings does not support more than one instance of the same "
184
+ " setting: " + param);
185
+ }
186
+ }
187
+
188
+ // Now that validation is done do the update work.
189
+ bool restart_required = false ;
190
+
191
+ for (const auto & setting : valid_settings)
192
+ {
193
+ const std::string& name = setting.first ;
194
+ const std::string& value = std::get<0 >(setting.second );
195
+ const bool & value_changed = std::get<1 >(setting.second );
196
+ const bool & immediate_effect = std::get<2 >(setting.second );
197
+
198
+ std::string param = name + " =" + value;
199
+
200
+ // Regardless, store in r-w settings file.
201
+ if (!updateRwSetting (name, value))
202
+ {
203
+ throw JSONRPCError (RPC_MISC_ERROR, " Error storing setting in read-write settings file." );
204
+ }
205
+
206
+ if (value_changed)
207
+ {
208
+ gArgs .ForceSetArg (name, value);
209
+
210
+ if (immediate_effect)
211
+ {
212
+ settings_immediate.push_back (param);
213
+ }
214
+ else
215
+ {
216
+ settings_applied_requiring_restart.push_back (param);
217
+
218
+ // Record if restart required.
219
+ restart_required |= !immediate_effect;
220
+ }
221
+ }
222
+ else
223
+ {
224
+ settings_stored_with_no_state_change.push_back (param);
225
+ }
226
+ }
227
+
228
+ result.pushKV (" settings_change_requires_restart" , restart_required);
229
+ result.pushKV (" settings_stored_with_no_state_change" , settings_stored_with_no_state_change);
230
+ result.pushKV (" settings_changed_taking_immediate_effect" , settings_immediate);
231
+ result.pushKV (" settings_changed_requiring_restart" , settings_applied_requiring_restart);
232
+
233
+ return result;
234
+ }
235
+
0 commit comments