mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-28 16:36:04 +01:00
wallet: bugfix: ensure atomicity in settings updates
- Settings updates were not thread-safe, as they were executed in three separate steps: 1) Obtain settings value while acquiring the settings lock. 2) Modify settings value. 3) Overwrite settings value while acquiring the settings lock. This approach allowed concurrent threads to modify the same base value simultaneously, leading to data loss. When this occurred, the final settings state would only reflect the changes from the last thread that completed the operation, overwriting updates from other threads. Fix this by making the settings update operation atomic. - Add test coverage for this behavior. Co-authored-by: furszy <matiasfurszyfer@protonmail.com>
This commit is contained in:
@@ -93,25 +93,30 @@ namespace wallet {
|
||||
|
||||
bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
|
||||
{
|
||||
common::SettingsValue setting_value = chain.getRwSetting("wallet");
|
||||
if (!setting_value.isArray()) setting_value.setArray();
|
||||
for (const common::SettingsValue& value : setting_value.getValues()) {
|
||||
if (value.isStr() && value.get_str() == wallet_name) return true;
|
||||
}
|
||||
setting_value.push_back(wallet_name);
|
||||
return chain.updateRwSetting("wallet", setting_value);
|
||||
const auto update_function = [&wallet_name](common::SettingsValue& setting_value) {
|
||||
if (!setting_value.isArray()) setting_value.setArray();
|
||||
for (const auto& value : setting_value.getValues()) {
|
||||
if (value.isStr() && value.get_str() == wallet_name) return interfaces::SettingsAction::SKIP_WRITE;
|
||||
}
|
||||
setting_value.push_back(wallet_name);
|
||||
return interfaces::SettingsAction::WRITE;
|
||||
};
|
||||
return chain.updateRwSetting("wallet", update_function);
|
||||
}
|
||||
|
||||
bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
|
||||
{
|
||||
common::SettingsValue setting_value = chain.getRwSetting("wallet");
|
||||
if (!setting_value.isArray()) return true;
|
||||
common::SettingsValue new_value(common::SettingsValue::VARR);
|
||||
for (const common::SettingsValue& value : setting_value.getValues()) {
|
||||
if (!value.isStr() || value.get_str() != wallet_name) new_value.push_back(value);
|
||||
}
|
||||
if (new_value.size() == setting_value.size()) return true;
|
||||
return chain.updateRwSetting("wallet", new_value);
|
||||
const auto update_function = [&wallet_name](common::SettingsValue& setting_value) {
|
||||
if (!setting_value.isArray()) return interfaces::SettingsAction::SKIP_WRITE;
|
||||
common::SettingsValue new_value(common::SettingsValue::VARR);
|
||||
for (const auto& value : setting_value.getValues()) {
|
||||
if (!value.isStr() || value.get_str() != wallet_name) new_value.push_back(value);
|
||||
}
|
||||
if (new_value.size() == setting_value.size()) return interfaces::SettingsAction::SKIP_WRITE;
|
||||
setting_value = std::move(new_value);
|
||||
return interfaces::SettingsAction::WRITE;
|
||||
};
|
||||
return chain.updateRwSetting("wallet", update_function);
|
||||
}
|
||||
|
||||
static void UpdateWalletSetting(interfaces::Chain& chain,
|
||||
|
||||
Reference in New Issue
Block a user