The full init/common.cpp is dependent on things like ArgsManager (which we wish to remove from libbitcoinkernel in the future) and sanity checks. These aren't necessary for libbitcoinkernel so we only extract the portion that is necessary (namely init::{Set,Unset}Globals().
[kernel 2c/n] Introduce `kernel::Context`, encapsulate global init/teardown #25065
pull dongcarl wants to merge 5 commits into bitcoin:master from dongcarl:2022-03-libbitcoinkernel-initcommon changing 16 files +180 −65-
dongcarl commented at 10:41 PM on May 4, 2022: contributor
- DrahtBot added the label Build system on May 4, 2022
- DrahtBot added the label Utils/log/libs on May 4, 2022
-
in src/Makefile.am:876 in d5876d1efb outdated
871 | @@ -870,7 +872,7 @@ libbitcoinkernel_la_SOURCES = \ 872 | index/base.cpp \ 873 | index/blockfilterindex.cpp \ 874 | index/coinstatsindex.cpp \ 875 | - init/common.cpp \ 876 | + kernel/init/common.cpp \
maflcko commented at 6:06 AM on May 5, 2022:Not sure if we want a
kernelfolder for code that is shared between node and kernel. An alternative would be to name itinit/kernel.cpporinit/globals.cpp?Otherwise it will be difficult to decide whether to put kernel code that is used elsewhere as well in
kernelor in the "normal" hierarchy? cc @ryanofsky
dongcarl commented at 1:33 PM on May 5, 2022:I think the main thing here is to have a name that clearly indicates that this contains "only the common initialization code that the kernel needs" so that people don't accidentally add non-kernel code to it (it would result in a linker error when building
bitcoin-chainstate).Other PRs in the project (e.g. #24410) does this as well, since "extracting only what the kernel needs" is the main goal of this phase of the project. I like using the
kernel/prefix since it makes the indication mentioned in the previous paragraph clear, and doesn't require inventing a new name.In this particular case though, perhaps
kernel/init.cppwould work.One question is: do we keep the two functions moved in the
init::namespace or thekernel::namespace.In the longer run, I think eventually (very far off when
libbitcoinkernelis very minimal) we could put everything that links into libbitcoinkernel into thesrc/kernel/folder.
maflcko commented at 1:39 PM on May 5, 2022:So is the goal to eventually split validation into kernel/validation.cpp and node/validation.cpp ? What about util functions that are included in the kernel?
dongcarl commented at 1:52 PM on May 5, 2022:So is the goal to eventually split validation into kernel/validation.cpp and node/validation.cpp ?
Yes, far off into the future we will likely do that (although I think in reality
node/validation.cppwill likely be either: 1. a very very short file, or 2. deleted because what would be left belongs better in a differently named file).What about util functions that are included in the kernel?
I've discussed this with Ryan in #24352, and we came to the conclusion that we will move all the utils that
libbitcoinkerneldepends on tolibbitcoin_util, now that's just w/re the libraries, we could do either one of two things for the hierarchy:src/kernel/andsrc/util/, orsrc/kernel/andsrc/kernel/util/
Either is fine with me. See here for more discussion: #24352 (comment)
maflcko commented at 3:19 PM on May 5, 2022:Hmm, so to recall the goals of kernel are:
- Provide a self-contained thing for other projects to use.
- Make it clear what code is consensus related and what code isn't.
(Correct me if I am wrong)
Putting all utils into the kernel util library helps neither goal. Though, at the same time anything used by kernel isn't strictly consensus code. For example logging is used, but it is not consensus critical. Still, anything not used by kernel can't be consensus code, so I am wondering if there should be two util libs? If yes, then it would make sense to have both
src/utilandsrc/kernel/util. If not, then I don't care what is done.
dongcarl commented at 3:25 PM on May 5, 2022:so I am wondering if there should be two util libs? If yes, then it would make sense to have both
src/utilandsrc/kernel/util. If not, then I don't care what is done.I think that the point of #24352 (comment) is to establish exactly what you're saying. In effect:
commonwill be the non-kernel "util lib" (i.e.src/util), andutilwill be the kernel "util lib" (i.e.src/kernel/util).
laanwj commented at 2:14 PM on May 24, 2022:I think that the point of #24352 (comment) is to establish exactly what you're saying. In effect:
SGTM
For example logging is used
Yes. Though, for the eventual libbitcoin kernel we need to find some way to do logging that doesn't make the client application depend on bitcoind's logging subsystem (say, a hook / notification registration). Out of scope here, of course.
in src/init/common.h:11 in d5876d1efb outdated
7 | @@ -8,11 +8,11 @@ 8 | #ifndef BITCOIN_INIT_COMMON_H 9 | #define BITCOIN_INIT_COMMON_H 10 | 11 | +#include <kernel/include/init/common.h>
maflcko commented at 6:06 AM on May 5, 2022:nit: Pretty sure this is illegal according to iwyu?
dongcarl commented at 1:40 PM on May 5, 2022:Ah right. Yeah the thought here (in general for the
libbitcoinkernelproject) is for the existing headers to export things from the "kernel-extracted version of headers" so that we don't have too much code churn adding#include <kernel/*.h>all over the place. (See my other comment here for more details: #25065 (review))I think a good solution would be to do:
#include <kernel/include/init/common.h> // IWYU pragma: export
dongcarl commented at 8:19 PM on May 5, 2022:Fixed as of: 31c21f3644f6f42f6e4c3c231e95bf0b87ab86f5
maflcko approvedDrahtBot commented at 2:14 PM on May 5, 2022: contributor<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--174a7506f384e20aa4161008e828411d-->
Conflicts
Reviewers, this pull request conflicts with the following ones:
- #21763 (test: Run AppInitSanityChecks before all tests by MarcoFalke)
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
dongcarl force-pushed on May 5, 2022dongcarl commented at 8:15 PM on May 5, 2022: contributorPushed d5876d1efbf01f45fff2b42e0bcf2bc12eb25240 -> 13e65511dba702d115b7bea147b12eefaea9d53f
- Adjusted according to #24410 (comment)
dongcarl force-pushed on May 5, 2022dongcarl commented at 8:20 PM on May 5, 2022: contributorPushed 13e65511dba702d115b7bea147b12eefaea9d53f -> 708e2711e591ce4958900715348cb0313763f2cb
- Addressed: #25065 (review)
dongcarl force-pushed on May 5, 2022dongcarl commented at 10:10 PM on May 5, 2022: contributorPushed 708e2711e591ce4958900715348cb0313763f2cb -> e4c35528e58a74138aa7e0560dd7f59f1086c765
- Fixed incorrect header
#ifdef: https://github.com/bitcoin/bitcoin/runs/6313105188
maflcko added the label DrahtBot Guix build requested on May 13, 2022DrahtBot commented at 2:34 AM on May 17, 2022: contributor<!--9cd9c72976c961c55c7acef8f6ba82cd-->
Guix builds
DrahtBot removed the label DrahtBot Guix build requested on May 17, 2022DrahtBot added the label Needs rebase on May 20, 2022dongcarl force-pushed on May 20, 2022DrahtBot removed the label Needs rebase on May 20, 2022DrahtBot added the label Needs rebase on May 24, 2022dongcarl force-pushed on May 24, 2022in src/init/common.h:11 in 46524a623e outdated
7 | @@ -8,11 +8,11 @@ 8 | #ifndef BITCOIN_INIT_COMMON_H 9 | #define BITCOIN_INIT_COMMON_H 10 | 11 | +#include <kernel/init/common.h> // IWYU pragma: export
theuni commented at 3:16 PM on May 24, 2022:This is the first of these pragmas I've seen. I suspect I'm out of the loop on something.
I'm assuming this is some hint to IWYU, but I'm not sure what it means?
dongcarl commented at 7:07 PM on May 25, 2022:No longer relevant as of 9bc9309bd61f36ac68b41fe2328d2e3f505397e1
in src/init/common.h:15 in 6d93c443a4 outdated
12 | + 13 | class ArgsManager; 14 | 15 | namespace init { 16 | -void SetGlobals(); 17 | -void UnsetGlobals();
theuni commented at 3:34 PM on May 24, 2022:I think it makes sense to move
SanityChecksout as well, as it's effectively a runtime test forSetGlobals(and it depends on it too).
dongcarl commented at 7:08 PM on May 25, 2022:Do you mean something like
bool kernel::Context::SanityCheck()? Doing that does mean we can't removecompat/glibcxx_sanity.cppfrom libbitcoinkernel, but I'm fine with it either way so just lmk what you prefer.
ryanofsky commented at 8:46 PM on May 25, 2022:re: #25065 (review)
Do you mean something like
bool kernel::Context::SanityCheck()? Doing that does mean we can't removecompat/glibcxx_sanity.cppfrom libbitcoinkernel, but I'm fine with it either way so just lmk what you prefer.I'd agree it would be good to move sanity checks to the kernel assuming using
glibcxx_sanity.cppdoesn't add costs or complications. (glibcxx_sanity.cppis already part of libbitcoin_util so it seems fine at first glance). But it doesn't seem essential to add the checks if it is a problem.I do think if you add the checks, you should move them to a standalone function
bool SanityChecks(Context&)insrc/kernel/checks.cppor similar. Abool Context::SanityChecks()method insrc/kernel/context.cppwould make kernel code less modular, and risk sending Context object down a road where it becomes a disorganizedCWallet-like object with methods that do many unrelated things.
ryanofsky commented at 9:12 PM on May 25, 2022:re: #25065 (review)
Doing that does mean we can't remove
compat/glibcxx_sanity.cppfrom libbitcoinkernelLooking at current
SanityChecks()function, maybe a bigger problem moving it into the kernel is that it is usingInitErrorfromui_interface.cpp. So might be worth postponing this or doing it separately if it would complicate this PR.
dongcarl commented at 10:28 PM on May 25, 2022:Fixed as of 9ac87854af62d271df2f383d8f2f798c70453448, feel free to reopen if still an issue.
theuni commented at 10:53 PM on May 25, 2022:Nice, thanks.
Now that we have the notion of a context, it would be possible to either:
- Make it impossible to create an invalid context (sanity checks called at construction time)
- Allow for "invalid" contexts, which api calls check for.
But those can be done much later when we start actually defining an api.
in src/kernel/init/common.cpp:13 in 6d93c443a4 outdated
8 | +#include <pubkey.h> 9 | +#include <random.h> 10 | + 11 | +#include <memory> 12 | + 13 | +static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
theuni commented at 3:36 PM on May 24, 2022:I don't love the idea of chopping up and rearranging and moving the static cruft to the new clean home.
Do you have a next step in mind for this stuff?
dongcarl commented at 7:07 PM on May 25, 2022:Fixed as of 9bc9309bd61f36ac68b41fe2328d2e3f505397e1
theuni commented at 3:42 PM on May 24, 2022: memberConcept ACK and looks good from a light review.
No comment on the naming/structure, what was discussed above SGTM. I suspect this will change around a few times before finally settling anyway.
The split here seems pretty arbitrary... I could imagine a few different approaches to chopping up common.cpp and (without digging too much) this isn't the most obvious one to me. But if this keeps things moving, sure 👍.
DrahtBot removed the label Needs rebase on May 24, 2022ryanofsky commented at 12:43 AM on May 25, 2022: contributorFew suggestions (feel free to ignore):
- Would squash 3 commits to 1 commit. There's like 7 lines of code moving in this PR. I don't think moving it in 3 parts instead of 1 part helps anyone!
- Would rename
src/kernel/init/common.h,cpptosrc/kernel/init.h,cpp - Would rename
namespace inittonamespace kernel(namespace name not matching directory name is like a sign pointing in wrong direction, probably worse than not having the sign) - Maybe for followup, instead of
kernel::SetGlobalskernel::UnsetGlobalscall thesekernel::Initkernel::DestroyorLoad/Unloador similar. If you wanted to be really fancy you could call thesekernel::Context::Context()andkernel::Context::~Context()but no need to go crazy with another context struct yet.
ryanofsky commented at 12:34 PM on May 25, 2022: contributorTo explain suggestions in #25065 (comment) a little, I think the libbitcoin_kernel external interface should not use global variables. libbitcoin_kernel is supposed to be a library, and having used many libraries, I'd claim that libraries which use global variables or other implicit singletons are a pain to develop and test with.
I understand bitcoin code uses global variables, and you don't want to make big changes to existing code to get rid of them. This is fine. But we shouldn't add kernel functions which require the implementation use to global variables, and make them difficult to get rid of in the future.
You can easily create a clean API that does not require other code to use global variables by defining a
kernel::Contextstruct that owns whatever state is needed to run kernel functions, and passingContext*to functions insrc/kernel/meant to be called externally. Internally (especially at first),Context*won't be accessible to a lot of existing code, so global variables should still be used. They just need to point to the context or to specific members of the context instead of owning the state directly. Not much existing code should have to change. The only code that might have to change is the lowest-level code directly referencing global variables that were moved. Only some of this code would have to change, and no code above it would have to change.At a higher level, the
kernel::Contextstruct could just be understood as a thing which lets libbitcoin_kernel code remember state between calls, and interact with the outside world without relying on globals. So it can ask where is the data dir? How do I log this message? How do I generate a random number? What time is it? And so ontheuni commented at 2:27 PM on May 25, 2022: memberI understand bitcoin code uses global variables, and you don't want to make big changes to existing code to get rid of them. This is fine. But we shouldn't add kernel functions which require the implementation use to global variables, and make them difficult to get rid of in the future.
Totally agree with this. I think I was pretty much complaining about the same thing here: #25065 (review)
I expect lots of weird in-between-ness at this stage. But I was generally hoping that for the most part, the stuff that gets moved into the library would be relatively clean and not in need of much more untangling. In that regard, this PR seems a bit regressive.
At a higher level, the
kernel::Contextstruct could just be understood as a thing which lets libbitcoin_kernel code remember state between calls, and interact with the outside world without relying on globals. So it can ask where is the data dir? How do I log this message? How do I generate a random number? What time is it? And so on100% agree with this as well. I've been expecting a new Context struct to come into play and at this point it's a bit weird that we don't have one. This PR may be a good opportunity to introduce it.
dongcarl force-pushed on May 25, 2022dongcarl force-pushed on May 25, 2022dongcarl commented at 7:06 PM on May 25, 2022: contributorPushed 6d93c443a44f06296e8014c65bc70f44cc494fca -> 9bc9309bd61f36ac68b41fe2328d2e3f505397e1
- Overhauled PR to introduce a
kernel::Contextand move the global initialization logic to its ctor/dtor. (Thanks Cory+Ryan) - Leaving
compat/glibcxx_sanity.cppin libbitcoinkernel for now until we figure out #25065 (review)
dongcarl commented at 7:24 PM on May 25, 2022: contributorThanks for all the feedback @ryanofsky and @theuni, I really appreciate them. I totally agree that in this case it was a great idea and easy to introduce the
kernel::Contextalong with setting the globals, I actually discovered I had an old branch that did exactly this 😅Although in this case it was quite easy to make this change so we get the N I C E C O D E, it might be the case that in future PRs there will be instances where getting the N I C E C O D E will require very intrusive changes that doesn't serve the goal of Phase 1, which is just about decoupling modules. Should these cases arise, I hope we can decide to table them for later (although most of these cases are likely solved by introducing a
kernel::Context g_kernel, but we'll do that when we get to it).ryanofsky approvedryanofsky commented at 9:01 PM on May 25, 2022: contributorCode review ACK 9bc9309bd61f36ac68b41fe2328d2e3f505397e1. Looks great, I'd say.
there will be instances where getting the N I C E C O D E will require very intrusive changes that doesn't serve the goal
This seems fine as long as we have a reasonable idea of what a good cleaned up state would look like. Would just want to avoid making a mess without a plan to clean it up.
dongcarl renamed this:[kernel 2c/n] Extract only what we use of `init/common.cpp`
[kernel 2c/n] Introduce `kernel::Context`, encapsulate global init/teardown
on May 25, 2022dongcarl force-pushed on May 25, 2022dongcarl commented at 10:27 PM on May 25, 2022: contributorPush 9bc9309bd61f36ac68b41fe2328d2e3f505397e1 -> 9ac87854af62d271df2f383d8f2f798c70453448
- Implemented: #25065 (review)
@ryanofsky I know you don't like overly-split commits, happy to merge the last two if you wish.
in src/kernel/checks.h:16 in 9ac87854af outdated
11 | 12 | struct Context; 13 | 14 | +enum class SanityCheckError { 15 | + ERROR_INITITALIZING_ECC, 16 | + ERROR_GLIBCXX_INSANITY,
dongcarl commented at 11:17 PM on May 25, 2022:Fixed as of 239501f5d0e1df8d36a62f10c4de4e9cdc913a9c
dongcarl force-pushed on May 25, 2022dongcarl commented at 11:17 PM on May 25, 2022: contributorPushed 9ac87854af62d271df2f383d8f2f798c70453448 -> 239501f5d0e1df8d36a62f10c4de4e9cdc913a9c
- Addressed #25065 (review)
dongcarl force-pushed on May 25, 2022in src/kernel/context.h:20 in 239501f5d0 outdated
15 | +//! kernel libary API is a work in progress, so state organization and member 16 | +//! list will evolve over time. 17 | +//! 18 | +//! State stored directly in this struct should be simple. More complex state 19 | +//! should be stored to std::unique_ptr members pointing to opaque types. 20 | +struct Context {
vasild commented at 11:55 AM on May 27, 2022:The commit message of the first commit
test: Use Set/UnsetGlobals in BasicTestingSetupreads:In a future PR, we will introduce a kernel::Context ...
However,
kernel::Contextis introduced in this PR. Maybes/a future PR/the next commit/.
dongcarl commented at 6:45 PM on May 27, 2022:Fixed in 4fa8d0b11aefa06f548013a35bbcfa9fdbed81ff
in src/kernel/context.h:13 in 239501f5d0 outdated
8 | +#include <memory> 9 | + 10 | +class ECCVerifyHandle; 11 | + 12 | +namespace kernel { 13 | +//! Context struct holding global the kernel library's global state, and passed
vasild commented at 11:58 AM on May 27, 2022://! Context struct holding the kernel library's state, and passed
dongcarl commented at 6:45 PM on May 27, 2022:Fixed in cae459cd9aa0da220da92e11b3a645b9980cdaf5
in src/bitcoin-chainstate.cpp:54 in 239501f5d0 outdated
50 | @@ -49,7 +51,7 @@ int main(int argc, char* argv[]) 51 | SelectParams(CBaseChainParams::MAIN); 52 | const CChainParams& chainparams = Params(); 53 | 54 | - init::SetGlobals(); // ECC_Start, etc. 55 | + kernel::Context context{};
vasild commented at 12:05 PM on May 27, 2022:The variable of type
kernel::Contextis calledcontexthere andkernelinsidestruct NodeContext.kernel_context,kernel_stateorkernel_ctxmay be better.
dongcarl commented at 6:44 PM on May 27, 2022:Fixed in 319031b9798f1ed8f0a06e679284be26e0b42c92
vasild commented at 8:22 AM on May 30, 2022:Now it is called
kernel_contexthere andkernelelsewhere. Not a big deal, but I think it is better to be consistent if there are no other reasons for the naming.in src/kernel/checks.cpp:13 in 239501f5d0 outdated
9 | +#include <random.h> 10 | +#include <util/time.h> 11 | + 12 | +namespace kernel { 13 | + 14 | +std::optional<SanityCheckError> SanityChecks(Context&)
vasild commented at 12:45 PM on May 27, 2022:Why bother introducing an argument if it is going to be unused?
ryanofsky commented at 1:01 PM on May 27, 2022:Why bother introducing an argument if it is going to be unused?
It's because src/kernel/ is supposed to provide a library API, and the API should not have to change as we remove globals internally.
dongcarl commented at 6:44 PM on May 27, 2022:Going to mark this as resolved, feel free to reopen if not!
in src/kernel/checks.h:15 in 239501f5d0 outdated
10 | +namespace kernel { 11 | + 12 | +struct Context; 13 | + 14 | +enum class SanityCheckError { 15 | + ERROR_ECC,
vasild commented at 12:48 PM on May 27, 2022:The word "error" is redundant in the enum name and in each enum value:
SanityCheckError::ERROR_ECC ^^^^^ ^^^^^Maybe strip the
ERROR_prefix:SanityCheckError::ECC?vasild approvedvasild commented at 12:54 PM on May 27, 2022: contributorACK 239501f5d0e1df8d36a62f10c4de4e9cdc913a9c
Some non-blockers below.
in src/init.cpp:1098 in bdb0ce983e outdated
1095 | +bool AppInitSanityChecks(NodeContext& node) 1096 | { 1097 | // ********************************************************* Step 4: sanity checks 1098 | 1099 | - init::SetGlobals(); 1100 | + node.kernel = std::make_unique<kernel::Context>();
theuni commented at 2:49 PM on May 27, 2022:Mmm, this whole function is a mess and doesn't really make much sense anymore.
I really don't like the creation of the
kernel::Contexthappening in here. That's not at all intuitive. I would much prefer to see the caller create and set it. Mind addressing that here?A few potential follow-ups for a later PR:
- I'm hoping that the SanityChecks move into the
kernel::Contextcreation as a next step. - I think it may make sense for
NodeContextto take akernel::Contextin its constructor so that it always exists in the NodeContext. That might be much easier said than done though, I haven't looked deeply into it. - Those changes would leave only
LockDataDirectoryhere, meaning thatAppInitSanityCheckswould just go away.
dongcarl commented at 6:42 PM on May 27, 2022:I would much prefer to see the caller create and set it. Mind addressing that here?
Let me know if you think 8d63a934cf4053851ba79d4a44326cd079bc8288 suffices. If so, I will squash it in.
dongcarl commented at 6:46 PM on May 27, 2022:A few potential follow-ups for a later PR: ...
I will open an issue after this PR is merged so we don't lose track of these!
theuni commented at 8:21 PM on May 27, 2022:Ah yes, this is much more straightforward imo. +1 for squashing that in.
dongcarl force-pushed on May 27, 2022dongcarl force-pushed on May 27, 2022dongcarl commented at 6:47 PM on May 27, 2022: contributorPushed cf4c2043f592afe1d175f4c54e9728da38c0b184 -> 8d63a934cf4053851ba79d4a44326cd079bc8288
- Addressed various review comments
dongcarl force-pushed on May 27, 2022dongcarl commented at 9:01 PM on May 27, 2022: contributorPushed 8d63a934cf4053851ba79d4a44326cd079bc8288 -> ded2ef302cd29d3dc88a847f0fe8c947b3a6044a
- Squashed in 8d63a934cf4053851ba79d4a44326cd079bc8288
in src/bitcoin-chainstate.cpp:55 in d0cafa206e outdated
50 | @@ -49,7 +51,7 @@ int main(int argc, char* argv[]) 51 | SelectParams(CBaseChainParams::MAIN); 52 | const CChainParams& chainparams = Params(); 53 | 54 | - init::SetGlobals(); // ECC_Start, etc. 55 | + kernel::Context kernel_context{};
theuni commented at 9:57 PM on May 27, 2022:This also needs a
kernel::SanityChecks(kernel_context), no? Another argument for making it part of context creation.(It was also missing before, but presumably because it was still tangled up with the ui).
theuni commented at 11:52 PM on May 27, 2022:Btw, I'm loving how this just untangled itself. Great suggestion from @ryanofsky here!
dongcarl commented at 7:20 PM on May 31, 2022:Fixed as of: fa2ee7b12c0c15be8e9807444443b5bd2c91c3e5
vasild commented at 1:30 PM on June 2, 2022:Hmm, it is strange to sanity-check a default constructed object:
Context foo; assert(sanity_check(foo));Shouldn't a default constructor create a sane object? If sometimes it can produce insane object (based on what? it takes no arguments) then it is better to throw from the constructor instead of assert()ing immediately after object creation.
theuni commented at 9:11 PM on June 2, 2022:Completely agree it's wonky, I had a similar complaint here: #25065 (review)
I think it's fine as-is for now though, as context creation will definitely be changing in subsequent PRs.
fanquake referenced this in commit cc61bc2e19 on May 28, 2022vasild approvedvasild commented at 8:23 AM on May 30, 2022: contributorACK ded2ef302cd29d3dc88a847f0fe8c947b3a6044a
I would expect the kernel API to be defined in
src/kernel/*.hinsidenamespace kerneland those files to not define anything else.src/kernel/chainstatemanager_opts.hdoes not fit that pattern - it definesChainstateManagerOptsoutside of thekernelnamespace. So, isChainstateManagerOptspart of the kernel API? If yes, then it should be insidenamespace kernel, if not then it should not be defined insrc/kernel/*.h.ChainstateManagerOptsis only used invalidation.h.maflcko referenced this in commit 8779adbdda on May 30, 2022DrahtBot added the label Needs rebase on May 30, 2022eeb4fc20c5test: Use Set/UnsetGlobals in BasicTestingSetup
...instead of calling initialization functions directly and having to keep around a ECCVerifyHandle member variable. This makes the initialization codepath of our tests more closely resemble those of AppInitMain and potentially eases the review of subsequent commit removing init::{Set,Unset}Globals. [META] In a future commit, we will introduce a kernel::Context which calls init::{Set,Unset}Globals in its ctor and dtor. It will be owned by node::NodeContext, so in the end, this patchset won't have made the previously local ECCVerifyHandle global.7d03feef81kernel: Introduce empty and unused kernel::Context
[META] In the next commit, we will move the init::{Set,Unset}Globals logic into this struct. Co-Authored-By: Ryan Ofsky <ryan@ofsky.org>dongcarl force-pushed on May 31, 2022dongcarl commented at 7:08 PM on May 31, 2022: contributorPushed ded2ef302cd29d3dc88a847f0fe8c947b3a6044a -> fa2ee7b12c0c15be8e9807444443b5bd2c91c3e5
- Rebased over merge of #25233
- Addressed #25065 (review)
- Fixed some
#includes insrc/bitcoin-chainstate.cpp
dongcarl commented at 7:15 PM on May 31, 2022: contributorI would expect the kernel API to be defined in
src/kernel/*.hinsidenamespace kerneland those files to not define anything else.src/kernel/chainstatemanager_opts.hdoes not fit that pattern - it definesChainstateManagerOptsoutside of thekernelnamespace. So, isChainstateManagerOptspart of the kernel API? If yes, then it should be insidenamespace kernel, if not then it should not be defined insrc/kernel/*.h.ChainstateManagerOptsis only used invalidation.h.Sorry about my cheeky post above 😄 To respond to your comment: yes it should eventually be in
namespace kernel, so should most ofvalidation.cpp. Haven't done it yet because it's not required by any of the "PRs in the main thrust of libbitcoinkernel".DrahtBot removed the label Needs rebase on May 31, 2022in src/init.cpp:1094 in fa2ee7b12c outdated
1090 | @@ -1089,13 +1091,23 @@ static bool LockDataDirectory(bool probeOnly) 1091 | return true; 1092 | } 1093 | 1094 | -bool AppInitSanityChecks() 1095 | +bool AppInitSanityChecks(kernel::Context& kernel)
theuni commented at 1:30 PM on June 1, 2022:This should be const ref I think.
in src/kernel/checks.h:23 in fa2ee7b12c outdated
18 | +}; 19 | + 20 | +/** 21 | + * Ensure a usable environment with all necessary library support. 22 | + */ 23 | +std::optional<SanityCheckError> SanityChecks(Context&);
theuni commented at 1:31 PM on June 1, 2022:Also const ref?
vasild commented at 1:33 PM on June 2, 2022:I agree, it would be weird for a sanity-check function to modify the object it is checking.
in src/node/interfaces.cpp:93 in fa2ee7b12c outdated
89 | @@ -90,8 +90,14 @@ class NodeImpl : public Node 90 | uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); } 91 | bool baseInitialize() override 92 | { 93 | - return AppInitBasicSetup(gArgs) && AppInitParameterInteraction(gArgs, /*use_syscall_sandbox=*/false) && AppInitSanityChecks() && 94 | - AppInitLockDataDirectory() && AppInitInterfaces(*m_context); 95 | + return AppInitBasicSetup(gArgs) &&
theuni commented at 1:35 PM on June 1, 2022:Heh, this has gotten unwieldy and hard to read imo.
How about (untested)
if (!AppInitBasicSetup(gArgs)) return false; if (!AppInitParameterInteraction(gArgs, /*use_syscall_sandbox=*/false)) return false; m_context->kernel = std::make_unique<kernel::Context>(); if (!AppInitSanityChecks(*m_context->kernel)) return false; if (!AppInitLockDataDirectory()) return false; if (!AppInitInterfaces(*m_context)) return false; return true;theuni commented at 1:39 PM on June 1, 2022: memberI took one last pass through, looking good.
Left a comment about a messy function, not the end of the world if it doesn't get addressed here.
I do think the const ref issues (there may be others) should be addressed though so that it's clear moving forward what's intended to be read-only.
vasild approvedvasild commented at 1:40 PM on June 2, 2022: contributorACK fa2ee7b12c0c15be8e9807444443b5bd2c91c3e5
yes it should eventually be in
namespace kernelOk, why not get it right from the first time, since it is trivial to do so:
--- i/src/kernel/chainstatemanager_opts.h +++ w/src/kernel/chainstatemanager_opts.h @@ -7,17 +7,20 @@ #include <cstdint> #include <functional> class CChainParams; +namespace kernel { + /** * An options struct for `ChainstateManager`, more ergonomically referred to as * `ChainstateManager::Options` due to the using-declaration in * `ChainstateManager`. */ struct ChainstateManagerOpts { const CChainParams& chainparams; const std::function<int64_t()> adjusted_time_callback{nullptr}; }; +} // namespace kernel #endif // BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H --- i/src/validation.h +++ w/src/validation.h @@ -854,13 +854,13 @@ private: const CBlockHeader& block, BlockValidationState& state, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); friend CChainState; public: - using Options = ChainstateManagerOpts; + using Options = kernel::ChainstateManagerOpts; explicit ChainstateManager(const Options& opts) : m_chainparams{opts.chainparams}, m_adjusted_time_callback{Assert(opts.adjusted_time_callback)} {}; const CChainParams& GetParams() const { return m_chainparams; }fed085a1a4init: Initialize globals with kernel::Context's life
...instead of explicitly calling init::{Set,Unset}Globals. Cool thing about this is that in both the testing and bitcoin-chainstate codepaths, we no longer need to explicitly unset globals. The kernel::Context goes out of scope and the globals are unset "automatically". Also construct kernel::Context outside of AppInitSanityChecks()Move init::SanityCheck to kernel::SanityCheck 265d6393bfdongcarl force-pushed on Jun 2, 2022dongcarl commented at 3:49 PM on June 2, 2022: contributorPushed fa2ee7b12c0c15be8e9807444443b5bd2c91c3e5 -> a8cdeca079a362d2a021aaf7387fbb75a15ebc18
- Addressed
dongcarl commented at 3:51 PM on June 2, 2022: contributorOk, why not get it right from the first time, since it is trivial to do so:
Yeah sorry I should have done that in the first place. But it's unrelated to the current PR right now so we'll just do it later. I've added it as a TODO to the umbrella issue!
d87784ac87kernel: SanityChecks: Return an error struct
This reduces libbitcoinkernel's coupling with ui_interface and translation.
in src/init.cpp:1109 in a8cdeca079 outdated
1109 | + case kernel::SanityCheckError::ERROR_RANDOM: 1110 | + InitError(Untranslated("OS cryptographic RNG sanity check failure. Aborting.")); 1111 | + break; 1112 | + case kernel::SanityCheckError::ERROR_CHRONO: 1113 | + InitError(Untranslated("Clock epoch mismatch. Aborting.")); 1114 | + break;
JeremyRubin commented at 3:59 PM on June 2, 2022:default: assert(0)?
dongcarl commented at 4:25 PM on June 2, 2022:Addressed in d87784ac87364fc977bbf9769c8bdb72dea8cbf9, feel free to reopen this convo if not resolved!
theuni commented at 9:04 PM on June 2, 2022:FWIW, gcc/clang have built-ins (
__builtin_unreachable) for expressing this explicitly.LLVM even has a macro for it, and specifies the use of
llvm_unreachablein its coding standard.Maybe we should borrow the idea and add a similar macro. Not in this PR though, of course :)
Edit: explanation of what
llvm_unreachabledoes:"When assertions are enabled, this will print the message if it’s ever reached and then exit the program. When assertions are disabled (i.e. in release builds), llvm_unreachable becomes a hint to compilers to skip generating code for this branch. If the compiler does not support this, it will fall back to the “abort” implementation."
maflcko commented at 6:37 AM on June 3, 2022:Interesting, though I think we'd always want to abort, even in release builds. For example, it would be UB to skip
returnin a non-void function, no? This is also what the docs say:llvm_unreachable() becomes an optimizer hint that the current location is not supposed to be reachable: the hint turns such code path into undefined behavior.
https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/Support/ErrorHandling.h#L131
For reference, in #24812 (review) I argued that
assert(0)is good enough for us. Also, I don't think there is a compiler that doesn't understandassert(0)?
theuni commented at 2:55 PM on June 3, 2022:The only reason I suggested is because imo it's nice to be able to state "shouldn't be able to get here" differently than "crash if ever here", as not stating the former clearly leads to (good) questions in review like this one from @JeremyRubin.
Even if
bitcoin_unreachable()is just a macro defined asassert(0), I think it'd be an improvement over nothing.
maflcko commented at 7:38 AM on June 4, 2022:I think the primary question here was why there is no default case, to which the answer is that we happily accept a fallthrough to an InitError. No objection to a macro that just calls
assert(0), if ppl think it is useful.
vasild commented at 10:40 AM on June 6, 2022:... why there is no default case ...
My favorite reason is that, because the switch value is an enum, we get a compile-time warning (or error with
-Werrorwhich is used by CI) if not all enum values are listed.dongcarl force-pushed on Jun 2, 2022dongcarl commented at 4:24 PM on June 2, 2022: contributorPushed a8cdeca079a362d2a021aaf7387fbb75a15ebc18 -> d87784ac87364fc977bbf9769c8bdb72dea8cbf9
- Added comment about missing default case (thanks Jeremy!)
in src/test/util/setup_common.h:84 in fed085a1a4 outdated
80 | @@ -81,7 +81,7 @@ static constexpr CAmount CENT{1000000}; 81 | * This just configures logging, data dir and chain parameters. 82 | */ 83 | struct BasicTestingSetup { 84 | - node::NodeContext m_node; 85 | + node::NodeContext m_node; // keep as first member to be destructed last
theuni commented at 9:32 PM on June 2, 2022:A foot-gun-proof way to do this would be to inherit from a class that holds a node::NodeContext.
dongcarl commented at 5:17 PM on June 3, 2022:Something like this?
diff --git a/src/node/context.h b/src/node/context.h index 31be308787..7ed1292180 100644 --- a/src/node/context.h +++ b/src/node/context.h @@ -29,6 +29,16 @@ class Init; class WalletLoader; } // namespace interfaces +namespace { +/** + * Dummy NodeContext to ensure that kernel::Context is always destructed last. + */ +struct BaseNodeContext { + //! libbitcoin_kernel context + std::unique_ptr<kernel::Context> kernel; +}; +} + namespace node { //! NodeContext struct containing references to chain state and connection //! state. @@ -40,9 +50,7 @@ namespace node { //! and make code more modular and testable. The struct isn't intended to have //! any member functions. It should just be a collection of references that can //! be used without pulling in unwanted dependencies or functionality. -struct NodeContext { - //! libbitcoin_kernel context - std::unique_ptr<kernel::Context> kernel; +struct NodeContext : BaseNodeContext { //! Init interface for initializing current process and connecting to other processes. interfaces::Init* init{nullptr}; std::unique_ptr<AddrMan> addrman; diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index 5c31cfc22b..87d5d4a24b 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -77,12 +77,20 @@ static inline bool InsecureRandBool() { return g_insecure_rand_ctx.randbool(); } static constexpr CAmount CENT{1000000}; +namespace { +/** + * Dummy TestingSetup to ensure that node::NodeContext (and by extension + * kernel::Context) is always destructed last. + */ +struct BaseTestingSetup { + node::NodeContext m_node; +}; +} + /** Basic testing setup. * This just configures logging, data dir and chain parameters. */ -struct BasicTestingSetup { - node::NodeContext m_node; // keep as first member to be destructed last - +struct BasicTestingSetup : BaseTestingSetup { explicit BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {}); ~BasicTestingSetup();
theuni commented at 5:53 PM on June 3, 2022:Yep, pretty much!
Sorry, I didn't mean to imply that needed to be done as part of this PR though. It might be worth taking a look at doing it generically with a template, which could help communicate the intent more clearly:
BasicTestingSetup : MustDestructLast<node::NodeContext>But maybe that's over-engineering, idk.
ryanofsky commented at 5:54 PM on June 3, 2022:A foot-gun-proof way to do this would be to inherit from a class that holds a node::NodeContext.
Would really encourage not doing this. There is no ambiguity about initialization order in the c++ language: earlier members are constructed first and destructed last, later members are constructed later and destructed earlier. Moving members into a base class to control what they are initialized here would seems mostly like a form of obfuscation.
It is true that if a future developer willingly wants to ignore a "this member should be first" comment it will be harder for them to do that if inheritance is involved, but it's true in general that if you obfuscate code it is harder to modify, and I don't think this logic leads to good places
theuni commented at 6:03 PM on June 3, 2022:@ryanofsky Points taken. I think the intents/relationships need to be made clear somehow. Programmatically is one way, but maybe a comment works just as well without all the obfuscation.
In any case, this definitely shouldn't slow down this PR.
ryanofsky commented at 6:18 PM on June 3, 2022:I do agree relationship should be explicit if one thing depends on the other. Another safeguard that may be useful is if thing A needs to be destroyed after thing B, thing B destructor can assert that thing A is not destroyed yet (assuming relevant code will already have test coverage since it is part of the test setup)
dongcarl commented at 8:57 PM on June 3, 2022:Okay, sounds like we're okay with leaving it as just a comment like in the latest push d87784ac87364fc977bbf9769c8bdb72dea8cbf9. Going to close this convo but feel free to re-open if further discussion is worth it.
theuni approvedvasild approvedvasild commented at 7:53 AM on June 3, 2022: contributorACK d87784ac87364fc977bbf9769c8bdb72dea8cbf9
fanquake merged this on Jun 4, 2022fanquake closed this on Jun 4, 2022sidhujag referenced this in commit ceee697fb1 on Jun 5, 2022in src/bitcoin-chainstate.cpp:56 in d87784ac87
51 | @@ -49,7 +52,11 @@ int main(int argc, char* argv[]) 52 | SelectParams(CBaseChainParams::MAIN); 53 | const CChainParams& chainparams = Params(); 54 | 55 | - init::SetGlobals(); // ECC_Start, etc. 56 | + kernel::Context kernel_context{}; 57 | + // We can't use a goto here, but we can use an assert since none of the
maflcko commented at 1:29 PM on June 6, 2022:unrelated: Probably a good time to get rid of
gotoinstead of adding comments on whygotocan't be used here. :sweat_smile:in src/kernel/context.cpp:24 in d87784ac87
19 | +{ 20 | + std::string sha256_algo = SHA256AutoDetect(); 21 | + LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo); 22 | + RandomInit(); 23 | + ECC_Start(); 24 | + ecc_verify_handle.reset(new ECCVerifyHandle());
maflcko commented at 1:31 PM on June 6, 2022:fed085a1a4cd2787202752b6a0d98e42dce97f09 nit: Why not change to make_unique while changing the line?
fanquake commented at 2:51 PM on January 17, 2023:This code no-longer exists. Was removed in the most recent secp256k1 update (#26691).
in src/test/util/setup_common.cpp:149 in fed085a1a4 outdated
145 | @@ -146,7 +146,6 @@ BasicTestingSetup::~BasicTestingSetup() 146 | LogInstance().DisconnectTestLogger(); 147 | fs::remove_all(m_path_root); 148 | gArgs.ClearArgs(); 149 | - init::UnsetGlobals();
maflcko commented at 1:43 PM on June 6, 2022:fed085a1a4cd2787202752b6a0d98e42dce97f09: Looks like
m_node.kernelisn't reset and left "dangling" until the end of~BasicTestingSetup, which only happens to be here? Seems both brittle and inconsistent with the shutdown sequence in bitcoind, no?in src/kernel/checks.cpp:4 in 265d6393bf outdated
0 | @@ -0,0 +1,33 @@ 1 | +// Copyright (c) 2022 The Bitcoin Core developers 2 | +// Distributed under the MIT software license, see the accompanying 3 | +// file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | +
maflcko commented at 1:51 PM on June 6, 2022:nit: Could have added new files to be checked by iwyu?
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh index e64af2ad5..f17d823ee 100755 --- a/ci/test/06_script_b.sh +++ b/ci/test/06_script_b.sh @@ -43,2 +41,4 @@ if [ "${RUN_TIDY}" = "true" ]; then " src/init"\ + " src/kernel/checks.cpp"\ + " src/kernel/context.cpp"\ " src/rpc/fees.cpp"\
fanquake commented at 2:50 PM on January 17, 2023:All of
src/kernelis now under IWYU.maflcko commented at 1:51 PM on June 6, 2022: memberLeft some nits and a test setup question.
in src/kernel/context.h:15 in d87784ac87
10 | +class ECCVerifyHandle; 11 | + 12 | +namespace kernel { 13 | +//! Context struct holding the kernel library's logically global state, and 14 | +//! passed to external libbitcoin_kernel functions which need access to this 15 | +//! state. The kernel libary API is a work in progress, so state organization
maflcko commented at 1:53 PM on June 6, 2022:src/kernel/context.h:15: libary ==> library
janus referenced this in commit f2b5f7ebf2 on Aug 4, 2022knst referenced this in commit 2929027a5b on Nov 5, 2023knst referenced this in commit 56e78b40ef on Nov 6, 2023PastaPastaPasta referenced this in commit 17d017ec88 on Nov 7, 2023achow101 referenced this in commit c981771bc3 on Nov 7, 2023bitcoin locked this on Jan 17, 2024
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: 2026-04-22 09:14 UTC
This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me
