init: handle empty settings file gracefully #29144

pull furszy wants to merge 2 commits into bitcoin:master from furszy:2023_empty_settings_file changing 4 files +26 −6
  1. furszy commented at 10:52 pm on December 26, 2023: member

    Small and simple issue reported here.

    Improving a confusing situation reported by users who did not understand why a settings parsing error occurred when the file was empty and did not know how to solve it.

    Empty setting file could be due (1) corruption or (2) an user manually cleaning up the file content. In both scenarios, the ‘Unable to parse settings file’ error does not help the user move forward.

  2. DrahtBot commented at 10:52 pm on December 26, 2023: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage

    For detailed information about the code coverage, see the test coverage report.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK hebasto, ryanofsky, shaavan, achow101

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

  3. 0xB10C commented at 11:43 am on December 27, 2023: contributor
    see previous discussion in #23096, #22591, and #21340 (comment)
  4. furszy commented at 1:40 pm on December 27, 2023: member

    see previous discussion in #23096, #22591, and #21340 (comment)

    Hmm, okay, agree. Thanks. It would probably be useful to introduce support for comments. This way, we can write something at the beginning of the file, ensuring that users and other software developers don’t clean it up manually, thinking that it will be regenerated automatically. Do you know if something like this has been proposed before? @0xB10C.

  5. shaavan commented at 12:58 pm on December 28, 2023: contributor

    I agree with the reasoning ryanofsky has given here.

    A zero-size settings file is a corrupt settings file.

    But going through the issue mentioned in the description. I don’t think Unable to parse settings file /data/.bitcoin/settings.json is a very helpful message when it comes to bitcoind detecting an empty settings.json file.

    I think we should still handle the case of empty file separately. But instead of passing the file as valid, we should rather print a very clear error message, pointing the user to the reason for failure and possible remedy. This will definitely better the User experience for the noderunners.

  6. furszy commented at 1:48 pm on December 28, 2023: member

    I think we should still handle the case of empty file separately. But instead of passing the file as valid, we should rather print a very clear error message, pointing the user to the reason for failure and possible remedy. This will definitely better the User experience for the noderunners.

    For GUI interactive users, this isn’t an issue. We show a dialog that allows continuing when a parsing error is found (still, we might want to be clearer about the fact that they could be disabling Tor and/or other important configurations by allowing this).

    For non-interactive ones, people or other softwares, I’m inclined to solve this situation by adding a comment at the top of the file. Something like “This is an auto-generated JSON-formatted file. Please refrain from modifying it unless you are certain about the potential consequences.”

  7. in src/common/settings.cpp:86 in 725a1fc7a7 outdated
    79@@ -80,7 +80,9 @@ bool ReadSettings(const fs::path& path, std::map<std::string, SettingsValue>& va
    80     }
    81 
    82     SettingsValue in;
    83-    if (!in.read(std::string{std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()})) {
    84+    std::string content{std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
    85+    if (content.empty()) return true; // Ok for empty file
    86+    if (!in.read(content)) {
    87         errors.emplace_back(strprintf("Unable to parse settings file %s", fs::PathToString(path)));
    


    anibilthare commented at 7:42 am on December 29, 2023:

    I agree with @shaavan here . What if we simply modify the error message here and keep rest of the code as is to be more user friendly. Referring to #23096, #22591, and #21340 (comment) as mentioned earlier, following change can be added to the error message

    0        errors.emplace_back(strprintf("Unable to parse settings file %s, the file may be corrupt or empty(Consider deleting the file if it is empty). If the settings file is getting truncated automatically, check if there is suffiecient disk space available.", fs::PathToString(path)));
    

    shaavan commented at 11:39 am on December 29, 2023:
    I see your point here. But wording like this provides a very unclear reason for failure. Don’t you think we would be throwing users in too many directions here?

    anibilthare commented at 12:24 pm on December 29, 2023:

    Can you please point out exactly what part of these statements might confuse the user? Although we’ll be asking the user to check for 2 things in the comment but I believe they are pretty straight forward, right?

    1. Is there any space left on the disk.
    2. Is settings.json empty or not?

    If none of the above conditions hold true and user is still seeing the issue then we are indicating the possibility of corruption of the settings file itself.


    furszy commented at 1:52 pm on December 29, 2023:

    Core does not works for umbrel @1440000bytes, I did not know about umbrel existence until you pointed it out.

    The PR tries to improve a confusing situation reported by users who did not understand why a settings parsing error occurred when the file was empty and did not know how to solve it. Still, I’m no longer in favor of the current approach. And proposed a different path #29144#pullrequestreview-1798109497.

  8. anibilthare changes_requested
  9. shaavan commented at 11:28 am on December 29, 2023: contributor

    I get your point, @furszy, and I can see your approach helping with smoother handling of the “file empty” situation.

    However, pointing back again to ryanofsky comment

    A zero-size settings file is a corrupt settings file.

    The interpretation I draw from this is if a file is empty (and hence corrupted once) there is no telling what could be the reason for that happening or whether such corruption could happen again. So, I believe being very critical and clear with the handling will be better for the following reasons:

    1. For crucial backend software, such as bitcoind, it seems negligent to not properly inform the user that their settings file has been lost to corruption.
    2. It seems to me that a regular user won’t tinker with their settings file regularly, so any kind of auto-generated message in the settings.json file loses its relevance there.
    3. Finally, say a user sets some custom settings once and later loses the settings to corruption (=> file now empty); it seems an improper approach to me for bitcoind to return to default settings without any kind of proper log or error to the user.

    Also, a gentle ping to @ryanofsky to confirm if my interpretation of the situation is correct, and also to get his take on this PR.

  10. kristapsk commented at 11:59 am on December 29, 2023: contributor

    It would probably be useful to introduce support for comments. This way, we can write something at the beginning of the file, ensuring that users and other software developers don’t clean it up manually, thinking that it will be regenerated automatically.

    This will not help if cause was full disk. #21340 (comment)

  11. furszy commented at 12:53 pm on December 29, 2023: member

    I get your point, @furszy, and I can see your approach helping with smoother handling of the “file empty” situation.

    However, pointing back again to ryanofsky comment

    A zero-size settings file is a corrupt settings file.

    The interpretation I draw from this is if a file is empty (and hence corrupted once) there is no telling what could be the reason for that happening or whether such corruption could happen again. So, I believe being very critical and clear with the handling will be better for the following reasons:

    1. For crucial backend software, such as bitcoind, it seems negligent to not properly inform the user that their settings file has been lost to corruption.
    2. It seems to me that a regular user won’t tinker with their settings file regularly, so any kind of auto-generated message in the settings.json file loses its relevance there.
    3. Finally, say a user sets some custom settings once and later loses the settings to corruption (=> file now empty); it seems an improper approach to me for bitcoind to return to default settings without any kind of proper log or error to the user.

    Also, a gentle ping to @ryanofsky to confirm if my interpretation of the situation is correct, and also to get his take on this PR.

    There is no discussion over that. I agreed with all previous arguments against the current implementation since my first comment on this PR. See #29144#pullrequestreview-1797199209.

    Thus I proposed a different solution for non-interactive users who are manually modifying the file. See #29144#pullrequestreview-1798109497. Stating that the file is JSON-formatted and auto-generated gives bitcoind users another hint over what they can and can’t do.

    It would probably be useful to introduce support for comments. This way, we can write something at the beginning of the file, ensuring that users and other software developers don’t clean it up manually, thinking that it will be regenerated automatically.

    This will not help if cause was full disk. #21340 (comment)

    Thats a different problematic @kristapsk. The comments support feature goal is to prevent users’, and/or other third party softwares, manual mistakes. Not OS level corruption issues.

  12. shaavan commented at 8:44 am on January 2, 2024: contributor

    Thus I proposed a different solution for non-interactive users who are manually modifying the file. See #29144#pullrequestreview-1798109497. Stating that the file is JSON-formatted and auto-generated gives bitcoind users another hint over what they can and can’t do.

    I see your point, @furszy

    But I think my points still apply to creating an “auto-generated” file.

    1. A regular user might not tinker with their settings file regularly and hence the “this file is auto-generated” might go unnoticed by the user essentially making the message irrelevant.

    2. If a user had a custom set of settings and later loses them to corruption, they might not know that this has happened for a while if they are not given an “on-the-face” alert. And for critical software such as bitcoind, this seems to me a non-optimal behavior.

    I think it’s a great idea to help the user with an auto-generated file in case of setting loss. But in the absence of an “on-the-face” alert, that change loses much of its significance.

  13. ryanofsky commented at 5:04 pm on January 8, 2024: contributor

    re: 725a1fc7a7dbb1153bec188eda2f17a217560352 I think it is important to treat an empty settings file as an error, because the most likely cause of an empty file is some kind of crash or corruption or disk full state, and it is safer to alert the user about the situation so they can fix it, than proceed as if the error didn’t happen and lose important settings that could affect security or stability.

    I think the error message “Unable to parse settings file %s” could definitely be improved though. Would suggest maybe “Settings file %s does not contain valid JSON. This is probably caused by disk corruption or a crash, and can be fixed by removing the file, which will reset settings to default values.” This would probably work OK for both command line and GUI (since the GUI already offers the option to reset the settings see https://github.com/bitcoin-core/gui/pull/379).

    As far as adding a comments to the settings file, I’m not sure it would necessarily help in the reported case from https://community.umbrel.com/t/bitcoin-docker-container-keeps-restarting/2144, but it probably depends on whatever caused the settings file to be truncated or created empty in that case, and it could be a good idea to add comments to the file regardless. JSON doesn’t have a syntax for comments, it but would be possible to add an extra field like:

    0{
    1  "_comment_": "This file is automatically generated and updated by Bitcoin Core. Please do not edit this file while the node is running, as any changes might be ignored or overwritten."
    2}
    
  14. furszy force-pushed on Jan 9, 2024
  15. furszy commented at 1:30 pm on January 9, 2024: member

    I think the error message “Unable to parse settings file %s” could definitely be improved though. Would suggest maybe “Settings file %s does not contain valid JSON. This is probably caused by disk corruption or a crash, and can be fixed by removing the file, which will reset settings to default values.” This would probably work OK for both command line and GUI (since the GUI already offers the option to reset the settings see bitcoin-core/gui#379).

    As far as adding a comments to the settings file, I’m not sure it would necessarily help in the reported case from https://community.umbrel.com/t/bitcoin-docker-container-keeps-restarting/2144, but it probably depends on whatever caused the settings file to be truncated or created empty in that case, and it could be a good idea to add comments to the file regardless. JSON doesn’t have a syntax for comments, it but would be possible to add an extra field like:

    0{
    1  "_comment_": "This file is automatically generated and updated by Bitcoin Core. Please do not edit this file while the node is running, as any changes might be ignored or overwritten."
    2}
    

    Sounds great. Thanks @ryanofsky! Updated per feedback.

  16. furszy force-pushed on Jan 9, 2024
  17. DrahtBot added the label CI failed on Jan 9, 2024
  18. DrahtBot commented at 1:38 pm on January 9, 2024: contributor

    🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the documentation.

    Possibly this is due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    Leave a comment here, if you need help tracking down a confusing failure.

  19. furszy force-pushed on Jan 9, 2024
  20. furszy commented at 1:45 pm on January 9, 2024: member
    Cool notification. The CI should be happy now.
  21. furszy force-pushed on Jan 9, 2024
  22. DrahtBot removed the label CI failed on Jan 9, 2024
  23. furszy force-pushed on Jan 9, 2024
  24. in test/functional/feature_settings.py:56 in 038c2f0d93 outdated
    52@@ -53,7 +53,7 @@ def run_test(self):
    53         # Test invalid json
    54         with settings.open("w") as fp:
    55             fp.write("invalid json")
    56-        node.assert_start_raises_init_error(expected_msg='Unable to parse settings file', match=ErrorMatch.PARTIAL_REGEX)
    57+        node.assert_start_raises_init_error(expected_msg=f'does not contain valid JSON. This is probably caused by disk corruption or a crash, and can be fixed by removing the file, which will reset settings to default values.', match=ErrorMatch.PARTIAL_REGEX)
    


    ryanofsky commented at 4:58 pm on January 11, 2024:

    In commit “settings: add auto-generated warning msg for editing the file manually” (6f3183e0f0dec375241db96db417aa26e7c3e987)

    Should probably drop f’’ format string prefix, since this doesn’t contain any formatting expressions.


    furszy commented at 10:24 pm on January 11, 2024:
    yeah. Leftover from a previous implementation. I was checking the complete error message, including the settings file path (which was making the Windows CI job angry).
  25. ryanofsky approved
  26. ryanofsky commented at 5:08 pm on January 11, 2024: contributor

    Code review ACK 6f3183e0f0dec375241db96db417aa26e7c3e987. This seems like a helpful change.

    But It does seem unfortunate that both of the commits here make tests more verbose and repetitive. And the tests even before this PR were probably unnecessarily fragile. But I’m not sure I see a better way to write the tests, or a way to avoid the repetition of warning and error messages. If anybody has any ideas on how to improve the tests here, I’d be interested to know.

  27. furszy force-pushed on Jan 11, 2024
  28. in src/qt/test/optiontests.cpp:65 in 634be7d206 outdated
    60@@ -61,7 +61,10 @@ void OptionTests::migrateSettings()
    61     QVERIFY(!settings.contains("addrSeparateProxyTor"));
    62 
    63     std::ifstream file(gArgs.GetDataDirNet() / "settings.json");
    64+    std::string default_warning = strprintf("This file is automatically generated and updated by %s. Please do not edit this file while the node "
    65+                                            "is running, as any changes might be ignored or overwritten.", PACKAGE_NAME);
    


    shaavan commented at 12:56 pm on January 12, 2024:

    Regarding commit 634be7d206b31d34b36de7e62bd216dbbc360195:

    The commit message states:

    “…file unless they are certain about the potential consequences.”

    While this addition is valuable, the subsequent update only advises users against modifying the file while the node is running. Considering this, would it be beneficial to think about revising the commit message to more effectively caution users before they adjust the settings? This would enhance clarity and help users make informed decisions when interacting with the code.


    ryanofsky commented at 1:28 pm on January 12, 2024:
    I think in general it is safe to edit the file, and main thing worth pointing out is when changes might be ignored or overwritten. It’s possible adding more information could be useful, but I don’t think there’s anything clearly missing. The commit message also seems ok and wouldn’t really be an appropriate place to caution users since they are unlikely to see it (in the file itself or in documentation would be better).

    furszy commented at 7:58 pm on January 15, 2024:
    Since the confusion over the empty settings file error is resolved by the first commit. I agree with ryanofsky; while extending the file warning message sounds plausible, I’m also ok with the current warning.
  29. shaavan commented at 12:58 pm on January 12, 2024: contributor

    Thanks for the update, @furszy The new error message and the settings.json warnings are very precise in their details and I believe will be better in guiding the user in case of error, and refraining them from modifying settings without being cautious.

    I just have one suggestion I want to add.

  30. DrahtBot added the label CI failed on Jan 15, 2024
  31. furszy commented at 7:34 pm on January 15, 2024: member

    But It does seem unfortunate that both of the commits here make tests more verbose and repetitive. And the tests even before this PR were probably unnecessarily fragile. But I’m not sure I see a better way to write the tests, or a way to avoid the repetition of warning and error messages. If anybody has any ideas on how to improve the tests here, I’d be interested to know.

    This is not a small change, but.. we could work on a Resources class that is auto-generated during the compile phase. It would store all static error and warning message strings in conjunction with an auto-generated ID for each of them. Allowing us to access messages via their IDs instead of using the strings directly. The ID names could follow a certain layering pattern; e.g. accessing a init error could be: R.getStr(R.errors.init.settings_invalid_json). (similar to how Android organizes app resources).

    Then, to prevent code and string repetition inside functional and unit tests, the Resources class generation script could output C++ and Python compatible code. @ryanofsky, just an idea. Not sure if it worth the efforts.

  32. furszy force-pushed on Jan 21, 2024
  33. furszy commented at 2:26 pm on January 21, 2024: member
    Rebased to cleanup spurious CI failure.
  34. hebasto approved
  35. hebasto commented at 12:07 pm on January 22, 2024: member

    ACK d664eab66ecfa1d318b11de5deafb04b1e3c4c06, tested on Ubuntu 23.10.

    nano-nit: There are some complaints from clang-format-diff.py.

  36. DrahtBot requested review from ryanofsky on Jan 22, 2024
  37. init: improve corrupted/empty settings file error msg
    The preceding "Unable to parse settings file" message lacked
    the necessary detail and guidance for users on what steps to
    take next in order to resolve the startup error.
    
    Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
    966f5de99a
  38. settings: add auto-generated warning msg for editing the file manually
    Hopefully, refraining users from modifying the file unless they are
    certain about the potential consequences.
    
    Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
    e9014042a6
  39. furszy force-pushed on Jan 22, 2024
  40. furszy commented at 1:53 pm on January 22, 2024: member

    nano-nit: There are some complaints from clang-format-diff.py.

    Done.

  41. hebasto approved
  42. hebasto commented at 1:53 pm on January 22, 2024: member
    re-ACK e9014042a6bed8c16cc9a31fc35cb709d4b3c766.
  43. ryanofsky approved
  44. ryanofsky commented at 3:08 pm on January 22, 2024: contributor
    Code review ACK e9014042a6bed8c16cc9a31fc35cb709d4b3c766. Just whitespace formatting changes and shortening a test string literal since last review
  45. DrahtBot removed the label CI failed on Jan 22, 2024
  46. shaavan commented at 12:13 pm on January 23, 2024: contributor

    Code review ACK e9014042a6bed8c16cc9a31fc35cb709d4b3c766

    After our chat in this thread, I believe this PR is good to go!

    There are just a few whitespace tweaks since my last comment, and they look great too.

  47. luke-jr commented at 5:30 pm on January 23, 2024: member
    Should we perhaps add (and recommend, for non-GUI users), a -resetguisettings for non-GUI?
  48. achow101 commented at 8:07 pm on January 23, 2024: member
    ACK e9014042a6bed8c16cc9a31fc35cb709d4b3c766
  49. achow101 merged this on Jan 23, 2024
  50. achow101 closed this on Jan 23, 2024

  51. furszy commented at 8:17 pm on January 23, 2024: member

    Should we perhaps add (and recommend, for non-GUI users), a -resetguisettings for non-GUI?

    Sure. We could introduce a -resetsettings in a follow-up.

  52. furszy deleted the branch on Jan 23, 2024
  53. fanquake commented at 11:11 pm on January 23, 2024: member

    So now we will (always?) log this on startup:

    02024-01-23T22:48:12.205684Z [init] Setting file arg: _warning_ = "This file is automatically generated and updated by Bitcoin Core. Please do not edit this file while the node is running, as any changes might be ignored or overwritten."
    

    Which seems a bit pointless/noisy, and could maybe even be confusing to users?

  54. furszy commented at 0:08 am on January 24, 2024: member

    So now we will (always?) log this on startup:

    02024-01-23T22:48:12.205684Z [init] Setting file arg: _warning_ = "This file is automatically generated and updated by Bitcoin Core. Please do not edit this file while the node is running, as any changes might be ignored or overwritten."
    

    Which seems a bit pointless/noisy, and could maybe even be confusing to users?

    Agree. Good catch. Fixed in #29301.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-07-01 10:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me