New -includeconf argument for including external configuration files #10267

pull kallewoof wants to merge 3 commits into bitcoin:master from kallewoof:feature-config-readconfig changing 11 files +133 −7
  1. kallewoof commented at 1:09 am on April 24, 2017: member

    Fixes: #10071.

    Done:

    • adds -includeconf=<path>, where <path> is relative to datadir or to the path of the file being read, if in a file
    • protects against circular includes
    • updates help docs
    0- ~~~I am not sure how to test this in a neat manner. Feedback on this would be nice. Will dig/think though.~~~
    
  2. kallewoof force-pushed on Apr 24, 2017
  3. jonasschnelli commented at 6:12 am on April 24, 2017: contributor

    Yeah. Why not. This can be useful.

    • I would recommend to use -addconf= (otherwise user may think it replaces the bitcoin.conf configuration file).
    • If I follow GetConfigFile() correctly, you can also use absolut paths, right?
  4. NicolasDorier commented at 7:15 am on April 24, 2017: contributor
    Why not making the existing -config a repeatable argument.
  5. kallewoof commented at 8:00 am on April 24, 2017: member
    @jonasschnelli Good point - will switch to -addconf=. Yes, you can use absolute paths. My worry above is for when a user presumes the path is relative to the config file when it is in fact not. @NicolasDorier I think -config simply tells what name to use and defaults to bitcoin.conf – it doesn’t actually load the file. This feature lets you load other files arbitrarily from within bitcoin.conf.
  6. kallewoof force-pushed on Apr 24, 2017
  7. kallewoof commented at 9:35 am on April 24, 2017: member
  8. laanwj commented at 11:53 am on April 24, 2017: member

    Concept ACK

    My worry above is for when a user presumes the path is relative to the config file when it is in fact not.

    Yes, making it relative to the data directory is a good choice. I think we should handle all relative paths in bitcoind that way.

    Why not making the existing -config a repeatable argument.

    That was also my first thought, but it may just be confusing as it changes the meaning of the option slightly. It’s possible that some setups already use multiple -conf options, and rely on the overriding behavior.

    So I’m good with making it an explicit option. Another suggestion for the name would be -includeconf.

  9. jtimon commented at 4:50 pm on April 24, 2017: contributor
    Concept ACK. Don’t care much about the name, but what about -extraconf ?
  10. kallewoof commented at 1:47 am on April 25, 2017: member

    From the given suggestions I think includeconf is the most clear so I’ll switch to that. @laanwj:

    Yes, making it relative to the data directory is a good choice. I think we should handle all relative paths in bitcoind that way.

    To clarify, you mean that the relative path inside /dir/file.conf should be /dir/, not [bitcoin datadir], right? It will require some lines of code I bet but I think that makes sense too.

  11. kallewoof force-pushed on Apr 25, 2017
  12. kallewoof commented at 3:00 am on April 25, 2017: member

    The includeconf feature now defines the path relative to the file being read, if any. For command line, it is [datadir], for /dir/abc.conf it is /dir/. I tested this with

    0src/testreadconfig/bitcoin.conf: [...] includeconf=../global.conf
    1src/global.conf: includeconf=secrets.conf
    2src/secrets.conf: rpcpassword=foo
    

    with bitcoind -datadir=testreadconfig. Ensured bitcoin-cli with password foo worked and password bar did not.

    […]: → 5⊱16⊱2

  13. kallewoof renamed this:
    New -readconfig argument for including external configuration files
    New -includeconf argument for including external configuration files
    on Apr 25, 2017
  14. laanwj commented at 5:14 am on April 25, 2017: member

    To clarify, you mean that the relative path inside /dir/file.conf should be /dir/, not [bitcoin datadir], right? It > will require some lines of code I bet but I think that makes sense too.

    Yes, seems good to me too. So it’s like C’s include "" - I wasn’t thinking about relative includes in other includes.

  15. kallewoof force-pushed on Apr 25, 2017
  16. kallewoof force-pushed on Apr 25, 2017
  17. kallewoof commented at 7:34 am on April 25, 2017: member
    To clarify, the code now does what @laanwj suggested.
  18. laanwj added the label RPC/REST/ZMQ on Apr 25, 2017
  19. laanwj commented at 11:59 am on May 1, 2017: member

    I am not sure how to test this in a neat manner. Feedback on this would be nice. Will dig/think though.

    Some ideas:

    • RPC test that creates a tree of bitcoin config files including each other beneath the data directory
    • Starts a node w/ -includeconf=<path>
    • Then interrogate node over RPC to verify the files got included, in the right order

    To achieve the latter the option uacomment= is useful, as these will be added to an array, then querying getnetworkinfo to see if the (...) part of the subversion matches expected content and order.

  20. jnewbery commented at 9:43 pm on May 1, 2017: member
    @laanwj’s suggested test method seems sensible. I’m happy to review that or lend a hand implementing it. Feel free to reach me on IRC.
  21. kallewoof commented at 1:28 am on May 2, 2017: member

    Thanks for the suggestion! I added a test that checks for load order and ensures circular include is guarded against. @jnewbery review would be wonderful :)

    Edit: If anyone has ideas why travis is failing I’d appreciate it. It works fine on all the machines I test it on locally (mac, linux).

  22. kallewoof force-pushed on May 2, 2017
  23. kallewoof force-pushed on May 2, 2017
  24. jnewbery commented at 3:33 pm on May 2, 2017: member

    If anyone has ideas why travis is failing I’d appreciate it

    You’ve made ReadConfigFile() recursive (through ProcessSetting()). ReadConfigFile() locks cs_args, and then at the end calls ClearDatadirCache(), which locks csPathCached. That means that the bottom-most ReadConfigFile() locks csPathCached while cs_args is still held.

    There’s already a function that locks in the other order: GetDataDir() locks csPathCached and then locks cs_args (in its call to IsArgSet()).

    If those two functions are called in different threads, we’d have a deadlock.

    There’s a CPP_FLAG option that checks lock ordering CPPFLAGS=-DDEBUG_LOCKORDER, which is used in Travis build 5. That’s why that build is failing. You can repro locally by running configure with that option.

    You can fix this by not locking cs_args recursively.

  25. kallewoof force-pushed on May 8, 2017
  26. kallewoof force-pushed on May 8, 2017
  27. kallewoof commented at 4:02 am on May 8, 2017: member

    @jnewbery Thanks a lot for the explanation! I should’ve paid closer attention to locks considering the added recursiveness.

    97ee63b fixes this by moving the conditionally-locked code into a new ReadConfigStream function which is called with locking/clearing in one case and without in the other, based on a bool lockAndClear added to ReadConfigFile.

    (Also had to tweak tests a tiny bit; 8fb6511.)

  28. jnewbery commented at 7:57 pm on May 15, 2017: member

    I think you’ve introduced a subtle bug here. If -datadir is configured in one of the additional config files, then the datadir cache won’t be cleared, which means that bitcoind will continue to use the old datadir.

    I think you should try to not make ReadConfigFile recursive. For me, it would be acceptable to only allow one level of redirection here (ie the “base” config file can specify -includeconf config file, but those included config files cannot themselves include other config files). I think that would be a simpler model and would remove a whole bunch of potential bugs (circular references, blowing the stack through too many -includeconf redirects, etc).

  29. kallewoof commented at 0:54 am on May 16, 2017: member

    @jnewbery Hm, no the datadir cache is cleared after any recursions happen, which means it is always cleared, just not directly after the config file has been parsed. There are two cases:

    1. ParseParameters (util.cpp:407 called from bitcoind.cpp:75) – this will work as normal and does not require cache clearing.
    2. Nested ReadConfigs from the initial bitcoin.conf file: bitcoind:107 calls ReadConfigFile with the lockAndClear flag set; recursion then happens in ProcessSetting (L401) via ReadConfigStream (L622) with lockAndClear unset. Eventually this gets back to original caller which leaves ReadConfigStream and gets to util.cpp:649 which clears the datadir cache. Or am I missing something?

    As for forbidding multiple levels of recursion, I think the value outweighs the issues personally (and I addressed circular refs I believe), but if people think it’s not worth it I’ll restrict it to one include.

  30. kallewoof force-pushed on May 16, 2017
  31. jnewbery commented at 3:00 pm on May 16, 2017: member

    @kallewoof yes you’re right. datadir cache is cleared after all files are read. My mistake.

    I still don’t like the recursion and the fact that there can be multiple levels of imports. It means there are more edge cases and unexpected behaviour. For example, if -includeconf is included as a command line parameter, then the includeconf file is read before the regular conf file, and so takes precedence. If an includeconf line is included in the regular conf file, then it is read during the regular config file, and which settings are taken from the regular conf file and which are taken from the includeconf file depend on the ordering of settings in the regular conf file.

    The new warnOnFailure and lockAndClear bool arguments to ReadConfigFile() seem pretty strange to me. They’re only used when ReadConfigFile() is being called recursively, and they control a large chunk of the behaviour within ReadConfigFile(). That’s a clue to me that maybe the functionality isn’t split up correctly - perhaps the locking/clearing should be in an outer function which calls an inner function for each of the config files?

    Finally, you’ve introduced a new crash bug. If -conf or -includeconf don’t refer to a valid file, the bitcoind will crash on startup. Here’s the backtrace:

     0Core was generated by `bitcoind -datadir=/tmp/user/1000/test6p7xn_xt/856/node0 -server -keypool=1 -dis'.
     1Program terminated with signal SIGABRT, Aborted.
     2[#0](/bitcoin-bitcoin/0/)  0x00007f3b77df0428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
     354	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
     4(gdb) bt
     5[#0](/bitcoin-bitcoin/0/)  0x00007f3b77df0428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
     6[#1](/bitcoin-bitcoin/1/)  0x00007f3b77df202a in __GI_abort () at abort.c:89
     7[#2](/bitcoin-bitcoin/2/)  0x00007f3b7873284d in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
     8[#3](/bitcoin-bitcoin/3/)  0x00007f3b787306b6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
     9[#4](/bitcoin-bitcoin/4/)  0x00007f3b78730701 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
    10[#5](/bitcoin-bitcoin/5/)  0x00007f3b78730919 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
    11[#6](/bitcoin-bitcoin/6/)  0x00007f3b79f29f82 in boost::filesystem::detail::canonical(boost::filesystem::path const&, boost::filesystem::path const&, boost::system::error_code*) () from /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.58.0
    12[#7](/bitcoin-bitcoin/7/)  0x000055e5c58b2ae2 in boost::filesystem::canonical (base=..., p=...) at /usr/include/boost/filesystem/operations.hpp:459
    13[#8](/bitcoin-bitcoin/8/)  GetConfigFile (confPath="global.conf", relativePath="") at util.cpp:603
    14[#9](/bitcoin-bitcoin/9/)  0x000055e5c58b4353 in ArgsManager::ProcessSetting (this=this@entry=0x55e5c5db1fa0 <gArgs>, strKey="-includeconf", strValue="global.conf", relativePath="") at util.cpp:386
    15[#10](/bitcoin-bitcoin/10/) 0x000055e5c58b487d in ArgsManager::ParseParameters (this=0x55e5c5db1fa0 <gArgs>, argc=<optimized out>, argv=<optimized out>) at util.cpp:424
    16[#11](/bitcoin-bitcoin/11/) 0x000055e5c5653d4a in ParseParameters (argv=0x7fff5492e618, argc=14) at util.h:263
    17[#12](/bitcoin-bitcoin/12/) AppInit (argc=14, argv=0x7fff5492e618) at bitcoind.cpp:75
    18[#13](/bitcoin-bitcoin/13/) 0x000055e5c5648bef in main (argc=14, argv=0x7fff5492e618) at bitcoind.cpp:196
    19(gdb) quit
    

    If I use an invalid filename for -conf on master. I don’t see this crash.

  32. kallewoof commented at 2:22 am on May 17, 2017: member

    @jnewbery Thanks a lot for all the feedback.

    I still don’t like the recursion and the fact that there can be multiple levels of imports. It means there are more edge cases and unexpected behaviour. For example, if -includeconf is included as a command line parameter, then the includeconf file is read before the regular conf file, and so takes precedence. If an includeconf line is included in the regular conf file, then it is read during the regular config file, and which settings are taken from the regular conf file and which are taken from the includeconf file depend on the ordering of settings in the regular conf file.

    That is the case without recursion as well, unless we forbid command line case. (Which I can do already, even while keeping recursion.)

    The new warnOnFailure and lockAndClear bool arguments to ReadConfigFile() seem pretty strange to me. They’re only used when ReadConfigFile() is being called recursively, and they control a large chunk of the behaviour within ReadConfigFile(). That’s a clue to me that maybe the functionality isn’t split up correctly - perhaps the locking/clearing should be in an outer function which calls an inner function for each of the config files?

    Hm.. the warnOnFailure was just a nice-to-have to inform the user when an explicitly included file didn’t actually exist, but I can remove it for cleanliness. Since I moved most of ReadConfigFile into ReadConfigStream, the only remaining stuff was the caching stuff, which doesn’t feel odd to me. I’m not actually sure why you consider this to be a problem: the ReadConfigFile is mostly there to do or not do the locking and data cache clearing, and the ReadConfigStream is there to do the actual reading/parsing part.

    That said, I’m not overly attached to the idea of allowing recursion, so unless someone speaks for it I am going to try to simplify the code to only allow one single include and to only allow it in the file, i.e. not from command line. I believe that would address most of your concerns.

    Edit: Oh, and thanks for finding the crash – I was sure I tested that, but I guess not.

    Edit 2: Yeah, I never tested the case where the path was not a valid path, only when it was a non-existent one.

  33. kallewoof force-pushed on May 17, 2017
  34. kallewoof force-pushed on May 17, 2017
  35. in src/util.cpp:612 in 9c20870eae outdated
    607+        }
    608+        mapMultiArgs[strKey].push_back(strValue);
    609+    }
    610+}
    611+
    612 void ArgsManager::ReadConfigFile(const std::string& confPath)
    


    jnewbery commented at 7:52 pm on May 31, 2017:

    I think it’d be clearer to rename this to ReadConfigFiles(). You could remove the confPath argument since it’s a property of the ArgsManager class. The three places where this is called can just call gArgs.ReadConfigFiles().

    The responsibilities of this function then becomes very clear: read all the config files.


    kallewoof commented at 3:27 am on June 1, 2017:
    Done!
  36. in src/util.cpp:595 in 9c20870eae outdated
    591@@ -592,26 +592,41 @@ fs::path GetConfigFile(const std::string& confPath)
    592     return pathConfigFile;
    593 }
    594 
    595+void ArgsManager::ReadConfigStream(fs::ifstream& streamConfig)
    


    jnewbery commented at 7:53 pm on May 31, 2017:
    I’d prefer to name this function ReadConfigFile(). At the moment, the only type of input it can read is a file, so naming it ReadInputStream() is a little misleading.

    kallewoof commented at 3:26 am on June 1, 2017:
    I named if for the fact it got anifstream as argument, but you’re right that it’s probably better to just name it ReadConfigFile.
  37. in src/util.cpp:670 in 9c20870eae outdated
    634+        if (mapArgs.count("-includeconf")) includeconf = mapArgs["-includeconf"];
    635+    }
    636+    if (includeconf != "") {
    637+        fs::path includeFile = GetConfigFile(includeconf);
    638+        fs::ifstream includeConfig(includeFile);
    639+        if (includeConfig.good()) {
    


    jnewbery commented at 8:02 pm on May 31, 2017:
    Can we have an else clause that prints an error message if we fail to open an includeconfig file?
  38. in src/util.cpp:625 in 9c20870eae outdated
    632-            mapMultiArgs[strKey].push_back(strValue);
    633+        ReadConfigStream(streamConfig);
    634+        if (mapArgs.count("-includeconf")) includeconf = mapArgs["-includeconf"];
    635+    }
    636+    if (includeconf != "") {
    637+        fs::path includeFile = GetConfigFile(includeconf);
    


    jnewbery commented at 8:02 pm on May 31, 2017:

    Why not directly:

    0fs::ifstream includeConfig(GetConfigFile(includeconf));
    

    (like above)

  39. in src/util.cpp:705 in 9c20870eae outdated
    591@@ -592,26 +592,41 @@ fs::path GetConfigFile(const std::string& confPath)
    592     return pathConfigFile;
    593 }
    594 
    595+void ArgsManager::ReadConfigStream(fs::ifstream& streamConfig)
    596+{
    597+    std::set<std::string> setOptions;
    


    jnewbery commented at 8:04 pm on May 31, 2017:

    Is it possible to add a log to this function to output which file it’s reading, or is it too early to start logging?

    Sorry - by my earlier comment, I didn’t mean you should remove the logging on failure, just that the structure of the function suggested to me that it shouldn’t be called recursively.


    kallewoof commented at 3:27 am on June 1, 2017:
    I am logging before the call to this method now. That should cover it I think.
  40. in test/functional/includeconf.py:27 in 9c20870eae outdated
    22+    def __init__(self):
    23+        super().__init__()
    24+        self.setup_clean_chain = False
    25+        self.num_nodes = 1
    26+
    27+    def setup_network(self):
    


    jnewbery commented at 8:08 pm on May 31, 2017:
    not required. setup_network() in the base class just calls setup_nodes() when there’s only one node.
  41. in test/functional/includeconf.py:30 in 9c20870eae outdated
    25+        self.num_nodes = 1
    26+
    27+    def setup_network(self):
    28+        self.setup_nodes()
    29+
    30+    def run_test (self):
    


    jnewbery commented at 8:08 pm on May 31, 2017:
    no space before open parentheses please.
  42. in test/functional/includeconf.py:16 in 9c20870eae outdated
    11+
    12+    def setup_chain(self):
    13+        super().setup_chain()
    14+        # Create additional config file
    15+        # - tmpdir/node0/relative.conf
    16+        with open(os.path.join(self.options.tmpdir+"/node0", "relative.conf"), "w", encoding="utf8") as f:
    


    jnewbery commented at 8:08 pm on May 31, 2017:
    nit: spaces around + please
  43. in test/functional/includeconf.py:31 in 9c20870eae outdated
    26+
    27+    def setup_network(self):
    28+        self.setup_nodes()
    29+
    30+    def run_test (self):
    31+        '''
    


    jnewbery commented at 8:09 pm on May 31, 2017:
    My personal preference is to have the description of the test in the module-level doc string (since that’s the first thing people see when they open the file).
  44. in test/functional/includeconf.py:1 in 9c20870eae outdated
    0@@ -0,0 +1,43 @@
    1+#!/usr/bin/env python3
    


    jnewbery commented at 8:10 pm on May 31, 2017:

    It’d be nice to have a couple of other subtests:

    • including --includeconf in the command line argument has no effect
    • including includeconf in an includeconf file has no effect.

    kallewoof commented at 3:29 am on June 1, 2017:
    I’m not sure what a neat and tidy way to test that would look like. Should I just make multiple classes, one for each, and then call them one at a time in the bottom if __name__ == '__main__':?

    jnewbery commented at 1:55 pm on June 1, 2017:

    These don’t actually need to be separate tests. You can just have the following in setup_chain():

    0        with open(os.path.join(self.options.tmpdir + "/node0", "relative.conf"), "w", encoding="utf8") as f:
    1            f.write("uacomment=relative\nincludeconf=relativeofrelative.conf\n")
    2        with open(os.path.join(self.options.tmpdir + "/node0", "bitcoin.conf"), 'a', encoding='utf8') as f:
    3            f.write("uacomment=main\nincludeconf=relative.conf\n")
    4        with open(os.path.join(self.options.tmpdir + "/node0", "commandline.conf"), "w", encoding="utf8") as f:
    5            f.write("uacomment=commandline\n")
    6        with open(os.path.join(self.options.tmpdir + "/node0", "relativeofrelative.conf"), "w", encoding="utf8") as f:
    7            f.write("uacomment=relativeofrelative\n")
    

    and the following line in __init__():

    0        self.extra_args = [['-includeconf=commandline.conf']]
    

    and then keep the same assert:

    0        assert subversion.endswith("main; relative)/")
    

    to check that neither comandline.conf nor relativeofrelative.conf have been included.

    (I recommend you also update the docstring to describe what’s happening)

  45. jnewbery commented at 8:27 pm on May 31, 2017: member

    This looks much much better. Thanks @kallewoof! I much prefer this implementation, which restricts the way --includeconf can be used and cuts out lots of edge cases.

    If it turns out that people need more flexibility, we can extend this later to allow multiple includeconfs, including multiple levels. That’s much easier than going the other way (from less restrictive to more restrictive).

    I have a few nits, mainly around naming.

    I think there’s one bug, or at least confusing behaviour. You said in your comment that you don’t allow -includeconf from the command line, but your new code is allowing that. Further, if an -includeconf is included on the command line and in the base config file, then the command line -importconf takes precedence. I don’t think that’s what we want. To fix that, I think the first thing ReadConfigFile() should do clear the -includeconf argument if it’s set.

  46. kallewoof force-pushed on Jun 1, 2017
  47. kallewoof commented at 5:45 am on June 1, 2017: member
    Updated and squashed. Unsquashed history.
  48. jnewbery commented at 1:56 pm on June 1, 2017: member

    Looks great. Tested ACK bc4f7a4b3f614dc2125c6af60da448606b622688

    One suggestion for adding to the testcase. Up to you whether you want to take it.

  49. jtimon commented at 2:32 pm on June 1, 2017: contributor

    This conflicts a little bit with https://github.com/bitcoin/bitcoin/pull/8994/commits/7246faea3e4421e609e6a24294bd23a45d2343de

    There I use the old ArgsManager::ReadConfigFile(path) which this PR remove. Could you conserve that method even if it’s temporarily unused (although preferrably using it internally like “ArgsManager::ReadConfigFile(fs::ifstream& streamConfig)”)?

    0void ArgsManager::ReadConfigFile(const std::string& confPath)
    1{
    2     fs::ifstream streamConfig(GetConfigFile(confPath));
    3      if (!streamConfig.good())
    4          return; // No bitcoin.conf file is OK
    5// ...
    6}
    

    Or perhaps I should restore it later if this PR gets merged first. utACK bc4f7a4b3f614dc2125c6af60da448606b622688 beyond that.

  50. in src/util.cpp:756 in 7a062e7f08 outdated
    650+            ReadConfigFile(includeConfig);
    651+        } else {
    652+            LogPrintf("Failed to include configuration file %s\n", includeconf.c_str());
    653         }
    654     }
    655     // If datadir is changed in .conf file:
    


    jtimon commented at 2:34 pm on June 1, 2017:
    Shouldn’t ClearDatadirCache() be called from ArgsManager::ReadConfigFile(fs::ifstream& streamConfig) ?

    kallewoof commented at 0:05 am on June 5, 2017:
    ReadConfigFile is only called from ReadConfigFiles, which clears the data cache already, so it should be fine I think.

    jtimon commented at 6:50 pm on June 5, 2017:
    Yes, unless you conserve a ArgsManager::ReadConfigFile(const std::string& confPath), then that will presumably call call ArgsManager::ReadConfigFile(fs::ifstream& streamConfig too.
  51. kallewoof commented at 0:06 am on June 5, 2017: member
    @jtimon The method was not removed, it was renamed. If you change to ReadConfigFiles you should get the exact same result after this is merged. Let me know if that is not the case!
  52. jtimon commented at 7:01 pm on June 5, 2017: contributor
    The method that is removed is the one that allows you to call with a path, ArgsManager::ReadConfigFile(const std::string& confPath). The new ReadConfigFiles() will work just fine here, but in #8994 I cannot use it, because want I want is precisely to load from a different file (and not allow -includeconf or command line for “custom chainparams” configuration). If I use AgsManager::ReadConfigFile(fs::ifstream& streamConfig) directly from chainparams.cpp, not only I will duplicate code, but also call things like GetConfigFile(), which I would prefer not to call from chainparams.cpp. So my conclusion is that I would just restore ArgsManager::ReadConfigFile(const std::string& confPath). That’s why I ask that you maintain it even if you don’t need it for anything (but it can also be removed and then restored, it’s not a big deal)
  53. kallewoof commented at 0:35 am on June 6, 2017: member
    Ohh, damn… It seems the removal of the path may have been premature. What do you think of ReadConfigFiles()ReadConfigFiles(std::string path = "", bool allowIncludes = true) whose default does exactly what ReadConfigFiles does now? @jtimon @jnewbery
  54. jnewbery commented at 5:14 pm on June 6, 2017: member
    I think ReadConfigFiles() shouldn’t take any arguments and should be responsible for finding and reading all config files. I don’t understand why you’d want to read config files from other places in the codebase in #8994. It seems to me to be much simpler to reason about what config is loaded if it all happens in one place.
  55. jtimon commented at 11:53 pm on June 6, 2017: contributor
    @kallewoof yeah, I think that would work too, and you could still call it without parameters. That solution is very simple for me to “restore” on #8994 if people don’t like it here. There’s no need to slow this down if other people don’t like my request. Thank you for offering a good and simple solution to my concern. @jnewbery I don’t want the chain custom parameters to be perceived as “config”. They select the chain you will be on, it is mostly intended to create new testnets, and sharing a “testnet config file” for a newly created one could be a useful thing. But perhaps that’s something to discuss on #8994 rather than here. I still have it on a separated commit in case people prefer to allow consensus critical parameters to be passed from command line or the other config files that con be loaded.
  56. jnewbery commented at 9:12 pm on June 14, 2017: member

    @jtimon

    I don’t want the chain custom parameters to be perceived as “config”.

    I actually think having the customchain config file contain general config could be useful. There seemed to be some enthusiasm for #9374 , which is similar in nature - it allows a separate config file for each separate chain.

    This is a bit of a sidetrack from this PR though, which I think is a good and useful improvement. This needs rebasing because of a conflict in test_runner.py. Assuming just that needs changing, then I still ACK this. I’ll give some more feedback in #9374.

  57. jnewbery commented at 9:30 pm on June 14, 2017: member

    alternative: this PR could move the:

    0fs::ifstream streamConfig(GetConfigFile(confPath));
    1if (!streamConfig.good())
    

    lines into the new ReadConfigFile() function instead of leaving them in ReadConfigFiles(), and have ReadConfigFile() take a std::string instead of a fs::ifstream&. That would remove some code duplication (since that’s called for both the ‘base’ config file and the -includeconf file).

    #9374 could then call ReadConfigFile() exactly as before.

  58. kallewoof force-pushed on Jun 15, 2017
  59. kallewoof commented at 3:44 am on June 15, 2017: member

    @jnewbery I would need to either change the return value to be a success flag for streamConfig.good(), or add an additional bool warnOnFailure flag, like I had before, as we currently don’t warn for the main config missing, but we do warn for includeconfs.

    Rebased, btw.

  60. kallewoof force-pushed on Jul 14, 2017
  61. laanwj assigned laanwj on Aug 10, 2017
  62. jnewbery commented at 6:14 pm on August 14, 2017: member

    Required rebase after gArgs PR #10607. I’ve rebased here: https://github.com/jnewbery/bitcoin/tree/pr10267

    I’ve also implemented my suggested change to make ReadConfigFile take a std::string here: https://github.com/jnewbery/bitcoin/tree/pr10267.1. @kallewoof - can you let me know what you think? I think this resolves @jtimon’s concerns so this doesn’t conflict badly with his PR.

  63. kallewoof force-pushed on Aug 15, 2017
  64. kallewoof commented at 3:12 am on August 15, 2017: member
    @jnewbery Looks great! I rebased and adopted your changes. I tried to pull your commits into my branch but things exploded. Sorry about that. :/ Will squash if you think ca507fc looks OK. (I picked slightly different varnames from you – any reason for using snake case? I don’t see it used elsewhere.)
  65. kallewoof force-pushed on Aug 15, 2017
  66. jnewbery commented at 2:09 pm on August 15, 2017: member

    @kallewoof - no problem. My branch was just an example. Feel free to do whatever you want with it. (for future reference if you want to take the commits from my branch, easiest way is to add github.com/jnewbery/bitcoin as a remote, then git fetch from my remote, then git reset --hard <sha of my branch> from your branch).

    For snake case convention, see ‘symbol naming conventions’ here: https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md#developer-notes . No need to change old code to use the conventions, but new PRs should follow them if possible.

  67. kallewoof commented at 5:12 am on August 16, 2017: member

    @jnewbery That’s what I did, but when I tried rebasing master on top of it things exploded. I’ll try again.

    As for the symbol naming convention, I’m amazed I didn’t catch that considering I’m a big fan of conventions myself. Will definitely start using it. The m_foo thing for class member vars looks ugly as hell to me, but ah well.

    Edit: worked fine this time. Must’ve fatfingered something. Thanks!

  68. kallewoof force-pushed on Aug 16, 2017
  69. kallewoof commented at 9:14 am on August 16, 2017: member

    @jnewbery Digging, but:

    0POTENTIAL DEADLOCK DETECTED
    1Previous lock order was:
    2 (1) cs_args  util.cpp:628
    3 (2) csPathCached  util.cpp:558
    4Current lock order is:
    5 (2) csPathCached  util.cpp:558
    6 (1) cs_args  util.cpp:432
    7Assertion failed: (false), function potential_deadlock_detected, file sync.cpp, line 98.
    

    It looks like there are two paths that may end up in a deadlock:

    1. First:
      • ReadConfigFiles() [locks cs_args]
      • ReadConfigFile(conf_path)
      • GetConfigFile(conf_path)
      • GetDataDir(false) [locks csPathCached]
      • gArgs.IsArgSet("-datadir") [locks cs_args]
    2. Second:
      • GetDataDir(_) [locks csPathCached]
      • gArgs.IsArgSet("-datadir") [locks cs_args]

    Path 1 will lock cs_args, then csPathCached, and path 2 will lock csPathCached, then cs_args. I’m not sure the effect of path 1 locking cs_args twice. Perhaps it’s a NOP when already locked, but in either case, this seems to be the issue.

    I’ve reset to the original version (rebased) for now as I can’t figure this one out right now.

  70. kallewoof force-pushed on Aug 16, 2017
  71. kallewoof force-pushed on Sep 28, 2017
  72. kallewoof force-pushed on Sep 28, 2017
  73. kallewoof force-pushed on Oct 11, 2017
  74. promag commented at 12:08 pm on November 23, 2017: member
    Needs rebase. Is this still valid?
  75. kallewoof force-pushed on Nov 24, 2017
  76. kallewoof commented at 4:20 am on November 24, 2017: member
    Rebased. It is valid, yes.
  77. kallewoof force-pushed on Dec 5, 2017
  78. meshcollider commented at 10:40 am on December 11, 2017: contributor
    Concept ACK N.B. this could be very useful in the context of #11862, using -regtest.includeconf for example
  79. kallewoof force-pushed on Dec 12, 2017
  80. kallewoof force-pushed on Jan 9, 2018
  81. kallewoof force-pushed on Jan 25, 2018
  82. kallewoof commented at 8:16 am on February 23, 2018: member
    @laanwj Ping (since you self-assigned)
  83. in doc/man/bitcoin-qt.1:47 in fd1ad5936d outdated
    43@@ -44,6 +44,10 @@ Specify configuration file (default: bitcoin.conf)
    44 .IP
    45 Specify data directory
    46 .HP
    47+\fB\-includeconf=\fR<dir>
    


    jnewbery commented at 2:51 pm on March 20, 2018:
    No need to update this file.
  84. in doc/man/bitcoind.1:52 in fd1ad5936d outdated
    48@@ -49,6 +49,10 @@ Run in the background as a daemon and accept commands
    49 .IP
    50 Specify data directory
    51 .HP
    52+\fB\-includeconf=\fR<dir>
    


    jnewbery commented at 2:51 pm on March 20, 2018:
    No need to update this file.
  85. in src/qt/bitcoinstrings.cpp:385 in fd1ad5936d outdated
    381@@ -382,6 +382,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" is not a director
    382 QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: %s)"),
    383 QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout in milliseconds (minimum: 1, default: %d)"),
    384 QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory"),
    385+QT_TRANSLATE_NOOP("bitcoin-core", "Specify additional configuration file, relative to the -datadir path"),
    


    jnewbery commented at 2:51 pm on March 20, 2018:
    No need to update this file.
  86. in src/init.cpp:361 in fd1ad5936d outdated
    337@@ -338,6 +338,7 @@ std::string HelpMessage(HelpMessageMode mode)
    338     if (showDebug) {
    339         strUsage += HelpMessageOpt("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize));
    340     }
    341+    strUsage += HelpMessageOpt("-includeconf=<file>", _("Specify additional configuration file, relative to the -datadir path"));
    


    jnewbery commented at 2:53 pm on March 20, 2018:
    This should be the only change in your second commit. I recommend just squashing it with the first commit.

    kallewoof commented at 4:00 am on March 23, 2018:
    Oh, coolness.
  87. in src/util.cpp:665 in fd1ad5936d outdated
    673-            InterpretNegativeSetting(strKey, strValue);
    674-            if (mapArgs.count(strKey) == 0)
    675-                mapArgs[strKey] = strValue;
    676-            mapMultiArgs[strKey].push_back(strValue);
    677+        ReadConfigFile(streamConfig);
    678+        if (mapArgs.count("-includeconf")) includeconf = mapArgs["-includeconf"];
    


    jnewbery commented at 3:27 pm on March 20, 2018:
    I think it’d be useful to be able to include multiple -includeconf arguments in the main config file (for example, if we want a main.includeconf, test.includeconf and regtest.includeconf). Can you make this a string vector and then iterate through the includeconfs?

    kallewoof commented at 4:01 am on March 23, 2018:
    That makes sense, yeah.
  88. in test/functional/includeconf.py:1 in fd1ad5936d outdated
    0@@ -0,0 +1,38 @@
    1+#!/usr/bin/env python3
    


    jnewbery commented at 3:30 pm on March 20, 2018:
    This test now needs to be named feature_includeconf
  89. jnewbery commented at 3:31 pm on March 20, 2018: member

    A few comments inline.

    I suggest you squash commits 1 and 2 (and please remove the # from the commit message!)

    I’ve made some suggested changes to the functional test here: https://github.com/jnewbery/bitcoin/commit/968c9158f0bffac8c91282f1789a5a1808ed13b9 . Feel free to take any of the code you want and squash into your commit.

    Needs release notes.

  90. kallewoof commented at 4:30 am on March 23, 2018: member

    @jnewbery Thanks a lot for review / code suggestions. I’ll add multiple includeconf support and then push updated code.

    Edit: I put some comments on your commit, and made the changes on my end.

  91. kallewoof force-pushed on Mar 23, 2018
  92. kallewoof force-pushed on Mar 23, 2018
  93. kallewoof force-pushed on Mar 23, 2018
  94. kallewoof commented at 8:09 am on March 23, 2018: member
    This PR times out on job 2 without the timeout bump in 47848d0. I have not investigated the cause for this increase, and I find it unlikely that the new tests would be the actual cause.
  95. jnewbery commented at 7:10 pm on March 23, 2018: member

    The travis job is timing out when running make check (the unit tests):

    0$ if [ "$RUN_TESTS" = "true" ]; then travis_wait 40 make $MAKEJOBS check VERBOSE=1; fi    1913.41s
    

    Here’s the end of the output from that command:

    0make[1]: Leaving directory `/home/travis/build/bitcoin/bitcoin/build/bitcoin-i686-w64-mingw32'
    1/home/travis/.travis/job_stages: line 169: 28077 Terminated              travis_jigger $! $timeout $cmd
    

    @MarcoFalke / @laanwj - any idea why the unit tests would stall for half an hour here?

  96. ryanofsky commented at 7:26 pm on March 23, 2018: member

    @MarcoFalke / @laanwj - any idea why the unit tests would stall for half an hour here?

    Something must have changed recently, but I think one reason why tests are slow is that they are running using wine to emulate windows. I’m also seeing the same timeouts with 11851.

  97. in test/functional/feature_includeconf.py:15 in 47848d0fb0 outdated
    10+   file to be loaded in the correct order.
    11+2. includeconf cannot be used as a command line argument.
    12+3. includeconf cannot be used recursively (ie includeconf can only
    13+   be used from the base config file).
    14+4. multiple includeconf arguments can be specified in the main config
    15+   file (Currently fails).
    


    jnewbery commented at 7:29 pm on March 23, 2018:
    Can remove (Currently fails)

    kallewoof commented at 3:30 am on March 24, 2018:
    Thanks, fixed.
  98. jnewbery commented at 7:30 pm on March 23, 2018: member
    utACK 47848d0fb0705facd7d4cf24c50d450386155f5a (although I’ll defer to @MarcoFalke on whether the travis timeout bump is a good idea)
  99. MarcoFalke commented at 7:33 pm on March 23, 2018: member

    I am fine with bumping to 40 or 50 minutes. In case we need that much time, it will time out due to the global limit anyway. The long term solution would be to somehow speed up the unit tests on Wine, but that doesn’t have to block this (and other) pull requests.

    Could cherry-pick that change to a separate pull request, though.

  100. jnewbery commented at 8:00 pm on March 23, 2018: member

    Could cherry-pick that change to a separate pull request, though.

    Here you go: #12772

  101. kallewoof force-pushed on Mar 24, 2018
  102. kallewoof force-pushed on Mar 24, 2018
  103. kallewoof force-pushed on Apr 9, 2018
  104. kallewoof force-pushed on Apr 11, 2018
  105. jnewbery commented at 7:11 pm on April 16, 2018: member

    #11862 is merged. Please rebase.

    I’ll commit to re-reviewing this once it’s rebased.

  106. kallewoof force-pushed on Apr 17, 2018
  107. kallewoof commented at 4:40 am on April 17, 2018: member
    Edit: resolved. I am now checking both "-includeconf" and "-" + GetChainName() + ".includeconf" explicitly.
  108. kallewoof force-pushed on Apr 17, 2018
  109. in src/init.cpp:361 in d46656f6b8 outdated
    357@@ -358,6 +358,7 @@ std::string HelpMessage(HelpMessageMode mode)
    358     if (showDebug) {
    359         strUsage += HelpMessageOpt("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize));
    360     }
    361+    strUsage += HelpMessageOpt("-includeconf=<file>", _("Specify additional configuration file, relative to the -datadir path"));
    


    jnewbery commented at 8:08 pm on April 17, 2018:
    Help text could be expanded a bit to say that this can’t be set from the command line - only from within the .conf file.

    kallewoof commented at 0:52 am on April 18, 2018:
    I thought I had done that already. Fixing.

    kallewoof commented at 1:04 am on April 18, 2018:
    Updated. Feedback welcome!
  110. in src/util.cpp:974 in d46656f6b8 outdated
    961     // ok to not have a config file
    962     if (stream.good()) {
    963         ReadConfigStream(stream);
    964+        std::vector<std::string> includeconf(GetArgs("-includeconf"));
    965+        {
    966+            std::vector<std::string> includeconf_net(GetArgs(std::string("-") + GetChainName() + ".includeconf"));
    


    jnewbery commented at 8:58 pm on April 17, 2018:

    I was going to say that this isn’t required because ArgsManager::GetArgs() already checks the network-specific config. However, we haven’t yet set m_network (that only happens in SelectParams()) so you’re right and you do need this manual check.

    I don’t know if there’s a better way to avoid doing this manually. Perhaps @ajtowns can suggest something? At the least, I think you should add a comment like:

    0        // We haven't set m_network yet (that happens in SelectParms()), so manually check
    1        // for network.includeconf args.
    

    You can also remove the block/braces.


    kallewoof commented at 0:52 am on April 18, 2018:
    Good point on adding comment. I added braces to throw includeconf_net out of scope as it was no longer used, and this makes that obvious.

    ajtowns commented at 4:30 am on April 18, 2018:

    I think this is subtly “wrong” fwiw: if you have [main] includeconf=foo.conf in bitcoin.conf, and then set testnet=1 in foo.conf, you’ll have foo.conf included, and be running testnet not mainnet, so you “shouldn’t” have included foo.conf (and any other settings from the [main] section won’t have been used). That might be too subtle to worry about though.

    It’s perhaps less subtly wrong in that if you said includeconf=force-testnet.conf [testnet] includeconf=testnet-params.conf, with force-testnet.conf setting testnet=1, you would not end up including testnet-params.conf, whereas if you set -testnet on the command line, you would.

    The easiest approach might be to not allow [regtest] includeconf=rt.conf at all, but that would probably be annoying (particularly with custom chains).

    A thought I had was that maybe [regtest] includeconf=rt.conf should treat all the options in rt.conf as being network-specific, so if rt.conf says connect=10.10.10.10 [main] connect=10.10.10.20 [regtest] connect=10.10.10.30, that would get interpreted as if it was [regtest] connect=10.10.10.10 connect=10.10.10.30. That would avoid the inconsistency above, in that it would turn [main] includeconf=foo.conf into essentially [main] testnet=1 which would just be ignored.

    I think it might be better to do it as four phases though: (1) read “-conf”, (2) read the includeconfs that aren’t under a section, (3) work out the chain based on everything noted so far, and (4) read the “-chain.includeconf” options from -conf (but not letting that change the chain).


    jnewbery commented at 1:49 pm on April 18, 2018:

    I think that these are good observations, but that we don’t necessarily need to police such pathological edge-cases. The special casing for [regtest] testnet=1 etc in https://github.com/bitcoin/bitcoin/pull/11862/commits/005ad266491f43d7a9bfd959396037416cb32a55 was useful because it’s easy enough to have a config file like:

    0option1=0
    1option2=1
    2[regtest]
    3option3=1
    

    and then append testnet=1 to the end, without realising that you’re actually adding regtest.testnet=1. (in fact, this PR does something similar here: https://github.com/bitcoin/bitcoin/pull/10267/files#diff-a3677de1e28a0e9b37d66c11cc9a760bR31 by appending an argument that becomes a network-specific argument). This kind of config error is easy to make, ambiguous, and ought to be policed.

    The config that you’re describing here:

    if you said includeconf=force-testnet.conf [testnet] includeconf=testnet-params.conf, with force-testnet.conf setting testnet=1, you would not end up including testnet-params.conf, whereas if you set -testnet on the command line, you would.

    seems much more contorted. I don’t think a user should reasonably expect that setting the network in an includeconf file should change how the network-specific includeconfs in the base config file are interpreted. That behaviour also feels a bit too multi-leveled in that we’re reading a specific includeconf file based on the content of a different includeconf file (I argued against such behaviour here: #10267 (comment) because I think it leads to an overly complex model).


    jnewbery commented at 2:06 pm on April 18, 2018:

    @kallewoof

    I added braces to throw includeconf_net out of scope

    I don’t know of any other places in the codebase that add blocks to throw local variables out of scope. Obviously functionally the same, but I’d personally have a preference to not add code blocks like this, since it makes the code slightly less clear.


    promag commented at 0:06 am on April 19, 2018:
    Agree with @jnewbery, there is no reason to do this. At first sight I thought there was a lock somewhere.
  111. jnewbery commented at 8:58 pm on April 17, 2018: member

    Looks great. Thanks for sticking with this.

    A couple of nits inline.

  112. kallewoof force-pushed on Apr 18, 2018
  113. kallewoof commented at 1:30 am on April 18, 2018: member
    Addressed @jnewbery nits (sans bracket removal).
  114. in doc/release-notes.md:100 in 13d536d9a5 outdated
     95@@ -96,6 +96,13 @@ Low-level RPC changes
     96   with any `-wallet=<path>` options, there is no change in behavior, and the
     97   name of any wallet is just its `<path>` string.
     98 
     99+Changed command-line options
    100+-----------------------------
    


    ajtowns commented at 3:31 am on April 18, 2018:
    Should use doc/release-notes-pr10267.md instead?

    kallewoof commented at 4:59 am on April 18, 2018:
    Should that be a new file with only the changes, or a copy of doc/release-notes.md? Never seen that way of adding release notes before.

    ajtowns commented at 5:12 am on April 18, 2018:
    It’s brand new! Just a new file with the section you want to add. There’s a couple there already (12823, 12892) to use as examples.
  115. in src/init.cpp:361 in 13d536d9a5 outdated
    357@@ -358,7 +358,7 @@ std::string HelpMessage(HelpMessageMode mode)
    358     if (showDebug) {
    359         strUsage += HelpMessageOpt("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize));
    360     }
    361-    strUsage += HelpMessageOpt("-includeconf=<file>", _("Specify additional configuration file, relative to the -datadir path"));
    362+    strUsage += HelpMessageOpt("-includeconf=<file>", _("Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)"));
    


    ajtowns commented at 3:32 am on April 18, 2018:
    Seems like this change should have been in the -includepath commit

    kallewoof commented at 5:00 am on April 18, 2018:
    You mean the -includeconf commit? I tend to separate doc and code commits, usually.

    ajtowns commented at 5:10 am on April 18, 2018:
    Err, yeah. You add the help message in the -includeconf commit, then change it in the release notes commit.

    kallewoof commented at 5:36 am on April 18, 2018:
    OH. Fixed! Thanks…
  116. in src/util.cpp:954 in 2f8d4a12b2 outdated
    950         LOCK(cs_args);
    951         m_config_args.clear();
    952+
    953+        // we do not allow -includeconf from command line, so we clear it here
    954+        auto it = m_override_args.find("-includeconf");
    955+        if (it != m_override_args.end()) m_override_args.erase(it);
    


    ajtowns commented at 3:35 am on April 18, 2018:
    Should this issue a warning rather than just silently ignoring it? I’d be inclined to move this check into ParseParameters fwiw.

    kallewoof commented at 5:01 am on April 18, 2018:
    A warning would probably be helpful, yeah. Will look into moving into ParseParameters.

    kallewoof commented at 5:36 am on April 18, 2018:
    Warning added – I used fprintf(stderr, ..) though, cause it hasn’t processed -printtoconsole or anything yet.
  117. in test/functional/feature_includeconf.py:50 in f945bdd90a outdated
    45+        self.restart_node(0, extra_args=["-includeconf=relative2.conf"])
    46+
    47+        subversion = self.nodes[0].getnetworkinfo()["subversion"]
    48+        assert subversion.endswith("main; relative)/")
    49+
    50+        self.log.info("-includeconf cannot be used recursively. subversion should end with 'main)/'")
    


    ajtowns commented at 4:35 am on April 18, 2018:
    I was expecting subversion to end with “main; relative”, which would ensure relative.conf’s options are being used despite it trying to recurse into relative2. No big deal either way.

    kallewoof commented at 5:05 am on April 18, 2018:
    Good point – I am readding uacomment=relative\n to relative.conf and checking that subversion ends with main; relative).
  118. ajtowns approved
  119. ajtowns commented at 4:44 am on April 18, 2018: member
    Some nits and suggestions, but looks good.
  120. kallewoof commented at 5:22 am on April 18, 2018: member

    @ajtowns

    I think this is subtly “wrong” fwiw: if you have [main] includeconf=foo.conf in bitcoin.conf, and then set testnet=1 in foo.conf, you’ll have foo.conf included, and be running testnet not mainnet, so you “shouldn’t” have included foo.conf (and any other settings from the [main] section won’t have been used). That might be too subtle to worry about though.

    I don’t think we need to care about that. If the user explicitly includes foo.conf from [main] and foo.conf sets to testnet, arguably they would want to use testnet “whenever main is used”. Maybe they want to guarantee never mainnet?

    A thought I had was that maybe [regtest] includeconf=rt.conf should treat all the options in rt.conf as being network-specific, so if rt.conf says connect=10.10.10.10 [main] connect=10.10.10.20 [regtest] connect=10.10.10.30, that would get interpreted as if it was [regtest] connect=10.10.10.10 connect=10.10.10.30. That would avoid the inconsistency above, in that it would turn [main] includeconf=foo.conf into essentially [main] testnet=1 which would just be ignored.

    I’m not sure I follow here. includeconf has the exact same semantics as #include in C++. The current default behavior seems the most logical one.

    I think it might be better to do it as four phases though: (1) read “-conf”, (2) read the includeconfs that aren’t under a section, (3) work out the chain based on everything noted so far, and (4) read the “-chain.includeconf” options from -conf (but not letting that change the chain).

    I noted above a case where a user want an included conf to change the chain. Is it worth the effort to prevent this?

  121. kallewoof force-pushed on Apr 18, 2018
  122. kallewoof commented at 5:37 am on April 18, 2018: member
    @ajtowns Thanks for review! I believe I addressed your concerns, except for the discussion ^.
  123. kallewoof force-pushed on Apr 18, 2018
  124. in test/functional/feature_includeconf.py:51 in f083a0e57c outdated
    46+
    47+        subversion = self.nodes[0].getnetworkinfo()["subversion"]
    48+        assert subversion.endswith("main; relative)/")
    49+
    50+        self.log.info("-includeconf cannot be used recursively. subversion should end with 'main)/'")
    51+        with open(os.path.join(self.options.tmpdir + "/node0", "relative.conf"), "w", encoding="utf8") as f:
    


    jnewbery commented at 1:57 pm on April 18, 2018:

    May be clearer to append to the config file, rather than rewrite the uacomment param:

    0        with open(os.path.join(self.options.tmpdir + "/node0", "relative.conf"), "a", encoding="utf8") as f:
    1            f.write("includeconf=relative2.conf\n")
    

    although you may disagree, in which case it’s fine to leave as is!

    You should certainly update the log above though:

    0self.log.info("-includeconf cannot be used recursively. subversion should end with 'main; relative)/'")
    

    kallewoof commented at 11:23 pm on April 18, 2018:
    Makes sense! Fixed.
  125. jnewbery commented at 2:08 pm on April 18, 2018: member

    ACK f083a0e57ca7c991af56425e44cb5aeeaa383a50 with a couple of comments.

    I agree with @kallewoof that the include precedence in the current implementation is fine. Perhaps more detailed documentation would satisfy @ajtowns ?

  126. ajtowns commented at 3:30 pm on April 18, 2018: member
    I’d be happier if there weren’t any weird edge cases, but I’m okay with not fixing them. I’ll have another look over the latest commits tomorrow, but expect I’d beh appy to ack them as is.
  127. kallewoof force-pushed on Apr 18, 2018
  128. in src/util.cpp:450 in a89353e950 outdated
    681@@ -682,6 +682,15 @@ void ArgsManager::ParseParameters(int argc, const char* const argv[])
    682             m_override_args[key].push_back(val);
    683         }
    684     }
    685+
    686+    // we do not allow -includeconf from command line, so we clear it here
    687+    auto it = m_override_args.find("-includeconf");
    


    promag commented at 11:42 pm on April 18, 2018:
    This should be a loop, otherwise only the first -includeconf is removed from m_override_args. Also update comment above accordingly.

    kallewoof commented at 0:19 am on April 19, 2018:
    It is defined as a std::map<std::string, std::vector<std::string>>, which may only have one entry per key. It removes the vector itself, which may contain multiple values. (I am only showing the first for simplicity in the error output.)

    promag commented at 0:25 am on April 19, 2018:
    Right. Either log all or nothing?

    kallewoof commented at 0:31 am on April 19, 2018:
    Makes sense. Added loop over vector.
  129. in src/util.cpp:985 in a89353e950 outdated
    979+                LogPrintf("Attempting to include configuration file %s\n", to_include.c_str());
    980+                fs::ifstream include_config(GetConfigFile(to_include));
    981+                if (include_config.good()) {
    982+                    ReadConfigStream(include_config);
    983+                } else {
    984+                    LogPrintf("Failed to include configuration file %s\n", to_include.c_str());
    


    promag commented at 11:46 pm on April 18, 2018:
    Maybe Skipping invalid configuration file ...?

    kallewoof commented at 0:21 am on April 19, 2018:

    Addressing the nit below (log success), I believe the current form looks better:

    0                    LogPrintf("Included configuration file %s\n", to_include.c_str());
    1                } else {
    2                    LogPrintf("Failed to include configuration file %s\n", to_include.c_str());
    
  130. in src/util.cpp:978 in a89353e950 outdated
    974+            includeconf.insert(includeconf.end(), includeconf_net.begin(), includeconf_net.end());
    975+        }
    976+
    977+        if (includeconf.size() > 0) {
    978+            for (const std::string& to_include : includeconf) {
    979+                LogPrintf("Attempting to include configuration file %s\n", to_include.c_str());
    


    promag commented at 11:52 pm on April 18, 2018:
    Prefer to log the success case since you also log the failure case?
  131. in src/init.cpp:361 in a89353e950 outdated
    357@@ -358,6 +358,7 @@ std::string HelpMessage(HelpMessageMode mode)
    358     if (showDebug) {
    359         strUsage += HelpMessageOpt("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize));
    360     }
    361+    strUsage += HelpMessageOpt("-includeconf=<file>", _("Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)"));
    


    promag commented at 11:54 pm on April 18, 2018:
    Nit, keep sorted?

    kallewoof commented at 0:22 am on April 19, 2018:
    Holy crap, it’s sorted! No idea how I failed to see that. Thanks.
  132. in doc/release-notes-pr10267.md:2 in a89353e950 outdated
    0@@ -0,0 +1,6 @@
    1+Changed command-line options
    2+-----------------------------
    


    promag commented at 11:55 pm on April 18, 2018:
    Nit, remove extra -.
  133. kallewoof force-pushed on Apr 19, 2018
  134. in src/util.cpp:978 in b9631d1746 outdated
    972+            // for network.includeconf args.
    973+            std::vector<std::string> includeconf_net(GetArgs(std::string("-") + GetChainName() + ".includeconf"));
    974+            includeconf.insert(includeconf.end(), includeconf_net.begin(), includeconf_net.end());
    975+        }
    976+
    977+        if (includeconf.size() > 0) {
    


    promag commented at 0:29 am on April 19, 2018:
    Remove this condition. If it’s empty then there is nothing to loop below.

    kallewoof commented at 0:32 am on April 19, 2018:
    If someone does -noincludeconf, I believe it will exist, but the vector will be empty. See line 682, which adds the key to the map, but clears it (the vector, not the map).

    kallewoof commented at 0:34 am on April 19, 2018:
    Sorry, line 950, not 682. 682 is for m_override_args.

    kallewoof commented at 0:36 am on April 19, 2018:
    Actually, nevermind, you’re right. The for loop will just skip.
  135. kallewoof force-pushed on Apr 19, 2018
  136. kallewoof force-pushed on Apr 19, 2018
  137. kallewoof force-pushed on Apr 19, 2018
  138. kallewoof commented at 1:01 am on April 19, 2018: member
    After testing -noincludeconf, I did some tweaks so that you can do -noincludeconf from command line to disable includeconf stuff inside the main config file.
  139. in src/util.cpp:748 in 6746e4349b outdated
    979+
    980+            for (const std::string& to_include : includeconf) {
    981+                fs::ifstream include_config(GetConfigFile(to_include));
    982+                if (include_config.good()) {
    983+                    ReadConfigStream(include_config);
    984+                    LogPrintf("Included configuration file %s\n", to_include.c_str());
    


    promag commented at 1:34 am on April 19, 2018:
    printf?
  140. in src/util.cpp:985 in 6746e4349b outdated
    981+                fs::ifstream include_config(GetConfigFile(to_include));
    982+                if (include_config.good()) {
    983+                    ReadConfigStream(include_config);
    984+                    LogPrintf("Included configuration file %s\n", to_include.c_str());
    985+                } else {
    986+                    LogPrintf("Failed to include configuration file %s\n", to_include.c_str());
    


    promag commented at 1:34 am on April 19, 2018:
    fprintf(stderr?
  141. promag commented at 1:41 am on April 19, 2018: member
    Release notes should mention the argument precedence. For instance, if printtoconsole=0 is specified in the main conf, then printtoconsole=1 in included conf are ignored. But arguments with multiple values, like `-wallet, are concatenated.
  142. kallewoof force-pushed on Apr 19, 2018
  143. kallewoof commented at 3:06 am on April 19, 2018: member

    Addressed @promag nits.

    Edit: Actually, hm. I didn’t address the release note point. Will make another update after verifying behavior.

    Edit 2: I believe I covered the specific case @promag is talking about now.

  144. kallewoof force-pushed on Apr 19, 2018
  145. in src/util.cpp:748 in 3c4dd4f386 outdated
    979+
    980+            for (const std::string& to_include : includeconf) {
    981+                fs::ifstream include_config(GetConfigFile(to_include));
    982+                if (include_config.good()) {
    983+                    ReadConfigStream(include_config);
    984+                    printf("Included configuration file %s\n", to_include.c_str());
    


    jnewbery commented at 4:16 pm on April 24, 2018:

    I don’t understand why this is a print statement. It’ll get printed every time bitcoind or bitcoin-qt is started, and each time bitcoin-cli is called.

    I think just a normal log here is fine.


    kallewoof commented at 2:24 am on April 25, 2018:
    The reason is because -printtoconsole or -debug etc. have not been activated yet. A log would effectively be a NOP.

    kallewoof commented at 5:54 am on April 25, 2018:
    Hm, you’re right that it prints every time you call bitcoin-cli etc. That’s ugly. I’ll think of something.

    kallewoof commented at 6:10 am on April 25, 2018:
    I’m removing this entirely. As LogPrintf it is NOP and as printf it is ugly. I think we can live without being told the include was successful. The error case will be spammy, but I think that’s okay.

    ajtowns commented at 11:05 pm on April 25, 2018:
    LogPrintf gets stored and replayed when going to a logfile; we could fix it so the same thing happens with printtoconsole?

    kallewoof commented at 3:41 am on April 26, 2018:
    @ajtowns Really? I thought I checked the log file and didn’t see it. If it is replayed, I should add it back.

    kallewoof commented at 3:46 am on April 26, 2018:
    I restored LogPrintf line.

    ajtowns commented at 12:16 pm on April 26, 2018:
    #13088 should add support replay for console logs as well as debug.log fwiw
  146. in src/util.cpp:735 in 3c4dd4f386 outdated
    966     fs::ifstream stream(GetConfigFile(confPath));
    967 
    968     // ok to not have a config file
    969     if (stream.good()) {
    970         ReadConfigStream(stream);
    971+        if (m_override_args.count("-includeconf") == 0) {
    


    jnewbery commented at 4:16 pm on April 24, 2018:
    Can you add a comment to explain why you’re checking that count == 0?
  147. in src/util.cpp:452 in 3c4dd4f386 outdated
    681@@ -682,6 +682,17 @@ void ArgsManager::ParseParameters(int argc, const char* const argv[])
    682             m_override_args[key].push_back(val);
    683         }
    684     }
    685+
    686+    // we do not allow -includeconf from command line, so we clear it here
    687+    auto it = m_override_args.find("-includeconf");
    688+    if (it != m_override_args.end()) {
    689+        if (it->second.size() > 0) {
    


    jnewbery commented at 4:25 pm on April 24, 2018:

    It’d be nice if we could be more aggressive here and fail to start if a -includeconf argument is provided on the command line (since continuing to startup would be continuing with config that the user has specified that they don’t want).

    ParseParameters() doesn’t currently have a way to return errors, and callers don’t wrap calls with try-except (unlike GetChainName() for example). Perhaps a future PR could change the function to return a bool, so we could indicate an error to the caller and abort startup.


    kallewoof commented at 2:29 am on April 25, 2018:
    Makes sense. I’m leaving it for now as it sounds like a future thing, I think.
  148. in test/functional/feature_includeconf.py:26 in 3c4dd4f386 outdated
    21+class IncludeConfTest(BitcoinTestFramework):
    22+    def setup_chain(self):
    23+        super().setup_chain()
    24+        # Create additional config files
    25+        # - tmpdir/node0/relative.conf
    26+        with open(os.path.join(self.options.tmpdir + "/node0", "relative.conf"), "w", encoding="utf8") as f:
    


    jnewbery commented at 4:32 pm on April 24, 2018:
    nit: prefer os.path.join(self.options.tmpdir, "node0", "relative.conf") for better portability.
  149. jnewbery commented at 4:32 pm on April 24, 2018: member

    Looks great. Just a few more nits!

    Thanks for the release notes

  150. kallewoof force-pushed on Apr 25, 2018
  151. kallewoof force-pushed on Apr 25, 2018
  152. kallewoof force-pushed on Apr 25, 2018
  153. in src/util.cpp:454 in 01e3fcccc3 outdated
    449+    // we do not allow -includeconf from command line, so we clear it here
    450+    auto it = m_override_args.find("-includeconf");
    451+    if (it != m_override_args.end()) {
    452+        if (it->second.size() > 0) {
    453+            for (const auto& ic : it->second) {
    454+                printf("warning: -includeconf cannot be used from commandline; ignoring -includeconf=%s\n", ic.c_str());
    


    laanwj commented at 8:05 am on April 25, 2018:
    fprintf(stderr, ...?

    kallewoof commented at 8:10 am on April 25, 2018:
    Makes sense. Done.

    kallewoof commented at 8:31 am on April 25, 2018:
    Actually, I remember now. The reason was because travis fails for certain tests when using fprintf.

    laanwj commented at 8:48 am on April 25, 2018:
    Should probably fix the test instead in that case :-)

    kallewoof commented at 9:04 am on April 25, 2018:
    I thought it was a travis internal thing to automatically assume error when stderr was printed to. I can’t find any reference to this though… digging.

    kallewoof commented at 9:10 am on April 25, 2018:
    It’s actually test_runner.py, not travis. Digging more.
  154. kallewoof force-pushed on Apr 25, 2018
  155. kallewoof force-pushed on Apr 25, 2018
  156. kallewoof force-pushed on Apr 25, 2018
  157. laanwj commented at 9:12 am on April 25, 2018: member
    utACK 8eebf2a55f43bbcf83b64051f5d1a6355b0d0145
  158. laanwj referenced this in commit 7192b8fca3 on Apr 25, 2018
  159. laanwj commented at 11:46 am on April 25, 2018: member
    @kallewoof Feel free to take over https://github.com/laanwj/bitcoin/commit/57b1b57cba84ea60e4de7cc0549aa448132e7573 to fix the stderr issue (and check stderr output)
  160. kallewoof force-pushed on Apr 26, 2018
  161. kallewoof commented at 3:45 am on April 26, 2018: member
    @laanwj Ohh, nice. Thanks for the fix. I squashed it into 488f947.
  162. -includeconf=<path> support in config handler, for including external configuration files 629ff8c358
  163. kallewoof force-pushed on Apr 26, 2018
  164. jnewbery commented at 8:54 pm on April 30, 2018: member

    I’d prefer to not to have special stderr checking for this test. I have a PR open here: #12755 which adds stderr checking to the test framework.

    I’ve also prepared a branch here: https://github.com/bitcoin/bitcoin/compare/master...jnewbery:pr10267.3?expand=1 which rebases this PR on #12755 and adds explicit stderr checking.

    Would you mind either:

  165. kallewoof commented at 4:31 am on May 1, 2018: member
    @jnewbery Wouldn’t it be simpler to fix this in a follow-up PR once #12755 is merged?
  166. in test/functional/feature_includeconf.py:20 in 6d5605517b outdated
    15+   file.
    16+"""
    17+import os
    18+
    19+from test_framework.test_framework import BitcoinTestFramework, assert_equal
    20+import tempfile
    


    jnewbery commented at 1:42 pm on May 1, 2018:
    nit: PEP8 import ordering please (std library first, then local application imports)
  167. in test/functional/feature_includeconf.py:27 in 6d5605517b outdated
    18+
    19+from test_framework.test_framework import BitcoinTestFramework, assert_equal
    20+import tempfile
    21+
    22+class IncludeConfTest(BitcoinTestFramework):
    23+    def setup_chain(self):
    


    jnewbery commented at 1:44 pm on May 1, 2018:
    micronit: all other tests have set_test_params() as the first method. I think that makes more logical sense since that method is called by __init__(). Do you mind doing the same here?
  168. jnewbery commented at 1:47 pm on May 1, 2018: member

    Tested ACK 6d5605517b477538f0447d41fe0bc734da27d10c. A couple of nits in the new test code, but nothing that should prevent merge.

    @jnewbery Wouldn’t it be simpler to fix this in a follow-up PR once #12755 is merged?

    Not 100% sure what you mean by ‘fix this’, but I’m guessing you mean merge this as is and then remove the specific stderr checking code from this test when the generic stderr checking is added in #12755? Sure - that’s fine, as long as you don’t mind reviewing #12755 for me :)

  169. test: Test includeconf parameter. 0f0badd5a3
  170. doc: Add release notes for -includeconf 25b7ab9c02
  171. kallewoof force-pushed on May 2, 2018
  172. kallewoof commented at 5:27 am on May 2, 2018: member
    @jnewbery Thanks for review! Addressed your nits.
  173. kallewoof commented at 5:31 am on May 2, 2018: member
    @jnewbery I’m a little confused. Should I close this PR in favor of #12755? I thought #12755 only added the error stuff, but it includes this PR as well now.
  174. jnewbery commented at 7:48 pm on May 3, 2018: member

    Tested ACK 25b7ab9c02f691be6c1aa71a9cf51ac1a6ea9db4.

    I’m a little confused. Should I close this PR in favor of #12755? I thought #12755 only added the error stuff, but it includes this PR as well now.

    Sorry - I haven’t been very clear in my updates. Now that this PR includes stderr testing, it conflicts with #12755. My initial suggestions were to remove the stderr testing from this test, or rebase on top of #12755. But now I think it would make more sense to rebase #12755 on this, since this PR has been around for so long and should almost be ready for merge.

    I’ve rebased #12755 on this. As soon as this PR is merged, #12755 will be ready to go in.

  175. jnewbery commented at 7:11 pm on May 8, 2018: member
    I think this is very nearly ready for merge. Are previous reviewers @laanwj, @ajtowns @promag, @ryanofsky, @MarcoFalke @MeshCollider, @jonasschnelli able to re-review this?
  176. laanwj commented at 7:40 pm on May 8, 2018: member
    utACK 25b7ab9c02f691be6c1aa71a9cf51ac1a6ea9db4
  177. promag commented at 9:20 pm on May 8, 2018: member

    utACK 25b7ab9.

    I suggest to add a warning if -includeconf is used in an included file (follow up PR).

  178. laanwj merged this on May 9, 2018
  179. laanwj closed this on May 9, 2018

  180. laanwj referenced this in commit 7b966d9e6e on May 9, 2018
  181. kallewoof deleted the branch on May 9, 2018
  182. laanwj referenced this in commit 612ba35ab1 on May 9, 2018
  183. practicalswift commented at 8:30 pm on May 12, 2018: contributor

    When working on the locking annotations (see #13126) I noticed that ArgsManager::ReadConfigFiles() introduced in this PR accesses m_override_args without first locking cs_args.

    The PR #13126 adds the correct locking. FWIW Travis will catch this type of cs_args locking violations when #13126 is merged :-)

  184. laanwj referenced this in commit 682698970d on May 14, 2018
  185. in test/functional/feature_includeconf.py:54 in 25b7ab9c02
    49+
    50+            subversion = self.nodes[0].getnetworkinfo()["subversion"]
    51+            assert subversion.endswith("main; relative)/")
    52+            log_stderr.seek(0)
    53+            stderr = log_stderr.read().decode('utf-8').strip()
    54+            assert_equal(stderr, 'warning: -includeconf cannot be used from commandline; ignoring -includeconf=relative2.conf')
    


    MarcoFalke commented at 8:13 pm on June 1, 2018:
    nit: should probably be an (init)error, since it is clearly an invalid command line
  186. in src/util.cpp:750 in 25b7ab9c02
    746+                fs::ifstream include_config(GetConfigFile(to_include));
    747+                if (include_config.good()) {
    748+                    ReadConfigStream(include_config);
    749+                    LogPrintf("Included configuration file %s\n", to_include.c_str());
    750+                } else {
    751+                    fprintf(stderr, "Failed to include configuration file %s\n", to_include.c_str());
    


    MarcoFalke commented at 8:14 pm on June 1, 2018:
    nit: return false on error?
  187. MarcoFalke commented at 8:15 pm on June 1, 2018: member

    Post-merge ACK 25b7ab9

    See #13367 to fix my nit about the errors.

  188. markblundeberg referenced this in commit 4c2024cfdb on May 23, 2019
  189. jtoomim referenced this in commit 6017b6a4b5 on Jun 29, 2019
  190. jasonbcox referenced this in commit 6dd7d19103 on Sep 27, 2019
  191. UdjinM6 referenced this in commit aa4488898c on May 21, 2021
  192. UdjinM6 referenced this in commit dc1830a2f0 on May 25, 2021
  193. TheArbitrator referenced this in commit da56b72f34 on Jun 7, 2021
  194. TheArbitrator referenced this in commit 92bb93cef0 on Jun 7, 2021
  195. UdjinM6 referenced this in commit a57a82be1a on Jun 18, 2021
  196. UdjinM6 referenced this in commit 207defb4c0 on Jun 18, 2021
  197. UdjinM6 referenced this in commit 9e9cd7c035 on Jun 24, 2021
  198. UdjinM6 referenced this in commit 5cf96e8fdf on Jun 24, 2021
  199. UdjinM6 referenced this in commit 37b4656d23 on Jun 26, 2021
  200. UdjinM6 referenced this in commit 62abb11c33 on Jun 26, 2021
  201. UdjinM6 referenced this in commit 18e8ca4fa1 on Jun 26, 2021
  202. UdjinM6 referenced this in commit c9edd3e8ea on Jun 26, 2021
  203. UdjinM6 referenced this in commit cc38451955 on Jun 28, 2021
  204. UdjinM6 referenced this in commit ec9f526cec on Jun 28, 2021
  205. DrahtBot locked this on Sep 8, 2021

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-03 13:13 UTC

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