Support output descriptors in scantxoutset #13697

pull sipa wants to merge 9 commits into bitcoin:master from sipa:201806_minedesc changing 10 files +994 −131
  1. sipa commented at 11:18 PM on July 17, 2018: member

    As promised, here is an implementation of my output descriptor concept (https://gist.github.com/sipa/e3d23d498c430bb601c5bca83523fa82) and integration within the scantxoutset RPC that was just added through #12196.

    It changes the RPC to use descriptors for everything; I hope the interface is simple enough to encompass all use cases. It includes support for P2PK, P2PKH, P2WPKH, P2SH, P2WSH, multisig, xpubs, xprvs, and chains of keys - combined in every possible way.

  2. in src/script/descriptor.cpp:5 in a6eba6912b outdated
       0 | @@ -0,0 +1,615 @@
       1 | +#include <script/descriptor.h>
    


    Empact commented at 3:26 AM on July 18, 2018:

    ~Missing copyright block~


    sipa commented at 3:30 AM on July 18, 2018:

    Fixed.

  3. sipa force-pushed on Jul 18, 2018
  4. in src/script/sign.h:40 in 422d08c1f9 outdated
      35 | +    std::map<CKeyID, CKey> keys;
      36 | +
      37 | +    bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
      38 | +    bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
      39 | +    bool GetKey(const CKeyID& keyid, CKey& key) const override;
      40 | +
    


    promag commented at 1:17 PM on July 18, 2018:

    nit, remove empty line.


    sipa commented at 7:26 PM on July 18, 2018:

    Done.

  5. in src/script/sign.h:57 in 1b7c0c7fbd outdated
      38 | +    bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
      39 | +    bool GetKey(const CKeyID& keyid, CKey& key) const override;
      40 | +
      41 | +};
      42 | +
      43 | +FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b);
    


    promag commented at 1:22 PM on July 18, 2018:

    At the moment this is only used in tests, move there?


    sipa commented at 7:26 PM on July 18, 2018:

    I'd rather not. I think more things will be able to use this.

  6. laanwj added the label RPC/REST/ZMQ on Jul 18, 2018
  7. in src/script/descriptor.cpp:82 in 1b7c0c7fbd outdated
      77 | +        if (!m_provider->ToPrivateString(arg, sub)) return false;
      78 | +        ret = OriginString() + ":" + std::move(sub);
      79 | +        return true;
      80 | +    }
      81 | +};
      82 | +#endif
    


    promag commented at 1:33 PM on July 18, 2018:

    nit, add // KEY_ORIGIN_SUPPORT.


    sipa commented at 7:26 PM on July 18, 2018:

    Done.

  8. in src/script/descriptor.cpp:29 in 1b7c0c7fbd outdated
      24 | +////////////////////////////////////////////////////////////////////////////
      25 | +
      26 | +typedef std::vector<uint32_t> KeyPath;
      27 | +
      28 | +/** Interface for public key objects in descriptors. */
      29 | +struct PubkeyProvider {
    


    promag commented at 1:34 PM on July 18, 2018:

    nit, { in new line.


    sipa commented at 7:26 PM on July 18, 2018:

    Done.

  9. in src/script/descriptor.cpp:30 in 1b7c0c7fbd outdated
      25 | +
      26 | +typedef std::vector<uint32_t> KeyPath;
      27 | +
      28 | +/** Interface for public key objects in descriptors. */
      29 | +struct PubkeyProvider {
      30 | +    virtual ~PubkeyProvider(){};
    


    promag commented at 1:34 PM on July 18, 2018:

    nit, = default?


    sipa commented at 7:26 PM on July 18, 2018:

    Done, here and elsewhere.

  10. promag commented at 1:38 PM on July 18, 2018: member

    Few nits, it this for 0.17? Is scantxoutset considered API experimental?

  11. in src/script/descriptor.cpp:422 in 1b7c0c7fbd outdated
     452 | +std::vector<Span<const char>> Split(const Span<const char>& sp, char sep)
     453 | +{
     454 | +    std::vector<Span<const char>> ret;
     455 | +    auto it = sp.begin();
     456 | +    auto start = it;
     457 | +    while (it != sp.end()) {
    


    promag commented at 3:34 PM on July 18, 2018:

    Add

    if (it == sp.end()) return ret;
    

    for when string is empty.


    sipa commented at 7:26 PM on July 18, 2018:

    Why?


    promag commented at 8:25 PM on July 18, 2018:

    The statement ret.emplace_back(start, it); below should not be executed if sp is empty.


    promag commented at 8:25 PM on July 18, 2018:

    I mean, should Split("", sep) equal []?


    sipa commented at 8:30 PM on July 18, 2018:

    No, it should be [""]. Callers can rely on there always being at least one argument in the result.


    promag commented at 8:35 PM on July 18, 2018:

    In that case 👍

  12. in src/script/descriptor.cpp:617 in 1b7c0c7fbd outdated
     612 | +
     613 | +std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out)
     614 | +{
     615 | +    Span<const char> sp(descriptor.data(), descriptor.size());
     616 | +    auto ret = ParseScript(sp, ParseScriptContext::TOP, out);
     617 | +    if (sp.size() == 0 && ret) return std::move(ret);
    


    promag commented at 4:01 PM on July 18, 2018:

    Compiler warning:

    script/descriptor.cpp:617:39: warning: moving a local object in a return statement prevents copy elision [-Wpessimizing-move]
        if (sp.size() == 0 && ret) return std::move(ret);
                                          ^
    script/descriptor.cpp:617:39: note: remove std::move call here
        if (sp.size() == 0 && ret) return std::move(ret);
                                          ^~~~~~~~~~  
    

    sipa commented at 7:27 PM on July 18, 2018:

    Fixed.

  13. in src/rpc/blockchain.cpp:2012 in 1b7c0c7fbd outdated
    2055 | -            "            \"pubkey\" : \"<pubkey\">,         (string, required) HEX encoded public key\n"
    2056 | -            "            \"script_types\" : [ ... ],      (array, optional) Array of script-types to derive from the pubkey (possible values: \"P2PK\", \"P2PKH\", \"P2SH-P2WPKH\", \"P2WPKH\")\n"
    2057 | -            "          }\n"
    2058 | +            "2. \"scanobjects\"                  (array, required) Array of scan objects\n"
    2059 | +            "    [                             Every scan object is either a string descriptor or an object:\n"
    2060 | +            "        \"descriptor\",             (string, optional) An output descriptor\n"
    


    promag commented at 4:20 PM on July 18, 2018:

    Why give both options? [{ "desc": "...", ...}, ...] is enough?


    sipa commented at 7:27 PM on July 18, 2018:

    It's pretty verbose to use the long form, and probably not all that often needed.


    promag commented at 8:41 PM on July 18, 2018:

    It's pretty verbose

    On the client side I think it doesn't matter (unless it's a human making the call).


    sipa commented at 10:33 PM on July 18, 2018:

    Yes, the reason to support the short notation is to simplify things for humans.

  14. in src/rpc/blockchain.cpp:2070 in 1b7c0c7fbd outdated
    2115 | +            int range = 1000;
    2116 | +            if (scanobject.isStr()) {
    2117 | +                desc_str = scanobject.get_str();
    2118 | +            } else if (scanobject.isObject()) {
    2119 | +                UniValue desc_uni = find_value(scanobject, "desc");
    2120 | +                if (desc_uni.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor needs to be provided in scan object");
    


    promag commented at 4:20 PM on July 18, 2018:

    Could have a test.


    sipa commented at 7:27 PM on July 18, 2018:

    Yes, will add when there's sufficient agreement about RPC.

  15. in src/rpc/blockchain.cpp:2074 in 1b7c0c7fbd outdated
    2120 | +                if (desc_uni.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor needs to be provided in scan object");
    2121 | +                desc_str = desc_uni.get_str();
    2122 | +                UniValue range_uni = find_value(scanobject, "range");
    2123 | +                if (!range_uni.isNull()) {
    2124 | +                    range = range_uni.get_int();
    2125 | +                    if (range < 1 || range > 1000000) throw JSONRPCError(RPC_INVALID_PARAMETER, "range out of range");
    


    promag commented at 4:21 PM on July 18, 2018:

    Could have a test.

  16. in src/script/descriptor.cpp:495 in 1b7c0c7fbd outdated
     548 | +{
     549 | +    auto expr = Expr(sp);
     550 | +    if (Func("pk", expr)) {
     551 | +        auto pubkey = ParsePubkey(expr, ctx != ParseScriptContext::P2WSH, out);
     552 | +        if (pubkey) return MakeUnique<SingleKeyDescriptor>(std::move(pubkey), P2PKGetScript, "pk");
     553 | +    }
    


    promag commented at 4:31 PM on July 18, 2018:

    Why not return nullptr in these cases?


    sipa commented at 7:28 PM on July 18, 2018:

    Done, here and elsewhere.

  17. in src/script/descriptor.h:100 in 1b7c0c7fbd outdated
      95 | +};
      96 | +
      97 | +/** Parse a descriptor string. Included private keys are put in out. Returns nullptr if parsing fails. */
      98 | +std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out);
      99 | +
     100 | +#endif
    


    promag commented at 4:32 PM on July 18, 2018:
    #endif // BITCOIN_SCRIPT_DESCRIPTOR_H
    

    sipa commented at 7:28 PM on July 18, 2018:

    Done.

  18. in src/script/descriptor.cpp:189 in 1143a75c2f outdated
     184 | +    bool ToPrivateString(const SigningProvider& arg, std::string& out) const override
     185 | +    {
     186 | +        CExtKey key;
     187 | +        if (!GetExtKey(arg, key)) return false;
     188 | +        out = EncodeExtKey(key);
     189 | +        for (auto entry : m_path) {
    


    achow101 commented at 7:11 PM on July 18, 2018:

    Can the path writing be separated out into another function to avoid code duplication and so that we can use it elsewhere?


    sipa commented at 10:41 PM on July 18, 2018:

    Fixed.

  19. sipa force-pushed on Jul 18, 2018
  20. sipa commented at 7:31 PM on July 18, 2018: member

    Rebased, removed future "key origin" support (not needed right now, ignore).

    Also, I'd like people to first review the descriptor language itself (a very short summary is in the RPC help, more of a reference in script/descriptor.h, and a design document in https://gist.github.com/sipa/e3d23d498c430bb601c5bca83523fa82). In particular, I'm not convinced about the "old" function (which maps pubkeys to P2PK,P2PKH,P2WPKH, and P2SH-PWPKH) - it's very useful for dealing with existing Core wallets, but "old" doesn't really convey the right meaning. However, I don't see what else to use. "legacy" is confusing (as it would have a different meaning than legacy in -addresstype). "default" sounds like it could change over time (the intention is that it wouldn't). "sk" or "singlekey" sounds like it's encouraged and/or could change over time, ...

  21. achow101 commented at 8:06 PM on July 18, 2018: member

    Concept ACK

  22. promag commented at 8:56 PM on July 18, 2018: member

    Regarding the "old" function, I think it could receive the version, for instance default(args..., version) — it should validate if args are compatible with the version specified (at the moment args should be only a pubkey).

  23. sipa commented at 9:06 PM on July 18, 2018: member

    @promag There is no intention of ever adding another of those "defaults". Future versions should work with specific derivations (only P2WSH directly for example, rather than a collection). It's only for compatibility with the backward way we used to derive what scriptPubKeys are ours that such a default is useful.

  24. sipa force-pushed on Jul 18, 2018
  25. sipa force-pushed on Jul 18, 2018
  26. laanwj added this to the milestone 0.17.0 on Jul 19, 2018
  27. jonasschnelli requested review from jonasschnelli on Jul 19, 2018
  28. sipa force-pushed on Jul 20, 2018
  29. in src/rpc/blockchain.cpp:2018 in 79b8939362 outdated
    2062 | +            "          \"desc\": \"descriptor\",   (string, required) An output descriptor\n"
    2063 | +            "          \"range\": n,             (numeric, optional) Up to what child index HD chains should be explored (default: 1000)\n"
    2064 |              "        },\n"
    2065 | -            "      ]\n"
    2066 | +            "        ...\n"
    2067 | +            "    ]\n"
    


    Sjors commented at 6:01 PM on July 21, 2018:

    Don't forget to add a command-line example here, it look me a while to figure out the syntax from reading the above.

    I suggest an example with a typical BIP44 (legacy) xpub + BIP49 xpub:

    ["pkh(legacy_xpub/0/*)", "pkh(legacy_xpub/1/*)", "sh(wpkh(segwit_xpub/0/*)", "sh(wpkh(segwit_xpub/1/*)"]
    

    A second example could show the root master xpriv and then do hardened derivation of xpriv/44'/0'/0'/0/* or xpriv/49'/0'/0'/1/*


    sipa commented at 8:02 PM on July 21, 2018:

    Done.

  30. in src/rpc/blockchain.cpp:1999 in 79b8939362 outdated
    2033 | +            "\nScans the unspent transaction output set for entries that match certain output descriptors.\n"
    2034 | +            "Examples of output descriptors are:\n"
    2035 | +            "    addr(<address>)                      Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK)\n"
    2036 | +            "    raw(<hex script>)                    Outputs whose scriptPubKey equals the specified hex scripts\n"
    2037 | +            "    old(<pubkey>)                        P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
    2038 | +            "    pkh(<pubkey>)                        P2PKH outputs for the given pubkey\n"
    


    Sjors commented at 6:02 PM on July 21, 2018:

    sh(wpkh()) is probably quite common, so maybe add that here?


    sipa commented at 8:02 PM on July 21, 2018:

    Done.

  31. Sjors approved
  32. Sjors commented at 6:34 PM on July 21, 2018: member

    Concept ACK, and lightly tested on Ledger (P2SH-P2WPKH) and Blockchain (P2PKH) xpubs.

  33. sipa force-pushed on Jul 21, 2018
  34. sipa force-pushed on Jul 21, 2018
  35. DrahtBot commented at 1:27 PM on July 22, 2018: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->No more conflicts as of last run.

  36. flack commented at 1:30 PM on July 25, 2018: contributor

    @sipa since you write that old is a "combination of P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH for public key P.", you could call it combo instead. Or ck if you want it to look more like the other things that use P. And potentially prepend bc to indicate it's for backwards compatibility (but in that case someone should check urban dictionary to make sure bcck isn't some newfangled swear word :-))

  37. sipa cross-referenced this on Jul 26, 2018 from issue Utils and libraries: Drops the boost/algorithm/string/split.hpp dependency by l2a5b1
  38. sipa force-pushed on Jul 26, 2018
  39. sipa commented at 7:11 PM on July 26, 2018: member

    @flack Oh, I like that. Changed to "combo".

  40. MarcoFalke commented at 8:08 PM on July 26, 2018: member

    Travis failure:

    test_framework.authproxy.JSONRPCException: Invalid descriptor 'old(03abcaca414970a8d36624011628045855cb01cded780445a33688a0b905a47224)' (-5)
    
  41. sipa force-pushed on Jul 26, 2018
  42. jonasschnelli commented at 8:47 AM on July 27, 2018: contributor

    First two findings:

    • I think supporting h as equivalent to ' in extended key derivation range would be great (JSON / shell / GUI). I suggest pulling in https://github.com/bitcoin/bitcoin/commit/203b4c94ce83981b0d76dd2adb778719ba868db1.

    • I think the IsHardened() function is not correct. Using 0'/0'/* will derive all hardened keys at the * level (same as 0'/0'/*'). Seems to be currently impossible to derive unhardened key with the asterisk.

  43. in src/rpc/blockchain.cpp:2086 in 852cf1f078 outdated
    2145 | +            auto desc = Parse(desc_str, provider);
    2146 | +            if (!desc) {
    2147 | +                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor '%s'", desc_str));
    2148 | +            }
    2149 | +            if (!desc->IsRange()) range = 1;
    2150 | +            for (int i = 0; i < range; ++i) {
    


    jonasschnelli commented at 9:13 AM on July 27, 2018:

    Seems like that results in an off-by-one issue (misses last key): Suggest pulling fix: https://github.com/bitcoin/bitcoin/commit/875431149745cc517350c0620baa887c748d0b35


    sipa commented at 6:02 PM on July 27, 2018:

    BIP32 indexes are 0-based, so I think the current code is correct. If you expand 1000 keys, those will be indices 0 through 999.

  44. jonasschnelli changes_requested
  45. jonasschnelli commented at 9:14 AM on July 27, 2018: contributor

    Additional xpub range tests can be pulled from here: https://github.com/bitcoin/bitcoin/commit/cc1ffb324b53855f7eae81a6b0df10bd677ca1a5

  46. Sjors commented at 9:24 AM on July 27, 2018: member

    +1 on h alias

    I only tested unhardened derivation (xpub/0/*) because most wallets only export account level xpubs. @jonasschnelli maybe add a test for the '/*) pattern to cc1ffb3? It currently only checks '/*')

  47. jonasschnelli commented at 9:54 AM on July 27, 2018: contributor

    @Sjors: A test for '/* would currently fail,... but it's simple to add (keys are already prepared in https://github.com/bitcoin/bitcoin/commit/cc1ffb324b53855f7eae81a6b0df10bd677ca1a5), just waiting for a fix for the hardened/non-hardened mix.

  48. jonasschnelli commented at 9:58 AM on July 27, 2018: contributor

    Suggest pulling in the experimental warning for scantxoutset here: https://github.com/bitcoin/bitcoin/commit/3ec0958ea746d0db5edefff9f423cd2caab32857

  49. sipa commented at 6:09 PM on July 27, 2018: member

    @jonasschnelli Good catch; the derivation for "/*" with a parent hardened step is incorrect. Fixing.

  50. Add more methods to Span class
    This introduces a rudimentary begin(), end(), operator[], and subspan to Span.
    29943a904a
  51. Add simple FlatSigningProvider e54d76044b
  52. Output descriptors module fe8a7dcd78
  53. Descriptor tests 0652c3284f
  54. Swap in descriptors support into scantxoutset 151600bb49
  55. [QA] Add xpub range tests in scantxoutset tests 1af237faef
  56. [QA] Extend tests to more combinations 6495849bfd
  57. Add experimental warning to scantxoutset fddea672eb
  58. sipa force-pushed on Jul 27, 2018
  59. sipa commented at 6:53 PM on July 27, 2018: member

    @jonasschnelli Ok, fixed the derivation, changed the range to be max index rather than count, included your tests and experimental warning, and added a number of tests myself (generated with an independent BIP32 implementation).

  60. Support h instead of ' in hardened descriptor paths f6b7fc349c
  61. sipa commented at 7:23 PM on July 27, 2018: member

    @jonasschnelli Added support for h instead of ' in hardened descriptor paths as well (plus some tests for it). Serializing a descriptor will always use '.

  62. jonasschnelli approved
  63. jonasschnelli commented at 7:19 AM on July 30, 2018: contributor

    Tested ACK f6b7fc349ccf9cfbeb7e91e19c20e2a2fcc9026f

  64. MarcoFalke commented at 3:52 PM on August 1, 2018: member

    Concept ACK f6b7fc3

  65. laanwj commented at 4:51 PM on August 1, 2018: member

    utACK f6b7fc349ccf9cfbeb7e91e19c20e2a2fcc9026f

  66. laanwj merged this on Aug 1, 2018
  67. laanwj closed this on Aug 1, 2018

  68. laanwj referenced this in commit f030410e88 on Aug 1, 2018
  69. practicalswift cross-referenced this on Aug 2, 2018 from issue tests: Remove unused variable by practicalswift
  70. in test/functional/rpc_scantxoutset.py:82 in f6b7fc349c
      83 | +        assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1)"])['total_amount'], Decimal("8.192"))
      84 | +        assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1500)"])['total_amount'], Decimal("16.384"))
      85 | +        assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0)"])['total_amount'], Decimal("4.096"))
      86 | +        assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1)"])['total_amount'], Decimal("8.192"))
      87 | +        assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1500)"])['total_amount'], Decimal("16.384"))
      88 | +        assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*')", "range": 1499}])['total_amount'], Decimal("1.536"))
    


    Sjors commented at 11:52 AM on August 2, 2018:

    Maybe use range: 1 and range: 2 everywhere to speed up these tests?

  71. Bushstar cross-referenced this on Aug 13, 2018 from issue commits from bitcoin/master by Bushstar
  72. sipa added the label Needs release notes on Aug 14, 2018
  73. jonasschnelli cross-referenced this on Aug 30, 2018 from issue scantxoutset help about descriptors refers to TODO document by jonasschnelli
  74. ryanofsky cross-referenced this on Nov 27, 2018 from issue test: Fix descriptor_tests not checking ToString output of public descriptors by ryanofsky
  75. MarcoFalke referenced this in commit 0fa3703c17 on Nov 27, 2018
  76. fanquake removed the label Needs release note on Mar 20, 2019
  77. kwvg referenced this in commit a1e043a62d on Mar 10, 2021
  78. kwvg referenced this in commit 494d99c29e on Mar 23, 2021
  79. kwvg referenced this in commit 10f923b82c on Apr 18, 2021
  80. UdjinM6 referenced this in commit bf01ed7881 on Apr 27, 2021
  81. kwvg referenced this in commit 24fb4555e8 on Jun 4, 2021
  82. kwvg cross-referenced this on Jun 4, 2021 from issue merge #12196, #13697: Add scantxoutset RPC method by kwvg
  83. furszy cross-referenced this on Jun 7, 2021 from issue Road to Tor v3 support (BIP155) by furszy
  84. kwvg referenced this in commit cbe1968254 on Jun 9, 2021
  85. furszy cross-referenced this on Jul 6, 2021 from issue Span sources updates, up-to-date with current upstream. by furszy
  86. kwvg referenced this in commit 3a39207e5b on Jul 9, 2021
  87. kwvg referenced this in commit 572170dc85 on Jul 13, 2021
  88. kwvg referenced this in commit 30a49a9470 on Jul 13, 2021
  89. kwvg referenced this in commit 5024e2bd97 on Jul 14, 2021
  90. kwvg referenced this in commit 463dca7e24 on Jul 15, 2021
  91. kwvg referenced this in commit 262a770c72 on Jul 15, 2021
  92. kwvg referenced this in commit 6113107854 on Jul 20, 2021
  93. kwvg referenced this in commit 9edc8caa14 on Jul 20, 2021
  94. kwvg referenced this in commit e3f4888b2b on Jul 20, 2021
  95. kwvg referenced this in commit 2bdb8540b6 on Jul 21, 2021
  96. random-zebra referenced this in commit 56f10aaa51 on Jul 21, 2021
  97. PastaPastaPasta referenced this in commit edf0552c0c on Jul 26, 2021
  98. linuxsh2 referenced this in commit d32d0e78fe on Jul 29, 2021
  99. linuxsh2 referenced this in commit 670d090a52 on Jul 30, 2021
  100. linuxsh2 referenced this in commit 7603e1ce8c on Aug 3, 2021
  101. random-zebra referenced this in commit b4751e10ce on Aug 11, 2021
  102. theStack cross-referenced this on Sep 11, 2021 from issue refactor: introduce single-separator split helper (boost::split replacement) by theStack
  103. bitcoin locked this on Dec 16, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-05-20 06:55 UTC