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.~~~
kallewoof force-pushed
on Apr 24, 2017
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?
NicolasDorier
commented at 7:15 am on April 24, 2017:
contributor
Why not making the existing -config a repeatable argument.
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.
kallewoof force-pushed
on Apr 24, 2017
kallewoof
commented at 9:35 am on April 24, 2017:
member
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.
jtimon
commented at 4:50 pm on April 24, 2017:
contributor
Concept ACK. Don’t care much about the name, but what about -extraconf ?
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.
kallewoof force-pushed
on Apr 25, 2017
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
kallewoof renamed this:
New -readconfig argument for including external configuration files
New -includeconf argument for including external configuration files
on Apr 25, 2017
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.
kallewoof force-pushed
on Apr 25, 2017
kallewoof force-pushed
on Apr 25, 2017
kallewoof
commented at 7:34 am on April 25, 2017:
member
To clarify, the code now does what @laanwj suggested.
laanwj added the label
RPC/REST/ZMQ
on Apr 25, 2017
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.
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.
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).
kallewoof force-pushed
on May 2, 2017
kallewoof force-pushed
on May 2, 2017
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.
kallewoof force-pushed
on May 8, 2017
kallewoof force-pushed
on May 8, 2017
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.)
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).
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:
ParseParameters (util.cpp:407 called from bitcoind.cpp:75) – this will work as normal and does not require cache clearing.
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.
kallewoof force-pushed
on May 16, 2017
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.610[#5](/bitcoin-bitcoin/5/) 0x00007f3b78730919 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.611[#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.012[#7](/bitcoin-bitcoin/7/) 0x000055e5c58b2ae2 in boost::filesystem::canonical (base=..., p=...) at /usr/include/boost/filesystem/operations.hpp:45913[#8](/bitcoin-bitcoin/8/) GetConfigFile (confPath="global.conf", relativePath="") at util.cpp:60314[#9](/bitcoin-bitcoin/9/) 0x000055e5c58b4353 in ArgsManager::ProcessSetting (this=this@entry=0x55e5c5db1fa0 <gArgs>, strKey="-includeconf", strValue="global.conf", relativePath="") at util.cpp:38615[#10](/bitcoin-bitcoin/10/) 0x000055e5c58b487d in ArgsManager::ParseParameters (this=0x55e5c5db1fa0 <gArgs>, argc=<optimized out>, argv=<optimized out>) at util.cpp:42416[#11](/bitcoin-bitcoin/11/) 0x000055e5c5653d4a in ParseParameters (argv=0x7fff5492e618, argc=14) at util.h:26317[#12](/bitcoin-bitcoin/12/) AppInit (argc=14, argv=0x7fff5492e618) at bitcoind.cpp:7518[#13](/bitcoin-bitcoin/13/) 0x000055e5c5648bef in main (argc=14, argv=0x7fff5492e618) at bitcoind.cpp:19619(gdb) quit
If I use an invalid filename for -conf on master. I don’t see this crash.
kallewoof
commented at 2:22 am on May 17, 2017:
member
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.
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.
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.
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.
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).
in
test/functional/includeconf.py:1
in
9c20870eaeoutdated
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__':?
to check that neither comandline.conf nor relativeofrelative.conf have been included.
(I recommend you also update the docstring to describe what’s happening)
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.
kallewoof force-pushed
on Jun 1, 2017
kallewoof
commented at 5:45 am on June 1, 2017:
member
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));
3if (!streamConfig.good())
4return; // No bitcoin.conf file is OK
5//...6}
Or perhaps I should restore it later if this PR gets merged first.
utACKbc4f7a4b3f614dc2125c6af60da448606b622688 beyond that.
in
src/util.cpp:756
in
7a062e7f08outdated
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:
Yes, unless you conserve a ArgsManager::ReadConfigFile(const std::string& confPath), then that will presumably call call ArgsManager::ReadConfigFile(fs::ifstream& streamConfig too.
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!
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)
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
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.
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.
jnewbery
commented at 9:12 pm on June 14, 2017:
member
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.
jnewbery
commented at 9:30 pm on June 14, 2017:
member
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.
kallewoof force-pushed
on Jun 15, 2017
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.
kallewoof force-pushed
on Jul 14, 2017
laanwj assigned laanwj
on Aug 10, 2017
jnewbery
commented at 6:14 pm on August 14, 2017:
member
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.
kallewoof force-pushed
on Aug 15, 2017
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.)
kallewoof force-pushed
on Aug 15, 2017
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).
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!
kallewoof force-pushed
on Aug 16, 2017
kallewoof
commented at 9:14 am on August 16, 2017:
member
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:
First:
ReadConfigFiles() [locks cs_args]
ReadConfigFile(conf_path)
GetConfigFile(conf_path)
GetDataDir(false) [locks csPathCached]
gArgs.IsArgSet("-datadir") [locks cs_args]
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.
kallewoof force-pushed
on Aug 16, 2017
kallewoof force-pushed
on Sep 28, 2017
kallewoof force-pushed
on Sep 28, 2017
kallewoof force-pushed
on Oct 11, 2017
promag
commented at 12:08 pm on November 23, 2017:
member
Needs rebase. Is this still valid?
kallewoof force-pushed
on Nov 24, 2017
kallewoof
commented at 4:20 am on November 24, 2017:
member
Rebased. It is valid, yes.
kallewoof force-pushed
on Dec 5, 2017
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
kallewoof force-pushed
on Dec 12, 2017
kallewoof force-pushed
on Jan 9, 2018
kallewoof force-pushed
on Jan 25, 2018
kallewoof
commented at 8:16 am on February 23, 2018:
member
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: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.
kallewoof force-pushed
on Mar 23, 2018
kallewoof force-pushed
on Mar 23, 2018
kallewoof force-pushed
on Mar 23, 2018
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.
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
@MarcoFalke / @laanwj - any idea why the unit tests would stall for half an hour here?
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.
in
test/functional/feature_includeconf.py:15
in
47848d0fb0outdated
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:30 pm on March 23, 2018:
member
utACK47848d0fb0705facd7d4cf24c50d450386155f5a (although I’ll defer to @MarcoFalke on whether the travis timeout bump is a good idea)
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.
jnewbery
commented at 8:00 pm on March 23, 2018:
member
Could cherry-pick that change to a separate pull request, though.
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"));
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.
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).
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).
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.
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+-----------------------------
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);
Warning added – I used fprintf(stderr, ..) though, cause it hasn’t processed -printtoconsole or anything yet.
in
test/functional/feature_includeconf.py:50
in
f945bdd90aoutdated
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)/'")
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.
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?
kallewoof force-pushed
on Apr 18, 2018
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 ^.
kallewoof force-pushed
on Apr 18, 2018
in
test/functional/feature_includeconf.py:51
in
f083a0e57coutdated
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:
May be clearer to append to the config file, rather than rewrite the uacomment param:
0with 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.
jnewbery
commented at 2:08 pm on April 18, 2018:
member
ACKf083a0e57ca7c991af56425e44cb5aeeaa383a50 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 ?
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.
kallewoof force-pushed
on Apr 18, 2018
in
src/util.cpp:450
in
a89353e950outdated
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");
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.)
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).
Actually, nevermind, you’re right. The for loop will just skip.
kallewoof force-pushed
on Apr 19, 2018
kallewoof force-pushed
on Apr 19, 2018
kallewoof force-pushed
on Apr 19, 2018
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.
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.
kallewoof force-pushed
on Apr 19, 2018
kallewoof
commented at 3:06 am on April 19, 2018:
member
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.
#13088 should add support replay for console logs as well as debug.log fwiw
in
src/util.cpp:735
in
3c4dd4f386outdated
966 fs::ifstream stream(GetConfigFile(confPath));
967968 // ok to not have a config file
969 if (stream.good()) {
970 ReadConfigStream(stream);
971+ if (m_override_args.count("-includeconf") == 0) {
Can you add a comment to explain why you’re checking that count == 0?
in
src/util.cpp:452
in
3c4dd4f386outdated
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) {
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.
nit: prefer os.path.join(self.options.tmpdir, "node0", "relative.conf") for better portability.
jnewbery
commented at 4:32 pm on April 24, 2018:
member
Looks great. Just a few more nits!
Thanks for the release notes
kallewoof force-pushed
on Apr 25, 2018
kallewoof force-pushed
on Apr 25, 2018
kallewoof force-pushed
on Apr 25, 2018
in
src/util.cpp:454
in
01e3fcccc3outdated
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());
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?
jnewbery
commented at 1:47 pm on May 1, 2018:
member
Tested ACK6d5605517b477538f0447d41fe0bc734da27d10c. 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 :)
test: Test includeconf parameter.0f0badd5a3
doc: Add release notes for -includeconf25b7ab9c02
kallewoof force-pushed
on May 2, 2018
kallewoof
commented at 5:27 am on May 2, 2018:
member
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.
jnewbery
commented at 7:48 pm on May 3, 2018:
member
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.
jnewbery
commented at 7:11 pm on May 8, 2018:
member
laanwj
commented at 7:40 pm on May 8, 2018:
member
utACK25b7ab9c02f691be6c1aa71a9cf51ac1a6ea9db4
promag
commented at 9:20 pm on May 8, 2018:
member
utACK25b7ab9.
I suggest to add a warning if -includeconf is used in an included file (follow up PR).
laanwj merged this
on May 9, 2018
laanwj closed this
on May 9, 2018
laanwj referenced this in commit
7b966d9e6e
on May 9, 2018
kallewoof deleted the branch
on May 9, 2018
laanwj referenced this in commit
612ba35ab1
on May 9, 2018
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 :-)
laanwj referenced this in commit
682698970d
on May 14, 2018
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')
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: 2025-06-28 06:13 UTC
This site is hosted by @0xB10C More mirrored repositories can be found on mirror.b10c.me