{
 "number": 35041,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/35041",
 "title": "descriptor: speed-up `Parse` (xpub/xpriv) in ~30%",
 "author": "brunoerg",
 "author_association": "MEMBER",
 "created_at": "2026-04-09T18:19:20Z",
 "updated_at": "2026-09-17T03:03:06Z",
 "age_days": 160,
 "draft": false,
 "labels": [
  "Descriptors"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "ddcacd25e735dad4868bab7f618961a363f23239",
 "head_ref": "2026-04-descriptor",
 "head_repo": "brunoerg/bitcoin",
 "head_history": [
  {
   "t": "2026-06-10T15:50:16Z",
   "sha": "0d8110a13579cee43b4d77bdbad943cc821cd6cb"
  },
  {
   "t": "2026-06-10T17:51:54Z",
   "sha": "6dd023abbc9a1d8ece5dc9f9e186e7f5b1fb6f91"
  },
  {
   "t": "2026-08-24T14:27:12Z",
   "sha": "0339b33e41f13f87111c2e03e1ddc42bc6a596c4"
  },
  {
   "t": "2026-09-02T01:02:59Z",
   "sha": "ddcacd25e735dad4868bab7f618961a363f23239"
  }
 ],
 "additions": 67,
 "deletions": 28,
 "changed_files": 5,
 "commit_count": 2,
 "size_bucket": "S",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "ack": [
     {
      "login": "hodlinator",
      "url": "https://github.com/bitcoin/bitcoin/pull/35041#pullrequestreview-5086723970"
     }
    ],
    "concept_ack": [
     {
      "login": "sedited",
      "url": "https://github.com/bitcoin/bitcoin/pull/35041#pullrequestreview-4445194698"
     }
    ]
   },
   "conflicts": [
    {
     "number": 36133,
     "title": "wallet: store multipath descriptor",
     "author": "Sjors"
    }
   ]
  }
 },
 "acks_parsed": {
  "sedited": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-06-07T14:04:32Z",
   "stale": false
  },
  "hodlinator": {
   "kind": "ack",
   "hash": "ddcacd25e735dad4868bab7f618961a363f23239",
   "t": "2026-09-02T07:29:39Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 1,
  "stale_ack": 0,
  "concept_ack": 1,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 1,
  "changes_requested": 0,
  "distinct_reviewers": [
   "hodlinator",
   "l0rinc",
   "maflcko",
   "sedited"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-09-02T01:07:31Z",
  "last_reviewer_activity": "2026-09-02T07:29:39Z",
  "last_reviewer": "hodlinator",
  "author_silent_days": 15,
  "waiting_on_author_days": 15,
  "days_since_update": 0
 },
 "refs": {
  "mentioned": [],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [],
  "conflicts": [
   36133
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "src/base58.cpp",
  "src/key_io.cpp",
  "src/script/descriptor.cpp"
 ],
 "body": "This PR speeds up descriptor parsing, for basically descriptors that use xpub/xpriv, through some targeted improvements (I've been working on fuzz targets for wallet stuff for a while. I've noticed that some of them are slow so I started to work on understanding why and improve what can be improved. The finding came from it):\n\n- Avoid redundant base58 decoding when parsing extended keys (this is the major improvement)\n\n  ParsePubkeyInner unconditionally called both DecodeExtKey() and DecodeExtPubKey(), each running a full DecodeBase58Check (two SHA256 passes over ~111 bytes). A new DecodeExtKeyOrPubKey() function performs a single base58 decode and then checks the prefix, halving the cryptographic work per key. The interfaces of DecodeSecret, DecodeExtKey, and DecodeExtPubKey are also updated to accept string_view instead of const std::string&, eliminating unnecessary string copies in the descriptor parser and allowing DecodeBase58/DecodeBase58Check to use pointer-range iteration instead of strlen.\n\n- Replace O(n) charset lookup with precomputed table\n\n  DescriptorChecksum previously called std::string::find() for every character in the descriptor string, doing up to 96 comparisons per character. This replaces it with a 256-entry precomputed lookup table for O(1) lookups. The benefit scales with descriptor length.\n\n-----------\n\n`Parse()` with the following descriptor:\n```sh\ntr(xpub6CGCzpvrZVssNNXuP1Awcz8GoakYyJHra2WHASXfCzsD9szbQFoT1pLMdQopyqaSqXUprH7fkk8NG2pUbQa5HpNzpWmEsdNZDHxXvSLPTrn/*,{{multi_a(20,xpub6CGCzpvrZVssNNXuP1Awcz8GoakYyJHra2WHASXfCzsD9szbQFoT1pLMdQopyqaSqXUprH7fkk8NG2pUbQa5HpNzpWmEsdNZDHxXvSLPTrn/*,xpub6C5MW95EE8hAmxm96LdAFYkweaAktQoojCf2MwJmNL9Fi6oUPeBnpFdEzhs9zHwr4HQEeF1r1yAUR8MqDJqk4YPteh75rNoCKCtud7shDDk/*,xpub6DNEUJP1zLAZ1P6gYRba9FyxuppmkrPmSKz3FLM7msRwn2LEr4LnKfAnNoSoAbnbW2orTfsitdfWTxLbJCZ6LizqV7cFUavSAjWzNjqdfCP/*,xpub6Cm5sAgCZQvYtnatYPdFuLhsD9VtgY3Rtt48TrdgqXm4DttXfM6nFmFTko8KcyGhPswTvPcTzfpMUvqV3F9tgLPvzfzoKwjmU668vBmGXEX/*,xpub6DN66R61Luv95HLvznR2ZWsbYuGBoK9LDR6XiNm1pvp5zRJ2vFhLQ4PBe2pDn59sKmRnEFbdLtBVZFN3QAujcGZ5PomGCvrnisxkP2fcgHg/*,xpub6D2GtAtYodmjwEoAzorKUta44NDvAB4JjafYXxsQ5hTWvCAK55nnkyNHfdjrsx3umfgGe1nnHut13mLuFqqi2fs7VVyv6rht76ddrDGhrTY/*,xpub6Bfi8jsDMuu2XHQ1TGRB6ehjdHKKmTwRFQYU6QcgHoZswqbzKsXs9Qd87nAxevjZwuQ37jaVnQoPF6wY34BJoeLxXkEYMpKz2CBHLcEmJVF/*,xpub6CYiNdQesStiBwZkWjPBxwxxf6oPMH9meBMujCwBX74X8nCpMF9zRZUbDrU9raQah1LQcnzLQrHC6Kr6LNCmsBpaMkYD3U6FyhHZfTHQGUB/*,xpub6CddszJHLa3VisZ6ufU4hiFcGsuuPHo7hYa24o3kPuPfAbMED4ajuDa6svuqxxBxYgUQhN8LK7MtTMetquNo7YsWhiV8hX2gBfjszJVXgkG/*,xpub6DAM262AxC4Um3rxBiP5FoA7SJJG3a7MjaJkEyXWyMA6iNuyqWueKZHSSNjKEWnn8Wi3PUQNTV1Z3a59C2Qaidha88GTWtAMhJBAWBBvuTN/*,xpub6ByZcsLsr8xTCJmYxvLpLrsFzuHNXRLR4xMyB9ZFLek1hDVh7zba2xAVTU8M6eonFFAAPYpTA76bDuopF5zyBkZqFc3rtJ3ziH1BUXkjC6j/*,xpub6Bx2LErujvR1noXrk7RHQB9htiDcPM5qYuV7Jg1nZh5jWeK8pYB4DnYQ73EX9sB9M6rnNsF8LDPUejHiXrBx2JJQSdVQ9i9FfEzJLuAnzEd/*,xpub6DSBog1uLngjBWVDUpLTQ19jGGKovgc3iTd1ijL4fjk9sgNqrnG5kGLjUWncay2jbqdgt6yrbYSHhfwsTMp7i8pUD1FMCQuFyqdsZpgUNH8/*,xpub6C53ov8LpuGp5MM4ghqUFJcdTnXJCRHyXaz1RVCys2uQErpdzUWHtm8Bsg8NJyaqfhGWvm9WPSE7jMneCRw1xs1CTajpToXyRqSCc41JiuY/*,xpub6CscWPNXdEybbJVvx7fJTrfHyTkKZtb97qcpQ9fH4k4xtm4nkckSpvy86heQsdyoF28CugwLHg5kLDwpGoPQAYXQ3RG9cJB2Na1FdeN1wt5/*,xpub6Cmrivt6w3kVAxw7NmcKSY19gSLmC2tVwx46cdigr9d1UEnttJCGZJ7NQu1MkugpZgF9rQ3j3NKUiZ2MoaC2QoZUfi4nwxbpH39SQZaBHut/*,xpub6D1Ey5JAYnBxFE8i2V2SUsEpJt7r3ykJKcShcpT2xN9CXtVQy5dKeYiZ9D1bdnkPrmgEajrSuA5nWqf94s6u7FwvXy3cU4BXUMgAt9C8wGT/*,xpub6CwJ2vicnoSJNFDzhonucHNVHDwyb1vyiu2VF6zmjQrzGb4qoAma1i2QJ7qRNe1qmpvvWwzSuQDgMnCECFQhZaPKuPFjcMo33r2xenBauxf/*,xpub6CiLNz8mFB4fB51x6gMNu44Up9PyVhq7fSxQb8UzYQermvMShwWyqzQe99Uiyxpfy1ow42xUGpPGBHf8ErxDbQojBf7Uy7hKFgYk8KpgMm2/*,xpub6DQ2qVMZ2o2QGGpYDsw5hpAcygNVEycAkkCib2Lexwm8gYWMCSecZ256AbAV93Rgze6h8yEoTcqUnvnz7L69WUqp7cXd85X8HoeKWjPHRRZ/*),multi_a(20,xpub6CGCzpvrZVssNNXuP1Awcz8GoakYyJHra2WHASXfCzsD9szbQFoT1pLMdQopyqaSqXUprH7fkk8NG2pUbQa5HpNzpWmEsdNZDHxXvSLPTrn/*,xpub6C5MW95EE8hAmxm96LdAFYkweaAktQoojCf2MwJmNL9Fi6oUPeBnpFdEzhs9zHwr4HQEeF1r1yAUR8MqDJqk4YPteh75rNoCKCtud7shDDk/*,xpub6DNEUJP1zLAZ1P6gYRba9FyxuppmkrPmSKz3FLM7msRwn2LEr4LnKfAnNoSoAbnbW2orTfsitdfWTxLbJCZ6LizqV7cFUavSAjWzNjqdfCP/*,xpub6Cm5sAgCZQvYtnatYPdFuLhsD9VtgY3Rtt48TrdgqXm4DttXfM6nFmFTko8KcyGhPswTvPcTzfpMUvqV3F9tgLPvzfzoKwjmU668vBmGXEX/*,xpub6DN66R61Luv95HLvznR2ZWsbYuGBoK9LDR6XiNm1pvp5zRJ2vFhLQ4PBe2pDn59sKmRnEFbdLtBVZFN3QAujcGZ5PomGCvrnisxkP2fcgHg/*,xpub6D2GtAtYodmjwEoAzorKUta44NDvAB4JjafYXxsQ5hTWvCAK55nnkyNHfdjrsx3umfgGe1nnHut13mLuFqqi2fs7VVyv6rht76ddrDGhrTY/*,xpub6Bfi8jsDMuu2XHQ1TGRB6ehjdHKKmTwRFQYU6QcgHoZswqbzKsXs9Qd87nAxevjZwuQ37jaVnQoPF6wY34BJoeLxXkEYMpKz2CBHLcEmJVF/*,xpub6CYiNdQesStiBwZkWjPBxwxxf6oPMH9meBMujCwBX74X8nCpMF9zRZUbDrU9raQah1LQcnzLQrHC6Kr6LNCmsBpaMkYD3U6FyhHZfTHQGUB/*,xpub6CddszJHLa3VisZ6ufU4hiFcGsuuPHo7hYa24o3kPuPfAbMED4ajuDa6svuqxxBxYgUQhN8LK7MtTMetquNo7YsWhiV8hX2gBfjszJVXgkG/*,xpub6DAM262AxC4Um3rxBiP5FoA7SJJG3a7MjaJkEyXWyMA6iNuyqWueKZHSSNjKEWnn8Wi3PUQNTV1Z3a59C2Qaidha88GTWtAMhJBAWBBvuTN/*,xpub6ByZcsLsr8xTCJmYxvLpLrsFzuHNXRLR4xMyB9ZFLek1hDVh7zba2xAVTU8M6eonFFAAPYpTA76bDuopF5zyBkZqFc3rtJ3ziH1BUXkjC6j/*,xpub6Bx2LErujvR1noXrk7RHQB9htiDcPM5qYuV7Jg1nZh5jWeK8pYB4DnYQ73EX9sB9M6rnNsF8LDPUejHiXrBx2JJQSdVQ9i9FfEzJLuAnzEd/*,xpub6DSBog1uLngjBWVDUpLTQ19jGGKovgc3iTd1ijL4fjk9sgNqrnG5kGLjUWncay2jbqdgt6yrbYSHhfwsTMp7i8pUD1FMCQuFyqdsZpgUNH8/*,xpub6C53ov8LpuGp5MM4ghqUFJcdTnXJCRHyXaz1RVCys2uQErpdzUWHtm8Bsg8NJyaqfhGWvm9WPSE7jMneCRw1xs1CTajpToXyRqSCc41JiuY/*,xpub6CscWPNXdEybbJVvx7fJTrfHyTkKZtb97qcpQ9fH4k4xtm4nkckSpvy86heQsdyoF28CugwLHg5kLDwpGoPQAYXQ3RG9cJB2Na1FdeN1wt5/*,xpub6Cmrivt6w3kVAxw7NmcKSY19gSLmC2tVwx46cdigr9d1UEnttJCGZJ7NQu1MkugpZgF9rQ3j3NKUiZ2MoaC2QoZUfi4nwxbpH39SQZaBHut/*,xpub6D1Ey5JAYnBxFE8i2V2SUsEpJt7r3ykJKcShcpT2xN9CXtVQy5dKeYiZ9D1bdnkPrmgEajrSuA5nWqf94s6u7FwvXy3cU4BXUMgAt9C8wGT/*,xpub6CwJ2vicnoSJNFDzhonucHNVHDwyb1vyiu2VF6zmjQrzGb4qoAma1i2QJ7qRNe1qmpvvWwzSuQDgMnCECFQhZaPKuPFjcMo33r2xenBauxf/*,xpub6CiLNz8mFB4fB51x6gMNu44Up9PyVhq7fSxQb8UzYQermvMShwWyqzQe99Uiyxpfy1ow42xUGpPGBHf8ErxDbQojBf7Uy7hKFgYk8KpgMm2/*,xpub6DQ2qVMZ2o2QGGpYDsw5hpAcygNVEycAkkCib2Lexwm8gYWMCSecZ256AbAV93Rgze6h8yEoTcqUnvnz7L69WUqp7cXd85X8HoeKWjPHRRZ/*)},{multi_a(20,xpub6CGCzpvrZVssNNXuP1Awcz8GoakYyJHra2WHASXfCzsD9szbQFoT1pLMdQopyqaSqXUprH7fkk8NG2pUbQa5HpNzpWmEsdNZDHxXvSLPTrn/*,xpub6C5MW95EE8hAmxm96LdAFYkweaAktQoojCf2MwJmNL9Fi6oUPeBnpFdEzhs9zHwr4HQEeF1r1yAUR8MqDJqk4YPteh75rNoCKCtud7shDDk/*,xpub6DNEUJP1zLAZ1P6gYRba9FyxuppmkrPmSKz3FLM7msRwn2LEr4LnKfAnNoSoAbnbW2orTfsitdfWTxLbJCZ6LizqV7cFUavSAjWzNjqdfCP/*,xpub6Cm5sAgCZQvYtnatYPdFuLhsD9VtgY3Rtt48TrdgqXm4DttXfM6nFmFTko8KcyGhPswTvPcTzfpMUvqV3F9tgLPvzfzoKwjmU668vBmGXEX/*,xpub6DN66R61Luv95HLvznR2ZWsbYuGBoK9LDR6XiNm1pvp5zRJ2vFhLQ4PBe2pDn59sKmRnEFbdLtBVZFN3QAujcGZ5PomGCvrnisxkP2fcgHg/*,xpub6D2GtAtYodmjwEoAzorKUta44NDvAB4JjafYXxsQ5hTWvCAK55nnkyNHfdjrsx3umfgGe1nnHut13mLuFqqi2fs7VVyv6rht76ddrDGhrTY/*,xpub6Bfi8jsDMuu2XHQ1TGRB6ehjdHKKmTwRFQYU6QcgHoZswqbzKsXs9Qd87nAxevjZwuQ37jaVnQoPF6wY34BJoeLxXkEYMpKz2CBHLcEmJVF/*,xpub6CYiNdQesStiBwZkWjPBxwxxf6oPMH9meBMujCwBX74X8nCpMF9zRZUbDrU9raQah1LQcnzLQrHC6Kr6LNCmsBpaMkYD3U6FyhHZfTHQGUB/*,xpub6CddszJHLa3VisZ6ufU4hiFcGsuuPHo7hYa24o3kPuPfAbMED4ajuDa6svuqxxBxYgUQhN8LK7MtTMetquNo7YsWhiV8hX2gBfjszJVXgkG/*,xpub6DAM262AxC4Um3rxBiP5FoA7SJJG3a7MjaJkEyXWyMA6iNuyqWueKZHSSNjKEWnn8Wi3PUQNTV1Z3a59C2Qaidha88GTWtAMhJBAWBBvuTN/*,xpub6ByZcsLsr8xTCJmYxvLpLrsFzuHNXRLR4xMyB9ZFLek1hDVh7zba2xAVTU8M6eonFFAAPYpTA76bDuopF5zyBkZqFc3rtJ3ziH1BUXkjC6j/*,xpub6Bx2LErujvR1noXrk7RHQB9htiDcPM5qYuV7Jg1nZh5jWeK8pYB4DnYQ73EX9sB9M6rnNsF8LDPUejHiXrBx2JJQSdVQ9i9FfEzJLuAnzEd/*,xpub6DSBog1uLngjBWVDUpLTQ19jGGKovgc3iTd1ijL4fjk9sgNqrnG5kGLjUWncay2jbqdgt6yrbYSHhfwsTMp7i8pUD1FMCQuFyqdsZpgUNH8/*,xpub6C53ov8LpuGp5MM4ghqUFJcdTnXJCRHyXaz1RVCys2uQErpdzUWHtm8Bsg8NJyaqfhGWvm9WPSE7jMneCRw1xs1CTajpToXyRqSCc41JiuY/*,xpub6CscWPNXdEybbJVvx7fJTrfHyTkKZtb97qcpQ9fH4k4xtm4nkckSpvy86heQsdyoF28CugwLHg5kLDwpGoPQAYXQ3RG9cJB2Na1FdeN1wt5/*,xpub6Cmrivt6w3kVAxw7NmcKSY19gSLmC2tVwx46cdigr9d1UEnttJCGZJ7NQu1MkugpZgF9rQ3j3NKUiZ2MoaC2QoZUfi4nwxbpH39SQZaBHut/*,xpub6D1Ey5JAYnBxFE8i2V2SUsEpJt7r3ykJKcShcpT2xN9CXtVQy5dKeYiZ9D1bdnkPrmgEajrSuA5nWqf94s6u7FwvXy3cU4BXUMgAt9C8wGT/*,xpub6CwJ2vicnoSJNFDzhonucHNVHDwyb1vyiu2VF6zmjQrzGb4qoAma1i2QJ7qRNe1qmpvvWwzSuQDgMnCECFQhZaPKuPFjcMo33r2xenBauxf/*,xpub6CiLNz8mFB4fB51x6gMNu44Up9PyVhq7fSxQb8UzYQermvMShwWyqzQe99Uiyxpfy1ow42xUGpPGBHf8ErxDbQojBf7Uy7hKFgYk8KpgMm2/*,xpub6DQ2qVMZ2o2QGGpYDsw5hpAcygNVEycAkkCib2Lexwm8gYWMCSecZ256AbAV93Rgze6h8yEoTcqUnvnz7L69WUqp7cXd85X8HoeKWjPHRRZ/*),multi_a(20,xpub6CGCzpvrZVssNNXuP1Awcz8GoakYyJHra2WHASXfCzsD9szbQFoT1pLMdQopyqaSqXUprH7fkk8NG2pUbQa5HpNzpWmEsdNZDHxXvSLPTrn/*,xpub6C5MW95EE8hAmxm96LdAFYkweaAktQoojCf2MwJmNL9Fi6oUPeBnpFdEzhs9zHwr4HQEeF1r1yAUR8MqDJqk4YPteh75rNoCKCtud7shDDk/*,xpub6DNEUJP1zLAZ1P6gYRba9FyxuppmkrPmSKz3FLM7msRwn2LEr4LnKfAnNoSoAbnbW2orTfsitdfWTxLbJCZ6LizqV7cFUavSAjWzNjqdfCP/*,xpub6Cm5sAgCZQvYtnatYPdFuLhsD9VtgY3Rtt48TrdgqXm4DttXfM6nFmFTko8KcyGhPswTvPcTzfpMUvqV3F9tgLPvzfzoKwjmU668vBmGXEX/*,xpub6DN66R61Luv95HLvznR2ZWsbYuGBoK9LDR6XiNm1pvp5zRJ2vFhLQ4PBe2pDn59sKmRnEFbdLtBVZFN3QAujcGZ5PomGCvrnisxkP2fcgHg/*,xpub6D2GtAtYodmjwEoAzorKUta44NDvAB4JjafYXxsQ5hTWvCAK55nnkyNHfdjrsx3umfgGe1nnHut13mLuFqqi2fs7VVyv6rht76ddrDGhrTY/*,xpub6Bfi8jsDMuu2XHQ1TGRB6ehjdHKKmTwRFQYU6QcgHoZswqbzKsXs9Qd87nAxevjZwuQ37jaVnQoPF6wY34BJoeLxXkEYMpKz2CBHLcEmJVF/*,xpub6CYiNdQesStiBwZkWjPBxwxxf6oPMH9meBMujCwBX74X8nCpMF9zRZUbDrU9raQah1LQcnzLQrHC6Kr6LNCmsBpaMkYD3U6FyhHZfTHQGUB/*,xpub6CddszJHLa3VisZ6ufU4hiFcGsuuPHo7hYa24o3kPuPfAbMED4ajuDa6svuqxxBxYgUQhN8LK7MtTMetquNo7YsWhiV8hX2gBfjszJVXgkG/*,xpub6DAM262AxC4Um3rxBiP5FoA7SJJG3a7MjaJkEyXWyMA6iNuyqWueKZHSSNjKEWnn8Wi3PUQNTV1Z3a59C2Qaidha88GTWtAMhJBAWBBvuTN/*,xpub6ByZcsLsr8xTCJmYxvLpLrsFzuHNXRLR4xMyB9ZFLek1hDVh7zba2xAVTU8M6eonFFAAPYpTA76bDuopF5zyBkZqFc3rtJ3ziH1BUXkjC6j/*,xpub6Bx2LErujvR1noXrk7RHQB9htiDcPM5qYuV7Jg1nZh5jWeK8pYB4DnYQ73EX9sB9M6rnNsF8LDPUejHiXrBx2JJQSdVQ9i9FfEzJLuAnzEd/*,xpub6DSBog1uLngjBWVDUpLTQ19jGGKovgc3iTd1ijL4fjk9sgNqrnG5kGLjUWncay2jbqdgt6yrbYSHhfwsTMp7i8pUD1FMCQuFyqdsZpgUNH8/*,xpub6C53ov8LpuGp5MM4ghqUFJcdTnXJCRHyXaz1RVCys2uQErpdzUWHtm8Bsg8NJyaqfhGWvm9WPSE7jMneCRw1xs1CTajpToXyRqSCc41JiuY/*,xpub6CscWPNXdEybbJVvx7fJTrfHyTkKZtb97qcpQ9fH4k4xtm4nkckSpvy86heQsdyoF28CugwLHg5kLDwpGoPQAYXQ3RG9cJB2Na1FdeN1wt5/*,xpub6Cmrivt6w3kVAxw7NmcKSY19gSLmC2tVwx46cdigr9d1UEnttJCGZJ7NQu1MkugpZgF9rQ3j3NKUiZ2MoaC2QoZUfi4nwxbpH39SQZaBHut/*,xpub6D1Ey5JAYnBxFE8i2V2SUsEpJt7r3ykJKcShcpT2xN9CXtVQy5dKeYiZ9D1bdnkPrmgEajrSuA5nWqf94s6u7FwvXy3cU4BXUMgAt9C8wGT/*,xpub6CwJ2vicnoSJNFDzhonucHNVHDwyb1vyiu2VF6zmjQrzGb4qoAma1i2QJ7qRNe1qmpvvWwzSuQDgMnCECFQhZaPKuPFjcMo33r2xenBauxf/*,xpub6CiLNz8mFB4fB51x6gMNu44Up9PyVhq7fSxQb8UzYQermvMShwWyqzQe99Uiyxpfy1ow42xUGpPGBHf8ErxDbQojBf7Uy7hKFgYk8KpgMm2/*,xpub6DQ2qVMZ2o2QGGpYDsw5hpAcygNVEycAkkCib2Lexwm8gYWMCSecZ256AbAV93Rgze6h8yEoTcqUnvnz7L69WUqp7cXd85X8HoeKWjPHRRZ/*)}})\n```\n\nThis PR:\n```sh\n|               ns/op |                op/s |    err% |     total | benchmark\n|--------------------:|--------------------:|--------:|----------:|:----------\n|           90,253.50 |           11,079.90 |    0.2% |      0.01 | `ParseDescriptor`\n```\n\nMaster:\n```sh\n|               ns/op |                op/s |    err% |     total | benchmark\n|--------------------:|--------------------:|--------:|----------:|:----------\n|          127,812.50 |            7,823.96 |    0.5% |      0.01 | `ParseDescriptor`\n```\n\nI didn't put the benchmark itself here but if reviewers think worth, I can do it.\n\n--------\n\nJoint work with claude \ud83d\ude05",
 "commits": [
  {
   "sha": "59daebcf05db41d83f9d1974b5c79be3eaf62770",
   "date": "2026-09-02T00:10:16Z",
   "message": "descriptor, key_io: avoid redundant work when parsing keys\n\nIn ParsePubkeyInner, every extended key required two full base58\ndecodes: once via DecodeExtKey and again via DecodeExtPubKey, even\nthough at most one can succeed. Replace both calls with a new\nDecodeExtKeyOrPubKey helper that performs a single DecodeBase58Check\nand dispatches on the 4-byte version prefix to populate either the\nxprv or xpub result.\n\nAlso eliminate the per-key std::string allocation in ParsePubkeyInner\nby switching the local 'str' variable to std::string_view over the\nexisting span, and update DecodeSecret / DecodeExtKey / DecodeExtPubKey\nto accept std::string_view directly (std::string and const char* callers\nare unaffected via implicit conversion).\n\nTo allow the string_view path all the way down, the internal base58\ndecoder is refactored from null-terminated const char* to a (psz, end)\npointer pair, replacing strlen() and *psz null checks with pointer\ncomparisons. The public DecodeBase58 / DecodeBase58Check APIs now take\nstd::string_view as well."
  },
  {
   "sha": "ddcacd25e735dad4868bab7f618961a363f23239",
   "date": "2026-09-02T00:10:16Z",
   "message": "descriptor: replace O(n) INPUT_CHARSET.find() with precomputed lookup table\n\nReplace the O(n) linear INPUT_CHARSET.find() in DescriptorChecksum with\na precomputed 256-entry lookup table, reducing the checksum pass from\nO(95 * len) to O(len)."
  }
 ],
 "timeline": [
  {
   "t": "2026-04-09T20:39:07Z",
   "kind": "comment",
   "who": "l0rinc",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThere have been a few base58 optimization attempts before (https://github.com/bitcoin/bitcoin/pull/29473 and independently before https://github.com/bitcoin/bitcoin/pull/21176) - would it help if we revived them?"
  },
  {
   "t": "2026-04-10T12:08:59Z",
   "kind": "comment",
   "who": "brunoerg",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nI'll take a look on those PRs and try, thank you. I think their focus is to improve/rewrites the algorithm itself, here is more about the way it's been used."
  },
  {
   "t": "2026-06-07T13:53:30Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/script/descriptor.cpp",
   "commit": "2d86114c1b90d94593bda7f54f02b1403f678af2",
   "in_reply_to": null,
   "text": "Shouldn't really matter, but I thinks this could be constexpr too."
  },
  {
   "t": "2026-06-07T14:04:32Z",
   "kind": "review",
   "who": "sedited",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "2d86114c1b90d94593bda7f54f02b1403f678af2",
   "text": "Concept ACK"
  },
  {
   "t": "2026-06-10T15:50:16Z",
   "kind": "force_push",
   "who": "brunoerg",
   "commit": "0d8110a13579cee43b4d77bdbad943cc821cd6cb"
  },
  {
   "t": "2026-06-10T15:52:00Z",
   "kind": "review_comment",
   "who": "brunoerg",
   "assoc": "MEMBER",
   "path": "src/script/descriptor.cpp",
   "commit": "2d86114c1b90d94593bda7f54f02b1403f678af2",
   "in_reply_to": 3369457038,
   "text": "Done."
  },
  {
   "t": "2026-06-10T17:51:54Z",
   "kind": "force_push",
   "who": "brunoerg",
   "commit": "6dd023abbc9a1d8ece5dc9f9e186e7f5b1fb6f91"
  },
  {
   "t": "2026-08-24T14:27:12Z",
   "kind": "force_push",
   "who": "brunoerg",
   "commit": "0339b33e41f13f87111c2e03e1ddc42bc6a596c4"
  },
  {
   "t": "2026-08-25T09:02:24Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/key_io.cpp",
   "commit": "ddcacd25e735dad4868bab7f618961a363f23239",
   "in_reply_to": null,
   "text": "Started experimenting with returning `std::optional<std::variant<CExtKey, CExtPubKey>>` and validating `IsValid()` inside of the function but seems cleaner to leave that out of this PR. :)"
  },
  {
   "t": "2026-08-25T09:49:17Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/base58.cpp",
   "commit": "0339b33e41f13f87111c2e03e1ddc42bc6a596c4",
   "in_reply_to": null,
   "text": "nit: Could document & enforce the `end` pointer not changing as well:\n```suggestion\n[[nodiscard]] static bool DecodeBase58(const char* psz, const char* const end, std::vector<unsigned char>& vch, int max_ret_len)\n```"
  },
  {
   "t": "2026-08-25T10:02:10Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/script/descriptor.cpp",
   "commit": "0339b33e41f13f87111c2e03e1ddc42bc6a596c4",
   "in_reply_to": null,
   "text": "nit-level suggestions:\n1. Omit `static` for `constexpr` variables as they are only evaluated once anyway (still needed for `INPUT_CHARSET` to simplify capture in lambda).\n2. Change element type of `INPUT_CHARSET_POS` to `int8_t` to better match range of possible values and decrease size.\n3. Omit cast to unsigned when indexing into `table` as at least GCC will trigger an assert at compile time when indexing out of bounds in `std::array`.\n4. Prefer `uint8_t` over longer `unsigned char`.\n```diff\n--- a/src/script/descriptor.cpp\n+++ b/src/script/descriptor.cpp\n@@ -143,23 +143,23 @@ std::string DescriptorChecksum(const std::span<const char>& span)\n         \"ijklmnopqrstuvwxyzABCDEFGH`#\\\"\\\\ \";\n\n     /** Lookup table mapping each ASCII byte to its position in INPUT_CHARSET, or -1 if not present. */\n-    static constexpr std::array<int, 256> INPUT_CHARSET_POS = []() {\n-        std::array<int, 256> table;\n+    constexpr std::array<int8_t, 256> INPUT_CHARSET_POS = []() {\n+        std::array<int8_t, 256> table;\n         table.fill(-1);\n         for (size_t i = 0; i < INPUT_CHARSET.size(); ++i) {\n-            table[static_cast<unsigned char>(INPUT_CHARSET[i])] = i;\n+            table[INPUT_CHARSET[i]] = i;\n         }\n         return table;\n     }();\n\n     /** The character set for the checksum itself (same as bech32). */\n-    static constexpr std::string_view CHECKSUM_CHARSET = \"qpzry9x8gf2tvdw0s3jn54khce6mua7l\";\n+    constexpr std::string_view CHECKSUM_CHARSET = \"qpzry9x8gf2tvdw0s3jn54khce6mua7l\";\n\n     uint64_t c = 1;\n     int cls = 0;\n     int clscount = 0;\n     for (auto ch : span) {\n-        auto pos = INPUT_CHARSET_POS[static_cast<unsigned char>(ch)];\n+        int8_t pos = INPUT_CHARSET_POS[static_cast<uint8_t>(ch)];\n         if (pos == -1) return \"\";\n         c = PolyMod(c, pos & 31); // Emit a symbol for the position inside the group, for every character.\n         cls = cls * 3 + (pos >> 5); // Accumulate the group numbers\n```"
  },
  {
   "t": "2026-08-25T12:10:31Z",
   "kind": "review",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "0339b33e41f13f87111c2e03e1ddc42bc6a596c4",
   "text": "ACK 0339b33e41f13f87111c2e03e1ddc42bc6a596c4\n\nWhy this change is acceptable when prior optimization attempts in this area were rejected (https://github.com/bitcoin/bitcoin/pull/35041#issuecomment-4217337173):\n* First commit is a *higher level* change to combine two calls to `DecodeBase58Check()` into one.\n* Second commit *trivially* replaces linear lookup with `O(1)` lookup table.\n\nIn my subjective view they have a lower impact on code readability than the rejected PRs. Also, the author of this PR motivates it through the concrete second-order effect of speeding up fuzz targets.\n\n(I'm still open to reviewing further optimizations in this area, without guarantees of priority).\n\nBenchmark code\n\n```diff\n--- a/src/bench/descriptors.cpp\n+++ b/src/bench/descriptors.cpp\n@@ -3,10 +3,12 @@\n // file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n #include <bench/bench.h>\n+#include <chainparams.h>\n #include <key.h>\n #include <script/descriptor.h>\n #include <script/script.h>\n #include <script/signingprovider.h>\n+#include <util/chaintype.h>\n #include <util/check.h>\n\n #include <cstdint>\n@@ -36,3 +38,21 @@ static void ExpandDescriptor(benchmark::Bench& bench)\n }\n\n BENCHMARK(ExpandDescriptor);\n+\n+static void ParseDescriptor(benchmark::Bench& bench)\n+{\n+    SelectParams(ChainType::MAIN);\n+\n+    constexpr std::string_view desc_str{\"tr(xpub6CGCzpvrZVssNNXuP1Awcz8GoakYyJHra2WHASXfCzsD9szbQFoT1pLMdQopyqaSqXUprH7fkk8NG2pUbQa5HpNzpWmEsdNZDHxXvSLPTrn/*,{{multi_a(20,xpub6CGCzpvrZVssNNXuP1Awcz8GoakYyJHra2WHASXfCzsD9szbQFoT1pLMdQopyqaSqXUprH7fkk8NG2pUbQa5HpNzpWmEsdNZDHxXvSLPTrn/*,xpub6C5MW95EE8hAmxm96LdAFYkweaAktQoojCf2MwJmNL9Fi6oUPeBnpFdEzhs9zHwr4HQEeF1r1yAUR8MqDJqk4YPteh75rNoCKCtud7shDDk/*,xpub6DNEUJP1zLAZ1P6gYRba9FyxuppmkrPmSKz3FLM7msRwn2LEr4LnKfAnNoSoAbnbW2orTfsitdfWTxLbJCZ6LizqV7cFUavSAjWzNjqdfCP/*,xpub6Cm5sAgCZQvYtnatYPdFuLhsD9VtgY3Rtt48TrdgqXm4DttXfM6nFmFTko8KcyGhPswTvPcTzfpMUvqV3F9tgLPvzfzoKwjmU668vBmGXEX/*,xpub6DN66R61Luv95HLvznR2ZWsbYuGBoK9LDR6XiNm1pvp5zRJ2vFhLQ4PBe2pDn59sKmRnEFbdLtBVZFN3QAujcGZ5PomGCvrnisxkP2fcgHg/*,xpub6D2GtAtYodmjwEoAzorKUta44NDvAB4JjafYXxsQ5hTWvCAK55nnkyNHfdjrsx3umfgGe1nnHut13mLuFqqi2fs7VVyv6rht76ddrDGhrTY/*,xpub6Bfi8jsDMuu2XHQ1TGRB6ehjdHKKmTwRFQYU6QcgHoZswqbzKsXs9Qd87nAxevjZwuQ37jaVnQoPF6wY34BJoeLxXkEYMpKz2CBHLcEmJVF/*,xpub6CYiNdQesStiBwZkWjPBxwxxf6oPMH9meBMujCwBX74X8nCpMF9zRZUbDrU9raQah1LQcnzLQrHC6Kr6LNCmsBpaMkYD3U6FyhHZfTHQGUB/*,xpub6CddszJHLa3VisZ6ufU4hiFcGsuuPHo7hYa24o3kPuPfAbMED4ajuDa6svuqxxBxYgUQhN8LK7MtTMetquNo7YsWhiV8hX2gBfjszJVXgkG/*,xpub6DAM262AxC4Um3rxBiP5FoA7SJJG3a7MjaJkEyXWyMA6iNuyqWueKZHSSNjKEWnn8Wi3PUQNTV1Z3a59C2Qaidha88GTWtAMhJBAWBBvuTN/*,xpub6ByZcsLsr8xTCJmYxvLpLrsFzuHNXRLR4xMyB9ZFLek1hDVh7zba2xAVTU8M6eonFFAAPYpTA76bDuopF5zyBkZqFc3rtJ3ziH1BUXkjC6j/*,xpub6Bx2LErujvR1noXrk7RHQB9htiDcPM5qYuV7Jg1nZh5jWeK8pYB4DnYQ73EX9sB9M6rnNsF8LDPUejHiXrBx2JJQSdVQ9i9FfEzJLuAnzEd/*,xpub6DSBog1uLngjBWVDUpLTQ19jGGKovgc3iTd1ijL4fjk9sgNqrnG5kGLjUWncay2jbqdgt6yrbYSHhfwsTMp7i8pUD1FMCQuFyqdsZpgUNH8/*,xpub6C53ov8LpuGp5MM4ghqUFJcdTnXJCRHyXaz1RVCys2uQErpdzUWHtm8Bsg8NJyaqfhGWvm9WPSE7jMneCRw1xs1CTajpToXyRqSCc41JiuY/*,xpub6CscWPNXdEybbJVvx7fJTrfHyTkKZtb97qcpQ9fH4k4xtm4nkckSpvy86heQsdyoF28CugwLHg5kLDwpGoPQAYXQ3RG9cJB2Na1FdeN1wt5/*,xpub6Cmrivt6w3kVAxw7NmcKSY19gSLmC2tVwx46cdigr9d1UEnttJCGZJ7NQu1MkugpZgF9rQ3j3NKUiZ2MoaC2QoZUfi4nwxbpH39SQZaBHut/*,xpub6D1Ey5JAYnBxFE8i2V2SUsEpJt7r3ykJKcShcpT2xN9CXtVQy5dKeYiZ9D1bdnkPrmgEajrSuA5nWqf94s6u7FwvXy3cU4BXUMgAt9C8wGT/*,xpub6CwJ2vicnoSJNFDzhonucHNVHDwyb1vyiu2VF6zmjQrzGb4qoAma1i2QJ7qRNe1qmpvvWwzSuQDgMnCECFQhZaPKuPFjcMo33r2xenBauxf/*,xpub6CiLNz8mFB4fB51x6gMNu44Up9PyVhq7fSxQb8UzYQermvMShwWyqzQe99Uiyxpfy1ow42xUGpPGBHf8ErxDbQojBf7Uy7hKFgYk8KpgMm2/*,xpub6DQ2qVMZ2o2QGGpYDsw5hpAcygNVEycAkkCib2Lexwm8gYWMCSecZ256AbAV93Rgze6h8yEoTcqUnvnz7L69WUqp7cXd85X8HoeKWjPHRRZ/*),multi_a(20,xpub6CGCzpvrZVssNNXuP1Awcz8GoakYyJHra2WHASXfCzsD9szbQFoT1pLMdQopyqaSqXUprH7fkk8NG2pUbQa5HpNzpWmEsdNZDHxXvSLPTrn/*,xpub6C5MW95EE8hAmxm96LdAFYkweaAktQoojCf2MwJmNL9Fi6oUPeBnpFdEzhs9zHwr4HQEeF1r1yAUR8MqDJqk4YPteh75rNoCKCtud7shDDk/*,xpub6DNEUJP1zLAZ1P6gYRba9FyxuppmkrPmSKz3FLM7msRwn2LEr4LnKfAnNoSoAbnbW2orTfsitdfWTxLbJCZ6LizqV7cFUavSAjWzNjqdfCP/*,xpub6Cm5sAgCZQvYtnatYPdFuLhsD9VtgY3Rtt48TrdgqXm4DttXfM6nFmFTko8KcyGhPswTvPcTzfpMUvqV3F9tgLPvzfzoKwjmU668vBmGXEX/*,xpub6DN66R61Luv95HLvznR2ZWsbYuGBoK9LDR6XiNm1pvp5zRJ2vFhLQ4PBe2pDn59sKmRnEFbdLtBVZFN3QAujcGZ5PomGCvrnisxkP2fcgHg/*,xpub6D2GtAtYodmjwEoAzorKUta44NDvAB4JjafYXxsQ5hTWvCAK55nnkyNHfdjrsx3umfgGe1nnHut13mLuFqqi2fs7VVyv6rht76ddrDGhrTY/*,xpub6Bfi8jsDMuu2XHQ1TGRB6ehjdHKKmTwRFQYU6QcgHoZswqbzKsXs9Qd87nAxevjZwuQ37jaVnQoPF6wY34BJoeLxXkEYMpKz2CBHLcEmJVF/*,xpub6CYiNdQesStiBwZkWjPBxwxxf6oPMH9meBMujCwBX74X8nCpMF9zRZUbDrU9raQah1LQcnzLQrHC6Kr6LNCmsBpaMkYD3U6FyhHZfTHQGUB/*,xpub6CddszJHLa3VisZ6ufU4hiFcGsuuPHo7hYa24o3kPuPfAbMED4ajuDa6svuqxxBxYgUQhN8LK7MtTMetquNo7YsWhiV8hX2gBfjszJVXgkG/*,xpub6DAM262AxC4Um3rxBiP5FoA7SJJG3a7MjaJkEyXWyMA6iNuyqWueKZHSSNjKEWnn8Wi3PUQNTV1Z3a59C2Qaidha88GTWtAMhJBAWBBvuTN/*,xpub6ByZcsLsr8xTCJmYxvLpLrsFzuHNXRLR4xMyB9ZFLek1hDVh7zba2xAVTU8M6eonFFAAPYpTA76bDuopF5zyBkZqFc3rtJ3ziH1BUXkjC6j/*,xpub6Bx2LErujvR1noXrk7RHQB9htiDcPM5qYuV7Jg1nZh5jWeK8pYB4DnYQ73EX9sB9M6rnNsF8LDPUejHiXrBx2JJQSdVQ9i9FfEzJLuAnzEd/*,xpub6DSBog1uLngjBWVDUpLTQ19jGGKovgc3iTd1ijL4fjk9sgNqrnG5kGLjUWncay2jbqdgt6yrbYSHhfwsTMp7i8pUD1FMCQuFyqdsZpgUNH8/*,xpub6C53ov8LpuGp5MM4ghqUFJcdTnXJCRHyXaz1RVCys2uQErpdzUWHtm8Bsg8NJyaqfhGWvm9WPSE7jMneCRw1xs1CTajpToXyRqSCc41JiuY/*,xpub6CscWPNXdEybbJVvx7fJTrfHyTkKZtb97qcpQ9fH4k4xtm4nkckSpvy86heQsdyoF28CugwLHg5kLDwpGoPQAYXQ3RG9cJB2Na1FdeN1wt5/*,xpub6Cmrivt6w3kVAxw7NmcKSY19gSLmC2tVwx46cdigr9d1UEnttJCGZJ7NQu1MkugpZgF9rQ3j3NKUiZ2MoaC2QoZUfi4nwxbpH39SQZaBHut/*,xpub6D1Ey5JAYnBxFE8i2V2SUsEpJt7r3ykJKcShcpT2xN9CXtVQy5dKeYiZ9D1bdnkPrmgEajrSuA5nWqf94s6u7FwvXy3cU4BXUMgAt9C8wGT/*,xpub6CwJ2vicnoSJNFDzhonucHNVHDwyb1vyiu2VF6zmjQrzGb4qoAma1i2QJ7qRNe1qmpvvWwzSuQDgMnCECFQhZaPKuPFjcMo33r2xenBauxf/*,xpub6CiLNz8mFB4fB51x6gMNu44Up9PyVhq7fSxQb8UzYQermvMShwWyqzQe99Uiyxpfy1ow42xUGpPGBHf8ErxDbQojBf7Uy7hKFgYk8KpgMm2/*,xpub6DQ2qVMZ2o2QGGpYDsw5hpAcygNVEycAkkCib2Lexwm8gYWMCSecZ256AbAV93Rgze6h8yEoTcqUnvnz7L69WUqp7cXd85X8HoeKWjPHRRZ/*)},{multi_a(20,xpub6CGCzpvrZVssNNXuP1Awcz8GoakYyJHra2WHASXfCzsD9szbQFoT1pLMdQopyqaSqXUprH7fkk8NG2pUbQa5HpNzpWmEsdNZDHxXvSLPTrn/*,xpub6C5MW95EE8hAmxm96LdAFYkweaAktQoojCf2MwJmNL9Fi6oUPeBnpFdEzhs9zHwr4HQEeF1r1yAUR8MqDJqk4YPteh75rNoCKCtud7shDDk/*,xpub6DNEUJP1zLAZ1P6gYRba9FyxuppmkrPmSKz3FLM7msRwn2LEr4LnKfAnNoSoAbnbW2orTfsitdfWTxLbJCZ6LizqV7cFUavSAjWzNjqdfCP/*,xpub6Cm5sAgCZQvYtnatYPdFuLhsD9VtgY3Rtt48TrdgqXm4DttXfM6nFmFTko8KcyGhPswTvPcTzfpMUvqV3F9tgLPvzfzoKwjmU668vBmGXEX/*,xpub6DN66R61Luv95HLvznR2ZWsbYuGBoK9LDR6XiNm1pvp5zRJ2vFhLQ4PBe2pDn59sKmRnEFbdLtBVZFN3QAujcGZ5PomGCvrnisxkP2fcgHg/*,xpub6D2GtAtYodmjwEoAzorKUta44NDvAB4JjafYXxsQ5hTWvCAK55nnkyNHfdjrsx3umfgGe1nnHut13mLuFqqi2fs7VVyv6rht76ddrDGhrTY/*,xpub6Bfi8jsDMuu2XHQ1TGRB6ehjdHKKmTwRFQYU6QcgHoZswqbzKsXs9Qd87nAxevjZwuQ37jaVnQoPF6wY34BJoeLxXkEYMpKz2CBHLcEmJVF/*,xpub6CYiNdQesStiBwZkWjPBxwxxf6oPMH9meBMujCwBX74X8nCpMF9zRZUbDrU9raQah1LQcnzLQrHC6Kr6LNCmsBpaMkYD3U6FyhHZfTHQGUB/*,xpub6CddszJHLa3VisZ6ufU4hiFcGsuuPHo7hYa24o3kPuPfAbMED4ajuDa6svuqxxBxYgUQhN8LK7MtTMetquNo7YsWhiV8hX2gBfjszJVXgkG/*,xpub6DAM262AxC4Um3rxBiP5FoA7SJJG3a7MjaJkEyXWyMA6iNuyqWueKZHSSNjKEWnn8Wi3PUQNTV1Z3a59C2Qaidha88GTWtAMhJBAWBBvuTN/*,xpub6ByZcsLsr8xTCJmYxvLpLrsFzuHNXRLR4xMyB9ZFLek1hDVh7zba2xAVTU8M6eonFFAAPYpTA76bDuopF5zyBkZqFc3rtJ3ziH1BUXkjC6j/*,xpub6Bx2LErujvR1noXrk7RHQB9htiDcPM5qYuV7Jg1nZh5jWeK8pYB4DnYQ73EX9sB9M6rnNsF8LDPUejHiXrBx2JJQSdVQ9i9FfEzJLuAnzEd/*,xpub6DSBog1uLngjBWVDUpLTQ19jGGKovgc3iTd1ijL4fjk9sgNqrnG5kGLjUWncay2jbqdgt6yrbYSHhfwsTMp7i8pUD1FMCQuFyqdsZpgUNH8/*,xpub6C53ov8LpuGp5MM4ghqUFJcdTnXJCRHyXaz1RVCys2uQErpdzUWHtm8Bsg8NJyaqfhGWvm9WPSE7jMneCRw1xs1CTajpToXyRqSCc41JiuY/*,xpub6CscWPNXdEybbJVvx7fJTrfHyTkKZtb97qcpQ9fH4k4xtm4nkckSpvy86heQsdyoF28CugwLHg5kLDwpGoPQAYXQ3RG9cJB2Na1FdeN1wt5/*,xpub6Cmrivt6w3kVAxw7NmcKSY19gSLmC2tVwx46cdigr9d1UEnttJCGZJ7NQu1MkugpZgF9rQ3j3NKUiZ2MoaC2QoZUfi4nwxbpH39SQZaBHut/*,xpub6D1Ey5JAYnBxFE8i2V2SUsEpJt7r3ykJKcShcpT2xN9CXtVQy5dKeYiZ9D1bdnkPrmgEajrSuA5nWqf94s6u7FwvXy3cU4BXUMgAt9C8wGT/*,xpub6CwJ2vicnoSJNFDzhonucHNVHDwyb1vyiu2VF6zmjQrzGb4qoAma1i2QJ7qRNe1qmpvvWwzSuQDgMnCECFQhZaPKuPFjcMo33r2xenBauxf/*,xpub6CiLNz8mFB4fB51x6gMNu44Up9PyVhq7fSxQb8UzYQermvMShwWyqzQe99Uiyxpfy1ow42xUGpPGBHf8ErxDbQojBf7Uy7hKFgYk8KpgMm2/*,xpub6DQ2qVMZ2o2QGGpYDsw5hpAcygNVEycAkkCib2Lexwm8gYWMCSecZ256AbAV93Rgze6h8yEoTcqUnvnz7L69WUqp7cXd85X8HoeKWjPHRRZ/*),multi_a(20,xpub6CGCzpvrZVssNNXuP1Awcz8GoakYyJHra2WHASXfCzsD9szbQFoT1pLMdQopyqaSqXUprH7fkk8NG2pUbQa5HpNzpWmEsdNZDHxXvSLPTrn/*,xpub6C5MW95EE8hAmxm96LdAFYkweaAktQoojCf2MwJmNL9Fi6oUPeBnpFdEzhs9zHwr4HQEeF1r1yAUR8MqDJqk4YPteh75rNoCKCtud7shDDk/*,xpub6DNEUJP1zLAZ1P6gYRba9FyxuppmkrPmSKz3FLM7msRwn2LEr4LnKfAnNoSoAbnbW2orTfsitdfWTxLbJCZ6LizqV7cFUavSAjWzNjqdfCP/*,xpub6Cm5sAgCZQvYtnatYPdFuLhsD9VtgY3Rtt48TrdgqXm4DttXfM6nFmFTko8KcyGhPswTvPcTzfpMUvqV3F9tgLPvzfzoKwjmU668vBmGXEX/*,xpub6DN66R61Luv95HLvznR2ZWsbYuGBoK9LDR6XiNm1pvp5zRJ2vFhLQ4PBe2pDn59sKmRnEFbdLtBVZFN3QAujcGZ5PomGCvrnisxkP2fcgHg/*,xpub6D2GtAtYodmjwEoAzorKUta44NDvAB4JjafYXxsQ5hTWvCAK55nnkyNHfdjrsx3umfgGe1nnHut13mLuFqqi2fs7VVyv6rht76ddrDGhrTY/*,xpub6Bfi8jsDMuu2XHQ1TGRB6ehjdHKKmTwRFQYU6QcgHoZswqbzKsXs9Qd87nAxevjZwuQ37jaVnQoPF6wY34BJoeLxXkEYMpKz2CBHLcEmJVF/*,xpub6CYiNdQesStiBwZkWjPBxwxxf6oPMH9meBMujCwBX74X8nCpMF9zRZUbDrU9raQah1LQcnzLQrHC6Kr6LNCmsBpaMkYD3U6FyhHZfTHQGUB/*,xpub6CddszJHLa3VisZ6ufU4hiFcGsuuPHo7hYa24o3kPuPfAbMED4ajuDa6svuqxxBxYgUQhN8LK7MtTMetquNo7YsWhiV8hX2gBfjszJVXgkG/*,xpub6DAM262AxC4Um3rxBiP5FoA7SJJG3a7MjaJkEyXWyMA6iNuyqWueKZHSSNjKEWnn8Wi3PUQNTV1Z3a59C2Qaidha88GTWtAMhJBAWBBvuTN/*,xpub6ByZcsLsr8xTCJmYxvLpLrsFzuHNXRLR4xMyB9ZFLek1hDVh7zba2xAVTU8M6eonFFAAPYpTA76bDuopF5zyBkZqFc3rtJ3ziH1BUXkjC6j/*,xpub6Bx2LErujvR1noXrk7RHQB9htiDcPM5qYuV7Jg1nZh5jWeK8pYB4DnYQ73EX9sB9M6rnNsF8LDPUejHiXrBx2JJQSdVQ9i9FfEzJLuAnzEd/*,xpub6DSBog1uLngjBWVDUpLTQ19jGGKovgc3iTd1ijL4fjk9sgNqrnG5kGLjUWncay2jbqdgt6yrbYSHhfwsTMp7i8pUD1FMCQuFyqdsZpgUNH8/*,xpub6C53ov8LpuGp5MM4ghqUFJcdTnXJCRHyXaz1RVCys2uQErpdzUWHtm8Bsg8NJyaqfhGWvm9WPSE7jMneCRw1xs1CTajpToXyRqSCc41JiuY/*,xpub6CscWPNXdEybbJVvx7fJTrfHyTkKZtb97qcpQ9fH4k4xtm4nkckSpvy86heQsdyoF28CugwLHg5kLDwpGoPQAYXQ3RG9cJB2Na1FdeN1wt5/*,xpub6Cmrivt6w3kVAxw7NmcKSY19gSLmC2tVwx46cdigr9d1UEnttJCGZJ7NQu1MkugpZgF9rQ3j3NKUiZ2MoaC2QoZUfi4nwxbpH39SQZaBHut/*,xpub6D1Ey5JAYnBxFE8i2V2SUsEpJt7r3ykJKcShcpT2xN9CXtVQy5dKeYiZ9D1bdnkPrmgEajrSuA5nWqf94s6u7FwvXy3cU4BXUMgAt9C8wGT/*,xpub6CwJ2vicnoSJNFDzhonucHNVHDwyb1vyiu2VF6zmjQrzGb4qoAma1i2QJ7qRNe1qmpvvWwzSuQDgMnCECFQhZaPKuPFjcMo33r2xenBauxf/*,xpub6CiLNz8mFB4fB51x6gMNu44Up9PyVhq7fSxQb8UzYQermvMShwWyqzQe99Uiyxpfy1ow42xUGpPGBHf8ErxDbQojBf7Uy7hKFgYk8KpgMm2/*,xpub6DQ2qVMZ2o2QGGpYDsw5hpAcygNVEycAkkCib2Lexwm8gYWMCSecZ256AbAV93Rgze6h8yEoTcqUnvnz7L69WUqp7cXd85X8HoeKWjPHRRZ/*)}})\"};\n+    FlatSigningProvider provider;\n+    std::string error;\n+\n+    bench.run([&] {\n+        FlatSigningProvider provider;\n+        std::string error;\n+        auto descs = Parse(desc_str, provider, error);\n+        assert(error.empty());\n+        assert(!descs.empty());\n+    });\n+}\n+BENCHMARK(ParseDescriptor);\n```\n\nBenchmark results - 36.7% less time\n\n```\n\u20bf cmake --build build -t bench_bitcoin && ./build/bin/bench_bitcoin -filter=ParseDescriptor -min-time=20000\n[1/4] Generating bitcoin-build-info.h\n\n|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark\n|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------\n|        2,279,668.50 |              438.66 |    0.0% |   21,336,811.84 |    8,410,310.10 |  2.537 |   2,425,190.55 |    1.9% |     22.00 | `ParseDescriptor`\n\n\u20bf cmake --build build -t bench_bitcoin && ./build/bin/bench_bitcoin -filter=ParseDescriptor -min-time=20000\n[37/37] Linking CXX executable bin/bench_bitcoin\n\n|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark\n|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------\n|        1,443,634.77 |              692.70 |    0.0% |   13,602,529.65 |    5,326,314.15 |  2.554 |   1,465,145.07 |    2.0% |     21.34 | `ParseDescriptor`\n```\n\n(Run under `doas pyperf system tune`)."
  },
  {
   "t": "2026-09-01T16:06:31Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/base58.cpp",
   "commit": "0339b33e41f13f87111c2e03e1ddc42bc6a596c4",
   "in_reply_to": 3851726243,
   "text": "Could also pass a string view in here to clean up the callers and then derive `psz` and `end` only in the first line of this function?"
  },
  {
   "t": "2026-09-01T23:53:26Z",
   "kind": "review_comment",
   "who": "brunoerg",
   "assoc": "MEMBER",
   "path": "src/base58.cpp",
   "commit": "0339b33e41f13f87111c2e03e1ddc42bc6a596c4",
   "in_reply_to": 3851726243,
   "text": "Yes, I like the string view approach, but I think we would have to rename the internal helpers to avoid recursion."
  },
  {
   "t": "2026-09-01T23:59:30Z",
   "kind": "review_comment",
   "who": "brunoerg",
   "assoc": "MEMBER",
   "path": "src/script/descriptor.cpp",
   "commit": "0339b33e41f13f87111c2e03e1ddc42bc6a596c4",
   "in_reply_to": 3851842372,
   "text": "Not sure about dropping `static` because it guarantees the value is computed at compile time; I cannot see why not using it, especially for debug builds.\n\nThe other points are valid, I'm going to address them since I intend to address https://github.com/bitcoin/bitcoin/pull/35041#discussion_r3909496481."
  },
  {
   "t": "2026-09-02T01:02:59Z",
   "kind": "force_push",
   "who": "brunoerg",
   "commit": "ddcacd25e735dad4868bab7f618961a363f23239"
  },
  {
   "t": "2026-09-02T01:05:02Z",
   "kind": "review_comment",
   "who": "brunoerg",
   "assoc": "MEMBER",
   "path": "src/base58.cpp",
   "commit": "0339b33e41f13f87111c2e03e1ddc42bc6a596c4",
   "in_reply_to": 3851726243,
   "text": "Done."
  },
  {
   "t": "2026-09-02T01:07:31Z",
   "kind": "comment",
   "who": "brunoerg",
   "assoc": "MEMBER",
   "text": "Force-pushed addressing https://github.com/bitcoin/bitcoin/pull/35041#discussion_r3906003696 (string view) and changed INPUT_CHARSET_POS element type from int to int8_t as well as the index casts from unsigned char to uint8_t. Thanks @hodlinator and @maflcko for reviewing it."
  },
  {
   "t": "2026-09-02T07:21:03Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/base58.cpp",
   "commit": "0339b33e41f13f87111c2e03e1ddc42bc6a596c4",
   "in_reply_to": 3851726243,
   "text": "nit: If you touch again, maybe you could use \"Internal\" as the disambiguating suffix rather than \"Raw\"?"
  },
  {
   "t": "2026-09-02T07:22:59Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/script/descriptor.cpp",
   "commit": "0339b33e41f13f87111c2e03e1ddc42bc6a596c4",
   "in_reply_to": 3851842372,
   "text": "Thanks for applying most of my feedback!\n\nIt is `constexpr` which guarantees the value to be computed at compile time, so `static` is redundant for `INPUT_CHARSET_POS` and `CHECKSUM_CHARSET`."
  },
  {
   "t": "2026-09-02T07:28:17Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/base58.cpp",
   "commit": "ddcacd25e735dad4868bab7f618961a363f23239",
   "in_reply_to": null,
   "text": "nit: Could further constrain `end` here:\n```suggestion\n    const char* const end = str.data() + str.size();\n```\n(It both cannot mutate the data it points to *and* it is not allowed to be modified to point at other memory)."
  },
  {
   "t": "2026-09-02T07:29:39Z",
   "kind": "review",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "ddcacd25e735dad4868bab7f618961a363f23239",
   "text": "re-ACK ddcacd25e735dad4868bab7f618961a363f23239\n\nInitial ACK: https://github.com/bitcoin/bitcoin/pull/35041#pullrequestreview-5016944887"
  }
 ],
 "labels_log": [
  {
   "t": "2026-04-09T18:19:26Z",
   "action": "labeled",
   "label": "Descriptors",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-10T17:17:54Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-10T19:19:54Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-24T11:32:47Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-24T15:55:24Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2026-04-09T18:19:29Z",
   "kind": "convert_to_draft",
   "who": "brunoerg"
  },
  {
   "t": "2026-04-09T18:25:53Z",
   "kind": "ready_for_review",
   "who": "brunoerg"
  }
 ],
 "text_chars": 29301,
 "text_tokens_estimate": 7325,
 "changed_paths": [
  "src/base58.cpp",
  "src/base58.h",
  "src/key_io.cpp",
  "src/key_io.h",
  "src/script/descriptor.cpp"
 ],
 "files": [
  {
   "path": "src/base58.cpp",
   "add": 15,
   "del": 13
  },
  {
   "path": "src/base58.h",
   "add": 3,
   "del": 2
  },
  {
   "path": "src/key_io.cpp",
   "add": 22,
   "del": 3
  },
  {
   "path": "src/key_io.h",
   "add": 10,
   "del": 3
  },
  {
   "path": "src/script/descriptor.cpp",
   "add": 17,
   "del": 7
  }
 ],
 "test_lines": 0,
 "git": {
  "head": "ddcacd25e735dad4868bab7f618961a363f23239",
  "head_matches_backup": true,
  "base": "135e05cfa07359725b603855d9a7655d877ac32c",
  "commits": [
   {
    "sha": "59daebcf05",
    "subject": "descriptor, key_io: avoid redundant work when parsing keys",
    "files": 5,
    "add": 52,
    "del": 24
   },
   {
    "sha": "ddcacd25e7",
    "subject": "descriptor: replace O(n) INPUT_CHARSET.find() with precomputed lookup table",
    "files": 1,
    "add": 15,
    "del": 4
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "b72801d0b011e222",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}