JSONRPCRequest-aware RPCHelpMan #16240

pull kallewoof wants to merge 4 commits into bitcoin:master from kallewoof:2019-06-json-aware-helper changing 18 files +253 −578
  1. kallewoof commented at 4:29 AM on June 19, 2019: member

    Every single RPC call has a helper-section at the start, which throws a help string if the user asks for help or if the user provided too few/many arguments.

    const RPCHelpMan help{...};
    if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
        throw std::runtime_error(help.ToString());
    }
    

    or (older version)

    if (request.fHelp || request.params.size() < min || request.params.size() > max)
        throw std::runtime_error(
            RPCHelpMan{...}.ToString()
        );
    

    It seems like an obvious improvement, and less copy-pasting, to make RPCHelpMan aware of JSONRPCRequest, and to let it handle the checks instead. Both of the above become

    RPCHelpMan{...}.Check(request);
    

    which means we save roughly 3 lines per RPC command, and the RPCHelpMan instance is never referenced afterwards, so the approach is a tiny fraction cleaner.

    This is a complete update, sans a few special case locations that had special rules. 623 lines turn into 284 (which includes the addition to RPCHelpMan).

  2. fanquake added the label RPC/REST/ZMQ on Jun 19, 2019
  3. fanquake added the label Refactoring on Jun 19, 2019
  4. kallewoof force-pushed on Jun 19, 2019
  5. kallewoof renamed this:
    JSONRPCRequest-aware RPCHelpMan
    RPCHelpMan-aware JSONRPCRequest
    on Jun 19, 2019
  6. kallewoof force-pushed on Jun 19, 2019
  7. sipa commented at 7:07 AM on June 19, 2019: member

    Concept ACK, though it seems more appropriate that the RPC help object would gain a method the check RPC arguments, than the RPC handling code to be aware of RPC help. I'm sure the circular dependency is resolvable; don't let it stop you from cleaning things up.

    Also, if these lines are all touched anyway, could you add a scripted diff to fix their indentation?

  8. promag commented at 7:18 AM on June 19, 2019: member

    Agree with @sipa, although the request already knows about fHelp.

  9. DrahtBot commented at 7:19 AM on June 19, 2019: member

    <!--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:

    • #16365 (Log RPC parameters (arguments) if -debug=rpcparams by LarryRuane)
    • #16362 (gui: Bilingual translation by hebasto)
    • #16244 (Move wallet creation out of the createwallet rpc into its own function by achow101)
    • #16224 (gui: Bilingual GUI error messages by hebasto)
    • #16185 (gettransaction: add an argument to decode the transaction by darosior)
    • #15974 (refactor: Avoid UniValue copy constructor by promag)
    • #15931 (Remove GetDepthInMainChain dependency on locked chain interface by ariard)
    • #15836 (Add feerate histogram to getmempoolinfo by jonasschnelli)
    • #15729 (rpc: Raise error in getbalance if minconf is not zero by promag)
    • #15450 ([GUI] Create wallet menu option by achow101)
    • #14898 (rpc listtransactions new argument options (paginatebypointer impl) by hosseinamin)
    • #14707 ([RPC] Include coinbase transactions in receivedby RPCs by andrewtoth)

    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.

  10. kallewoof commented at 7:43 AM on June 19, 2019: member

    @sipa I initially added one, but it needs to know about JSONRPCRequest to fetch the fHelp and params.size(), but if I #include <rpc/server.h>, the linters detect a circular dependency util -> server -> util. I definitely think this would be better in RPCHelpMan, but alas..

    I would love to fix the indentation, but not sure how a scripted-diff would be used in this case. (I started working on that, with a sample commit at https://github.com/kallewoof/bitcoin/commit/b9694578fa6401508e18761954ded33ed053df94 in https://github.com/kallewoof/bitcoin/commits/json-aware-helper-whitespaced-sample but got stuck on how to do scripted-diff part).

    Edit: it may be acceptable to link to commit with ?w=1 which should show it empty, like https://github.com/kallewoof/bitcoin/commit/b9694578fa6401508e18761954ded33ed053df94?w=1 -- that's almost as good as a scripted diff..

  11. fanquake commented at 8:26 AM on June 19, 2019: member

    Concept ACK - nice cleanup / deduplication.

  12. kallewoof force-pushed on Jun 19, 2019
  13. kallewoof renamed this:
    RPCHelpMan-aware JSONRPCRequest
    JSONRPCRequest-aware RPCHelpMan
    on Jun 19, 2019
  14. kallewoof commented at 9:42 AM on June 19, 2019: member

    @sipa @promag I realized I could inline the helper method and implement it after JSONRPCRequest to get around linker issues, so this is now an RPCHelpMan method, as you recommended.

    There is also a whitespace only commit (e7124e3) which blows the diff up a bit, but if reviewers check per-commit and use -w/?w=1 properly, it should be manageable. I can drop the whitespace commit too.

  15. promag commented at 10:08 AM on June 19, 2019: member

    @kallewoof see dfdf7f213cd84756f8f17bb3c7cb25a1ee7989e2 for a scripted diff, produced by running on your 31599d8:

    git diff -U0 HEAD~3.. | ./contrib/devtools/clang-format-diff.py -p0 -i -v
    
  16. kallewoof force-pushed on Jun 19, 2019
  17. kallewoof commented at 11:47 AM on June 19, 2019: member

    @promag I had no idea you could do that. Thanks, very cool!

    Edit: not sure what is going wrong. Running this from cli gives me

    Formatting b/src/rpc/blockchain.cpp
    No such file or directory
    
  18. in src/rpc/util.h:245 in 2512d3d2e2 outdated
     237 | @@ -236,6 +238,7 @@ class RPCHelpMan
     238 |      std::string ToString() const;
     239 |      /** If the supplied number of args is neither too small nor too high */
     240 |      bool IsValidNumArgs(size_t num_args) const;
     241 | +    inline void Check(const JSONRPCRequest& request) const;
    


    MarcoFalke commented at 12:50 PM on June 19, 2019:

    in commit 2512d3d2e2f2a2b891f9a3baa1a1309edaf41e01:

    Could add a doc string?


    kallewoof commented at 1:30 PM on June 19, 2019:

    Done!

  19. MarcoFalke commented at 12:53 PM on June 19, 2019: member

    Tend to NACK on fixing the code style in lines that are not touched otherwise. This breaks git blame and all cherry-pick/rebase/merge operations by default (see the list of conflicts).

  20. promag commented at 1:29 PM on June 19, 2019: member

    Makes sense @MarcoFalke, not worth it.

  21. kallewoof force-pushed on Jun 19, 2019
  22. kallewoof commented at 1:32 PM on June 19, 2019: member

    @MarcoFalke

    Tend to NACK on fixing the code style in lines that are not touched otherwise. This breaks git blame and all cherry-pick/rebase/merge operations by default (see the list of conflicts).

    I would normally agree, but the RPC code is out-of-this-world awful with indentation. I think it may be worth to run through it once, especially since the review effort required is near-nil.

  23. kallewoof force-pushed on Jun 19, 2019
  24. MarcoFalke commented at 1:55 PM on June 19, 2019: member

    especially since the review effort required is near-nil.

    Just because something is easy to review doesn't mean it should be done. Beside the things it breaks that I mentioned previously, it will also conflict with a bunch of my local branches, where I restructure the help to make it more consistent and compile-time-safe (use compile time checks and compile-time generated help). Those changes are going to actually touch the lines, so a reformat could make sense at that point in time (maybe).

    Also, I'd say it is not clear if the rpc help must live in the scope of the rpc method. Maybe the help should live at the same scope as the rpc method? I'd say unclear right now, but if it is ever going to change, it would need another reformat. Doing another project-wide break of git blame/cherry-pick/merge/rebase

    I think you underestimate the cost of merge conflicts. If you feel strong about the reformat, it should probably be split up into a separate pull request to be evaluated on its own. Otherwise, my NACK will still hold on this pull.

  25. kallewoof force-pushed on Jun 19, 2019
  26. kallewoof commented at 2:03 PM on June 19, 2019: member

    Understood. Would have been a nice clean up but I'm not gonna lose sleep over it. :) Dropped the whitespace commit.

  27. in src/rpc/mining.cpp:305 in fcf6f426f5 outdated
     301 | @@ -302,7 +302,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
     302 |                  "    https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
     303 |                  "    https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n",
     304 |                  {
     305 | -                    {"template_request", RPCArg::Type::OBJ, RPCArg::Optional::NO, "A json object in the following spec",
     306 | +                    {"template_request", RPCArg::Type::OBJ, "{\"mode\":\"template\"}", "A json object in the following spec",
    


    MarcoFalke commented at 3:02 PM on June 19, 2019:

    Does this need backport? Should be a separate pull request, since behavior changes should not be mixed with refactoring.


    MarcoFalke commented at 3:03 PM on June 19, 2019:

    This is wrong anyway, it is required and needs to be set to:

    getblocktemplate must be called with the segwit rule set (call with {"rules": ["segwit"]}) (code -8)
    

    kallewoof commented at 3:47 PM on June 19, 2019:

    It may be wrong doc-wise, but tests break if you make this mandatory. And it is optional in the code.

    Edit: on the same note, this is not a behavior change, for the reasons stated above. It always behaved this way, even if the docs indicated differently.

    Edit 2: the thing you pointed at actually throws the help topic because it does not provide any values;

    https://github.com/bitcoin/bitcoin/blob/0221420d1a0550cd849e0f3a5ada3738d5931bdd/test/functional/mining_basic.py#L107-L108

    When running with

    $ git diff | cat
    diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
    index 1744acbb2..7b664e73b 100644
    --- a/src/rpc/mining.cpp
    +++ b/src/rpc/mining.cpp
    @@ -291,7 +291,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
                     "    https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
                     "    https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n",
                     {
    -                    {"template_request", RPCArg::Type::OBJ, "{\"mode\":\"template\"}", "A json object in the following spec",
    +                    {"template_request", RPCArg::Type::OBJ, RPCArg::Optional::NO, "A json object in the following spec",
                             {
                                 {"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
                                 {"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings",
    

    the output ends up as

    $ ./mining_basic.py
    [..]
    2019-06-19T15:51:46.621000Z TestFramework (INFO): Create some old blocks
    2019-06-19T15:51:48.842000Z TestFramework (INFO): getmininginfo
    2019-06-19T15:51:48.849000Z TestFramework (INFO): getblocktemplate: Test capability advertised
    2019-06-19T15:51:48.870000Z TestFramework (INFO): getblocktemplate: segwit rule must be set
    2019-06-19T15:51:48.871000Z TestFramework (ERROR): Assertion failed
    Traceback (most recent call last):
      File "/Users/user/git/bitcoin/test/functional/test_framework/util.py", line 113, in try_rpc
        fun(*args, **kwds)
      File "/Users/user/git/bitcoin/test/functional/test_framework/coverage.py", line 47, in __call__
        return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs)
      File "/Users/user/git/bitcoin/test/functional/test_framework/authproxy.py", line 141, in __call__
        raise JSONRPCException(response['error'], status)
    test_framework.authproxy.JSONRPCException: getblocktemplate "template_request"
    
    If the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.
    It returns data needed to construct a block to work on.
    For full specification, see BIPs 22, 23, 9, and 145:
        https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki
    [...]
    > curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getblocktemplate", "params": [{"rules": ["segwit"]}] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/
     (-1)
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/Users/user/git/bitcoin/test/functional/test_framework/test_framework.py", line 193, in main
        self.run_test()
      File "./mining_basic.py", line 108, in run_test
        assert_raises_rpc_error(-8, "getblocktemplate must be called with the segwit rule set", node.getblocktemplate)
      File "/Users/user/git/bitcoin/test/functional/test_framework/util.py", line 105, in assert_raises_rpc_error
        assert try_rpc(code, message, fun, *args, **kwds), "No exception raised"
      File "/Users/user/git/bitcoin/test/functional/test_framework/util.py", line 117, in try_rpc
        raise AssertionError("Unexpected JSONRPC error code %i" % e.error["code"])
    AssertionError: Unexpected JSONRPC error code -1
    2019-06-19T15:51:48.937000Z TestFramework (INFO): Stopping nodes
    2019-06-19T15:51:49.579000Z TestFramework (WARNING): Not cleaning up dir /var/folders/92/y_j8bzw95kn_lky71wr033dw0000gr/T/bitcoin_func_test_7trykhuw
    2019-06-19T15:51:49.579000Z TestFramework (ERROR): Test failed. Test logging available at /var/folders/92/y_j8bzw95kn_lky71wr033dw0000gr/T/bitcoin_func_test_7trykhuw/test_framework.log
    2019-06-19T15:51:49.580000Z TestFramework (ERROR): Hint: Call /Users/user/git/bitcoin/test/functional/combine_logs.py '/var/folders/92/y_j8bzw95kn_lky71wr033dw0000gr/T/bitcoin_func_test_7trykhuw' to consolidate all logs
    

    which is why I did this fix in the first place.


    MarcoFalke commented at 3:51 PM on June 19, 2019:

    Which tests break?


    kallewoof commented at 4:16 PM on June 19, 2019:

    minig_basic.py (see above log)


    MarcoFalke commented at 4:40 PM on June 19, 2019:

    Ah, so the default is not {\"mode\":\"template\"}, but the empty dict {}? The help text for mode says "This must be set to "template", "proposal" (see BIP 23), or omitted" (emphasis mine)


    kallewoof commented at 4:58 PM on June 19, 2019:

    ~If it can be omitted, Optional::NO is probably wrong, then.~ (I read too fast; you were talking about mode, not template_request) I can change the default to simply say {}~, but the code essentially acts as if it was {"mode":"template"}.~

  28. kallewoof force-pushed on Jun 19, 2019
  29. kallewoof commented at 5:01 PM on June 19, 2019: member

    @MarcoFalke: Updated getblocktemplate to display default as {} rather than {"mode":"template"}.

  30. in src/rpc/server.h:49 in 09e176a958 outdated
      43 | @@ -42,6 +44,10 @@ class JSONRPCRequest
      44 |      void parse(const UniValue& valRequest);
      45 |  };
      46 |  
      47 | +inline void RPCHelpMan::Check(const JSONRPCRequest& request) const {
      48 | +    if (request.fHelp || !IsValidNumArgs(request.params.size())) throw std::runtime_error(ToString());
      49 | +}
    


    MarcoFalke commented at 5:28 PM on June 19, 2019:

    In commit 09e176a958 Make the RPCHelpMan aware of JSONRPCRequest and add Check() helper

    Looks like you added the implementation to an unrelated header file (should be in rpc/util.cpp).

    You can solve the circular dependency by moving JSONRPCRequest to rpc/protocol.h


    kallewoof commented at 5:36 PM on June 19, 2019:

    That sounds like a good solution, yeah. Thanks, doing that.

  31. kallewoof force-pushed on Jun 19, 2019
  32. kallewoof force-pushed on Jun 19, 2019
  33. in src/rpc/server.cpp:10 in b93d7ab629 outdated
       6 | @@ -7,7 +7,6 @@
       7 |  
       8 |  #include <fs.h>
       9 |  #include <key_io.h>
      10 | -#include <rpc/util.h>
    


    MarcoFalke commented at 6:02 PM on June 19, 2019:

    ? :eyes:


    kallewoof commented at 6:09 PM on June 19, 2019:

    Sigh. I moved it to .h because it needed RPCHelpMan at one point. Fixed!

  34. kallewoof force-pushed on Jun 19, 2019
  35. promag commented at 3:23 PM on June 21, 2019: member

    ACK 36ad069e8a2641fc7a04af3b924ca05b8b91b6f0.

  36. DrahtBot added the label Needs rebase on Jun 22, 2019
  37. kallewoof force-pushed on Jun 24, 2019
  38. DrahtBot removed the label Needs rebase on Jun 24, 2019
  39. rpc: fix RPC help requirements for getblocktemplate
    First argument is optional, and defaults to {mode:template}.
    0ab8ba1ac6
  40. kallewoof force-pushed on Jul 3, 2019
  41. in src/rpc/protocol.h:109 in 85493edddc outdated
     105 | @@ -106,4 +106,19 @@ void DeleteAuthCookie();
     106 |  /** Parse JSON-RPC batch reply into a vector */
     107 |  std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num);
     108 |  
     109 | +class JSONRPCRequest
    


    laanwj commented at 12:11 PM on July 4, 2019:

    I'm not 100% convinced that protocol.h is the right place for this architecturally, as it's supposed to be functions and data structures shared between RPC client and server, and JSONRPCRequest is internal to the server. I understand the rationale, though (but we might just want to create a new header instead for it).


    kallewoof commented at 2:16 AM on July 5, 2019:

    I think you're right, but I also think we have stuff in protocol that does not belong there to begin with. I made an attempt at cleaning this up by splitting the 'request' stuff into a separate file. This moves stuff from server.cpp and server.h and protocol.h into request.h, and protocol.cpp is replaced by request.cpp.

  42. laanwj commented at 12:15 PM on July 4, 2019: member

    Concept ACK on the approach, I think making this checking data-driven is, overall, a good idea (it enforces consistency), and this seems to be a good way to go about it. I do think this is slightly risky, as it gets rid of a lot of special-case code, is our test coverage of RPC good enough to be confident about changing this for all methods at once?

  43. kallewoof force-pushed on Jul 5, 2019
  44. kallewoof force-pushed on Jul 5, 2019
  45. kallewoof commented at 2:17 AM on July 5, 2019: member

    @laanwj

    I do think this is slightly risky, as it gets rid of a lot of special-case code, is our test coverage of RPC good enough to be confident about changing this for all methods at once?

    I'm not sure about "a lot" of special-case code, to be honest. There were a few exceptions but I mostly left special case stuff alone.

  46. kallewoof force-pushed on Jul 5, 2019
  47. rpc: migrate JSONRPCRequest functionality into request.cpp 5c5e32bbe3
  48. kallewoof force-pushed on Jul 5, 2019
  49. laanwj commented at 10:57 AM on July 5, 2019: member

    I'm not sure about "a lot" of special-case code, to be honest. There were a few exceptions but I mostly left special case stuff alone.

    OK, I just wanted to bring it up.

  50. in src/rpc/util.h:251 in 09f0bf5f1a outdated
     242 | @@ -243,6 +243,13 @@ class RPCHelpMan
     243 |      std::string ToString() const;
     244 |      /** If the supplied number of args is neither too small nor too high */
     245 |      bool IsValidNumArgs(size_t num_args) const;
     246 | +    /**
     247 | +     * Check if the given request is valid according to this command or if
     248 | +     * the user is asking for help information, and throw help when appropriate.
     249 | +     */
     250 | +    inline void Check(const JSONRPCRequest& request) const {
     251 | +        if (request.fHelp || !IsValidNumArgs(request.params.size())) throw std::runtime_error(ToString());
    


    promag commented at 3:54 PM on July 6, 2019:

    09f0bf5f1a5a50168d64c488c2b8972774711a98

    nit, add { }.


    kallewoof commented at 12:54 AM on July 8, 2019:

    Added.

  51. promag commented at 3:59 PM on July 6, 2019: member

    ACK d9c41cc4cb, github commit sort ftw.. Yet another simple tidy up to RPC documentation. Renaming rpc/protocol.{h.cpp} LGTM - thanks to @laanwj. Also confirmed moved code.

  52. Make the RPCHelpMan aware of JSONRPCRequest and add Check() helper c7a9fc234f
  53. rpc: switch to using RPCHelpMan.Check() b6fb617aaa
  54. kallewoof force-pushed on Jul 8, 2019
  55. kallewoof commented at 12:56 AM on July 8, 2019: member

    @promag Thanks for the review! Note that I only renamed protocol.cpp, and moved some parts out of protocol.h into request.h -- protocol.h is still there, just smaller.

  56. laanwj commented at 3:16 PM on July 8, 2019: member

    code rview and lightly tested ACK b6fb617aaaad5f9cdd7f2ad2825b253ca792055d

  57. MarcoFalke commented at 4:29 PM on July 8, 2019: member
    I do think this is slightly risky, as it gets rid of a lot of special-case code, is our test coverage of RPC good enough to be confident about changing this for all methods at once?

    I checked all call-sites as part of

    • rpc: Actually throw help when passed invalid number of params #15401

    so this should only be refactoring. Though, you are right, most of it is not covered by tests.

  58. MarcoFalke commented at 11:31 PM on July 9, 2019: member

    ACK b6fb617aaa, looked at the diff, verified move-only where applicable

    <details><summary>Show signature and timestamp</summary>

    Signature:

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA512
    
    ACK b6fb617aaa, looked at the diff, verified move-only where applicable
    -----BEGIN PGP SIGNATURE-----
    
    iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
    pUhX0AwAtwImLc9meZaRYasAtXwhpkTQpZ9bC0l6hK6uvUGSr4N8n3v63bezavGZ
    pbddzccHclbs5gAtbJMsWkFmR7vKbfDgZi02MZLQqLwc5r+X8/rJdgscfFhMeHNy
    WCQ8ZCJy5VAC5GA6SfshB8VWK+oQpx9GHCKc5OEMFRr7Sc8go0osRxWbMaNuJQdg
    RGgzZ0/e2FS17czydBb5O3k2XTawUUfIa49zFq69kxSntpJdnmMJrqbAg8l0cKDK
    OYd/HkWIVgx1LBtTBmLEF0sKuymhmqMfPbEoFOUXYqiGSTaQsZeS9cJDpc+Cy8Qa
    +icW5+C23plWHC/+N89AeE6g3zcdxG1P1pIRP0YfRjQMx1lKxCuYeCep8vr2pNw7
    X+SpZaoyRJWaoQnL4mPjtGP/7n+QXXjYj2MCq8yNz2uPzyqrvcfq7ZaP+IW5SBmY
    Yl+J9K6FwTkneVkhDMjYMzoJLDwDH4yVrgChwMHYN7HEVY2M0WZhsSE9/HDgscqg
    jEii4j6x
    =rpAy
    -----END PGP SIGNATURE-----
    

    Timestamp of file with hash 890e34cddd2f763e5555c79809bdd129b142d59574aa8799ab8f1a06a0c076c6 -

    </details>

  59. MarcoFalke merged this on Jul 9, 2019
  60. MarcoFalke closed this on Jul 9, 2019

  61. MarcoFalke referenced this in commit 357488f660 on Jul 9, 2019
  62. sidhujag referenced this in commit 66e5f14325 on Jul 10, 2019
  63. kallewoof deleted the branch on Oct 17, 2019
  64. laanwj added the label Needs backport (0.19) on Dec 12, 2019
  65. laanwj referenced this in commit a595011f5a on Dec 15, 2019
  66. sidhujag referenced this in commit f7bd9de01a on Dec 16, 2019
  67. fanquake removed the label Needs backport (0.19) on Jan 6, 2020
  68. deadalnix referenced this in commit 209aacadfa on Jun 10, 2020
  69. deadalnix referenced this in commit d4d128d90d on Jun 10, 2020
  70. deadalnix referenced this in commit 9d61ae2738 on Jun 10, 2020
  71. CathCathub approved
  72. sidhujag referenced this in commit 6dead92bf8 on Nov 10, 2020
  73. PastaPastaPasta referenced this in commit a7fa9f4c7e on Dec 22, 2021
  74. PastaPastaPasta referenced this in commit 240b816f2b on Dec 22, 2021
  75. PastaPastaPasta referenced this in commit 39d1440fba on Dec 22, 2021
  76. PastaPastaPasta referenced this in commit ae20d30726 on Dec 28, 2021
  77. vijaydasmp referenced this in commit aed0925594 on Jan 23, 2022
  78. vijaydasmp referenced this in commit 02a02899b6 on Jan 25, 2022
  79. vijaydasmp referenced this in commit 60ec74e9ba on Jan 25, 2022
  80. DrahtBot locked this on Feb 15, 2022

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-13 15:14 UTC

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