[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
  1. dongcarl commented at 10:41 pm on May 4, 2022: contributor
    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().
  2. DrahtBot added the label Build system on May 4, 2022
  3. DrahtBot added the label Utils/log/libs on May 4, 2022
  4. 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 kernel folder for code that is shared between node and kernel. An alternative would be to name it init/kernel.cpp or init/globals.cpp?

    Otherwise it will be difficult to decide whether to put kernel code that is used elsewhere as well in kernel or 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.cpp would work.

    One question is: do we keep the two functions moved in the init:: namespace or the kernel:: namespace.

    In the longer run, I think eventually (very far off when libbitcoinkernel is very minimal) we could put everything that links into libbitcoinkernel into the src/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.cpp will 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 libbitcoinkernel depends on to libbitcoin_util, now that’s just w/re the libraries, we could do either one of two things for the hierarchy:

    1. src/kernel/ and src/util/, or
    2. src/kernel/ and src/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/util and src/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/util and src/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:

    • common will be the non-kernel “util lib” (i.e. src/util), and
    • util will 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.

  5. 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 libbitcoinkernel project) 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:

    0#include <kernel/include/init/common.h> // IWYU pragma: export
    

    dongcarl commented at 8:19 pm on May 5, 2022:
    Fixed as of: 31c21f3644f6f42f6e4c3c231e95bf0b87ab86f5
  6. maflcko approved
  7. DrahtBot commented at 2:14 pm on May 5, 2022: contributor

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

    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.

  8. dongcarl force-pushed on May 5, 2022
  9. dongcarl commented at 8:15 pm on May 5, 2022: contributor

    Pushed d5876d1efbf01f45fff2b42e0bcf2bc12eb25240 -> 13e65511dba702d115b7bea147b12eefaea9d53f

  10. dongcarl force-pushed on May 5, 2022
  11. dongcarl commented at 8:20 pm on May 5, 2022: contributor

    Pushed 13e65511dba702d115b7bea147b12eefaea9d53f -> 708e2711e591ce4958900715348cb0313763f2cb

  12. dongcarl force-pushed on May 5, 2022
  13. dongcarl commented at 10:10 pm on May 5, 2022: contributor

    Pushed 708e2711e591ce4958900715348cb0313763f2cb -> e4c35528e58a74138aa7e0560dd7f59f1086c765

  14. maflcko added the label DrahtBot Guix build requested on May 13, 2022
  15. DrahtBot commented at 2:34 am on May 17, 2022: contributor

    Guix builds

    File commit 225e5b57b2ee2bc1acd7f09c89ccccc15ef8c85f(master) commit a35aa55df7cab97be04bdae6cba6c7912f2d45be(master and this pull)
    SHA256SUMS.part 1b58b80ca65983b3... 697fe8221c822555...
    *-aarch64-linux-gnu-debug.tar.gz 26b50f702207b949... 05f6440c047876da...
    *-aarch64-linux-gnu.tar.gz 93156ddbf46f81df... 67a244cd13c03670...
    *-arm-linux-gnueabihf-debug.tar.gz 448908d67e456427... cb9335c39864cd59...
    *-arm-linux-gnueabihf.tar.gz 595189752c32bf97... edfeeb3c6586e579...
    *-arm64-apple-darwin-unsigned.dmg 8fe9a774204a88c7... 0efc857243f4834c...
    *-arm64-apple-darwin-unsigned.tar.gz 293f411c2dc51edb... 3def6f714f5c9ac2...
    *-arm64-apple-darwin.tar.gz abca1d81d437a08a... c7ef8d7b1ffa0ff3...
    *-powerpc64-linux-gnu-debug.tar.gz 1744beebac78a5d6... 2ed359d1c868c668...
    *-powerpc64-linux-gnu.tar.gz ec4d4712136dc767... 6334b422a3a3e628...
    *-powerpc64le-linux-gnu-debug.tar.gz ac1890b8743df6a5... f63b456b18ad54e0...
    *-powerpc64le-linux-gnu.tar.gz b0ebc5e4120bf000... bd14c28c65a5966e...
    *-riscv64-linux-gnu-debug.tar.gz 702be3dc495a5a10... 434bec65cbf9eeed...
    *-riscv64-linux-gnu.tar.gz ad1394d672c7b965... b95c9bec21a376cb...
    *-win64-debug.zip 5464743530003d4d... 1ed6bffb08973b9b...
    *-win64-setup-unsigned.exe 955c755466eb2b07... 6cac9eed002e77df...
    *-win64-unsigned.tar.gz 0126640c2d061f14... 2f217181be03e5e8...
    *-win64.zip 5b07889e2dce9103... 1589a390a05ca335...
    *-x86_64-apple-darwin-unsigned.dmg c5526437a0193c3b... 061d5c7851f79fd4...
    *-x86_64-apple-darwin-unsigned.tar.gz e1d81f18176fab2e... 2283101f6da8291c...
    *-x86_64-apple-darwin.tar.gz d34e5f7fe086c51f... 3b0e96d379306eda...
    *-x86_64-linux-gnu-debug.tar.gz acb6561a5919c80f... e83da3071ae21cad...
    *-x86_64-linux-gnu.tar.gz 00bb67a5b4e29ca3... e947650852f0918d...
    *.tar.gz ab4e54f5d920eb45... 6167eae7a1103d2c...
    guix_build.log 68d9a71f1973680b... e17425caa820c218...
    guix_build.log.diff a2f6c50b1586c11b...
  16. DrahtBot removed the label DrahtBot Guix build requested on May 17, 2022
  17. DrahtBot added the label Needs rebase on May 20, 2022
  18. dongcarl force-pushed on May 20, 2022
  19. dongcarl commented at 9:31 pm on May 20, 2022: contributor

    Pushed e4c35528e58a74138aa7e0560dd7f59f1086c765 -> e6f8606007a1690dcf9265d15c7fe15cf5eb5239

    • Rebased over master after merge of #25064
  20. DrahtBot removed the label Needs rebase on May 20, 2022
  21. DrahtBot added the label Needs rebase on May 24, 2022
  22. dongcarl force-pushed on May 24, 2022
  23. dongcarl commented at 2:16 pm on May 24, 2022: contributor

    Push e6f8606007a1690dcf9265d15c7fe15cf5eb5239 -> 6d93c443a44f06296e8014c65bc70f44cc494fca

    • Rebased over master after merge of #24410
  24. in 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
  25. 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 SanityChecks out as well, as it’s effectively a runtime test for SetGlobals (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 remove compat/glibcxx_sanity.cpp from 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 remove compat/glibcxx_sanity.cpp from 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.cpp doesn’t add costs or complications. (glibcxx_sanity.cpp is 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&) in src/kernel/checks.cpp or similar. A bool Context::SanityChecks() method in src/kernel/context.cpp would make kernel code less modular, and risk sending Context object down a road where it becomes a disorganized CWallet-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.cpp from libbitcoinkernel

    Looking at current SanityChecks() function, maybe a bigger problem moving it into the kernel is that it is using InitError from ui_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.

  26. 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
  27. theuni commented at 3:42 pm on May 24, 2022: member

    Concept 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 👍.

  28. DrahtBot removed the label Needs rebase on May 24, 2022
  29. ryanofsky commented at 0:43 am on May 25, 2022: contributor

    Few 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,cpp to src/kernel/init.h,cpp
    • Would rename namespace init to namespace 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::SetGlobals kernel::UnsetGlobals call these kernel::Init kernel::Destroy or Load/Unload or similar. If you wanted to be really fancy you could call these kernel::Context::Context() and kernel::Context::~Context() but no need to go crazy with another context struct yet.
  30. ryanofsky commented at 12:34 pm on May 25, 2022: contributor

    To 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::Context struct that owns whatever state is needed to run kernel functions, and passing Context* to functions in src/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::Context struct 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 on

  31. theuni commented at 2:27 pm on May 25, 2022: member

    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.

    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::Context struct 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 on

    100% 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.

  32. dongcarl force-pushed on May 25, 2022
  33. dongcarl force-pushed on May 25, 2022
  34. dongcarl commented at 7:06 pm on May 25, 2022: contributor

    Pushed 6d93c443a44f06296e8014c65bc70f44cc494fca -> 9bc9309bd61f36ac68b41fe2328d2e3f505397e1

    • Overhauled PR to introduce a kernel::Context and move the global initialization logic to its ctor/dtor. (Thanks Cory+Ryan)
    • Leaving compat/glibcxx_sanity.cpp in libbitcoinkernel for now until we figure out #25065 (review)
  35. dongcarl commented at 7:24 pm on May 25, 2022: contributor

    Thanks 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::Context along 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).

  36. ryanofsky approved
  37. ryanofsky commented at 9:01 pm on May 25, 2022: contributor

    Code 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.

  38. 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, 2022
  39. dongcarl force-pushed on May 25, 2022
  40. dongcarl commented at 10:27 pm on May 25, 2022: contributor

    Push 9bc9309bd61f36ac68b41fe2328d2e3f505397e1 -> 9ac87854af62d271df2f383d8f2f798c70453448


    @ryanofsky I know you don’t like overly-split commits, happy to merge the last two if you wish.

  41. 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,
    


    theuni commented at 11:10 pm on May 25, 2022:

    Though it’s quite literal here, keeping with precedent, let’s not reintroduce this language: #5727

    The errors are already namespaced as part of the enum class anyway, how about just SanityCheckError::ERROR_GLIBCXX ?


    dongcarl commented at 11:17 pm on May 25, 2022:
    Fixed as of 239501f5d0e1df8d36a62f10c4de4e9cdc913a9c
  42. dongcarl force-pushed on May 25, 2022
  43. dongcarl commented at 11:17 pm on May 25, 2022: contributor

    Pushed 9ac87854af62d271df2f383d8f2f798c70453448 -> 239501f5d0e1df8d36a62f10c4de4e9cdc913a9c

  44. dongcarl force-pushed on May 25, 2022
  45. in 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 BasicTestingSetup reads:

    In a future PR, we will introduce a kernel::Context …

    However, kernel::Context is introduced in this PR. Maybe s/a future PR/the next commit/.


    dongcarl commented at 6:45 pm on May 27, 2022:
    Fixed in 4fa8d0b11aefa06f548013a35bbcfa9fdbed81ff
  46. 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:
    0//! Context struct holding the kernel library's state, and passed
    

    dongcarl commented at 6:45 pm on May 27, 2022:
    Fixed in cae459cd9aa0da220da92e11b3a645b9980cdaf5
  47. 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::Context is called context here and kernel inside struct NodeContext. kernel_context, kernel_state or kernel_ctx may 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_context here and kernel elsewhere. Not a big deal, but I think it is better to be consistent if there are no other reasons for the naming.
  48. 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!
  49. 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:

    0SanityCheckError::ERROR_ECC
    1           ^^^^^  ^^^^^
    

    Maybe strip the ERROR_ prefix: SanityCheckError::ECC?

  50. vasild approved
  51. vasild commented at 12:54 pm on May 27, 2022: contributor

    ACK 239501f5d0e1df8d36a62f10c4de4e9cdc913a9c

    Some non-blockers below.

  52. 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::Context happening 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::Context creation as a next step.
    • I think it may make sense for NodeContext to take a kernel::Context in 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 LockDataDirectory here, meaning that AppInitSanityChecks would 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.
  53. dongcarl force-pushed on May 27, 2022
  54. dongcarl force-pushed on May 27, 2022
  55. dongcarl commented at 6:47 pm on May 27, 2022: contributor

    Pushed cf4c2043f592afe1d175f4c54e9728da38c0b184 -> 8d63a934cf4053851ba79d4a44326cd079bc8288

    • Addressed various review comments
  56. dongcarl force-pushed on May 27, 2022
  57. dongcarl commented at 9:01 pm on May 27, 2022: contributor

    Pushed 8d63a934cf4053851ba79d4a44326cd079bc8288 -> ded2ef302cd29d3dc88a847f0fe8c947b3a6044a

    • Squashed in 8d63a934cf4053851ba79d4a44326cd079bc8288
  58. 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:

    0Context foo;
    1assert(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.

  59. fanquake referenced this in commit cc61bc2e19 on May 28, 2022
  60. vasild approved
  61. vasild commented at 8:23 am on May 30, 2022: contributor

    ACK ded2ef302cd29d3dc88a847f0fe8c947b3a6044a

    I would expect the kernel API to be defined in src/kernel/*.h inside namespace kernel and those files to not define anything else. src/kernel/chainstatemanager_opts.h does not fit that pattern - it defines ChainstateManagerOpts outside of the kernel namespace. So, is ChainstateManagerOpts part of the kernel API? If yes, then it should be inside namespace kernel, if not then it should not be defined in src/kernel/*.h. ChainstateManagerOpts is only used in validation.h.

  62. maflcko referenced this in commit 8779adbdda on May 30, 2022
  63. DrahtBot added the label Needs rebase on May 30, 2022
  64. dongcarl commented at 4:17 pm on May 31, 2022: contributor

    @vasild Your comment inspired me to make this, I think I’m going to use it in every libbitcoinkernel PR from now on!

    kernel-disclaimer

  65. test: 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.
    eeb4fc20c5
  66. kernel: 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>
    7d03feef81
  67. dongcarl force-pushed on May 31, 2022
  68. dongcarl commented at 7:08 pm on May 31, 2022: contributor

    Pushed ded2ef302cd29d3dc88a847f0fe8c947b3a6044a -> fa2ee7b12c0c15be8e9807444443b5bd2c91c3e5

    • Rebased over merge of #25233
    • Addressed #25065 (review)
    • Fixed some #includes in src/bitcoin-chainstate.cpp
  69. dongcarl commented at 7:15 pm on May 31, 2022: contributor

    @vasild

    I would expect the kernel API to be defined in src/kernel/*.h inside namespace kernel and those files to not define anything else. src/kernel/chainstatemanager_opts.h does not fit that pattern - it defines ChainstateManagerOpts outside of the kernel namespace. So, is ChainstateManagerOpts part of the kernel API? If yes, then it should be inside namespace kernel, if not then it should not be defined in src/kernel/*.h. ChainstateManagerOpts is only used in validation.h.

    Sorry about my cheeky post above 😄 To respond to your comment: yes it should eventually be in namespace kernel, so should most of validation.cpp. Haven’t done it yet because it’s not required by any of the “PRs in the main thrust of libbitcoinkernel”.

  70. DrahtBot removed the label Needs rebase on May 31, 2022
  71. in 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.
  72. 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.
  73. 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)

    0if (!AppInitBasicSetup(gArgs)) return false;
    1if (!AppInitParameterInteraction(gArgs, /*use_syscall_sandbox=*/false)) return false;
    2
    3m_context->kernel = std::make_unique<kernel::Context>();
    4if (!AppInitSanityChecks(*m_context->kernel)) return false;
    5if (!AppInitLockDataDirectory()) return false;
    6if (!AppInitInterfaces(*m_context)) return false;
    7return true;
    
  74. theuni commented at 1:39 pm on June 1, 2022: member

    I 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.

  75. vasild approved
  76. vasild commented at 1:40 pm on June 2, 2022: contributor

    ACK fa2ee7b12c0c15be8e9807444443b5bd2c91c3e5

    yes it should eventually be in namespace kernel

    Ok, why not get it right from the first time, since it is trivial to do so:

     0--- i/src/kernel/chainstatemanager_opts.h
     1+++ w/src/kernel/chainstatemanager_opts.h
     2@@ -7,17 +7,20 @@
     3 
     4 #include <cstdint>
     5 #include <functional>
     6 
     7 class CChainParams;
     8 
     9+namespace kernel {
    10+
    11 /**
    12  * An options struct for `ChainstateManager`, more ergonomically referred to as
    13  * `ChainstateManager::Options` due to the using-declaration in
    14  * `ChainstateManager`.
    15  */
    16 struct ChainstateManagerOpts {
    17     const CChainParams& chainparams;
    18     const std::function<int64_t()> adjusted_time_callback{nullptr};
    19 };
    20+} // namespace kernel
    21 
    22 #endif // BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H
    23--- i/src/validation.h
    24+++ w/src/validation.h
    25@@ -854,13 +854,13 @@ private:
    26         const CBlockHeader& block,
    27         BlockValidationState& state,
    28         CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
    29     friend CChainState;
    30 
    31 public:
    32-    using Options = ChainstateManagerOpts;
    33+    using Options = kernel::ChainstateManagerOpts;
    34 
    35     explicit ChainstateManager(const Options& opts)
    36         : m_chainparams{opts.chainparams},
    37           m_adjusted_time_callback{Assert(opts.adjusted_time_callback)} {};
    38 
    39     const CChainParams& GetParams() const { return m_chainparams; }
    
  77. init: 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()
    fed085a1a4
  78. Move init::SanityCheck to kernel::SanityCheck 265d6393bf
  79. dongcarl force-pushed on Jun 2, 2022
  80. dongcarl commented at 3:49 pm on June 2, 2022: contributor

    Pushed fa2ee7b12c0c15be8e9807444443b5bd2c91c3e5 -> a8cdeca079a362d2a021aaf7387fbb75a15ebc18

  81. dongcarl commented at 3:51 pm on June 2, 2022: contributor

    @vasild

    Ok, 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!

  82. kernel: SanityChecks: Return an error struct
    This reduces libbitcoinkernel's coupling with ui_interface and
    translation.
    d87784ac87
  83. 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:
    0default:
    1   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_unreachable in 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_unreachable does:

    “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 return in 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 understand assert(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 as assert(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 -Werror which is used by CI) if not all enum values are listed.

  84. dongcarl force-pushed on Jun 2, 2022
  85. dongcarl commented at 4:24 pm on June 2, 2022: contributor

    Pushed a8cdeca079a362d2a021aaf7387fbb75a15ebc18 -> d87784ac87364fc977bbf9769c8bdb72dea8cbf9

    • Added comment about missing default case (thanks Jeremy!)
  86. 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?

     0diff --git a/src/node/context.h b/src/node/context.h
     1index 31be308787..7ed1292180 100644
     2--- a/src/node/context.h
     3+++ b/src/node/context.h
     4@@ -29,6 +29,16 @@ class Init;
     5 class WalletLoader;
     6 } // namespace interfaces
     7 
     8+namespace {
     9+/**
    10+ * Dummy NodeContext to ensure that kernel::Context is always destructed last.
    11+ */
    12+struct BaseNodeContext {
    13+    //! libbitcoin_kernel context
    14+    std::unique_ptr<kernel::Context> kernel;
    15+};
    16+}
    17+
    18 namespace node {
    19 //! NodeContext struct containing references to chain state and connection
    20 //! state.
    21@@ -40,9 +50,7 @@ namespace node {
    22 //! and make code more modular and testable. The struct isn't intended to have
    23 //! any member functions. It should just be a collection of references that can
    24 //! be used without pulling in unwanted dependencies or functionality.
    25-struct NodeContext {
    26-    //! libbitcoin_kernel context
    27-    std::unique_ptr<kernel::Context> kernel;
    28+struct NodeContext : BaseNodeContext {
    29     //! Init interface for initializing current process and connecting to other processes.
    30     interfaces::Init* init{nullptr};
    31     std::unique_ptr<AddrMan> addrman;
    32diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
    33index 5c31cfc22b..87d5d4a24b 100644
    34--- a/src/test/util/setup_common.h
    35+++ b/src/test/util/setup_common.h
    36@@ -77,12 +77,20 @@ static inline bool InsecureRandBool() { return g_insecure_rand_ctx.randbool(); }
    37 
    38 static constexpr CAmount CENT{1000000};
    39 
    40+namespace {
    41+/**
    42+ * Dummy TestingSetup to ensure that node::NodeContext (and by extension
    43+ * kernel::Context) is always destructed last.
    44+ */
    45+struct BaseTestingSetup {
    46+    node::NodeContext m_node;
    47+};
    48+}
    49+
    50 /** Basic testing setup.
    51  * This just configures logging, data dir and chain parameters.
    52  */
    53-struct BasicTestingSetup {
    54-    node::NodeContext m_node; // keep as first member to be destructed last
    55-
    56+struct BasicTestingSetup : BaseTestingSetup {
    57     explicit BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {});
    58     ~BasicTestingSetup();
    59 
    

    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:

    0BasicTestingSetup : 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.
  87. theuni approved
  88. theuni commented at 9:45 pm on June 2, 2022: member

    ACK d87784ac87364fc977bbf9769c8bdb72dea8cbf9

    There are a few good outstanding suggestions, but this work is such a continuum that I think it’s fine to address them in subsequent PRs if that’s easier for @dongcarl.

  89. vasild approved
  90. vasild commented at 7:53 am on June 3, 2022: contributor
    ACK d87784ac87364fc977bbf9769c8bdb72dea8cbf9
  91. fanquake merged this on Jun 4, 2022
  92. fanquake closed this on Jun 4, 2022

  93. sidhujag referenced this in commit ceee697fb1 on Jun 5, 2022
  94. in 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 goto instead of adding comments on why goto can’t be used here. :sweat_smile:
  95. 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).
  96. 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.kernel isn’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?
  97. 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?

    0diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
    1index e64af2ad5..f17d823ee 100755
    2--- a/ci/test/06_script_b.sh
    3+++ b/ci/test/06_script_b.sh
    4@@ -43,2 +41,4 @@ if [ "${RUN_TIDY}" = "true" ]; then
    5           " src/init"\
    6+          " src/kernel/checks.cpp"\
    7+          " src/kernel/context.cpp"\
    8           " src/rpc/fees.cpp"\
    

    fanquake commented at 2:50 pm on January 17, 2023:
    All of src/kernel is now under IWYU.
  98. maflcko commented at 1:51 pm on June 6, 2022: member
    Left some nits and a test setup question.
  99. 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:
    0src/kernel/context.h:15: libary ==> library
    

    fanquake commented at 12:04 pm on June 9, 2022:
    being done in #25307
  100. janus referenced this in commit f2b5f7ebf2 on Aug 4, 2022
  101. knst referenced this in commit 2929027a5b on Nov 5, 2023
  102. knst referenced this in commit 56e78b40ef on Nov 6, 2023
  103. PastaPastaPasta referenced this in commit 17d017ec88 on Nov 7, 2023
  104. achow101 referenced this in commit c981771bc3 on Nov 7, 2023
  105. bitcoin 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: 2024-11-17 15:12 UTC

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