{
 "number": 25665,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/25665",
 "title": "refactor: Add util::Result failure types and ability to merge result values",
 "author": "ryanofsky",
 "author_association": "MEMBER",
 "created_at": "2022-07-21T12:46:09Z",
 "updated_at": "2026-09-13T15:19:58Z",
 "age_days": 1519,
 "draft": false,
 "labels": [
  "Refactoring"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "389ab06bb04dee0f056ac27760840bb09e440efb",
 "head_ref": "pr/bresult2",
 "head_repo": "ryanofsky/bitcoin",
 "head_history": [
  {
   "t": "2022-07-21T17:02:18Z",
   "sha": "6e84015ea56b4ff9743466bb9880db2b58a533b7"
  },
  {
   "t": "2022-07-21T18:49:07Z",
   "sha": "9ba210bf6e9ba259caf499a649c2954240cbfa40"
  },
  {
   "t": "2022-07-21T19:43:35Z",
   "sha": "10e78ee295e2069620ea3f5a9286fe4a1a7f2f70"
  },
  {
   "t": "2022-07-22T10:43:15Z",
   "sha": "358e0fe5f205048333a728df3a67041c1b2e5bd1"
  },
  {
   "t": "2022-07-25T22:22:28Z",
   "sha": "32dd8ebbb33b27b717d656c7c8c1de24a40a1b67"
  },
  {
   "t": "2022-07-26T15:36:10Z",
   "sha": "33d5f039151912bb5e7d5031d3fb349786ed8c40"
  },
  {
   "t": "2022-07-26T17:43:53Z",
   "sha": "3b03b1a6d2ae1096528a3d753cd8965f50ec3c17"
  },
  {
   "t": "2022-07-26T21:19:08Z",
   "sha": "78ddee78b1b95d66b62db88177b220b93d0500f6"
  },
  {
   "t": "2022-07-27T19:27:53Z",
   "sha": "c2dc8a8a747d639acfa4a26db2c61c25b6f82571"
  },
  {
   "t": "2022-08-05T18:47:15Z",
   "sha": "590bc615a3120a8f11712220546f9654058b82f0"
  },
  {
   "t": "2022-08-15T18:14:55Z",
   "sha": "65481de0646f21349f24327410e4d7eb5189e5b3"
  },
  {
   "t": "2022-08-17T19:24:26Z",
   "sha": "9bd10728bada8b04d86f5621ee127713f628a9ad"
  },
  {
   "t": "2022-08-24T18:25:10Z",
   "sha": "10e158a5b57ba3a26e5046a9b42fcc757652f35a"
  },
  {
   "t": "2022-08-25T16:30:27Z",
   "sha": "5aff7baf375c432746dff6862e9d06064ea1fb18"
  },
  {
   "t": "2022-08-30T18:19:54Z",
   "sha": "834857e56b8de0bfabee7315622c0211b4a48746"
  },
  {
   "t": "2022-09-01T15:17:53Z",
   "sha": "82c549aa538a5318fdb56d91117b4c9fc43737de"
  },
  {
   "t": "2022-09-01T20:57:46Z",
   "sha": "c14e904f66505b3e89ca1138c8d2fa4e3d0916d0"
  },
  {
   "t": "2022-09-13T15:07:55Z",
   "sha": "05a97d3208cc365cdeac9de281529568b3cd056c"
  },
  {
   "t": "2022-09-13T15:18:55Z",
   "sha": "e04d8a754ff1b25cab483996319a583e6e3e680a"
  },
  {
   "t": "2022-09-13T19:14:09Z",
   "sha": "52a4e50fb4b1171ee0f6814b0a50bc70cdd77134"
  },
  {
   "t": "2022-09-15T15:25:29Z",
   "sha": "f9accbc6e296adadac374eca085f8b2ce095c8a4"
  },
  {
   "t": "2022-09-15T15:33:53Z",
   "sha": "776d9b3fbb4cf83c81cc38c44cae10d3f3344b1b"
  },
  {
   "t": "2022-09-20T15:52:50Z",
   "sha": "456e3d4eccf010eba30096061b83adc45c371b92"
  },
  {
   "t": "2022-10-14T20:59:22Z",
   "sha": "28a6934da980703006e028776d276ae77121c586"
  },
  {
   "t": "2023-01-06T18:50:37Z",
   "sha": "f4d55d858d9da08612a8ba3b7ceeaf36dfe6cc30"
  },
  {
   "t": "2023-02-10T20:41:46Z",
   "sha": "b57a898a987c63a8dadcb21dd5c94737e86ee107"
  },
  {
   "t": "2023-02-10T22:38:10Z",
   "sha": "eb50fcd6859d1730663159995e8477f6d892e7f4"
  },
  {
   "t": "2023-02-16T18:53:42Z",
   "sha": "501ef88b9412b0d924abf32cf2de7fbcbbb69b8d"
  },
  {
   "t": "2023-03-01T16:05:51Z",
   "sha": "d785176df3e9cccaab9fbbe12d9f8d2c28d3336f"
  },
  {
   "t": "2023-03-16T19:05:19Z",
   "sha": "e766928ed15cf43cda0773b886b7fb8f53b04dd4"
  },
  {
   "t": "2023-04-04T20:31:21Z",
   "sha": "6d7d7bbb7bef40b61cf5862beb8e36e46cdfc455"
  },
  {
   "t": "2023-05-02T19:59:11Z",
   "sha": "28a954c7034077ac3a45083dd5e2b5cdb4d4cdde"
  },
  {
   "t": "2023-07-21T16:43:58Z",
   "sha": "40f09de73e61e7ae62d6639a49b7c7ac48d514d9"
  },
  {
   "t": "2023-07-21T19:59:21Z",
   "sha": "775b54e88107b0b976bf995e607926013fa9bc42"
  },
  {
   "t": "2023-08-01T20:13:58Z",
   "sha": "1de05ef9190202f04f8cbe7746a47cbd66ab540c"
  },
  {
   "t": "2023-08-01T22:28:29Z",
   "sha": "08f5febfc571220043436bbec96a326beebdee22"
  },
  {
   "t": "2023-08-03T20:39:06Z",
   "sha": "b0beb4c504da29c27358d4602a045aaab39305f6"
  },
  {
   "t": "2023-08-04T11:24:47Z",
   "sha": "9e80d0b754a28733c79a52c8e0431616c31d071c"
  },
  {
   "t": "2023-08-07T18:03:24Z",
   "sha": "7f883b33bb89205a9d00c2d20d363a36a0167c7c"
  },
  {
   "t": "2023-09-06T17:58:05Z",
   "sha": "956bec1ecadcfef13e16f1364ae3a7043ff50e48"
  },
  {
   "t": "2023-10-18T19:24:37Z",
   "sha": "29f6cfdabecbdecafc52ccc86425a1c7bb7f5c40"
  },
  {
   "t": "2023-10-26T00:48:05Z",
   "sha": "f158686962e1a229d0382c739b78cd9644aa7ada"
  },
  {
   "t": "2024-01-24T16:52:25Z",
   "sha": "f822ac9a24d684937f1258da89812e99c4b205ba"
  },
  {
   "t": "2024-02-21T19:16:51Z",
   "sha": "4ec6b060a80045049adc53b4db0b0837ba169cfc"
  },
  {
   "t": "2024-02-21T22:55:09Z",
   "sha": "20556598140030237861d21a61f646252002ddff"
  },
  {
   "t": "2024-02-22T11:35:00Z",
   "sha": "cdf7bb17563b92e48b0576a0975c168619c5aa34"
  },
  {
   "t": "2024-03-26T18:44:07Z",
   "sha": "efb463788f8be12bcf2bacfbf99cd2308fb54c9e"
  },
  {
   "t": "2024-03-26T20:30:47Z",
   "sha": "110bccc3715a40d68cb4a09fce9384ee45ac4f58"
  },
  {
   "t": "2024-03-26T21:27:46Z",
   "sha": "6adeafab68a410b663d60045415f1fb8ea7c273a"
  },
  {
   "t": "2024-03-27T03:00:18Z",
   "sha": "d4579e303b014c1522a054bb307cda6e225d45c5"
  },
  {
   "t": "2024-03-28T16:34:08Z",
   "sha": "7a4741eaf892646e9d02e440c39fbbfa03f29fc3"
  },
  {
   "t": "2024-04-18T16:10:24Z",
   "sha": "28e20812109757e307bc29a4adbef8aae90d94a6"
  },
  {
   "t": "2024-04-24T19:55:39Z",
   "sha": "990f9d65c5e15ab26c341c21829a697f5cddfa6c"
  },
  {
   "t": "2024-04-26T00:54:31Z",
   "sha": "55d7de92bbbe035c1833c89f885af14e5b243932"
  },
  {
   "t": "2024-04-26T12:05:08Z",
   "sha": "0c8a1bb1445e8b88bb0ad9d440830ef215e9e8f8"
  },
  {
   "t": "2024-05-01T17:39:44Z",
   "sha": "db91dbb5a9a0413d6ee22ed6e32d1221d5b6d996"
  },
  {
   "t": "2024-06-17T22:57:25Z",
   "sha": "b08548336eda489ad5be9e25542d2b73e7606204"
  },
  {
   "t": "2024-07-09T22:35:06Z",
   "sha": "4eb36d1c41704f947f22d3b52f7799be23e4261c"
  },
  {
   "t": "2024-07-19T14:36:09Z",
   "sha": "15b673d122532d44fea2e6d026172ac90929da14"
  }
 ],
 "additions": 732,
 "deletions": 169,
 "changed_files": 13,
 "commit_count": 7,
 "size_bucket": "L",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "arejula27",
      "url": "https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-3620230189"
     },
     {
      "login": "polespinasa",
      "url": "https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-4418588840"
     }
    ],
    "approach_ack": [
     {
      "login": "hebasto",
      "url": "https://github.com/bitcoin/bitcoin/pull/25665#pullrequestreview-1294756069"
     }
    ],
    "stale_ack": [
     {
      "login": "w0xlt",
      "url": "https://github.com/bitcoin/bitcoin/pull/25665#pullrequestreview-1091053363"
     },
     {
      "login": "stickies-v",
      "url": "https://github.com/bitcoin/bitcoin/pull/25665#pullrequestreview-1099419063"
     },
     {
      "login": "hernanmarino",
      "url": "https://github.com/bitcoin/bitcoin/pull/25665#pullrequestreview-1423032563"
     },
     {
      "login": "jonatack",
      "url": "https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-1668402066"
     },
     {
      "login": "maflcko",
      "url": "https://github.com/bitcoin/bitcoin/pull/25665#pullrequestreview-1602705708"
     },
     {
      "login": "laanwj",
      "url": "https://github.com/bitcoin/bitcoin/pull/25665#pullrequestreview-3369087923"
     },
     {
      "login": "achow101",
      "url": "https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-3453170678"
     },
     {
      "login": "sedited",
      "url": "https://github.com/bitcoin/bitcoin/pull/25665#pullrequestreview-2144994913"
     }
    ]
   },
   "conflicts": [
    {
     "number": 35713,
     "title": "Remove boost as a unit test runner",
     "author": "rustaceanrob"
    },
    {
     "number": 35557,
     "title": "kernel, validation: Add btck_chainstate_manager_set_clock_time",
     "author": "ryanofsky"
    },
    {
     "number": 35187,
     "title": "kernel: Block validation without a complete UTXO set",
     "author": "sedited"
    },
    {
     "number": 34909,
     "title": "wallet, refactor: modularise wallet by extracting out legacy wallet migration",
     "author": "rkrux"
    },
    {
     "number": 34374,
     "title": "kernel: use struct-based logging and simplify logging interface",
     "author": "stickies-v"
    },
    {
     "number": 34132,
     "title": "coins, dbwrapper: remove error catcher, make point-read failures fatal",
     "author": "l0rinc"
    },
    {
     "number": 30342,
     "title": "kernel, logging: Pass Logger instances to kernel objects",
     "author": "ryanofsky"
    },
    {
     "number": 28690,
     "title": "build: Introduce internal kernel library",
     "author": "sedited"
    },
    {
     "number": 26022,
     "title": "Add util::ResultPtr class",
     "author": "ryanofsky"
    },
    {
     "number": 19461,
     "title": "multiprocess: Add bitcoin-gui -ipcconnect option",
     "author": "ryanofsky"
    },
    {
     "number": 19460,
     "title": "multiprocess: Add bitcoin-wallet -ipcconnect option",
     "author": "ryanofsky"
    },
    {
     "number": 10102,
     "title": "Multiprocess bitcoin",
     "author": "ryanofsky"
    }
   ]
  }
 },
 "acks_parsed": {
  "hernanmarino": {
   "kind": "ack",
   "hash": "f822ac9a24d684937f1258da89812e99c4b205ba",
   "t": "2024-02-05T16:41:28Z",
   "stale": true
  },
  "stickies-v": {
   "kind": "ack",
   "hash": "834857e56",
   "t": "2022-08-31T11:33:15Z",
   "stale": true
  },
  "w0xlt": {
   "kind": "ack",
   "hash": null,
   "t": "2022-08-30T22:42:00Z",
   "stale": true
  },
  "hebasto": {
   "kind": "approach_ack",
   "hash": "eb50fcd6859d1730663159995e8477f6d892e7f4",
   "t": "2023-02-12T17:42:51Z",
   "stale": false
  },
  "jonatack": {
   "kind": "ack",
   "hash": "7f883b33bb89205a9d00c2d20d363a36a0167c7c",
   "t": "2023-08-07T18:39:11Z",
   "stale": true
  },
  "sedited": {
   "kind": "ack",
   "hash": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "t": "2025-12-02T20:47:05Z",
   "stale": true
  },
  "achow101": {
   "kind": "ack",
   "hash": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "t": "2025-10-27T20:26:24Z",
   "stale": true
  },
  "arejula27": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2025-12-06T12:55:13Z",
   "stale": false
  },
  "polespinasa": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-05-11T07:53:34Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 6,
  "concept_ack": 2,
  "approach_ack": 1,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 11,
  "changes_requested": 0,
  "distinct_reviewers": [
   "AryanJ-NYC",
   "Riahiamirreza",
   "achow101",
   "arejula27",
   "dongcarl",
   "hebasto",
   "hernanmarino",
   "hodlinator",
   "jonatack",
   "laanwj",
   "maflcko",
   "pablomartin4btc",
   "polespinasa",
   "sedited",
   "sipa",
   "stickies-v",
   "w0xlt"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-09-03T11:32:49Z",
  "last_reviewer_activity": "2026-05-29T06:49:07Z",
  "last_reviewer": "sedited",
  "author_silent_days": 14,
  "waiting_on_author_days": 0,
  "days_since_update": 4
 },
 "refs": {
  "mentioned": [
   24513,
   24531,
   25218,
   25499,
   25667,
   25721,
   25722,
   25977,
   26022,
   26289,
   26661,
   27585,
   27596,
   27877,
   29642,
   29700,
   29906,
   30132,
   30214,
   30255,
   30344,
   30377,
   30595,
   30965,
   31072,
   31483,
   32987,
   34005,
   34006,
   34544,
   34589,
   35182,
   35205,
   35673
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 25722,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "refactor: Use util::Result class for wallet loading"
   },
   {
    "number": 29700,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "kernel, refactor: return error status on all fatal errors"
   },
   {
    "number": 25218,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2022-07-12",
    "title": "refactor: introduce generic 'Result' class and connect it to CreateTransaction and GetNewDestination"
   },
   {
    "number": 34005,
    "type": "pull",
    "state": "closed",
    "merged": false,
    "merged_at": null,
    "title": "util: generalize `util::Result` to support custom errors"
   },
   {
    "number": 34006,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2025-12-09",
    "title": "Add util::Expected (std::expected)"
   },
   {
    "number": 26022,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "Add util::ResultPtr class"
   },
   {
    "number": 24513,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2022-09-13",
    "title": "CChainState -> Chainstate"
   },
   {
    "number": 24531,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2022-06-02",
    "title": "Use designated initializers"
   },
   {
    "number": 25499,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2022-09-16",
    "title": "Use steady clock for all millis bench logging"
   },
   {
    "number": 25667,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2022-10-13",
    "title": "assumeutxo: snapshot initialization"
   },
   {
    "number": 25721,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2022-08-05",
    "title": "refactor: Replace BResult with util::Result"
   },
   {
    "number": 25977,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2023-05-26",
    "title": "refactor: Replace `std::optional<bilingual_str>` with `util::Result`"
   },
   {
    "number": 26289,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2023-01-03",
    "title": "Use util::Result in for calculating mempool ancestors"
   },
   {
    "number": 26661,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2023-01-03",
    "title": "wallet: Coin Selection, return accurate error messages"
   },
   {
    "number": 27585,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2023-08-24",
    "title": "fuzz: improve `coinselection`"
   },
   {
    "number": 27596,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2023-10-02",
    "title": "assumeutxo (2)"
   },
   {
    "number": 27877,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2024-02-09",
    "title": "wallet: Add CoinGrinder coin selection algorithm"
   },
   {
    "number": 29642,
    "type": "pull",
    "state": "closed",
    "merged": false,
    "merged_at": null,
    "title": "kernel: Handle fatal errors through return values"
   },
   {
    "number": 29906,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2024-04-30",
    "title": "Disable util::Result copying and assignment"
   },
   {
    "number": 30132,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2024-06-10",
    "title": "indexes: Don't wipe indexes again when continuing a prior reindex"
   },
   {
    "number": 30214,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2025-12-16",
    "title": "refactor: Improve assumeutxo state representation"
   },
   {
    "number": 30255,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2024-06-14",
    "title": "log: use error level for critical log messages"
   },
   {
    "number": 30344,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2024-07-02",
    "title": "kernel: remove mempool_persist"
   },
   {
    "number": 30377,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2024-08-31",
    "title": "refactor: Replace ParseHex with consteval \\\"\\\"_hex literals"
   },
   {
    "number": 30595,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2025-11-04",
    "title": "kernel: Introduce C header API"
   },
   {
    "number": 30965,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2025-01-31",
    "title": "kernel: Move block tree db open to block manager"
   },
   {
    "number": 31072,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2024-12-06",
    "title": "refactor: Clean up messy strformat and bilingual_str usages"
   },
   {
    "number": 31483,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2025-01-16",
    "title": "kernel: Move kernel-related cache constants to kernel cache"
   },
   {
    "number": 32987,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2025-07-30",
    "title": "init: [gui] Avoid UB/crash in InitAndLoadChainstate"
   },
   {
    "number": 34544,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-05-02",
    "title": "wallet: Disallow wallet names that are paths including `..` and `.` elements"
   },
   {
    "number": 34589,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-03-23",
    "title": "ci: Temporarily use clang in valgrind tasks"
   },
   {
    "number": 35182,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-06-22",
    "title": "Replace libevent with our own HTTP and socket-handling implementation"
   },
   {
    "number": 35205,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-08-04",
    "title": "kernel,node: add `dbcache` setter and clarify defaults"
   },
   {
    "number": 35673,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-07-08",
    "title": "refactor: Move LoadGenesisBlock to ChainstateManager"
   }
  ],
  "conflicts": [
   35713,
   35557,
   35187,
   34909,
   34374,
   34132,
   30342,
   28690,
   26022,
   19461,
   19460,
   10102
  ]
 },
 "stack": {
  "shares_commits_with": [
   29700
  ],
  "based_on": [],
  "base_for": [
   29700
  ]
 },
 "review_paths": [
  "ci/test/00_setup_env_native_fuzz_with_valgrind.sh",
  "src/bench/wallet_loading.cpp",
  "src/node/chainstate.cpp",
  "src/node/chainstate.h",
  "src/test/result_tests.cpp",
  "src/util/result.cpp",
  "src/util/result.h",
  "src/wallet/wallet.cpp"
 ],
 "body": "Add `util::Result` support for returning more error information and make use of it in [LoadChainstate method](https://github.com/bitcoin/bitcoin/pull/25665/commits/8a4be9e25490388f68404eae45aef1298001abfa) as an initial application. Followup PRs [#25722](https://github.com/bitcoin/bitcoin/pull/25722) and [#29700](https://github.com/bitcoin/bitcoin/pull/29700) use it more broadly to return errors and warnings from wallet and kernel functions as well.\n\nThis change adds two major features to the result class:\n\n- For better error handling, adds the ability to return a value on failure, not just a value on success. This is a key missing feature that makes the result class not useful for functions like `LoadChainstate()` which produce different errors that need to be handled differently [^1].\n\n[^1]: Ability to return error values was actually present in the original implementation of [#25218](https://github.com/bitcoin/bitcoin/pull/25218), but unfortunately removed in later iterations. See [design notes](https://github.com/bitcoin-core/bitcoin-devwiki/wiki/util::Result-design-notes).\n\n- For better error reporting, adds the ability to return warning messages and multiple errors, not just a single error string. This provides a way for functions to report errors and warnings in a standard way, and simplifies interfaces:\n\n    ```diff\n    -virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;\n    +virtual util::Result<std::unique_ptr<Wallet>> loadWallet(const std::string& name) = 0;\n    ```\n\n    ```diff\n    -std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);\n    +util::Result<std::unique_ptr<WalletDatabase>, DatabaseError> MakeDatabase(const fs::path& path, const DatabaseOptions& options);\n   ```\n\nThis change also makes some more minor improvements:\n\n- Smaller type size. `util::Result<int>` is 16 bytes, and `util::Result<void>` is 8 bytes. Previously both were 72 bytes.\n\n- Broader type compatibility. Supports noncopyable and nonmovable success and error types.\n\n### Comparison with `std::expected`\n\nCurrently, the `util::Result` class is useful for error reporting\u2014returning translated, user-facing error strings\u2014but not as useful for error handling, where callers need structured failure information to decide how to proceed. By contrast, `std::expected` / `util::Expected` (#34005, #34006) is good for error handling but less helpful for reporting. This PR closes the gap between the two classes.\n\nWith this PR, `std::expected` remains a good choice for lower-level functions or simple functions that fail in only a few well-defined ways. Meanwhile,\n\n- `Result` becomes a better choice for operations that can fail in many different ways\u2014loading a wallet, connecting a block, etc.\u2014where callers may want complete error traces, not just low-level errors without context or high-level errors without detail. (Followup [#25722](https://github.com/bitcoin/bitcoin/pull/25722) applies this to wallet-loading functions.)\n- `Result` can also be more useful than `expected` when merging status information from multiple calls. (Followup [#29700](https://github.com/bitcoin/bitcoin/pull/29700) uses this to reliably propagate flush and fatal-error status from validation code that can internally trigger flushes or shutdowns.)\n- `Result` may also be a better choice than `std::expected` when returning pointer values. (Followup [#26022](https://github.com/bitcoin/bitcoin/pull/26022) adds a `ResultPtr` specialization that avoids double dereferencing.)\n- `Result` can be more efficient than `std::expected` when failures are rare but failure objects are large, since failure values are heap-allocated.\n\nThis PR effectively makes `Result` a superset of `expected`, making the representations compatible and allowing them to be used together.",
 "commits": [
  {
   "sha": "f1e827bc2058f97daa82a7f9b4dbebac1584ba3b",
   "date": "2026-09-03T11:32:49Z",
   "message": "refactor: Add util::Result failure values\n\nAdd util::Result support for returning more error information. For better error\nhandling, adds the ability to return a value on failure, not just a value on\nsuccess. This is a key missing feature that made the result class not useful\nfor functions like LoadChainstate() which produce different errors that need to\nbe handled differently.\n\nThis change also makes some more minor improvements:\n\n- Smaller type size. On 64-bit platforms, util::Result<int> is 16 bytes, and\n  util::Result<void> is 8 bytes. Previously util::Result<int> and\n  util::Result<void> were 72 bytes.\n\n- More documentation and tests."
  },
  {
   "sha": "2a59241faf280a80b9a0f22fe56cf773b1549410",
   "date": "2026-09-03T11:32:49Z",
   "message": "wallet: fix clang-tidy warning performance-no-automatic-move\n\nPrevious commit causes the warning to be triggered, but the suboptimal return\nfrom const statement was added earlier in 517e204bacd9d.\n\nWarning was causing CI failure https://cirrus-ci.com/task/6159914970644480"
  },
  {
   "sha": "335a6af84ef0e656e49016c6b87c70e58f75a131",
   "date": "2026-09-03T11:32:49Z",
   "message": "refactor: Add util::Result::Update() method\n\nAdd util::Result Update method to make it possible to change the value of an\nexisting Result object. This will be useful for functions that can return\nmultiple error and warning messages, and want to be able to change the result\nvalue while keeping existing messages."
  },
  {
   "sha": "f3d9b8993ab36d8bc199730ade447a63e8435d0a",
   "date": "2026-09-03T11:32:49Z",
   "message": "refactor: Use util::Result class in LoadChainstate and VerifyLoadedChainstate"
  },
  {
   "sha": "b7640ff7db2f97f5102a409bfce46628e3b9c6e9",
   "date": "2026-09-03T11:32:49Z",
   "message": "refactor: Add util::Result multiple error and warning messages\n\nAdd util::Result support for returning warning messages and multiple errors,\nnot just a single error string. This provides a way for functions to report\nerrors and warnings in a standard way, and simplifies interfaces.\n\nThe functionality is unit tested here, and put to use in followup PR\nhttps://github.com/bitcoin/bitcoin/pull/25722"
  },
  {
   "sha": "fdeb223231ecd2031beed368365037fdb31c0871",
   "date": "2026-09-03T11:32:49Z",
   "message": "test: add static test for util::Result memory usage\n\nSuggested by Martin Leitner-Ankerl <martin.ankerl@gmail.com>\nhttps://github.com/bitcoin/bitcoin/pull/25722#discussion_r1174298529\n\nCo-authored-by: Martin Leitner-Ankerl <martin.ankerl@gmail.com>"
  },
  {
   "sha": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "date": "2026-09-03T11:32:49Z",
   "message": "ci: Avoid -Wno-error=maybe-uninitialized false positives\n\nAvoid false positive maybe-uninitialized errors in native_previous_releases\nCI job.\n\nFix was suggested by maflcko in\nhttps://github.com/bitcoin/bitcoin/pull/25665#issuecomment-3457573218\n\nCI errors look like:\nhttps://github.com/bitcoin/bitcoin/actions/runs/25426711469/job/74581986567?pr=25665\n\n/home/admin/actions-runner/_work/_temp/src/wallet/test/util.cpp: In function \u2018wallet::DescriptorScriptPubKeyMan* wallet::CreateDescriptor(CWallet&, const std::string&, bool)\u2019:\n/home/admin/actions-runner/_work/_temp/src/wallet/test/util.cpp:143:10: error: \u2018*(const std::reference_wrapper<wallet::DescriptorScriptPubKeyMan>*)((char*)&spkm + offsetof(util::Result<std::reference_wrapper<wallet::DescriptorScriptPubKeyMan>, void, util::Messages>,util::Result<std::reference_wrapper<wallet::DescriptorScriptPubKeyMan>, void, util::Messages>::<unnamed>.util::detail::SuccessHolder<std::reference_wrapper<wallet::DescriptorScriptPubKeyMan>, void, util::Messages>::<unnamed>)).std::reference_wrapper<wallet::DescriptorScriptPubKeyMan>::_M_data\u2019 may be used uninitialized [-Werror=maybe-uninitialized]\n  143 |     auto spkm = Assert(keystore.AddWalletDescriptor(w_desc, keys,/*label=*/\"\", /*internal=*/false));\n      |          ^~~~\ncc1plus: all warnings being treated as errors"
  }
 ],
 "timeline": [
  {
   "t": "2022-07-21T13:05:47Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/bench/wallet_loading.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "This pull changes both the interface, as well as the internal representation. I wonder if changing the interface and renames can be done separate from the restructuring.\n\nHopefully those would be uncontroversial and could be reviewed easier/faster, so that less silent merge conflicts arise as the class gets used more and more. Also, less code will need to be changes if the interface changes are made earlier rather than later."
  },
  {
   "t": "2022-07-21T13:12:19Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/bench/wallet_loading.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 926651294,
   "text": "[quoted text omitted]\n\nOnly the third commit drops BResult usages, so the answer should be yes. IMO std::optional has a nice interface and it is a shame to reinvent it with stranger HasRes GetObj ReleaseObj methods."
  },
  {
   "t": "2022-07-21T13:14:54Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/bench/wallet_loading.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 926651294,
   "text": "With separate I meant separate pulls :sweat_smile:"
  },
  {
   "t": "2022-07-21T13:18:25Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Draft PR since I want to add a commit taking advantages of ability to return chain results and return warnings."
  },
  {
   "t": "2022-07-21T13:20:49Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/bench/wallet_loading.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 926651294,
   "text": "[quoted text omitted]\n\nOh sorry, I thought you were asking literally if it is possible"
  },
  {
   "t": "2022-07-21T17:02:18Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "6e84015ea56b4ff9743466bb9880db2b58a533b7"
  },
  {
   "t": "2022-07-21T18:49:07Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "9ba210bf6e9ba259caf499a649c2954240cbfa40"
  },
  {
   "t": "2022-07-21T19:43:35Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "10e78ee295e2069620ea3f5a9286fe4a1a7f2f70"
  },
  {
   "t": "2022-07-22T10:43:15Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "358e0fe5f205048333a728df3a67041c1b2e5bd1"
  },
  {
   "t": "2022-07-22T13:23:40Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/bench/wallet_loading.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 926651294,
   "text": "I think the stuff that can be split out:\n\n* Makes Result class provide same operators and methods as std::optional\n* Puts src/util/ code in the util:: namespace so naming reflects code organization and it is obvious where the class is coming from. Drops \"B\" from name because it is undocumented what it stands for (bilingual?)\n* Supports Result<bilingual_str> return values. Drops ambiguous and potentially misleading BResult constructor that treats any bilingual string as an error, and any other type as a non-error. Adds util::Error constructor so errors have to be explicitly constructed and not any bilingual_str will be turned into one."
  },
  {
   "t": "2022-07-22T14:22:33Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/bench/wallet_loading.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 926651294,
   "text": "I think these things are already split out. The first two commits do not change the interface or naming or functionality of BResult in any way. If you want me to move the last commit to another, PR I can do that."
  },
  {
   "t": "2022-07-22T14:27:20Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/bench/wallet_loading.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 926651294,
   "text": "Yeah, I think that makes sense, so that we can first figure out the interface, and then start using it more widely, not the other way round."
  },
  {
   "t": "2022-07-25T22:22:28Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "32dd8ebbb33b27b717d656c7c8c1de24a40a1b67"
  },
  {
   "t": "2022-07-26T15:36:10Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "33d5f039151912bb5e7d5031d3fb349786ed8c40"
  },
  {
   "t": "2022-07-26T17:43:53Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "3b03b1a6d2ae1096528a3d753cd8965f50ec3c17"
  },
  {
   "t": "2022-07-26T21:19:08Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "78ddee78b1b95d66b62db88177b220b93d0500f6"
  },
  {
   "t": "2022-07-26T21:58:03Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/bench/wallet_loading.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 926651294,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r927707935\n\n[quoted text omitted]\nThanks, moved to #25721 now and rewrote PR description"
  },
  {
   "t": "2022-07-27T19:27:53Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "c2dc8a8a747d639acfa4a26db2c61c25b6f82571"
  },
  {
   "t": "2022-07-27T19:32:29Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Moved out of draft, since result interface is more complete now and there's more code using it"
  },
  {
   "t": "2022-07-27T19:44:30Z",
   "kind": "comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "text": "As said on the previous pull, I'd prefer if the order of the changes was inversed: First, change the existing interface methods and names, then change the internal class implementation. Otherwise we'll end up with the odd state of two classes that do the same thing but have a different name and people will continue to add more used of the \"deprecated\" class. I'd also find it easier to review an incremental diff than having a full separate implementation. But no strong opinion, if you and the other reviewers prefer it as-is now.\n\nEdit: My comment was https://github.com/bitcoin/bitcoin/pull/25665#discussion_r927707935 and I just realized that it was ambiguous and could be interpreted the opposite of what I meant."
  },
  {
   "t": "2022-07-27T20:13:40Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Thanks, Marco! I will just tweak #25721 to be a standalone PR instead of depending on this PR"
  },
  {
   "t": "2022-07-27T21:39:43Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThis is done now"
  },
  {
   "t": "2022-08-05T18:47:15Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "590bc615a3120a8f11712220546f9654058b82f0"
  },
  {
   "t": "2022-08-05T18:48:33Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Rebased c2dc8a8a747d639acfa4a26db2c61c25b6f82571 -> 590bc615a3120a8f11712220546f9654058b82f0 ([`pr/bresult2.10`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.10) -> [`pr/bresult2.11`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.11), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.10-rebase..pr/bresult2.11)) due to conflicts with #25721"
  },
  {
   "t": "2022-08-11T18:12:09Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit:\n```suggestion\n    bilingual_str result{ErrorString(errors)};\n```"
  },
  {
   "t": "2022-08-11T18:33:11Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "I'm not sure why iwyu [doesn't](https://cirrus-ci.com/task/6358959639494656) catch it, but shouldn't `forward`, `types` and `utility` also be included here?"
  },
  {
   "t": "2022-08-12T11:18:55Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "Could probably make sense to split this up and use it there: https://github.com/bitcoin/bitcoin/pull/25616#discussion_r942704207"
  },
  {
   "t": "2022-08-13T16:42:21Z",
   "kind": "review_comment",
   "who": "Riahiamirreza",
   "assoc": "CONTRIBUTOR",
   "path": "src/util/result.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": null,
   "text": "What is the difference between when the `this->m_info` is `true` and when it is `false`? While as far as I understand in both cases the `this->m_info` is destroyed and replaced by `other.m_info`.  Am I correct? So why bother to check `other.m_info && !this->m_info` and  `other.m_info && this->m_info`?"
  },
  {
   "t": "2022-08-13T20:02:49Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 945167440,
   "text": "[quoted text omitted]\n\nThe implementation is optimized for the \"happy path\" where a success value is set and there is no failure value and no error or warning message strings. In the happy path case, `m_info` is null and no allocation is needed. Otherwise, if there has been any kind of error or warning `m_info` will be non-null.\n\n[quoted text omitted]\nNo that's not really correct. As the comment \"Operator moving warning and error messages from one result to another\" says, only warning and error strings are moved from `other` to `*this`. The success and value statuses of `other` and `*this` objects are unchanged, and the success and failure values of both objects (if any) are also unchanged. Existing warning and error strings in `*this` are also not affected, the new errors and warnings just get appended and don't replace existing one.\n\n[quoted text omitted]\nI'm not sure what other code you might expect to see here, but in both cases this is just moving `other.m_info->errors` strings to `this->m_info->errors` and moving `other.m_info->warnings` strings to `this->m_info->warnings` while not deleting any existing strings and not changing `other.m_info->failure` and `this->m_info->failure` values."
  },
  {
   "t": "2022-08-15T08:39:35Z",
   "kind": "review_comment",
   "who": "Riahiamirreza",
   "assoc": "CONTRIBUTOR",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "I don't understand why the `m_value` is in a `union` while there is only one member in the `union`? Would you explain why?"
  },
  {
   "t": "2022-08-15T08:49:22Z",
   "kind": "review_comment",
   "who": "Riahiamirreza",
   "assoc": "CONTRIBUTOR",
   "path": "src/util/result.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 945167440,
   "text": "Thanks for your explanation. My wrong assumption was that by replacing the warnings and errors the `this` is completely like the `other`, so why checking whether `this->m_info` is null or not.\nBut as you mentioned the success and value statuses remained unchanged."
  },
  {
   "t": "2022-08-15T12:47:28Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 945529940,
   "text": "[quoted text omitted]\n\nI'll add a code comment, but using a union avoids `m_value` getting constructor and destructor being called automatically, so in the failure case `m_value` is never constructed."
  },
  {
   "t": "2022-08-15T13:07:36Z",
   "kind": "review",
   "who": "Riahiamirreza",
   "assoc": "CONTRIBUTOR",
   "state": "APPROVED",
   "commit": "590bc615a3120a8f11712220546f9654058b82f0",
   "text": ""
  },
  {
   "t": "2022-08-15T15:31:51Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 944367210,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r944367210\n\n[quoted text omitted]\nIs the suggestion to add the GetErrors() method in this PR, but delay adding the GetWarnings() method until followup PR  #25722? I could do that, but I don't think it would simplify this PR very much (it would remove a few lines) and it would add more churn to result implementation/documentation/unit tests review"
  },
  {
   "t": "2022-08-15T15:34:24Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 944367210,
   "text": "No, I was wondering if `GetWarnings` could be added by itself in the other pull, maybe conflicting with this one, but otherwise unrelated from this one."
  },
  {
   "t": "2022-08-15T15:35:48Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 944367210,
   "text": "This would allow reviewers to just look at the `GetWarnings` implementation, API, and proposed usage, without having to think about `union/void/...` etc."
  },
  {
   "t": "2022-08-15T16:41:01Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 944367210,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r945881360\n\n[quoted text omitted]\nOh. I guess there could be a third PR independent of this PR and #25722 that adds a `std::vector<bilingual_str> m_warnings;` field to `util::Result` and `AddWarning()/GetWarnings()` methods. I don't think it would be as useful as you might be thinking without template constructors that can move errors & warnings from one result object to another, though.\n\nMaybe if you are interested you could open a PR that does this? I'd be happy to review it. I'm just not sure exactly what you want to do here because the goal of #25722 is a lot broader. Not just dropping `std::vector<bilingual_str>& warnings` output arguments but also dropping `DatabaseStatus& status` output arguments and returning errors and warnings directly from nested calls."
  },
  {
   "t": "2022-08-15T18:14:55Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "65481de0646f21349f24327410e4d7eb5189e5b3"
  },
  {
   "t": "2022-08-15T18:16:04Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Updated 590bc615a3120a8f11712220546f9654058b82f0 -> 65481de0646f21349f24327410e4d7eb5189e5b3 ([`pr/bresult2.11`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.11) -> [`pr/bresult2.12`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.12), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.11..pr/bresult2.12)) just adding some comments to answer review questions"
  },
  {
   "t": "2022-08-16T18:08:37Z",
   "kind": "review_comment",
   "who": "dongcarl",
   "assoc": "CONTRIBUTOR",
   "path": "src/node/chainstate.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "Perhaps could take the opportunity to make this something like:\n\n```suggestion\nenum class ChainstateLoadError { FAILURE_TRY_REINDEX, FAILURE_FATAL, INTERRUPTED };\n```\n\nSo that it's more inline with indicating \"what to do about the failure\".\n\nCould also move the \"4 types of outcomes\" comment up here where it's clearer."
  },
  {
   "t": "2022-08-17T15:10:04Z",
   "kind": "review_comment",
   "who": "AryanJ-NYC",
   "assoc": "NONE",
   "path": "src/node/chainstate.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "This comment is no longer true."
  },
  {
   "t": "2022-08-17T17:21:13Z",
   "kind": "review_comment",
   "who": "sipa",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "Would it be sufficient to use `explicit operator bool() const` instead here? That would avoid e.g. \"(result + 3)\" from compiling (and evaluating to 3 or 4)."
  },
  {
   "t": "2022-08-17T17:59:50Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 948068576,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r948068576\n\n[quoted text omitted]\nThanks, removed"
  },
  {
   "t": "2022-08-17T18:00:42Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 948230244,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r948230244\n\n[quoted text omitted]\nGood catch, added explicit. This was an unintended regression (operator bool was explicit before this PR)"
  },
  {
   "t": "2022-08-17T18:22:16Z",
   "kind": "review_comment",
   "who": "hernanmarino",
   "assoc": "CONTRIBUTOR",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 948230244,
   "text": "+1 to @sipa 's comment."
  },
  {
   "t": "2022-08-17T18:31:20Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 947098272,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r947098272\n\n[quoted text omitted]\nI agree it's good to suggest how failures can be handled, so I tried to do that in the comment. But I think if failure has a clear cause it's best for the error name to describe the cause, especially since not every application will want to handle errors the same way, and `bitcoin-qt`, `bitcoind`, and `bitcoin-chainstate` all handle errors differently.\n\nI'm also don't think `FAILURE_TRY_REINDEX` is an appropriate synonym for `FAILURE`, since generic failures can happen on any exception, even if reindexing was already requested. Trying to reindex when reindexing fails does not make a lot of sense. I'd be happy to rename `FAILURE` to `FAILURE_GENERIC`. But would probably do it in a separate PR to not complicate this one.\n\n[quoted text omitted]\nThanks for pointing it out. I think that comment actually does not add much information anymore, and is a little confusing because it is mentioning shutdowns when the `check_interrupt` callback and `INTERRUPTED` error could indicate any custom interruption, not just a shutdown.\n\nI can add more documentation if you think anything is missing, but I think a simple message of \"It is fine to treat any error code as a failure and ignore the specific cause\" is the most helpful takeaway. Setting interrupt callbacks and trying to reindex are optional enhancements mostly helpful for interactive applications."
  },
  {
   "t": "2022-08-17T19:24:26Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "9bd10728bada8b04d86f5621ee127713f628a9ad"
  },
  {
   "t": "2022-08-17T19:26:55Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "9bd10728bada8b04d86f5621ee127713f628a9ad",
   "text": "Updated 65481de0646f21349f24327410e4d7eb5189e5b3 -> 9bd10728bada8b04d86f5621ee127713f628a9ad ([`pr/bresult2.12`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.12) -> [`pr/bresult2.13`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.13), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.12..pr/bresult2.13)) with suggestions"
  },
  {
   "t": "2022-08-18T04:38:22Z",
   "kind": "review",
   "who": "hernanmarino",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "9bd10728bada8b04d86f5621ee127713f628a9ad",
   "text": "Tested ACK and Code review ACK. I got a few warnings while compiling though (missing-field-initializers)"
  },
  {
   "t": "2022-08-18T14:18:21Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThanks for testing! @hernanmarino could you post the warnings, and maybe post your compiler version? I don't think I'm seeing these and I don't think they are happening on CI because those builds treat warnings as errors. I'd like to fix this if possible."
  },
  {
   "t": "2022-08-19T13:53:02Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "Do we want to expose these 2 helper methods in the header?"
  },
  {
   "t": "2022-08-19T13:54:55Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "What about renaming this function to `ErrorWarningString()` since at the moment it can contain both? I can see some scenario where people would want to access just the error but not the warning string (and of course it's just a convenience fn), so that would allow them to create the more narrow `ErrorString()` later on?\n\nPerhaps a brief docstring above this fn would be beneficial as well since that's the one people will mostly use."
  },
  {
   "t": "2022-08-19T14:02:58Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit: I think this docstring is more relevant for `m_info`, perhaps move it to above its declaration in `ResultBase`?"
  },
  {
   "t": "2022-08-19T14:07:37Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit: You could add a bit more info on T, F for quick understanding?\n```suggestion\n//! Result base class which is inherited by Result<T, F>.\n//! T is the type of the success return value, or void if there is none.\n//! F is the type of the failure return value, or void if there is none.\n```"
  },
  {
   "t": "2022-08-19T14:30:07Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "This is repeated a few times, what do you think about this:\n\n```diff\ndiff --git a/src/util/result.h b/src/util/result.h\nindex 60e0b3db6..c6aa65891 100644\n--- a/src/util/result.h\n+++ b/src/util/result.h\n@@ -56,17 +56,19 @@ public:\n     void AddError(bilingual_str error)\n     {\n         if (error.empty()) return;\n-        if (!m_info) m_info = std::make_unique<ErrorInfo<F>>();\n+        CheckInitInfo();\n         m_info->errors.emplace_back(std::move(error));\n     }\n\n     void AddWarning(bilingual_str warning)\n     {\n         if (warning.empty()) return;\n-        if (!m_info) m_info = std::make_unique<ErrorInfo<F>>();\n+        CheckInitInfo();\n         m_info->warnings.emplace_back(std::move(warning));\n     }\n\n+    void CheckInitInfo() { if (!m_info) m_info = std::make_unique<ErrorInfo<F>>(); }\n+\n     //! Success check.\n     explicit operator bool() const { return !m_info || !m_info->failure; }\n\n@@ -159,7 +161,7 @@ protected:\n     {\n         this->AddError(std::move(error.message));\n         Construct([&](auto&&... x) {\n-            if (!this->m_info) this->m_info = std::make_unique<detail::ErrorInfo<F>>();\n+            this->CheckInitInfo();\n             this->m_info->failure.emplace(std::forward<decltype(x)>(x)...);\n         }, std::forward<Args>(args)...);\n     }\n\n```"
  },
  {
   "t": "2022-08-19T14:36:53Z",
   "kind": "comment",
   "who": "hernanmarino",
   "assoc": "CONTRIBUTOR",
   "text": "[quoted text omitted]\n\nYes, this is one of them (there are a few more , all similar)\n\n```\n In file included from ./interfaces/wallet.h:15,\n                 from wallet/interfaces.cpp:5:\n./util/result.h: In instantiation of \u2018util::Result<OT, OF>&& util::Result<T, F>::operator<<(util::Result<OT, OF>&&) [with OT = std::unique_ptr<interfaces::Wallet>; OF = void; T = std::unique_ptr<interfaces::Wallet>; F = void]\u2019:\n\n./util/result.h:187:15:   required from \u2018void util::Result<T, F>::MoveConstruct(util::Result<OT, OF>&) [with OT = std::unique_ptr<interfaces::Wallet>; OF = void; T = std::unique_ptr<interfaces::Wallet>; F = void]\u2019\n\n./util/result.h:202:51:   required from \u2018util::Result<T, F>::Result(util::Result<OT, OF>&&) [with OT = std::unique_ptr<interfaces::Wallet>; OF = void; T = std::unique_ptr<interfaces::Wallet>; F = void]\u2019\n\nwallet/interfaces.cpp:580:16:   required from here\n\n./util/result.h:218:32: warning: missing initializer for member \u2018util::detail::ErrorInfo<void>::failure\u2019 [-Wmissing-field-initializers]\n  218 |             this->m_info.reset(new detail::ErrorInfo<F>{.errors = std::move(other.m_info->errors),\n      |                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n  219 |                                                         .warnings = std::move(other.m_info->warnings)});\n      |                                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n```\n\nI'm using  gcc  11.2.0 . If you need them all, just let me know"
  },
  {
   "t": "2022-08-19T14:53:26Z",
   "kind": "comment",
   "who": "pablomartin4btc",
   "assoc": "MEMBER",
   "text": "@ryanofsky, @hernanmarino I also get those warnings.\n\nMy version of g++ is 9.4.0; please let me know if you need any other details."
  },
  {
   "t": "2022-08-19T15:05:22Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "As part of the public interface, I think these could benefit from a very brief per-method docstring (that probably just mirrors the std::optional docstring)?"
  },
  {
   "t": "2022-08-19T15:24:59Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit: slightly more concise and clear on intent imo\n```suggestion\n    bool has_value() const { return bool(*this); }\n```"
  },
  {
   "t": "2022-08-19T15:43:55Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": null,
   "text": "I think it would be helpful to also test success with a falsy non-void value and failure with a truthy non-void value"
  },
  {
   "t": "2022-08-19T15:50:56Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "I think this line is redundant since we already call `this->AddError()` right above?"
  },
  {
   "t": "2022-08-19T15:54:14Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit: I think this should be on a new line"
  },
  {
   "t": "2022-08-19T16:18:57Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit: ternary looks more appropriate?\n```suggestion\n        *this ? this->DestroyValue() : this->m_info->failure.reset();\n```"
  },
  {
   "t": "2022-08-19T16:23:58Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit:\n```suggestion\n    //! Operator moving warning and error messages from other Result to this.\n```"
  },
  {
   "t": "2022-08-19T16:42:35Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "Since `ErrorInfo` doesn't have a move constructor, do the move semantics make sense here? _(I'm still easily confused by move semantics, so I'm probably missing something - sorry)_"
  },
  {
   "t": "2022-08-19T16:58:43Z",
   "kind": "review_comment",
   "who": "hernanmarino",
   "assoc": "CONTRIBUTOR",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "@ryanofsky the following change fixes the warnings for me, but i don't know if this is the best way to deal with this\n\n```suggestion\n    std::optional<std::conditional_t<std::is_same<F, void>::value, std::monostate, F>> failure = std::nullopt;\n```"
  },
  {
   "t": "2022-08-19T17:05:32Z",
   "kind": "review",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "9bd10728bada8b04d86f5621ee127713f628a9ad",
   "text": "Concept ACK 9bd10728bada8b04d86f5621ee127713f628a9ad\n\nI'm not getting any compilation warnings:\n```sh\ng++ --version\nApple clang version 13.1.6 (clang-1316.0.21.2.5)\nTarget: arm64-apple-darwin21.5.0\n```\n\nIt's a beautiful implementation and I've learned a lot while reviewing this. That's both a compliment and a warning that my review shouldn't weigh heavily, even if I'm doing it as thoroughly as I can. My main concern is that for everyone not already intimately familiar with C++, I think this takes a _long_ time to review thoroughly. The genericness made it difficult to reason about for me. I haven't come up with a simpler alternative so I don't think I'll want that to stand in the way of anything, though. Just something to be mindful of."
  },
  {
   "t": "2022-08-22T20:37:18Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 950331132,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950331132\n\n[quoted text omitted]\nMakes sense, added tests"
  },
  {
   "t": "2022-08-22T20:37:26Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 943789301,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r943789301\n\n[quoted text omitted]\nThanks, used suggestion."
  },
  {
   "t": "2022-08-22T20:37:34Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 943807162,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r943807162\n\n[quoted text omitted]\nThanks, added `utility`. (I think the others are nonstandard.) IWYU might not catch references to code in templates that aren't instantiated, so I'm not too surprised it didn't add this."
  },
  {
   "t": "2022-08-22T20:37:42Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r943776125\n\n[quoted text omitted]\nIt would be ok to move this somewhere, especially if something else was calling it. But I don't think span.h would be the right place since this shouldn't work on a span due to spans having fixed size. It also seems ok to me to keep this as a private helper function in a detail namespace as long as it is only called one place."
  },
  {
   "t": "2022-08-22T20:37:50Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950223870,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950223870\n\n[quoted text omitted]\nI think it's relevant here because the struct is pretty big thing to have in a return type, so good to say it won't typically be needed.\n\nAlso, this may be a stylistic thing, but I tend to prefer class-level documentation that gets at _why/how_ questions, over member level documentation only answers more basic _what_ questions, and can also clutter the class definition."
  },
  {
   "t": "2022-08-22T20:38:00Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950228362,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950228362\n\n[quoted text omitted]\nAdded. Nice suggestion!"
  },
  {
   "t": "2022-08-22T20:38:14Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950253178,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950253178\n\n[quoted text omitted]\nNice catch! I implemented something similar to what you suggested to dedup"
  },
  {
   "t": "2022-08-22T20:38:34Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950310915,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950310915\n\n[quoted text omitted]\nOk! I would have defaulted to that but had seen some feedback `bool()` was not good https://github.com/bitcoin/bitcoin/pull/25616#discussion_r940933709, https://github.com/bitcoin/bitcoin/pull/25721#discussion_r938763403 so was trying to avoid it. Switched to `bool{}` for now."
  },
  {
   "t": "2022-08-22T20:38:55Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950293020,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950293020\n\n[quoted text omitted]\nI'm a little reluctant to change this code here because it is just moving (not new), but would encourage you to submit a separate PR to add more documentation to existing code if it would be helpful. I'm happy to rebase this as other PR are merged.\n\nI do personally tend not to like documenting individual class members if it's obvious what they do, and save comments for when there is something non-obvious or higher level to point out, but I wouldn't have any objection to more detailed documentation."
  },
  {
   "t": "2022-08-22T20:39:12Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950338812,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950338812\n\n[quoted text omitted]\nI think it was needed to avoid a segfault if the error message was empty, but in any case this line is gone now from implementing your earlier suggestion to dedup this."
  },
  {
   "t": "2022-08-22T20:56:19Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950398142,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950398142\n\n[quoted text omitted]\nThanks! I think it might be sufficient to replace `= std::nullopt` with `{}`, so I will try that first."
  },
  {
   "t": "2022-08-23T19:59:10Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950214121,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r943807162\n\n[quoted text omitted]\nNope, good point. Moved these to the details namespace."
  },
  {
   "t": "2022-08-23T19:59:34Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950215859,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950215859\n\n[quoted text omitted]\nAdded some more documentation about how this should be used. I think a function that just puts errors not warnings in a result message could be a potential footgun, because warnings could be unintentionally dropped if errors and warnings are returned together. For example if code initially doesn't generate any warnings, then someone adds one not realizing it won't show up anywhere."
  },
  {
   "t": "2022-08-23T20:02:34Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950342467,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950342467\n\n[quoted text omitted]\nI dropped the `else if` here since it was redundant, but I think I do prefer the compact style with one line"
  },
  {
   "t": "2022-08-23T20:03:40Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950365637,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950365637\n\n[quoted text omitted]\nI think I prefer `if` statement to ternary here, and I'm not used to seeing ternary statements rather than expressions in the codebase, but would be happy to change if there are other opinions."
  },
  {
   "t": "2022-08-23T20:04:01Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950369435,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950369435\n\n[quoted text omitted]\nThanks, that's clearer"
  },
  {
   "t": "2022-08-23T20:04:14Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950383459,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r950383459\n\n[quoted text omitted]\n`ErrorInfo` should have an implicit `ErrorInfo(ErrorInfo&&)` move constructor, but it actually isn't relevant here, because the new ErrorInfo object that's being allocated isn't being constructed with that constructor. Instead the newly allocated ErrorInfo is [aggregate initialized](https://en.cppreference.com/w/cpp/language/aggregate_initialization), and the two `errors` and `warnings` variables are individually move-constructed, rather than the whole `ErrorInfo` object being move constructed.\n\nIf the question here is whether the `std::move` calls here have any effect, the answer is yes they do because `errors` and `warnings` variables are vectors, and vectors have move constructors."
  },
  {
   "t": "2022-08-24T18:25:10Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "10e158a5b57ba3a26e5046a9b42fcc757652f35a"
  },
  {
   "t": "2022-08-24T18:30:42Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "10e158a5b57ba3a26e5046a9b42fcc757652f35a",
   "text": "Thanks for testing and reviews!\n\nUpdated 9bd10728bada8b04d86f5621ee127713f628a9ad -> 10e158a5b57ba3a26e5046a9b42fcc757652f35a ([`pr/bresult2.13`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.13) -> [`pr/bresult2.14`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.14), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.13..pr/bresult2.14)) with suggestions"
  },
  {
   "t": "2022-08-24T18:58:34Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950383459,
   "text": "Thank you for the thoughtful response, that was very helpful. Your usage of move semantics here now makes sense to me.\n\nNow I'm just confused that the [designated initialization](https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers) compiles fine even though the spec says it's since C++20 and I haven't configured with `--enable-c++20` (as does the CI I think)?"
  },
  {
   "t": "2022-08-24T19:03:05Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950383459,
   "text": "[quoted text omitted]\n\nOh, we are just outside of the c++17 spec there. The build enables designated initializers as an extension since #24531"
  },
  {
   "t": "2022-08-24T19:11:40Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 951889285,
   "text": "Sorry for the ghost comment. I had realized after posting that this comment about moving it to span.h wasn't really applicable so I removed it, but apparently not timely enough. I agree with you.\n\nThe only further thought I had was that if there's no need to be generic (yet - and maybe never) it might be worth not doing that to simplify things a bit where possible? E.g. the below is easier to quickly understand imo (and maybe compiles a bit faster?):\n\n```suggestion\n//! Helper to move warnings and errors from one ErrorInfo to another.\nvoid MoveMessages(std::vector<bilingual_str>& src, std::vector<bilingual_str>& dest)\n{\n    dest.insert(dest.end(), std::make_move_iterator(src.begin()), std::make_move_iterator(src.end()));\n    src.clear();\n}\n```\n\nNo strong views either way though, so feel free to ignore. Just trying to minimize on what's already a lot of genericness."
  },
  {
   "t": "2022-08-24T19:21:36Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950215859,
   "text": "I didn't think about the footgun, that's a good point why we probably indeed won't want to add the other fn later. I still think it's a bit awkward that the function name doesn't entirely capture what the function is doing, but I think it's within reason and may be worth the trade-off for brevity (vs `ErrorWarningString()`. Not sure what I prefer, so feel free to ignore.\n\nThe new docstring is great, thanks!"
  },
  {
   "t": "2022-08-24T19:32:52Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950253178,
   "text": "I like your solution, very elegant!"
  },
  {
   "t": "2022-08-24T19:53:58Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950365637,
   "text": "Hmm you're right, we're not using ternaries as statements it seems. I couldn't find a single instance of a one-line `if ...; else` either though, and unfortunately the developer notes are rather ambiguous on the topic.\n\nIn that case I'd prefer `if` and `else` on separate lines (personal preference and to not be the first in the repo) but no strong view so won't comment on it further."
  },
  {
   "t": "2022-08-25T14:55:36Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950215859,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r954211552\n\n[quoted text omitted]\nCould call it `util::MessageString(result)` instead of `util::ErrorString(result)`. I think the longer name would be ok too. I was pushing back more against changing the functionality than changing the name.\n\nI do think any renaming should happen in a separate PR, before or after this one. The function already exists and is called in current code. This PR is backwards compatible just extends the Result API without requiring changes to existing code."
  },
  {
   "t": "2022-08-25T15:13:44Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 951889285,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r954200376\n\nInteresting! I do think the generic version is shorter and easier to understand. But I like moving more code from the `.h` file to the `.cpp` file, and I like the consistency between `JoinMessages` and `MoveMessages`, so I took this suggestion. Thanks!"
  },
  {
   "t": "2022-08-25T15:28:02Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950215859,
   "text": "[quoted text omitted]\n\nRight, I did not consider that. Don't think it's worth the extra PR without more demand for it so I'm happy to just leave it at `ErrorString` until then."
  },
  {
   "t": "2022-08-25T16:30:27Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "5aff7baf375c432746dff6862e9d06064ea1fb18"
  },
  {
   "t": "2022-08-25T16:34:04Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "5aff7baf375c432746dff6862e9d06064ea1fb18",
   "text": "Updated 10e158a5b57ba3a26e5046a9b42fcc757652f35a -> 5aff7baf375c432746dff6862e9d06064ea1fb18 ([`pr/bresult2.14`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.14) -> [`pr/bresult2.15`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.15), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.14..pr/bresult2.15)) adding MoveMessages suggestion and few more comments and simplifications."
  },
  {
   "t": "2022-08-29T15:35:26Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 944367210,
   "text": "The thing is that you are basically adding a ton of dead code in this pull. `bitcoind` compiles fine without it, so I might be picky, but my preference would be to only add the code when it is needed. This also makes it easier for reviewers because they can think about actual use cases and don't have to imagine them from the unit tests.\n\n```diff\ndiff --git a/src/util/result.cpp b/src/util/result.cpp\nindex 9526b5b785..199a6579d7 100644\n--- a/src/util/result.cpp\n+++ b/src/util/result.cpp\n@@ -3,26 +3,8 @@\n // file COPYING or https://www.opensource.org/licenses/mit-license.php.\n\n #include <util/result.h>\n-#include <util/string.h>\n\n namespace util {\n namespace detail {\n-bilingual_str JoinMessages(const std::vector<bilingual_str>& errors, const std::vector<bilingual_str> warnings)\n-{\n-    bilingual_str result;\n-    for (const auto& messages : {errors, warnings}) {\n-        for (const auto& message : messages) {\n-            if (!result.empty()) result += Untranslated(\" \");\n-            result += message;\n-        }\n-    }\n-    return result;\n-}\n-\n-void MoveMessages(std::vector<bilingual_str>& src, std::vector<bilingual_str>& dest)\n-{\n-    dest.insert(dest.end(), std::make_move_iterator(src.begin()), std::make_move_iterator(src.end()));\n-    src.clear();\n-}\n } // namespace detail\n } // namespace util\ndiff --git a/src/util/result.h b/src/util/result.h\nindex 32fe40763f..8eb5b552d3 100644\n--- a/src/util/result.h\n+++ b/src/util/result.h\n@@ -17,21 +17,11 @@\n\n namespace util {\n namespace detail {\n-//! Empty string list\n-const std::vector<bilingual_str> EMPTY_LIST{};\n-\n-//! Helper function to join messages in space separated string.\n-bilingual_str JoinMessages(const std::vector<bilingual_str>& errors, const std::vector<bilingual_str> warnings);\n-\n-//! Helper function to move messages from one vector to another.\n-void MoveMessages(std::vector<bilingual_str>& src, std::vector<bilingual_str>& dest);\n-\n-//! Error information only allocated if there are errors or warnings.\n+//! Error information only allocated if there is an error.\n template <typename F>\n struct ErrorInfo {\n     std::optional<std::conditional_t<std::is_same<F, void>::value, std::monostate, F>> failure{};\n-    std::vector<bilingual_str> errors;\n-    std::vector<bilingual_str> warnings;\n+    bilingual_str error;\n };\n\n //! Result base class which is inherited by Result<T, F>.\n@@ -66,25 +56,7 @@ protected:\n public:\n     void AddError(bilingual_str error)\n     {\n-        if (!error.empty()) Info().errors.emplace_back(std::move(error));\n-    }\n-\n-    void AddWarning(bilingual_str warning)\n-    {\n-        if (!warning.empty()) Info().warnings.emplace_back(std::move(warning));\n-    }\n-\n-    //! Operator moving warning and error messages from other result to this.\n-    //! Only moves message strings, does not change success or failure values of\n-    //! either Result object.\n-    template<typename O>\n-    O&& operator<<(O&& other)\n-    {\n-        if (other.m_info) {\n-            if (!other.m_info->errors.empty()) MoveMessages(other.m_info->errors, Info().errors);\n-            if (!other.m_info->warnings.empty()) MoveMessages(other.m_info->warnings, Info().warnings);\n-        }\n-        return std::forward<O>(other);\n+        Info().error = std::move(error);\n     }\n\n     //! Success check.\n@@ -93,8 +65,7 @@ public:\n     //! Error retrieval.\n     template <typename _F = F>\n     std::enable_if_t<!std::is_same<_F, void>::value, const _F&> GetFailure() const { assert(!*this); return *m_info->failure; }\n-    const std::vector<bilingual_str>& GetErrors() const { return m_info ? m_info->errors : EMPTY_LIST; }\n-    const std::vector<bilingual_str>& GetWarnings() const { return m_info ? m_info->warnings : EMPTY_LIST; }\n+    bilingual_str GetError() const { return m_info ? m_info->error : bilingual_str{}; }\n };\n\n //! Result base class for T value type. Holds value and provides accessor methods.\n@@ -145,9 +116,6 @@ public:\n struct Error {\n     bilingual_str message;\n };\n-struct Warning {\n-    bilingual_str message;\n-};\n\n //! The util::Result class provides a standard way for functions to return error\n //! and warning strings in addition to optional result values.\n@@ -190,23 +158,11 @@ protected:\n         }, std::forward<Args>(args)...);\n     }\n\n-    template <typename Fn, typename... Args>\n-    void Construct(const Fn& fn, Warning warning, Args&&... args)\n-    {\n-        this->AddWarning(std::move(warning.message));\n-        Construct(fn, std::forward<Args>(args)...);\n-    }\n-\n-    template <typename Fn, typename OT, typename OF, typename... Args>\n-    void Construct(const Fn& fn, Result<OT, OF>&& other, Args&&... args)\n-    {\n-        *this << other;\n-        Construct(fn, std::forward<Args>(args)...);\n-    }\n-\n     void MoveConstruct(Result& other)\n     {\n-        *this << other;\n+        if (other.m_info) {\n+            this->AddError(std::move(other.m_info->error));\n+        }\n         if (other) this->MoveValue(other); else this->Info().failure = std::move(other.m_info->failure);\n     }\n\n@@ -233,7 +189,7 @@ public:\n //! are present. More complicated applications should use GetErrors() and\n //! GetWarning() methods directly.\n template <typename T, typename F>\n-bilingual_str ErrorString(const Result<T, F>& result) { return detail::JoinMessages(result.GetErrors(), result.GetWarnings()); }\n+bilingual_str ErrorString(const Result<T, F>& result) { return result.GetError(); }\n } // namespace util\n\n #endif // BITCOIN_UTIL_RESULT_H"
  },
  {
   "t": "2022-08-29T15:36:04Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "In case you don't remove this, this is wrong anyway, as it is missing a `&` in the second argument"
  },
  {
   "t": "2022-08-29T15:39:32Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit: Can use `is_same_v` instead of `...::value`? Also, missing LIFETIMEBOUND?\n\n(Same feedback on other lines where this is applicable)"
  },
  {
   "t": "2022-08-29T16:15:49Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 944367210,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r957494674\n\n[quoted text omitted]\nInteresting and thanks for the diff! Now I understand what you are suggesting, and I think I'd be ok with making that change. I wasn't really looking at that code as dead because I'm immediately using it in the next pull #25722 and also using it in unit tests this PR. I also didn't consider it to be a ton of code, since the code in your diff is just getter/setter functions that provide access to errors/warnings variables. But no objection to splitting it off into another pull."
  },
  {
   "t": "2022-08-30T06:22:43Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 944367210,
   "text": "Yeah, I don't feel too strong as well. Though, if you keep it, it would be good to fixup the typo: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r957495310"
  },
  {
   "t": "2022-08-30T16:11:29Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 957495310,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r957495310\n\n[quoted text omitted]\nThanks, removed from the main commit and added&"
  },
  {
   "t": "2022-08-30T16:11:38Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 957498746,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r957498746\n\n[quoted text omitted]\nThanks, added these improvements"
  },
  {
   "t": "2022-08-30T18:19:54Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "834857e56b8de0bfabee7315622c0211b4a48746"
  },
  {
   "t": "2022-08-30T18:25:17Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 944367210,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r958050929\n\n[quoted text omitted]\nOk, I'm hedging right now by moving multiple error & warning support into a separate commit but not a separate PR. I maybe have a slight preference for just squashing the commits again to reduce churn, but I'm also fine with keeping separate commits, or moving the commit to another PR if one of those alternatives seems better, so let me know!\n\nAlso fixed the typo"
  },
  {
   "t": "2022-08-30T18:27:31Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "834857e56b8de0bfabee7315622c0211b4a48746",
   "text": "Updated 5aff7baf375c432746dff6862e9d06064ea1fb18 -> 834857e56b8de0bfabee7315622c0211b4a48746 ([`pr/bresult2.15`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.15) -> [`pr/bresult2.16`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.16), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.15..pr/bresult2.16)) with suggestions, and splitting the main commit"
  },
  {
   "t": "2022-08-30T19:21:03Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit: `EMPTY_LIST` ( and `#include <vector>` ) seems unnecessary in this commit, think it belongs in \"[refactor: Add util::Result multiple error and warning messages](https://github.com/bitcoin/bitcoin/pull/25665/commits/834857e56b8de0bfabee7315622c0211b4a48746)\""
  },
  {
   "t": "2022-08-30T22:41:54Z",
   "kind": "review_comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "I think it's a little confusing.\nIf I understand correctly, `template <typename F> class ResultBase<void, F>` needs to know about `template <typename T, typename F> class ResultBase;` but the latter can only be declared after the former because it is a derived class. Therefore, a forward declaration is required.\n\nIf the `ResultBase` classes shouldn't be used anywhere outside of `result.h` and their only purpose is to be the base class of `Result`, I would suggest merging them all into a single class."
  },
  {
   "t": "2022-08-30T22:42:00Z",
   "kind": "review",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "state": "APPROVED",
   "commit": "834857e56b8de0bfabee7315622c0211b4a48746",
   "text": "ACK https://github.com/bitcoin/bitcoin/pull/25665/commits/834857e56b8de0bfabee7315622c0211b4a48746"
  },
  {
   "t": "2022-08-31T01:57:58Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 958993493,
   "text": "Hmm, I wonder if you can say more about what is confusing or misleading. This is just a forward declaration for a template class.\n\n It is true that the reason for the forward declaring `ResultBase<T, F>` is to allow it to inherit from `ResultBase<void, F>`. So `ResultBase<T, F>` must be defined after `ResultBase<void, F>`, but declared before it.\n\nBut this is a pretty standard thing for C and C++ code. Definition of one thing 1 depends on declaration of thing 2, so thing 2 needs to be forward declared. It can happen for normal classes and functions as well as templates.\n\n[quoted text omitted]\nThis isn't easily possible because `Result<void, F>` inherits directly from `detail::ResultBase<void, F>` and does **not** inherit from `detail::ResultBase<T, F>`. It does not have an `m_value` member or `value()` functions or a dereferencing operator. If the result type `T` is void the `Result` class doesn't hold a value and can't be dereferenced."
  },
  {
   "t": "2022-08-31T10:50:34Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "Since the `friend` declaration is gone, I think this should be `inline`?\n```suggestion\ninline bilingual_str ErrorString(const Result<T, F>& result) { return detail::JoinMessages(result.GetErrors(), result.GetWarnings()); }\n```"
  },
  {
   "t": "2022-08-31T11:23:55Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950223870,
   "text": "Maybe I'm confused, but I don't think I agree. Since the optional allocation of an `ErrorInfo` is a result of how `Info()` is implemented, not of how the `ErrorInfo` struct is defined - isn't that where it should be documented? Unless you're talking about the optional allocation of `failure` instead of `ErrorInfo`, in which case I would agree that this should be explained at this location (and you might want to add another one to info explaining the dynamic allocation of `m_info`)?"
  },
  {
   "t": "2022-08-31T11:33:15Z",
   "kind": "review",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "834857e56b8de0bfabee7315622c0211b4a48746",
   "text": "Code Review ACK 834857e56"
  },
  {
   "t": "2022-09-01T14:05:27Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 958847991,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r958847991\n\n[quoted text omitted]\nGood catch! Removed"
  },
  {
   "t": "2022-09-01T14:06:34Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 959440278,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r959440278\n\n[quoted text omitted]\nYes, makes sense to be inline."
  },
  {
   "t": "2022-09-01T14:07:34Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 950223870,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r959467658\n\n[quoted text omitted]\nI'm only pushing back against removing this comment here. I'm happy to add more documentation anywhere would would like.\n\nI think the answer to your question is no, because this isn't a general purpose API. This is a custom, private struct that is never exposed externally and exists for one purpose. The comment is describing what the purpose is. If I were reading this code and saw this struct, I would be wondering why there is such a heavyweight struct being used in a lightweight result type, why error information is segregated from normal result information, and why a separate struct definition is needed at all instead using normal class members. This comment explains what the purpose of the struct is, why it exists and how it is used, and I think is appropriate documentation for an single-purpose piece of a larger implementation."
  },
  {
   "t": "2022-09-01T15:17:53Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "82c549aa538a5318fdb56d91117b4c9fc43737de"
  },
  {
   "t": "2022-09-01T15:21:46Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "82c549aa538a5318fdb56d91117b4c9fc43737de",
   "text": "Thanks for the reviews! Just tweaked a few things as suggested.\n\nUpdated 834857e56b8de0bfabee7315622c0211b4a48746 -> 82c549aa538a5318fdb56d91117b4c9fc43737de ([`pr/bresult2.16`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.16) -> [`pr/bresult2.17`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.17), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.16..pr/bresult2.17)) with suggestions"
  },
  {
   "t": "2022-09-01T20:57:46Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "c14e904f66505b3e89ca1138c8d2fa4e3d0916d0"
  },
  {
   "t": "2022-09-01T21:02:16Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Some changes made earlier in https://github.com/bitcoin/bitcoin/pull/25665#pullrequestreview-1085638384 broke derived-to-base type conversions used in followup PR #25722. Latest push fixes this and adds a test.\n\nUpdated 82c549aa538a5318fdb56d91117b4c9fc43737de -> c14e904f66505b3e89ca1138c8d2fa4e3d0916d0 ([`pr/bresult2.17`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.17) -> [`pr/bresult2.18`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.18), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.17..pr/bresult2.18)) adding fix and test for derived to base conversions"
  },
  {
   "t": "2022-09-07T15:42:05Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit: typo\n```suggestion\n    //! Value accessors that do nothing because this class has value type T=void.\n```"
  },
  {
   "t": "2022-09-07T16:40:07Z",
   "kind": "review",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "c14e904f66505b3e89ca1138c8d2fa4e3d0916d0",
   "text": "Code review re-ACK c14e904f66505b3e89ca1138c8d2fa4e3d0916d0"
  },
  {
   "t": "2022-09-12T12:51:18Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit in https://github.com/bitcoin/bitcoin/commit/3507da864a1dd7be1bc72ada26d830a4da0c37ae:\n\nI think in C++17 you can remove all of the template and enable_if_t stuff and just write `const auto& GetFailure() const` for the return type."
  },
  {
   "t": "2022-09-12T13:38:07Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit in c14e904f66505b3e89ca1138c8d2fa4e3d0916d0:\n\nCan remove `inline`, as all `template` are `inline` by definition."
  },
  {
   "t": "2022-09-12T14:14:31Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit in 3507da864a1dd7be1bc72ada26d830a4da0c37ae:\n\nMaybe add a comment to explain those a bit more? While the `ResultBase()` constructor leaves the object uninitialized, the `Result` constructor guarantees that the object is either filled with a value or an error."
  },
  {
   "t": "2022-09-12T14:18:44Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit in 3507da864a1dd7be1bc72ada26d830a4da0c37ae:\n\ndoxygen will attach the comment to the constructor. In any case, I think this can be removed since it is not adding any info that isn't already there."
  },
  {
   "t": "2022-09-12T14:23:40Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit in 3507da864a1dd7be1bc72ada26d830a4da0c37ae:\n\nAre those really \"accessors\", not \"setters\"?"
  },
  {
   "t": "2022-09-12T14:29:21Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit in 3507da864a1dd7be1bc72ada26d830a4da0c37ae:\n\nSeems overkill to include variant, when it could be replaced by copy-pasting the one line:\n\n```\nstruct MonoState{}; // Similar to std::monostate"
  },
  {
   "t": "2022-09-12T15:36:21Z",
   "kind": "review",
   "who": "maflcko",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "c14e904f66505b3e89ca1138c8d2fa4e3d0916d0",
   "text": "review ACK f7b4fa870783ecd5f9a408bd603ff9cf0399cc3e \ud83d\udecd\n\nShow signature\n\nSignature:\n\n```\n-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA512\n\nreview ACK f7b4fa870783ecd5f9a408bd603ff9cf0399cc3e \ud83d\udecd\n-----BEGIN PGP SIGNATURE-----\n\niQGyBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p\npUjixAv439pj0FjYrwKsRqf1jJfBZhalBe6IAeD8yperLaCmdGfmSp0udgbTwuGI\n5YMasCELJ3PikDrscmn6snYiYBb+0PMgPMqriUKMWxmmMDW5v9aiqefxSgEGBQro\n2euNt+qSvycWOHt2We2oZiRyqGZZooQNMBOETo4y6v164pdysueFKNFac3ppI3AW\nLLepp/FEaId5t8dIlaVo7q49I55AQ0xdduptslA2GmZCcXyVA7bNZrcQxc2NxoH7\nXZFFTbkYri51Nn8bRcD/EK47Cc04CCqw8p9XVeD4xpkZBzqoHKIk/3wlaqN2qgJb\n8cgK6xoBOQIsKk43ez3Kxhip6pjQ3fAVwqThz9S9Csf7Td1qCmrhM59n/2eMOz5Y\n30XwsiGigRr9IDr5Hi3XxrRZzyUwmqZyvN+n3JvT7lkzQhCDPkIozJPGFWgQEfRC\nXuJQdRQW7LOZH1GVnXRP1/wCSNpcXwjqNDT+syYEQk91/qezM+NJ1yfToQJkXC7i\neIhpCy8=\n=b8pq\n-----END PGP SIGNATURE-----\n```"
  },
  {
   "t": "2022-09-12T18:59:40Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 965007804,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r965007804\n\n[quoted text omitted]\nThanks, fixed"
  },
  {
   "t": "2022-09-12T19:01:21Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 968378495,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r968378495\n\n[quoted text omitted]\nThanks, that is better. Simplified now."
  },
  {
   "t": "2022-09-12T19:02:44Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 968432479,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r968432479\n\n[quoted text omitted]\nThanks, removed `inline`"
  },
  {
   "t": "2022-09-12T19:03:27Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 968475794,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r968475794\n\n[quoted text omitted]\nSure, I moved the DestroyValue call to this `~ResultBase` destructor instead of the other `Result` constructor to make this more self contained and clear. Also added a comment explaining why the empty constructor is required. Hopefully these are improvements. Also happy to make other changes to clarify."
  },
  {
   "t": "2022-09-12T19:04:32Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 968480620,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r968480620\n\n[quoted text omitted]\nThanks, dropped. This was used to group methods in an earlier version of PR that had more methods below."
  },
  {
   "t": "2022-09-12T19:05:13Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 968486440,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r968486440\n\n[quoted text omitted]\nChanged to setters (I thought accessors was a general term for getters and setters)"
  },
  {
   "t": "2022-09-12T19:05:49Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 968493416,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r968493416\n\n[quoted text omitted]\nThanks, dropped the dependency on variant"
  },
  {
   "t": "2022-09-13T15:07:55Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "05a97d3208cc365cdeac9de281529568b3cd056c"
  },
  {
   "t": "2022-09-13T15:18:55Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "e04d8a754ff1b25cab483996319a583e6e3e680a"
  },
  {
   "t": "2022-09-13T15:22:18Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "e04d8a754ff1b25cab483996319a583e6e3e680a",
   "text": "Thanks for the reviews! New pushes implement all the suggested changes.\n\nUpdated c14e904f66505b3e89ca1138c8d2fa4e3d0916d0 -> 05a97d3208cc365cdeac9de281529568b3cd056c ([`pr/bresult2.18`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.18) -> [`pr/bresult2.19`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.19), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.18..pr/bresult2.19)) with suggestions. Also replaced operator<< with operator>> to simplify followup PR #25722 a bit\nRebased 05a97d3208cc365cdeac9de281529568b3cd056c -> e04d8a754ff1b25cab483996319a583e6e3e680a ([`pr/bresult2.19`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.19) -> [`pr/bresult2.20`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.20), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.19-rebase..pr/bresult2.20)) due to conflict with #24513"
  },
  {
   "t": "2022-09-13T17:33:07Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 968378495,
   "text": "Hmm, I meant `const auto&`, not `auto`, or is `auto` in this context magically the same as `const auto&`?"
  },
  {
   "t": "2022-09-13T17:36:10Z",
   "kind": "comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "text": "Still need to review the last commit\n\nreview ACK 3af5f5adbb \ud83c\udf52\n\nShow signature\n\nSignature:\n\n```\n-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA512\n\nreview ACK 3af5f5adbb \ud83c\udf52\n-----BEGIN PGP SIGNATURE-----\n\niQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p\npUg+kgv/VMHBkcM/thQ5I6k4qE4vJdWFYuZQJFTe/KVPIpkC6nxuEr6Gi3staL6n\nmdRzkHsqS1Wpsm/kMUREBvEuTqUk+SPyv+spyWhnd86VSTa66clfJvrp0AD2kV6w\nuX5DlPzhb5fvgK59gJZ59Yq8bIcwqLe+hzvRBKdlqh5qxqnm1zSAB0O+KK4pwk9N\nz0mlPBWnM8qgmB3nnS9tWN58E4PUsue1Xb89GgNHh4DrnZTo/UrAPC9qsABeSU7+\nu1pU1Z9rpn57qmQI1LkQ9FDjZE8mL5NZ12OpISsNiXYVzQey6IiKsxzjfVtg3R4q\n5qtHzHtzx7XjDT40oAeb1Z1EWm+an5KME7Gk4/olR0PqDo2f2LILuwp9kCJJY7qt\nIdRWvHwAmU5J9EvgPOTWzWtU+LbsVwS3qoBwee2tlWrAxBjkdezuESFCDepq42wL\nTqzGBWAL40+MdjLBSeOYJm0ZuZHSHmqIDfykVyDmdM9SBaPstfkRmBngRIEKoCpM\n9PGi4h4Y\n=W7bY\n-----END PGP SIGNATURE-----\n```"
  },
  {
   "t": "2022-09-13T18:56:49Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 968378495,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r969906681\n\n[quoted text omitted]\nNo, I just messed up and unintentionally did a copy. Fixed this and added tests to make sure GetFailure() does not copy."
  },
  {
   "t": "2022-09-13T19:14:09Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "52a4e50fb4b1171ee0f6814b0a50bc70cdd77134"
  },
  {
   "t": "2022-09-13T19:17:18Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "52a4e50fb4b1171ee0f6814b0a50bc70cdd77134",
   "text": "Updated e04d8a754ff1b25cab483996319a583e6e3e680a -> 52a4e50fb4b1171ee0f6814b0a50bc70cdd77134 ([`pr/bresult2.20`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.20) -> [`pr/bresult2.21`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.21), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.20..pr/bresult2.21)) fixing unintentional GetFailure copy introduced last push, and adding test to detect this copy"
  },
  {
   "t": "2022-09-14T09:34:25Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "52a4e50fb4b1171ee0f6814b0a50bc70cdd77134: I don't like that this takes over error strings, but leaves the value and failure untouched. It seems fine to have a result and warnings, but having a result and also an error at the same time seems odd.\n\nSame with operator=. I think this is the first time I've seen that after calling `=`, state is preserved from before `=` was called."
  },
  {
   "t": "2022-09-14T20:37:54Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 970561659,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r970561659\n\n[quoted text omitted]\nAgree having both a result value and an error message should be avoided. Also having neither a result value nor an error message should be avoided. But there are tradeoffs around where and how strictly you want to enforce these things. The main thing currently enforcing value/error consistency is having a constructor that sets error messages and failure values at the same time and does not allow setting a result value, and a constructor that only sets a success value and does not allow setting an error message.\n\nBut this leaves open the question of what helpers functions like `operator>>` should do when they combine multiple result values that have already been constructed.\n\nThe use-case for `operator>>` is when you have an outer function returning `Result<T, F>` calling inner functions returning `Result<T1, F1>`, and `Result<T2, F2>`, etc. Examples would be [`LoadWalletInternal`](https://github.com/ryanofsky/bitcoin/blob/4e533926fe5549aafb70caf94718447ea497c84c/src/wallet/wallet.cpp#L229), [`CreateWallet`](https://github.com/ryanofsky/bitcoin/blob/4e533926fe5549aafb70caf94718447ea497c84c/src/wallet/wallet.cpp#L298), and [`DoMigration`](https://github.com/ryanofsky/bitcoin/blob/4e533926fe5549aafb70caf94718447ea497c84c/src/wallet/wallet.cpp#L3862) from #25722. The outer function can handle failures from inner functions it calls any way it wants: passing failure values up to its caller, translating failure values, ignoring failures, retrying after failures, falling back to an alternate approaches, etc. It sets success and failure values directly, and it can use `operator>>` to collect error and warning messages separately and pass them along. I don't think `operator>>` should be involved in success and failure value handling. I think it would be bad if `operator>>` discarded error messages, or it it threw runtime exceptions, instead of just passing messages on to ultimately get displayed or logged.\n\nIn C++ generally `operator>>` is used for things as varied as bit shifting and stream I/O and can be interpreted as \"move data from this place to another place\" so I think it reasonable that this `operator>>` just moves error and warning messages from one `Result` object to another, as long as behavior is clearly documented.\n\n[quoted text omitted]\nYes it is true that assigning to an existing result does not erase warning and errors messages already accumulated in the result. It only sets the success or failure value and appends new warning and error messages to existing ones.\n\nI think this this behavior is safe and useful. Setting a value should not automatically erase warning and error messages that are meant to be displayed or logged. But if this behavior is too surprising for an `operator=` method, we don't actually need to make `Result` assignable, and could rename `operator=()` to `Set()` or `SetValue()`. It looks like even after #25722 there are only 3 `operator=` calls in the codebase outside of tests, so this would be an easy change."
  },
  {
   "t": "2022-09-15T07:53:38Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 970561659,
   "text": "[quoted text omitted]\n\nWell, this is already impossible for the reasons you gave. (Edit: When calling only the constructors)\n\n[quoted text omitted]\nThen, why not make it impossible? If there is an outer function returning `Result<T, F>` that wants to combine `Result<T1, F1>` and `Result<T2, F2>`, then it seems better if it explicitly takes (moves) the result T1/F1 out and translates it into T/F. For example, if it passes up a failure value, it seems best to just create a fresh Result (of the outer type) with the failure and return that. (Same if it translates failure values). If it ignores failures, it would be good to translate them to warnings first and not blindly take them over as errors with the `>>` operator. (Same if it retries or falls back).\n\n[quoted text omitted]\nWhy couldn't the same be achieved by explicitly constructing a new Result with either an error or a value?"
  },
  {
   "t": "2022-09-15T09:24:13Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 970561659,
   "text": "[quoted text omitted]\n\n[quoted text omitted]\n\"Should be avoided\" means that users should avoid it, and the implementation makes it easy to avoid by default. The reasons I gave were reasons why a function combining multiple result values needs to either (1) allow result values and error messages to exist at the same time or (2) discard error messages or result values or (3) throw exceptions. And I believe the best choice for `operator>>` is (1), just to be a plain message mover that moves message strings and leaves result values alone. I linked to use-cases showing how this works in practice.\n\n[quoted text omitted]\nThis is actually what the implementation does. But if the outer function returns success value, and there are error messages, I don't think it is good default behavior to throw away the error messages or raise an exception. I think the best default behavior is to keep error messages so they can be displayed or logged.\n\n[quoted text omitted]\nSo change you are asking for there is basically:\n\n```diff\n--- a/src/util/result.h\n+++ b/src/util/result.h\n@@ -222,7 +222,7 @@ public:\n     Result&& operator>>(O&& other LIFETIMEBOUND) &&\n     {\n         if (this->m_info) {\n-            if (!this->m_info->errors.empty()) detail::MoveMessages(this->m_info->errors, other.Info().errors);\n+            if (!this->m_info->errors.empty()) detail::MoveMessages(this->m_info->errors, other ? other.Info().warnings : other.Info().errors);\n             if (!this->m_info->warnings.empty()) detail::MoveMessages(this->m_info->warnings, other.Info().warnings);\n         }\n         return std::move(*this);\n```\n\nI wouldn't object to it, but it just seems more invasive and doesn't offer practical benefits.\n\n[quoted text omitted]\nI think\n\n```c++\nWarnFn1() >> result;\nWarnFn2() >> result;\nresult = FailFn(...);\nreturn result;\n```\n\nor\n\n```c++\nWarnFn1() >> result;\nWarnFn2() >> result;\nresult.Set(FailFn(...));\nreturn result;\n```\n\nis cleaner than\n\n```c++\nWarnFn1() >> result;\nWarnFn2() >> result;\nauto result2 = FailFn(...);\nstd::move(result) >> result2;\nreturn result2;\n```\n\nbecause it doesn't require introducing multiple result variables. If you are trying to get rid of both `operator=` and `operator>>`, I believe `operator=` or `Set` is also better than:\n\n```c++\nauto result2 = FailFn(...);\nreturn result2 ? Result<int, FnError>(std::move(result), result2.value()) : Result<int, FnError>(std::move(result), Error{}, resul2t.GetFailure());\n```\n\nI'm happy to rename `operator=` to `Set` if you think `operator=` is misleading. But if you look at the places where these functions are used, it is easier to see why they are useful. Conversely, if you think there is a footgun here, it would be helpful to see an example of the footgun."
  },
  {
   "t": "2022-09-15T09:54:02Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 970561659,
   "text": "[quoted text omitted]\n\nI linked to some places where `operator>>` is used already: [`LoadWalletInternal`](https://github.com/ryanofsky/bitcoin/blob/4e533926fe5549aafb70caf94718447ea497c84c/src/wallet/wallet.cpp#L229-L245), [`CreateWallet`](https://github.com/ryanofsky/bitcoin/blob/4e533926fe5549aafb70caf94718447ea497c84c/src/wallet/wallet.cpp#L298-L346), and [`DoMigration`](https://github.com/ryanofsky/bitcoin/blob/4e533926fe5549aafb70caf94718447ea497c84c/src/wallet/wallet.cpp#L3862-L3940) from #25722\n\nFor `operator=` (again happy to rename this to `Set`) examples are: [`AddressTableModel::addRow`](https://github.com/ryanofsky/bitcoin/blob/4e533926fe5549aafb70caf94718447ea497c84c/src/qt/addresstablemodel.cpp#L381), [`SQLiteDatabase::Verify`](https://github.com/ryanofsky/bitcoin/blob/4e533926fe5549aafb70caf94718447ea497c84c/src/wallet/sqlite.cpp#L172), [`AvailableCoinsTestingSetup`](https://github.com/ryanofsky/bitcoin/blob/4e533926fe5549aafb70caf94718447ea497c84c/src/wallet/test/availablecoins_tests.cpp#L78-L99), [`FuzzedWallet::GetScriptPubKey`](https://github.com/ryanofsky/bitcoin/blob/4e533926fe5549aafb70caf94718447ea497c84c/src/wallet/test/fuzz/notifications.cpp#L72-L74)"
  },
  {
   "t": "2022-09-15T15:25:29Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "f9accbc6e296adadac374eca085f8b2ce095c8a4"
  },
  {
   "t": "2022-09-15T15:30:36Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 970561659,
   "text": "Went ahead and renamed `operator=` to `Set` for now. Seems like a good way to avoid some confusion."
  },
  {
   "t": "2022-09-15T15:31:58Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "f9accbc6e296adadac374eca085f8b2ce095c8a4",
   "text": "Updated 52a4e50fb4b1171ee0f6814b0a50bc70cdd77134 -> f9accbc6e296adadac374eca085f8b2ce095c8a4 ([`pr/bresult2.21`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.21) -> [`pr/bresult2.22`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.22), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.21..pr/bresult2.22)) just renaming `operator=` to `Set` to avoid some confusion\nUpdated f9accbc6e296adadac374eca085f8b2ce095c8a4 -> 776d9b3fbb4cf83c81cc38c44cae10d3f3344b1b ([`pr/bresult2.22`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.22) -> [`pr/bresult2.23`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.23), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.22..pr/bresult2.23)) tweaking commit message\nRebased 776d9b3fbb4cf83c81cc38c44cae10d3f3344b1b -> 456e3d4eccf010eba30096061b83adc45c371b92 ([`pr/bresult2.23`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.23) -> [`pr/bresult2.24`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.24), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.23-rebase..pr/bresult2.24)) due to conflict with #25499\nRebased 456e3d4eccf010eba30096061b83adc45c371b92 -> 28a6934da980703006e028776d276ae77121c586 ([`pr/bresult2.24`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.24) -> [`pr/bresult2.25`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.25), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.24-rebase..pr/bresult2.25)) due to conflict with #25667\nRebased 28a6934da980703006e028776d276ae77121c586 -> f4d55d858d9da08612a8ba3b7ceeaf36dfe6cc30 ([`pr/bresult2.25`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.25) -> [`pr/bresult2.26`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.26), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.25-rebase..pr/bresult2.26)) due to conflicts with #26289 and #26661"
  },
  {
   "t": "2022-09-15T15:33:53Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "776d9b3fbb4cf83c81cc38c44cae10d3f3344b1b"
  },
  {
   "t": "2022-09-20T15:52:50Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "456e3d4eccf010eba30096061b83adc45c371b92"
  },
  {
   "t": "2022-10-14T20:59:22Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "28a6934da980703006e028776d276ae77121c586"
  },
  {
   "t": "2023-01-06T18:50:37Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "f4d55d858d9da08612a8ba3b7ceeaf36dfe6cc30"
  },
  {
   "t": "2023-02-10T20:41:46Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "b57a898a987c63a8dadcb21dd5c94737e86ee107"
  },
  {
   "t": "2023-02-10T22:38:10Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "eb50fcd6859d1730663159995e8477f6d892e7f4"
  },
  {
   "t": "2023-02-12T14:54:59Z",
   "kind": "comment",
   "who": "hebasto",
   "assoc": "MEMBER",
   "text": "Concept ACK."
  },
  {
   "t": "2023-02-12T15:27:31Z",
   "kind": "comment",
   "who": "hebasto",
   "assoc": "MEMBER",
   "text": "It seems the 7cdb7d1e9573ae60e7335af5d3de99191ad68b3f commit adds `src/wallet/test/availablecoins_tests.cpp` by accident, doesn't it?"
  },
  {
   "t": "2023-02-12T17:42:51Z",
   "kind": "review",
   "who": "hebasto",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "eb50fcd6859d1730663159995e8477f6d892e7f4",
   "text": "Approach ACK eb50fcd6859d1730663159995e8477f6d892e7f4.\n\n---\nStyle nit:\n\nhttps://github.com/bitcoin/bitcoin/pull/25665/files#r954244319:\n[quoted text omitted]\n\nAgree. From [Developer Notes](https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md#coding-style-c):\n[quoted text omitted]"
  },
  {
   "t": "2023-02-13T10:42:23Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "Allowing for a `void` failure type seems to make this incompatible to be switched out to `std::expected` https://en.cppreference.com/w/cpp/utility/expected ?\n\nWith multiple warning and error messages this may already be incompatible, though?"
  },
  {
   "t": "2023-02-13T15:27:49Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1104282294,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1104282294\n\n[quoted text omitted]\nYes, if you are thinking that `util::Result` could wrap `std::expected`, that would be probably be awkward and not worth it.\n\nBut I don't think there is a conflict because the two classes are mostly doing different things. The `util::Result` class is mostly providing error-reporting functionality (passing error and warning strings up to the user). The `std::expected` class is only providing error-handling functionality (passing failure and success values between functions). Here is how I would choose the between the two classes:\n\n- If your function never fails, it should just return success value directly.\n- If your function can fail, but doesn't provide any error strings or specific failure information, it should return `std::optional`.\n- If your function can fail, and provides failure information but not error strings, it should return `std::expected`.\n- If your function can fail, and generates error or warning strings it should return `util::Result`.\n\nWe have a lot of functions that generate error strings as you can see by all the code using `util::Error` and `util::Result` presently, and in more code that is converted to use `util::Result` in this PR and #25722. After `std::expected` is available, most of these functions still be better off using `util::Result` instead of `std::expected` so they are able to pass back error strings in a uniform way.\n\nBut when `std::expected` is available, we may want to tweak the `util::Result` class to make it easier to switch between `std::expected` and `util::Result` with minimal code changes. For example, the `util::Result` already has a `value_or` method to be compatible with `std::optional`. It could also have `and_then` and `or_else` methods to be compatible with `std::expected`."
  },
  {
   "t": "2023-02-16T18:53:42Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "501ef88b9412b0d924abf32cf2de7fbcbbb69b8d"
  },
  {
   "t": "2023-02-16T18:54:47Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#pullrequestreview-1294756069\n\nThanks for the review! I got rid of the unused test file and changed the `if` formatting as suggested\n\n---\n\nUpdated eb50fcd6859d1730663159995e8477f6d892e7f4 -> 501ef88b9412b0d924abf32cf2de7fbcbbb69b8d ([`pr/bresult2.28`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.28) -> [`pr/bresult2.29`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.29), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.28..pr/bresult2.29)) with suggested changes"
  },
  {
   "t": "2023-03-01T16:05:51Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "d785176df3e9cccaab9fbbe12d9f8d2c28d3336f"
  },
  {
   "t": "2023-03-16T19:05:19Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "e766928ed15cf43cda0773b886b7fb8f53b04dd4"
  },
  {
   "t": "2023-04-04T20:31:21Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "6d7d7bbb7bef40b61cf5862beb8e36e46cdfc455"
  },
  {
   "t": "2023-05-02T19:59:11Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "28a954c7034077ac3a45083dd5e2b5cdb4d4cdde"
  },
  {
   "t": "2023-05-11T16:42:27Z",
   "kind": "review",
   "who": "hernanmarino",
   "assoc": "CONTRIBUTOR",
   "state": "APPROVED",
   "commit": "28a954c7034077ac3a45083dd5e2b5cdb4d4cdde",
   "text": "re ACK 28a954c7034077ac3a45083dd5e2b5cdb4d4cdde"
  },
  {
   "t": "2023-05-11T17:30:02Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Thanks for the review.\n\nNote: @martinus left several review comments on https://github.com/bitcoin/bitcoin/pull/25722#pullrequestreview-1386736519, which is based on this PR, which apply to this PR and can improve it a little. I'm planning to update this PR to incorporate the suggestions."
  },
  {
   "t": "2023-05-26T13:35:00Z",
   "kind": "comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "text": "`void` can be removed from OP?"
  },
  {
   "t": "2023-06-19T16:28:24Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": null,
   "text": "Can you add an example for when the Result error type in a chain of function calls remains the same, but the value type changes? Is there a better way to do this conversion than manually constructing the result again (like below)?\n\n```suggestion\nutil::Result<std::string, FnError> CastFailFn() {\n    auto res = IntFailFn(1, false);\n    return {util::Error{ErrorString(res)}, res.GetFailure()};\n}\n```"
  },
  {
   "t": "2023-07-21T16:25:52Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 1234264247,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1234264247\n\n[quoted text omitted]\nYes, there is definitely a better way to pass along errors and warnings from one result to another without calling `ErrorString` and flattening them. The `util::Result` constructor will move errors and warnings directly from an existing result object if you just pass the other result object as an argument with `std::move`. If you look at the `MultiWarnFn` there was an example of this feature in the success case. But I added a new `StrFailFn` function now based on your code that demonstrates it in both the success and failure cases.\n\nI am also thinking of adding a `util::Messages{Result&&}` helper similar to existing `util::Error{std::string}` and `util::Warning{std::string}` helpers to make it more obvious how you can construct a Result value with errors and warning from different sources.\n\nRevisiting this makes me realize I should probably add a tutorial-style document that describes how to use the Result class with standalone functions that return util::Result, chained functions that return util::Result values of the same type, and chained functions that return util::Result values of different types."
  },
  {
   "t": "2023-07-21T16:43:58Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "40f09de73e61e7ae62d6639a49b7c7ac48d514d9"
  },
  {
   "t": "2023-07-21T16:47:03Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "40f09de73e61e7ae62d6639a49b7c7ac48d514d9",
   "text": "Rebased 28a954c7034077ac3a45083dd5e2b5cdb4d4cdde -> 40f09de73e61e7ae62d6639a49b7c7ac48d514d9 ([`pr/bresult2.33`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.33) -> [`pr/bresult2.34`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.34), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.33-rebase..pr/bresult2.34)) due to conflict with various PR and making many suggested changes from review #25722 (which is based on this PR)\n\nre: https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-1564406303\n\n[quoted text omitted]\nThanks, no longer mentioning it since #25977 added support for `Result<void>`"
  },
  {
   "t": "2023-07-21T19:02:25Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "f1b46f4017a\n```\ninit.cpp:948:12: error: 'operator=' is a private member of 'util::Result<void>'\n    result = init::SetLoggingLevel(args);\n    ~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~\n./util/result.h:47:13: note: declared private here\n    Result& operator=(Result&&) = default;\n            ^\n```"
  },
  {
   "t": "2023-07-21T19:10:47Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "40f09de73e6 `lint-locale-dependence.py`\n\n```\nThe locale dependent function std::to_string(...) appears to be used:\nsrc/test/result_tests.cpp:101:    return {std::move(result), std::to_string(*result)};\n```"
  },
  {
   "t": "2023-07-21T19:52:07Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1271000370,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1271000370\n\nThanks, this should be fixed now"
  },
  {
   "t": "2023-07-21T19:52:42Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1270993538,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1270993538\n\nThanks for testing the early commit, should be fixed now"
  },
  {
   "t": "2023-07-21T19:59:21Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "775b54e88107b0b976bf995e607926013fa9bc42"
  },
  {
   "t": "2023-07-21T20:04:52Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "775b54e88107b0b976bf995e607926013fa9bc42",
   "text": "Updated 40f09de73e61e7ae62d6639a49b7c7ac48d514d9 -> 775b54e88107b0b976bf995e607926013fa9bc42 ([`pr/bresult2.34`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.34) -> [`pr/bresult2.35`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.35), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.34..pr/bresult2.35)) with compile/lint fixes"
  },
  {
   "t": "2023-07-21T20:43:20Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": null,
   "text": "332e847c9ec tuple not needed per iwyu in tidy ci https://cirrus-ci.com/task/6540065057275904?logs=ci#L20325, while touching could add the others\n\n```diff\n+#include <assert.h>\n #include <memory>\n #include <optional>\n-#include <tuple>\n #include <utility>\n #include <vector>\n+#include <new>\n+#include <type_traits>\n```"
  },
  {
   "t": "2023-07-21T20:45:45Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/util/result.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "https://github.com/bitcoin/bitcoin/commit/332e847c9ec0241efd9681eee3b03ff819aaddc3 per iwyu in https://cirrus-ci.com/task/6540065057275904?logs=ci#L20305\n\n```diff\n #include <util/result.h>\n-#include <util/string.h>\n+#include \"util/translation.h\"\n+\n+#include <algorithm>\n+#include <initializer_list>\n+#include <iterator>\n```"
  },
  {
   "t": "2023-07-21T21:20:49Z",
   "kind": "review",
   "who": "jonatack",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "775b54e88107b0b976bf995e607926013fa9bc42",
   "text": "First-pass ACK 775b54e88107b0b976bf995e607926013fa9bc42\n\nIn https://github.com/bitcoin/bitcoin/commit/332e847c9ec0241efd9681eee3b03ff819aaddc3 and 4d995d3fa66fbc3eb87c6627e5ba1b2a809402a4, I wonder if some of the custom operator (i.e. move) definitions should have a noexcept-specification. Also, notating any methods where it would be incorrect if the return value isn't checked (e.g. for error-handling) and optionally getter-like pure functions with `nodiscard` may aid reviewers / readers of the code."
  },
  {
   "t": "2023-07-23T19:32:16Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 1234264247,
   "text": "[quoted text omitted]\n\nI think this would be valuable, either in `util/result.h` directly or in `doc/developer-notes.md` or another file in `/doc`."
  },
  {
   "t": "2023-07-27T14:33:47Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 1234264247,
   "text": "[quoted text omitted]\n\nThat sounds like a worthwhile improvement of the ergonomics here."
  },
  {
   "t": "2023-07-27T14:57:25Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "It strikes me as unfortunate that the move constructor cannot move the failure values across different result value types, meaning the failure needs to be passed in as a separate argument. At the same time the user would be allowed to return a `{std::move(result), util::Error{Untranslated(\"str error\")}`, potentially without the user noticing that this will not move the failure value ~and instead initialize a `Monostate` failure~ and instead default construct the failure value."
  },
  {
   "t": "2023-07-28T14:02:49Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "Would it make sense to rename this to `emplace`, to keep the interface in line with `optional` and `expected`?"
  },
  {
   "t": "2023-07-28T14:06:09Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit: would it be more idiomatic to use `has_value()` here?\n```suggestion\n    const T& value() const LIFETIMEBOUND { assert(has_value()); return m_value; }\n    T& value() LIFETIMEBOUND { assert(has_value()); return m_value; }\n```"
  },
  {
   "t": "2023-07-28T14:44:23Z",
   "kind": "review_comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit: would `m_error` or (`m_error_info`) be a more appropriate name? E.g. in `bool()`, the meaning of `!m_error` is much more intuitive at first sight compared to `!m_info`, I think? (i.e. it's not really clear what it means to \"not have info\", whereas \"not have error\" is clear).\n\n```\nexplicit operator bool() const { return !m_info; }\n```"
  },
  {
   "t": "2023-07-28T16:55:09Z",
   "kind": "review",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "775b54e88107b0b976bf995e607926013fa9bc42",
   "text": "Will continue my (re-)review next week, this is mostly up until 332e847c9ec0241efd9681eee3b03ff819aaddc3"
  },
  {
   "t": "2023-08-01T17:45:06Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 1234264247,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1276382028\n\n[quoted text omitted]\nThanks, added this"
  },
  {
   "t": "2023-08-01T17:45:16Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 1271094067,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1271094067\n\n[quoted text omitted]\nThanks, updated includes"
  },
  {
   "t": "2023-08-01T17:45:24Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1277642391,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1277642391\n\n[quoted text omitted]\nCalling it `m_error` would be misleading in later commits. The purpose of this field isn't to indicate the presence of an error. It happens to do that temporarily in the \"Add util::Result failure values\" commit, but in later commit \"Add util::Result multiple error and warning messages\", it can hold error and warning messages even in the success state."
  },
  {
   "t": "2023-08-01T17:45:39Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1277588274,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1277588274\n\n[quoted text omitted]\nI don't think it's more idiomatic but the suggestion seems fine so I adopted it."
  },
  {
   "t": "2023-08-01T17:46:03Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1277584643,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1277584643\n\n[quoted text omitted]\nThis isn't an actually an emplace method, it's an assignment method. An emplace method for a `Result<T>` object would take arguments that would be accepted by one of `T`'s constructors, and construct a new `T` object in place with them.\n\nBy contrast, this method doesn't accept arguments that could be forwarded to a `T` constructor. Instead this method takes a `Result<T>` argument, and is basically the same as an `operator=(Result&&)` method.\n\nAdded better documentation about this in the \"multiple error and warning messages\" commit:\n\n```c++\n    //! Move success or failure values from another result object to this\n    //! object. Also move any error and warning messages from the other result\n    //! object to this one. If this result object has an existing success or\n    //! failure value it is cleared and replaced by the other value. If this\n    //! result object has any error or warning messages, they are not cleared\n    //! the messages will accumulate.\n    Result& Set(Result&& other) LIFETIMEBOUND\n```"
  },
  {
   "t": "2023-08-01T17:46:38Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1276417417,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1276417417\n\n[quoted text omitted]\nYes agree that would have been misleading. This should be fixed with the new `util::Messages` helper. Now just passing a bare `std::move(result)` is no longer allowed, so it shouldn't look like the failure value is being moved. If you want to return a value from a `Result<T1, F>` function using a `Result<T2, F> result` value, now you have to write:\n\n```c++\nreturn {util::Error{}, util::Messages(std::move(result), result.GetFailure()};\n```\n\n---\n\n- EDIT: After the latest push, `util::Messages` is replaced by `util::MoveMessages` so this is now:\n\n  ```c++\n  return {util::Error{}, util::MoveMessages(result), result.GetFailure()};\n  ```\n---\n\nI'm not sure how common it will be to have functions calling each other that have different success types but the same failure type. If it does turn out to be common, it should be possible to add syntax sugar so that can be shortened to:\n\n```c++\nreturn {util::Error{}, std::move(result)};\n```"
  },
  {
   "t": "2023-08-01T17:46:45Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1271096350,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1271096350\n\n[quoted text omitted]\nThanks, updated includes"
  },
  {
   "t": "2023-08-01T20:13:58Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "1de05ef9190202f04f8cbe7746a47cbd66ab540c"
  },
  {
   "t": "2023-08-01T20:26:22Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "1de05ef9190202f04f8cbe7746a47cbd66ab540c",
   "text": "Updated 775b54e88107b0b976bf995e607926013fa9bc42 -> 1de05ef9190202f04f8cbe7746a47cbd66ab540c ([`pr/bresult2.35`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.35) -> [`pr/bresult2.36`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.36), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.35..pr/bresult2.36)) making suggested changes\n\nI still want to do more work to make the result class to enforce more safety with bool/optional/pointer types as discussed https://github.com/bitcoin/bitcoin/pull/25722#discussion_r1174297928, and work better with the `ResultPtr` class from #26022. I also want to write better documentation with usage examples. So I'll keep working on this, and push more changes here or in followup PRs."
  },
  {
   "t": "2023-08-01T22:28:29Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "08f5febfc571220043436bbec96a326beebdee22"
  },
  {
   "t": "2023-08-01T22:37:46Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Updated 1de05ef9190202f04f8cbe7746a47cbd66ab540c -> 08f5febfc571220043436bbec96a326beebdee22 ([`pr/bresult2.36`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.36) -> [`pr/bresult2.37`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.37), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.36..pr/bresult2.37)) replacing `util::Messages` with `util::MoveMessages` to work around clang-tidy error `bugprone-use-after-move` (https://cirrus-ci.com/task/6657022251237376?logs=ci#L3119). This makes usage less verbose in most cases, too."
  },
  {
   "t": "2023-08-02T22:56:44Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "Here and line 192 below: \"earning\"?"
  },
  {
   "t": "2023-08-02T23:22:25Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": null,
   "text": "584e3fa Not sure, but these `if (!result) return result;` idioms (here and lines 228-229 below) seem \"odd\" enough that an explanatory comment might be helpful."
  },
  {
   "t": "2023-08-02T23:29:37Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "```suggestion\n//! Substitute for std::monostate that doesn't depend on std::variant.\n```\n-----\n\nalso, per the lint CI / spelling linter\n\n```\nsrc/util/result.h:30: Subsitute ==> Substitute\nsrc/util/result.h:200: OT ==> TO, OF, OR, NOT\nsrc/util/result.h:201: OT ==> TO, OF, OR, NOT\nsrc/util/result.h:221: OT ==> TO, OF, OR, NOT\nsrc/util/result.h:222: OT ==> TO, OF, OR, NOT\n^ Warning: codespell identified likely spelling errors. Any false positives? Add them to the list of ignored words in test/lint/spelling.ignore-words.txt\n```"
  },
  {
   "t": "2023-08-02T23:32:58Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": null,
   "text": "Tidy CI iwyu suggestions\n\n```diff\n+#include <tinyformat.h>\n+#include <util/translation.h3\n\n+#include <algorithm>\n+#include <memory>\n+#include <ostream>\n+#include <string>\n+#include <utility>\n```"
  },
  {
   "t": "2023-08-02T23:40:53Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "6ddcc9be `GetErrors()` and `GetWarnings()` don't seem to have any test coverage yet. Note that there is also already a `GetWarnings()` in `src/warnings.{h.cpp}`, perhaps disambiguate naming/grepping-wise in addition to namespace-wise."
  },
  {
   "t": "2023-08-02T23:45:57Z",
   "kind": "review",
   "who": "jonatack",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "08f5febfc571220043436bbec96a326beebdee22",
   "text": "ACK 08f5febfc571220043436bbec96a326beebdee22\n\nSome non-blocking comments follow."
  },
  {
   "t": "2023-08-03T19:20:33Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 1282499219,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1282499219\n\n[quoted text omitted]\nI think this will probably be a common pattern and it would be too verbose to explain what is happening each place it is used. If the code were misleading, I think I would want to do something to fix it now. But if it's just a little unusual looking, I think that's expected at this point, and we can see what improvements would be useful in the future as it is used more widely."
  },
  {
   "t": "2023-08-03T19:20:48Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 1282503773,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1282503773\n\n[quoted text omitted]\nThanks applied these"
  },
  {
   "t": "2023-08-03T19:21:31Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1282502389,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1282502389\n\n[quoted text omitted]\nThanks, fixed spelling"
  },
  {
   "t": "2023-08-03T19:26:24Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1282507096,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1282507096\n\n[quoted text omitted]\nThanks, added some test coverage. On the `warnings.h` overlap, I think that `GetWarnings()` is not a great name for a top level function, and that function would be better to rename (or delete) regardless."
  },
  {
   "t": "2023-08-03T19:26:57Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1282487687,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1282487687\n\n[quoted text omitted]\nThanks, rewrote these comments now"
  },
  {
   "t": "2023-08-03T20:39:06Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "b0beb4c504da29c27358d4602a045aaab39305f6"
  },
  {
   "t": "2023-08-03T20:42:17Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "b0beb4c504da29c27358d4602a045aaab39305f6",
   "text": "Updated 08f5febfc571220043436bbec96a326beebdee22 -> b0beb4c504da29c27358d4602a045aaab39305f6 ([`pr/bresult2.37`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.37) -> [`pr/bresult2.38`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.38), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.37..pr/bresult2.38)) moving a lot more functionality from the `Result` class to the `ResultBase` class so the new code can be compatible with the `ResultPtr` class from #26022. Also rewrote and added more documentation and implemented latest review suggestions."
  },
  {
   "t": "2023-08-04T11:24:47Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "9e80d0b754a28733c79a52c8e0431616c31d071c"
  },
  {
   "t": "2023-08-04T11:26:25Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Updated b0beb4c504da29c27358d4602a045aaab39305f6 -> 9e80d0b754a28733c79a52c8e0431616c31d071c ([`pr/bresult2.38`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.38) -> [`pr/bresult2.39`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.39), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.38..pr/bresult2.39)) to fix `operator>>` compile error that seemed to happen with newer versions of clang: https://cirrus-ci.com/task/4622529512341504?logs=ci#L2370"
  },
  {
   "t": "2023-08-04T16:53:26Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "835f094 It looks like this empty vector might be declarable `constexpr`, at least with clang 16.0.6 arm64. Possibly not uniformly until C++20."
  },
  {
   "t": "2023-08-04T16:54:58Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "9ec1bda Can `Base` here be private instead of protected?"
  },
  {
   "t": "2023-08-04T17:05:08Z",
   "kind": "review_comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "9ec1bda\n```\nsrc/util/result.h:300: OT ==> TO, OF, OR, NOT\nsrc/util/result.h:301: OT ==> TO, OF, OR, NOT\n^ Warning: codespell identified likely spelling errors. Any false positives? Add them to the list of ignored words in test/lint/spelling.ignore-words.txt\n```"
  },
  {
   "t": "2023-08-04T17:08:42Z",
   "kind": "review",
   "who": "jonatack",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "9e80d0b754a28733c79a52c8e0431616c31d071c",
   "text": "ACK 9e80d0b754a28733c79a52c8e0431616c31d071c\n\nNice documentation, code, and commit message improvements.  Some non-blocking comments.  Consider also making swap/move/destructors in Result/ResultBase noexcept.  FWIW I didn't hit the CI build error in the previous push with arm64 clang 16.0.6."
  },
  {
   "t": "2023-08-04T18:01:26Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1284654294,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1284654294\n\n[quoted text omitted]\nIt could, but in general I prefer to use `protected` over `private` when it is safe for extensibility and testing, and in this case I want to support adding a `ResultPtr` type like the one in #26022 which inherits from `Result`. Also, `Base` is just a type alias for a public type, so making it private could only make the alias private, not the type, and only force type declarations to be more verbose.\n\nConceptually, I think the inheritance used in result.h is basically just an implementation detail, and that ResultBase/Result/ResultPtr classes should act like a single class and have full access to result state without any unnecessary obstacles or verbosity or layers of abstraction. In the future it would even be nice to combine Result and ResultBase classes together using [c++23's deduced this](https://devblogs.microsoft.com/cppblog/cpp23-deducing-this/#crtp) or maybe doing it without waiting for c++23 using the CRTP pattern mentioned at that link."
  },
  {
   "t": "2023-08-07T14:54:48Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1284653088,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1284653088\n\n[quoted text omitted]\nThis is a good idea, but I think you are right it requires c++20. With my compiler (clang 13) I see:\n\n```c++\n./util/result.h:85:38: error: constexpr variable cannot have non-literal type 'const std::vector<bilingual_str>'\nconstexpr std::vector<bilingual_str> EMPTY_LIST{};\n                                     ^\n/nix/store/acbklvmaxi32lj3f7k1m1y00017f89ix-gcc-11.3.0/include/c++/11.3.0/bits/stl_vector.h:389:11: note: 'vector<bilingual_str>' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors\n    class vector : protected _Vector_base<_Tp, _Alloc>\n```"
  },
  {
   "t": "2023-08-07T17:22:01Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1284664601,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1284664601\n\n[quoted text omitted]\nThanks, added"
  },
  {
   "t": "2023-08-07T18:03:24Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "7f883b33bb89205a9d00c2d20d363a36a0167c7c"
  },
  {
   "t": "2023-08-07T18:06:51Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "7f883b33bb89205a9d00c2d20d363a36a0167c7c",
   "text": "Updated 9e80d0b754a28733c79a52c8e0431616c31d071c -> 7f883b33bb89205a9d00c2d20d363a36a0167c7c ([`pr/bresult2.39`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.39) -> [`pr/bresult2.40`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.40), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.39..pr/bresult2.40)) responding to new review comments and also making some internal changes within the PR to reduce unnecessary diffs between commits."
  },
  {
   "t": "2023-08-07T18:39:11Z",
   "kind": "comment",
   "who": "jonatack",
   "assoc": "MEMBER",
   "text": "ACK 7f883b33bb89205a9d00c2d20d363a36a0167c7c"
  },
  {
   "t": "2023-08-11T13:36:49Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "Style nit: Missing space."
  },
  {
   "t": "2023-08-29T07:30:50Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "This line is missing test coverage. It could be achieved with the following diff (though there might be a more elegant way to achieve this):\n```diff\n-util::Result<int, FnError> AccumulateFn(bool success)\n+util::Result<int, FnError> AccumulateFn(bool success, bool init_success)\n {\n-    util::Result<int, FnError> result;\n+    util::Result<int, FnError> result = IntFailFn(0, init_success);\n     util::Result<int> x = MultiWarnFn(1) >> result;\n     BOOST_REQUIRE(x);\n     util::Result<int> y = MultiWarnFn(2) >> result;\n@@ -195,8 +195,10 @@ BOOST_AUTO_TEST_CASE(check_returned)\n     ExpectFail(EnumFailFn(ERR2), Untranslated(\"enum fail.\"), ERR2);\n     ExpectFail(ChainedFailFn(ERR1, 5), Untranslated(\"chained fail. enum fail. warn.\"), 5);\n     ExpectSuccess(MultiWarnFn(3), Untranslated(\"warn 0. warn 1. warn 2.\"), 3);\n-    ExpectSuccess(AccumulateFn(true), Untranslated(\"warn 0. warn 0. warn 1. int 3 warn.\"), 3);\n-    ExpectFail(AccumulateFn(false), Untranslated(\"int 3 error. warn 0. warn 0. warn 1.\"), ERR1);\n+    ExpectSuccess(AccumulateFn(true, true), Untranslated(\"int 0 warn. warn 0. warn 0. warn 1. int 3 warn.\"), 3);\n+    ExpectFail(AccumulateFn(false, true), Untranslated(\"int 3 error. int 0 warn. warn 0. warn 0. warn 1.\"), ERR1);\n+    ExpectSuccess(AccumulateFn(true, false), Untranslated(\"int 0 error. warn 0. warn 0. warn 1. int 3 warn.\"), 3);\n+    ExpectFail(AccumulateFn(false, false), Untranslated(\"int 0 error. int 3 error. warn 0. warn 0. warn 1.\"), ERR1);\n     ExpectSuccess(TruthyFalsyFn(0, true), {}, 0);\n     ExpectFail(TruthyFalsyFn(0, false), Untranslated(\"failure value 0.\"), 0);\n     ExpectSuccess(TruthyFalsyFn(1, true), {}, 1);\n```"
  },
  {
   "t": "2023-08-29T07:34:43Z",
   "kind": "review",
   "who": "sedited",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "7f883b33bb89205a9d00c2d20d363a36a0167c7c",
   "text": "ACK 7f883b33bb89205a9d00c2d20d363a36a0167c7c"
  },
  {
   "t": "2023-08-29T18:51:28Z",
   "kind": "comment",
   "who": "achow101",
   "assoc": "MEMBER",
   "text": "ACK 7f883b33bb89205a9d00c2d20d363a36a0167c7c"
  },
  {
   "t": "2023-08-29T18:54:26Z",
   "kind": "comment",
   "who": "achow101",
   "assoc": "MEMBER",
   "text": "Silent merge conflict:\n\n```\nIn file included from ../../../src/wallet/coinselection.h:16,\n                 from ../../../src/wallet/test/fuzz/coinselection.cpp:12:\n../../../src/util/result.h: In instantiation of \u2018void util::detail::ResultBase<T, F>::ConstructValue(Args&& ...) [with Args = {util::Result<wallet::SelectionResult, void>&}; T = wallet::SelectionResult; F = void]\u2019:\n../../../src/util/result.h:141:34:   required from \u2018static void util::detail::ResultBase<void, F>::ConstructResult(Result&, Args&& ...) [with bool Failure = false; Result = util::Result<wallet::SelectionResult>; Args = {util::Result<wallet::SelectionResult, void>&}; F = void]\u2019\n../../../src/util/result.h:295:58:   required from \u2018util::Result<T, F>::Result(Args&& ...) [with Args = {util::Result<wallet::SelectionResult, void>&}; T = wallet::SelectionResult; F = void]\u2019\n../../../src/wallet/test/fuzz/coinselection.cpp:152:95:   required from here\n../../../src/util/result.h:243:43: error: no matching function for call to \u2018wallet::SelectionResult::SelectionResult(<brace-enclosed initializer list>)\u2019\n  243 |     void ConstructValue(Args&&... args) { new (&m_value) T{std::forward<Args>(args)...}; }\n      |                                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n../../../src/wallet/coinselection.h:352:14: note: candidate: \u2018wallet::SelectionResult::SelectionResult(CAmount, wallet::SelectionAlgorithm)\u2019\n  352 |     explicit SelectionResult(const CAmount target, SelectionAlgorithm algo)\n      |              ^~~~~~~~~~~~~~~\n../../../src/wallet/coinselection.h:352:14: note:   candidate expects 2 arguments, 1 provided\n../../../src/wallet/coinselection.h:324:8: note: candidate: \u2018wallet::SelectionResult::SelectionResult(const wallet::SelectionResult&)\u2019\n  324 | struct SelectionResult\n      |        ^~~~~~~~~~~~~~~\n../../../src/wallet/coinselection.h:324:8: note:   no known conversion for argument 1 from \u2018util::Result<wallet::SelectionResult>\u2019 to \u2018const wallet::SelectionResult&\u2019\n../../../src/wallet/coinselection.h:324:8: note: candidate: \u2018wallet::SelectionResult::SelectionResult(wallet::SelectionResult&&)\u2019\n../../../src/wallet/coinselection.h:324:8: note:   no known conversion for argument 1 from \u2018util::Result<wallet::SelectionResult>\u2019 to \u2018wallet::SelectionResult&&\u2019\nIn file included from /usr/include/c++/13.2.1/memory:69,\n                 from ../../../src/serialize.h:17,\n                 from ../../../src/policy/feerate.h:10,\n                 from ../../../src/wallet/test/fuzz/coinselection.cpp:5:\n/usr/include/c++/13.2.1/bits/stl_uninitialized.h: In instantiation of \u2018constexpr bool std::__check_constructible() [with _ValueType = util::Result<wallet::SelectionResult>; _Tp = const util::Result<wallet::SelectionResult>&]\u2019:\n/usr/include/c++/13.2.1/bits/stl_uninitialized.h:182:4:   required from \u2018_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const util::Result<wallet::SelectionResult>*; _ForwardIterator = util::Result<wallet::SelectionResult>*]\u2019\n/usr/include/c++/13.2.1/bits/stl_uninitialized.h:373:37:   required from \u2018_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, allocator<_Tp>&) [with _InputIterator = const util::Result<wallet::SelectionResult>*; _ForwardIterator = util::Result<wallet::SelectionResult>*; _Tp = util::Result<wallet::SelectionResult>]\u2019\n/usr/include/c++/13.2.1/bits/stl_vector.h:1692:33:   required from \u2018void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const util::Result<wallet::SelectionResult>*; _Tp = util::Result<wallet::SelectionResult>; _Alloc = std::allocator<util::Result<wallet::SelectionResult> >]\u2019\n/usr/include/c++/13.2.1/bits/stl_vector.h:679:21:   required from \u2018std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = util::Result<wallet::SelectionResult>; _Alloc = std::allocator<util::Result<wallet::SelectionResult> >; allocator_type = std::allocator<util::Result<wallet::SelectionResult> >]\u2019\n../../../src/wallet/test/fuzz/coinselection.cpp:152:95:   required from here\n/usr/include/c++/13.2.1/bits/stl_uninitialized.h:90:56: error: static assertion failed: result type must be constructible from input type\n   90 |       static_assert(is_constructible<_ValueType, _Tp>::value,\n      |                                                        ^~~~~\n/usr/include/c++/13.2.1/bits/stl_uninitialized.h:90:56: note: \u2018std::integral_constant<bool, false>::value\u2019 evaluates to false\nmake[2]: *** [Makefile:16569: wallet/test/fuzz/test_fuzz_fuzz-coinselection.o] Error 1\n```"
  },
  {
   "t": "2023-08-30T13:24:26Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": null,
   "text": "in https://github.com/bitcoin/bitcoin/commit/03595104ccda64f301cac217d7de9aae69c0de67: clang-format new code to reduce this diff here?"
  },
  {
   "t": "2023-08-30T13:29:19Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "in https://github.com/bitcoin/bitcoin/commit/03595104ccda64f301cac217d7de9aae69c0de67: Doesn't matter, but could add `contexpr` here, or remove it above, for consistency, if it compiles?"
  },
  {
   "t": "2023-08-30T13:32:15Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "in https://github.com/bitcoin/bitcoin/commit/03595104ccda64f301cac217d7de9aae69c0de67: Is there a unit test for this method? I am thinking about a test to check what happens when an error-result is `Set` a value-result, and vice-versa."
  },
  {
   "t": "2023-08-30T13:33:02Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "in https://github.com/bitcoin/bitcoin/commit/03595104ccda64f301cac217d7de9aae69c0de67: Why inline? IIUC every member is inline, so this seems confusing, no?\n\nFrom the usage below it looks like this is `static` for some reason? Is `inline friend` an alias for `static friend`?"
  },
  {
   "t": "2023-08-30T13:36:19Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "in https://github.com/bitcoin/bitcoin/commit/03595104ccda64f301cac217d7de9aae69c0de67: Obviously doesn't matter, but if there is an alternative to say the same without `c_str()`, I'd prefer that :sweat_smile:"
  },
  {
   "t": "2023-08-30T13:57:00Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit in b21e2b067e28e49a289e55a1bd25f67a7c342f76: The self-include must be in the first line and first section to catch missing includes."
  },
  {
   "t": "2023-08-30T13:57:23Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit in b21e2b067e28e49a289e55a1bd25f67a7c342f76: `2022-present` or no year for new code to avoid having to ever touch this again?"
  },
  {
   "t": "2023-08-30T14:02:11Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit in https://github.com/bitcoin/bitcoin/commit/b21e2b067e28e49a289e55a1bd25f67a7c342f76: Are the `&&` on the right side needed? IIUC this should only affect `Result& m_result;`, which should be equal to `Result && & m_result;`, no?"
  },
  {
   "t": "2023-08-30T14:07:32Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit in https://github.com/bitcoin/bitcoin/commit/b21e2b067e28e49a289e55a1bd25f67a7c342f76: Missing `assert(m_info)` to avoid UB, no?"
  },
  {
   "t": "2023-08-30T14:11:48Z",
   "kind": "review",
   "who": "maflcko",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "7f883b33bb89205a9d00c2d20d363a36a0167c7c",
   "text": "left some nits/questions. Feel free to ignore.\n\nreview ACK 7f883b33bb89205a9d00c2d20d363a36a0167c7c \ud83d\udd73\n\nShow signature\n\nSignature:\n\n```\nuntrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm \"${path_to_any_empty_file}\" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x \"${path_to_this_whole_four_line_signature_blob}\"\nRUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=\ntrusted comment: review ACK 7f883b33bb89205a9d00c2d20d363a36a0167c7c \ud83d\udd73\nDXdFmPbNLbWwTTSe/r0eJM/R9zvFrppA/gKmtEb5GH8jQwPbsPAsyPCB50Bm3n6kNKRUxcLFgHTIPbfDn0E9CQ==\n```"
  },
  {
   "t": "2023-09-05T19:19:16Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1310327644,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1310327644\n\n[quoted text omitted]\nJust leaving alone for now. The \"present\" idea is interesting but doesn't seem right. I'd expect \"present\" to mean \"when I'm writing this,\" or \"when you're reading this,\" not \"when this code was last changed,\" which is what we want. Would be happy to drop the year or drop the whole line though."
  },
  {
   "t": "2023-09-05T19:19:23Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1310327102,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1310327102\n\n[quoted text omitted]\nMakes sense, moved"
  },
  {
   "t": "2023-09-05T19:19:30Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1310295516,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1310295516\n\n[quoted text omitted]\nMakes sense, switched to LogPrintf"
  },
  {
   "t": "2023-09-05T19:19:36Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1310334699,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1310334699\n\n[quoted text omitted]\nGood catch, dropped this."
  },
  {
   "t": "2023-09-05T19:19:51Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1310285158,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1310285158\n\n[quoted text omitted]\nGood catch, done."
  },
  {
   "t": "2023-09-05T19:19:59Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1308342946,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1308342946\n\n[quoted text omitted]\nThanks, I added a test just calling the `Set` method to cover these branches. Suggestion to modify the AccumulateFn function instead was good, too, just seemed more complicated."
  },
  {
   "t": "2023-09-05T19:20:06Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1310341914,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1310341914\n\n[quoted text omitted]\nThis won't be UB unless the assert is disabled because the assert is checking that m_info is non-null and contains a failure value (see operator bool above)"
  },
  {
   "t": "2023-09-05T19:20:12Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 1310277702,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1310277702\n\n[quoted text omitted]\nI can do it if there's another request, but I think simple accessor methods are more readable if declarations are on the left, implementations are on the right, to make it easier to find relevant information and notice differences between functions."
  },
  {
   "t": "2023-09-05T19:20:33Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1310289598,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1310289598\n\n[quoted text omitted]\nGood suggestion. Added a test to exercise the Set() method with success & failure values."
  },
  {
   "t": "2023-09-05T19:20:39Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1291349874,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1291349874\n\n[quoted text omitted]\nThanks, fixed"
  },
  {
   "t": "2023-09-05T19:31:06Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1310290697,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1310290697\n\n[quoted text omitted]\nThis is just a friend function that is able to access private fields of the Result class, not a member. So I think inline was required to avoid duplicate symbol errors from the linker. I would have preferred to just make the `ErrorString` function a friend function directly, but this did not seem to be possible because it has template parameters, so I declared `_ErrorString` to be a friend function which can called by `ErrorString` to specify the template parameters.\n\nThis complexity goes away later when GetWarnings() / GetErrors() accessors are added. My main goal for all this is just to make the Result class a container for error strings, and keep any code dealing with the strings separate."
  },
  {
   "t": "2023-09-06T17:58:05Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "956bec1ecadcfef13e16f1364ae3a7043ff50e48"
  },
  {
   "t": "2023-09-06T18:02:36Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "956bec1ecadcfef13e16f1364ae3a7043ff50e48",
   "text": "Rebased 7f883b33bb89205a9d00c2d20d363a36a0167c7c -> 956bec1ecadcfef13e16f1364ae3a7043ff50e48 ([`pr/bresult2.40`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.40) -> [`pr/bresult2.41`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.41), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.40-rebase..pr/bresult2.41)) to fix silent conflict with #27585, and made many suggested improvements"
  },
  {
   "t": "2023-09-06T19:19:59Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "Nice, Re-ACK 956bec1ecadcfef13e16f1364ae3a7043ff50e48"
  },
  {
   "t": "2023-10-18T19:24:37Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "29f6cfdabecbdecafc52ccc86425a1c7bb7f5c40"
  },
  {
   "t": "2023-10-18T19:27:30Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Rebased 956bec1ecadcfef13e16f1364ae3a7043ff50e48 -> 29f6cfdabecbdecafc52ccc86425a1c7bb7f5c40 ([`pr/bresult2.41`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.41) -> [`pr/bresult2.42`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.42), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.41-rebase..pr/bresult2.42)) due to silent conflict with #27596"
  },
  {
   "t": "2023-10-19T06:01:48Z",
   "kind": "review",
   "who": "sedited",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "f158686962e1a229d0382c739b78cd9644aa7ada",
   "text": "Re-ACK 29f6cfdabecbdecafc52ccc86425a1c7bb7f5c40\n\nChanges are resolving a simple silent conflict and adapting for the new clang-tidy lint case."
  },
  {
   "t": "2023-10-25T09:11:34Z",
   "kind": "comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "text": "Did you compile each commit locally and ran the tests? See CI:\n\n```\ntest/result_tests.cpp(112): error: in \"result_tests/check_set\": check util::ErrorString(result) == str has failed [bilingual_str('' , '') != bilingual_str('error' , 'error')]"
  },
  {
   "t": "2023-10-26T00:48:05Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "f158686962e1a229d0382c739b78cd9644aa7ada"
  },
  {
   "t": "2023-10-26T00:54:34Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-1778841023\n[quoted text omitted]\n\nThanks, I didn't realize the test was broken in earlier commits. I backported it further and got it working in all commits with no changes to the final diff.\n\nUpdated 29f6cfdabecbdecafc52ccc86425a1c7bb7f5c40 -> f158686962e1a229d0382c739b78cd9644aa7ada ([`pr/bresult2.42`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.42) -> [`pr/bresult2.43`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.43), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.42..pr/bresult2.43)) fixing test failure in intermediate commit 96667abecbd9c0e185fb4914897cc6ec07b39d9c (https://github.com/bitcoin/bitcoin/actions/runs/6565613863/job/17834513251?pr=25665)"
  },
  {
   "t": "2023-10-26T11:34:04Z",
   "kind": "review",
   "who": "sedited",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "f158686962e1a229d0382c739b78cd9644aa7ada",
   "text": "Re-ACK f158686962e1a229d0382c739b78cd9644aa7ada"
  },
  {
   "t": "2024-01-24T16:52:25Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "f822ac9a24d684937f1258da89812e99c4b205ba"
  },
  {
   "t": "2024-01-24T19:35:46Z",
   "kind": "review",
   "who": "sedited",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "f822ac9a24d684937f1258da89812e99c4b205ba",
   "text": "Re-ACK f822ac9a24d684937f1258da89812e99c4b205ba"
  },
  {
   "t": "2024-02-05T16:41:28Z",
   "kind": "review",
   "who": "hernanmarino",
   "assoc": "CONTRIBUTOR",
   "state": "APPROVED",
   "commit": "f822ac9a24d684937f1258da89812e99c4b205ba",
   "text": "re ack f822ac9a24d684937f1258da89812e99c4b205ba"
  },
  {
   "t": "2024-02-13T09:17:44Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "I think there is a silent merge conflict on the first commit."
  },
  {
   "t": "2024-02-13T10:57:40Z",
   "kind": "comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "text": "At the risk of having asked this previously: Why not postpone the 1c7d8be commit to a later pull? This would also make review easier, because the code change comes with the changes to actually use it in real code, outside of just unit tests."
  },
  {
   "t": "2024-02-21T18:06:51Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nSure, I'm happy to split up this PR.\n\nI don't think this idea came up before (or I can't remember if it did). From my perspective commit 1c7d8bea4f0b25f9adb89e402a130fa114220494 is basically the point of this PR, and the other commits are less important. Usually when we have errors we want to return descriptive error strings and fail, not return error codes and branch. So I think the part of this PR that returns better error and warning messages is more interesting than the part that returns error codes.\n\nAs far as using the changes in real code, not just tests, I opened #25722 at the same time as this PR to start using it throughout wallet code, so there are actually a _lot_ of usages to look at outside of tests. The usage patterns in the test are also meant to be realistic, with test functions returning errors and warnings, accumulating them, and returning them as part of their own Results .\n\nI don't think it hurts anything to split this PR up, so I can try that, **but I'm also curious if other reviewers want me to split this or leave it alone.** According to draftbot this has 1 current ack and 6 stale acks, and it seems like this needs rebase due to a silent conflict. So maybe the problem is more that it hasn't gotten enough simultaneous acks at the same time, and that I've been lazy about rebasing, than that it should be split up."
  },
  {
   "t": "2024-02-21T19:16:51Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "4ec6b060a80045049adc53b4db0b0837ba169cfc"
  },
  {
   "t": "2024-02-21T19:18:21Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Rebased f822ac9a24d684937f1258da89812e99c4b205ba -> 4ec6b060a80045049adc53b4db0b0837ba169cfc ([`pr/bresult2.44`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.44) -> [`pr/bresult2.45`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.45), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.44-rebase..pr/bresult2.45)) due to silent conflict with #27877"
  },
  {
   "t": "2024-02-21T22:55:09Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "20556598140030237861d21a61f646252002ddff"
  },
  {
   "t": "2024-02-21T22:56:02Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Updated 4ec6b060a80045049adc53b4db0b0837ba169cfc -> 20556598140030237861d21a61f646252002ddff ([`pr/bresult2.45`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.45) -> [`pr/bresult2.46`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.46), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.45..pr/bresult2.46)) making a few changes to improve compatibility with #26022"
  },
  {
   "t": "2024-02-22T09:30:02Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "If I'm reading this right, not specifying a failure value will lead to it being default constructed, so this will have a value of `ChainstateLoadError::FAILURE`. Could omitting a failure value be a compile-time error if the failure type is non-void?"
  },
  {
   "t": "2024-02-22T11:14:45Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1498934743,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1498934743\n\n[quoted text omitted]\nNice catch. That's an interesting idea but it seems extreme because it would make it difficult to call a failure value's default constructor, and impossible to call it the class is not copyable or movable.\n\nI think in general if you don't want a failure value to be default-constructed you should pass a failure type that doesn't have a default constructor. But we could add a check for specifically for enums. The following seems to work:\n\n```diff\n--- a/src/util/result.h\n+++ b/src/util/result.h\n@@ -136,6 +136,7 @@ protected:\n     static void ConstructResult(Result& result, Args&&... args)\n     {\n         if constexpr (Failure) {\n+            static_assert(sizeof...(args) > 0 || !std::is_enum_v<F>, \"Refusing to default-construct enum failure value, please specify explicit value\");\n             result.Info().failure.emplace(std::forward<Args>(args)...);\n         } else {\n             result.ConstructValue(std::forward<Args>(args)...);\n\n```"
  },
  {
   "t": "2024-02-22T11:35:00Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "cdf7bb17563b92e48b0576a0975c168619c5aa34"
  },
  {
   "t": "2024-02-22T11:47:58Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1498934743,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1499084153\n\n[quoted text omitted]\nLatest push adds a slightly more general check that doesn't allow any scalar failure value (int, float, enum, or pointer) to be default constructed. Could adjust this condition or make it an option if default-constructing these types of values seems useful in the future.\n\nThis check is arguably too heavy handed because it is enforcing that the `result.GetFailure()` value is not default-constructed even though it technically has a default constructor. Even without the check, the Result object would be still constructed in a failure state and `if (result)` and `if (result.has_value())` would be false.  But it seems safest to start off requiring explicit scalar failure values in case they were omitted by accident."
  },
  {
   "t": "2024-02-22T11:54:40Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "cdf7bb17563b92e48b0576a0975c168619c5aa34",
   "text": "Updated 20556598140030237861d21a61f646252002ddff -> cdf7bb17563b92e48b0576a0975c168619c5aa34 ([`pr/bresult2.46`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.46) -> [`pr/bresult2.47`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.47), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.46..pr/bresult2.47)) adding a check requiring scalar failure values to be specified explicitly (https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1498934743)"
  },
  {
   "t": "2024-02-22T13:05:47Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1498934743,
   "text": "Nice, the compile-time check can be tested with:\n```diff\ndiff --git a/src/test/result_tests.cpp b/src/test/result_tests.cpp\nindex 261e1f0b9b..053b45fceb 100644\n--- a/src/test/result_tests.cpp\n+++ b/src/test/result_tests.cpp\n@@ -28,0 +29,10 @@ BOOST_AUTO_TEST_SUITE(result_tests)\n+enum class DummyError {\n+    FAILURE_1,\n+    FAILURE_2,\n+    FAILURE_3,\n+};\n+\n+util::Result<void, DummyError> VoidDummyError() {\n+    return util::Error{Untranslated(\"void fail.\")};\n+}\n+\n@@ -203,0 +214,3 @@ BOOST_AUTO_TEST_CASE(check_returned)\n+\n+    auto res{VoidDummyError()};\n+    BOOST_CHECK(res.GetFailure() == DummyError::FAILURE_1);\n```"
  },
  {
   "t": "2024-02-22T13:20:21Z",
   "kind": "review",
   "who": "sedited",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "cdf7bb17563b92e48b0576a0975c168619c5aa34",
   "text": "Re-ACK cdf7bb17563b92e48b0576a0975c168619c5aa34"
  },
  {
   "t": "2024-03-22T22:02:08Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Converting to draft. Working on #29700 and #29642 made me want to implement more improvements to the Result class (308e38e94fcac5aedf8ed1247a096c0d271fa666 if curious)"
  },
  {
   "t": "2024-03-26T18:44:07Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "efb463788f8be12bcf2bacfbf99cd2308fb54c9e"
  },
  {
   "t": "2024-03-26T19:23:22Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Updated cdf7bb17563b92e48b0576a0975c168619c5aa34 -> efb463788f8be12bcf2bacfbf99cd2308fb54c9e ([`pr/bresult2.47`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.47) -> [`pr/bresult2.48`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.48), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.47..pr/bresult2.48)) with improvements for https://github.com/bitcoin/bitcoin/pull/29700 and https://github.com/bitcoin/bitcoin/pull/29642.\n\nThe changes are:\n\n- The Result::Set() method is renamed Result::Update() and now has ability to merge success and failure values from different results together instead of just replacing them. This is used in [#29700](https://github.com/bitcoin/bitcoin/pull/29700) to bubble up AbortFailure values indicating whether or not AbortNode calls happened as part of failures.\n- The result class now takes a generic MessagesType parameter and isn't hardcoded to use vector\\<blingual_str>. This gets rid of some complexity in the implementation and lets it handle SuccessType FailureType and MessagesType fields in a more consistent way."
  },
  {
   "t": "2024-03-26T20:30:47Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "110bccc3715a40d68cb4a09fce9384ee45ac4f58"
  },
  {
   "t": "2024-03-26T21:27:46Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "6adeafab68a410b663d60045415f1fb8ea7c273a"
  },
  {
   "t": "2024-03-27T03:00:18Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "d4579e303b014c1522a054bb307cda6e225d45c5"
  },
  {
   "t": "2024-03-28T16:34:08Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "7a4741eaf892646e9d02e440c39fbbfa03f29fc3"
  },
  {
   "t": "2024-04-04T21:17:04Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "Reviewers might be wondering what the benefits of  the ResultTraits are. They are useful for potential future extensions of the move behaviour: https://github.com/bitcoin/bitcoin/pull/29700/commits/3951afc3b708326cea653951ef331d8f96a28682 ."
  },
  {
   "t": "2024-04-04T21:30:34Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": null,
   "text": "I have not quite grasped yet what the immediate benefit of these more generic decorators on the Messages are. Am I missing something from your draft PRs? I like shiny generics though, so to me a clear benefit of this approach would be to future-proof the result type. I was asking myself if this could be a bit more readable if instead of a forward-declared struct, the `MessagesTraits` were made a concept. After implementing it, I think it is indeed a bit easier to parse at the call site. It also potentially allows the user to define their own types for the warnings and errors fields like this: https://github.com/TheCharlatan/bitcoin/commit/f5e5442cf80c58c0509562d8c689243c8d9becf2 . Could this also be leveraged in place of your future addition of an info type?"
  },
  {
   "t": "2024-04-18T13:58:41Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": 1552474458,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1552474458\n\n[quoted text omitted]\nThe benefit is letting the `Result` struct work with any possible `MessagesType` without placing requirements on it. The PR provides a simple default type to hold error and warning messages:\n\n```c++\nstruct Messages {\n    std::vector<bilingual_str> errors{};\n    std::vector<bilingual_str> warnings{};\n};\n```\n\nThe type was defined this way because we currently have wallet code which returns lists of errors and warnings and wallet RPCs which return them in separate arrays. But I don't want to hardcode the `Result` type to use this particular struct, because it shouldn't care about `MessagesType` internals and because other representations of errors and warnings are reasonable too. Maybe a representation that preserved the relative order of errors and warnings instead of keeping them in separate arrays would be good. Maybe a representation that discarded translated strings, or only held errors without allowing warnings, or used a different data structure would be good. The `MessagesTraits` class lets the `Result` class not care about these things and work with any messages type.\n\n[quoted text omitted]\nThat is interesting to see but I'm not sure it is more readable if you are familiar with the traits pattern. Another drawback is it requires every `MessagesType` to be a struct that has AddError, AddWarning, HasMessages, ErrorType, and WarningType members, which is not the case right now. Right now `MessagesType` could be any type including the simple `Messages` struct above, a plain string, even something like a bool or a custom type without public members. The suggestion is also +57 -36 lines excluding tests, so it doesn't really seem like a simplification, and the more complicated `Messages` struct definition also does not seem good to expose."
  },
  {
   "t": "2024-04-18T14:00:07Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1552459477,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1552459477\n\n[quoted text omitted]\nThanks I added a comment to the traits struct to make this clearer. Traits are an old pattern in c++ and are commonly used. The standard library has std::allocator_traits, std::iterator_traits, std::pointer_traits, std::hash, std::formatter, std::tuple_element, and std::tuple_size trait structs which allow generic library functions to work with user defined types. They all work the same way, by defining a template struct in the library that user code can specialize to control the behavior of library functions when called with custom types. This is an old explanation of traits which may be helpful: http://erdani.org/publications/traits.html"
  },
  {
   "t": "2024-04-18T16:10:24Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "28e20812109757e307bc29a4adbef8aae90d94a6"
  },
  {
   "t": "2024-04-18T16:24:24Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "28e20812109757e307bc29a4adbef8aae90d94a6",
   "text": "Updated 7a4741eaf892646e9d02e440c39fbbfa03f29fc3 -> 28e20812109757e307bc29a4adbef8aae90d94a6 ([`pr/bresult2.52`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.52) -> [`pr/bresult2.53`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.53), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.52..pr/bresult2.53)) just improving some comments"
  },
  {
   "t": "2024-04-18T19:13:07Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Converted to draft since first 2 commits were moved to a separate PR, #29906\n\n---\n\nRebased 28e20812109757e307bc29a4adbef8aae90d94a6 -> 990f9d65c5e15ab26c341c21829a697f5cddfa6c ([`pr/bresult2.53`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.53) -> [`pr/bresult2.54`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.54), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.53-rebase..pr/bresult2.54)) on top of updated base PR #29906, also adding more comments, simplifying code a little bit by util::MoveFrom helper, and using `Update()` method more places for consistency."
  },
  {
   "t": "2024-04-24T19:55:39Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "990f9d65c5e15ab26c341c21829a697f5cddfa6c"
  },
  {
   "t": "2024-04-26T00:54:31Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "55d7de92bbbe035c1833c89f885af14e5b243932"
  },
  {
   "t": "2024-04-26T12:05:08Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "0c8a1bb1445e8b88bb0ad9d440830ef215e9e8f8"
  },
  {
   "t": "2024-04-26T13:22:13Z",
   "kind": "comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "text": "Posting my response to part of [your comment on #29906](https://github.com/bitcoin/bitcoin/pull/29906#issuecomment-2078452007) here, since `Update()` is no longer relevant to that PR:\n\n[quoted text omitted]\nHad just a quick look, but this looks like how I'd expect `Update()` to be used, indeed.\n\n[quoted text omitted]\nI don't think this is good usage of `Update()`, since there is no chaining happening here. I would find list initialization more readable and less error-prone:\n\ngit diff on 1376583dca\n\n```diff\ndiff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp\nindex 0671f75515..8cc43c53e5 100644\n--- a/src/node/chainstate.cpp\n+++ b/src/node/chainstate.cpp\n@@ -40,7 +40,6 @@ static util::Result<InterruptResult, ChainstateLoadError> CompleteChainstateInit\n     const CacheSizes& cache_sizes,\n     const ChainstateLoadOptions& options) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)\n {\n-    util::Result<InterruptResult, ChainstateLoadError> result;\n     auto& pblocktree{chainman.m_blockman.m_block_tree_db};\n     // new BlockTreeDB tries to delete the existing file, which\n     // fails if it's still open from the previous loop. Close it first:\n@@ -61,8 +60,7 @@ static util::Result<InterruptResult, ChainstateLoadError> CompleteChainstateInit\n     }\n\n     if (chainman.m_interrupt) {\n-        result.Update(Interrupted{});\n-        return result;\n+        return Interrupted{};\n     }\n\n     // LoadBlockIndex will load m_have_pruned if we've ever removed a\n@@ -71,26 +69,23 @@ static util::Result<InterruptResult, ChainstateLoadError> CompleteChainstateInit\n     // From here on, fReindex and options.reindex values may be different!\n     if (!chainman.LoadBlockIndex()) {\n         if (chainman.m_interrupt) {\n-            result.Update(Interrupted{});\n+            return Interrupted{};\n         } else {\n-            result.Update({util::Error{_(\"Error loading block database\")}, ChainstateLoadError::FAILURE});\n+            return {util::Error{_(\"Error loading block database\")}, ChainstateLoadError::FAILURE};\n         }\n-        return result;\n     }\n\n     if (!chainman.BlockIndex().empty() &&\n             !chainman.m_blockman.LookupBlockIndex(chainman.GetConsensus().hashGenesisBlock)) {\n         // If the loaded chain has a wrong genesis, bail out immediately\n         // (we're likely using a testnet datadir, or the other way around).\n-        result.Update({util::Error{_(\"Incorrect or no genesis block found. Wrong datadir for network?\")}, ChainstateLoadError::FAILURE_INCOMPATIBLE_DB});\n-        return result;\n+        return {util::Error{_(\"Incorrect or no genesis block found. Wrong datadir for network?\")}, ChainstateLoadError::FAILURE_INCOMPATIBLE_DB};\n     }\n\n     // Check for changed -prune state.  What we are concerned about is a user who has pruned blocks\n     // in the past, but is now trying to run unpruned.\n     if (chainman.m_blockman.m_have_pruned && !options.prune) {\n-        result.Update({util::Error{_(\"You need to rebuild the database using -reindex to go back to unpruned mode.  This will redownload the entire blockchain\")}, ChainstateLoadError::FAILURE});\n-        return result;\n+        return {util::Error{_(\"You need to rebuild the database using -reindex to go back to unpruned mode.  This will redownload the entire blockchain\")}, ChainstateLoadError::FAILURE};\n     }\n\n     // At this point blocktree args are consistent with what's on disk.\n@@ -98,8 +93,7 @@ static util::Result<InterruptResult, ChainstateLoadError> CompleteChainstateInit\n     // (otherwise we use the one already on disk).\n     // This is called again in ImportBlocks after the reindex completes.\n     if (!fReindex && !chainman.ActiveChainstate().LoadGenesisBlock()) {\n-        result.Update({util::Error{_(\"Error initializing block database\")}, ChainstateLoadError::FAILURE});\n-        return result;\n+        return {util::Error{_(\"Error initializing block database\")}, ChainstateLoadError::FAILURE};\n     }\n\n     auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {\n@@ -133,17 +127,15 @@ static util::Result<InterruptResult, ChainstateLoadError> CompleteChainstateInit\n         // Refuse to load unsupported database format.\n         // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate\n         if (chainstate->CoinsDB().NeedsUpgrade()) {\n-            result.Update({util::Error{_(\"Unsupported chainstate database format found. \"\n+            return {util::Error{_(\"Unsupported chainstate database format found. \"\n                                          \"Please restart with -reindex-chainstate. This will \"\n                                          \"rebuild the chainstate database.\")},\n-                                       ChainstateLoadError::FAILURE_INCOMPATIBLE_DB});\n-            return result;\n+                                       ChainstateLoadError::FAILURE_INCOMPATIBLE_DB};\n         }\n\n         // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate\n         if (!chainstate->ReplayBlocks()) {\n-            result.Update({util::Error{_(\"Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.\")}, ChainstateLoadError::FAILURE});\n-            return result;\n+            return {util::Error{_(\"Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.\")}, ChainstateLoadError::FAILURE};\n         }\n\n         // The on-disk coinsdb is now in a good state, create the cache\n@@ -153,8 +145,7 @@ static util::Result<InterruptResult, ChainstateLoadError> CompleteChainstateInit\n         if (!is_coinsview_empty(chainstate)) {\n             // LoadChainTip initializes the chain based on CoinsTip()'s best block\n             if (!chainstate->LoadChainTip()) {\n-                result.Update({util::Error{_(\"Error initializing block database\")}, ChainstateLoadError::FAILURE});\n-                return result;\n+                return {util::Error{_(\"Error initializing block database\")}, ChainstateLoadError::FAILURE};\n             }\n             assert(chainstate->m_chain.Tip() != nullptr);\n         }\n@@ -164,9 +155,8 @@ static util::Result<InterruptResult, ChainstateLoadError> CompleteChainstateInit\n         auto chainstates{chainman.GetAll()};\n         if (std::any_of(chainstates.begin(), chainstates.end(),\n                         [](const Chainstate* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {\n-            result.Update({util::Error{strprintf(_(\"Witness data for blocks after height %d requires validation. Please restart with -reindex.\"),\n-                                                 chainman.GetConsensus().SegwitHeight)}, ChainstateLoadError::FAILURE});\n-            return result;\n+            return {util::Error{strprintf(_(\"Witness data for blocks after height %d requires validation. Please restart with -reindex.\"),\n+                                                 chainman.GetConsensus().SegwitHeight)}, ChainstateLoadError::FAILURE};\n         };\n     }\n\n@@ -175,7 +165,7 @@ static util::Result<InterruptResult, ChainstateLoadError> CompleteChainstateInit\n     // on the condition of each chainstate.\n     chainman.MaybeRebalanceCaches();\n\n-    return result;\n+    return {};\n }\n\n util::Result<InterruptResult, ChainstateLoadError> LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes,\n\n```"
  },
  {
   "t": "2024-04-26T15:27:40Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-2079388456\n\n[quoted text omitted]\nThe diff you suggested is actually the way this function was implemented before #29700. The problem is that #29700 updates some validation functions to return `util::Result` instead of `bool`. So instead of `CompleteChainstateInitialization` being a function that just returns a `util::Result` value, it becomes a function that returns a `util::Result` value and also calls other functions returning `util::Result`. Which is the scenario where the `result.Update()` pattern is useful, because it allows returning warning and error messages from functions being called instead of discarding them, so more complete error information is returned by default when a problem happens.\n\nIf you think this pattern is not readable enough or too error prone, we could probably come up with an alternate pattern that doesn't require updating a variable (but may require copying around data more manually). In general, I'd agree that all other things being equal, it's better to initialize variables once than change them over time. But in this case, if the goal is to accumulate error and warning messages, I think a pattern where you declare a single variable at the top of the function holding the messages, and update the variable over the course of the function, and then return the variable at the end is a pretty simple and readable pattern. I'm sure other patterns could work too, though.\n\nI guess I'd want to know if there's another pattern you'd prefer, or what more specific problems you see with the current code."
  },
  {
   "t": "2024-04-27T14:57:01Z",
   "kind": "comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nI see, that was not apparent in the [link](https://github.com/ryanofsky/bitcoin/blob/55d7de92bbbe035c1833c89f885af14e5b243932/src/node/chainstate.cpp#L38-L179) you shared earlier. Would it make sense to do that refactoring in #29700 then, instead of in this PR? Because in this PR, I don't think the change makes a lot of sense on its own.\n\n[quoted text omitted]\nI agree, I think that's a reasonable pattern. For this situation, I would prefer using two functions: `Update()` when chaining is happening, and `Set()`, `Replace()`, `operator=()`, ... when we expect `Result` to be empty. This way, we can more easily identify potential bugs when e.g. `Set()` is used but the `Result` has already had a value assigned to it earlier. Potentially, could even do a run-time assertion (I don't think compile time is possible?).\n\nCombining both would be suitable in this case, I think. Pseudo-code diff (since `Set()` isn't implemented) where we only keep `Update()` for the chaining bits:\n\ngit diff on 4d2c9de249\n\n```diff\ndiff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp\nindex 014f6915ad..bc8d547153 100644\n--- a/src/node/chainstate.cpp\n+++ b/src/node/chainstate.cpp\n@@ -64,7 +64,7 @@ static FlushResult<InterruptResult, ChainstateLoadError> CompleteChainstateIniti\n     }\n\n     if (chainman.m_interrupt) {\n-        result.Update(Interrupted{});\n+        result.Set(Interrupted{});\n         return result;\n     }\n\n@@ -85,14 +85,14 @@ static FlushResult<InterruptResult, ChainstateLoadError> CompleteChainstateIniti\n             !chainman.m_blockman.LookupBlockIndex(chainman.GetConsensus().hashGenesisBlock)) {\n         // If the loaded chain has a wrong genesis, bail out immediately\n         // (we're likely using a testnet datadir, or the other way around).\n-        result.Update({util::Error{_(\"Incorrect or no genesis block found. Wrong datadir for network?\")}, ChainstateLoadError::FAILURE_INCOMPATIBLE_DB});\n+        result.Set({util::Error{_(\"Incorrect or no genesis block found. Wrong datadir for network?\")}, ChainstateLoadError::FAILURE_INCOMPATIBLE_DB});\n         return result;\n     }\n\n     // Check for changed -prune state.  What we are concerned about is a user who has pruned blocks\n     // in the past, but is now trying to run unpruned.\n     if (chainman.m_blockman.m_have_pruned && !options.prune) {\n-        result.Update({util::Error{_(\"You need to rebuild the database using -reindex to go back to unpruned mode.  This will redownload the entire blockchain\")}, ChainstateLoadError::FAILURE});\n+        result.Set({util::Error{_(\"You need to rebuild the database using -reindex to go back to unpruned mode.  This will redownload the entire blockchain\")}, ChainstateLoadError::FAILURE});\n         return result;\n     }\n\n@@ -101,7 +101,7 @@ static FlushResult<InterruptResult, ChainstateLoadError> CompleteChainstateIniti\n     // (otherwise we use the one already on disk).\n     // This is called again in ImportBlocks after the reindex completes.\n     if (!fReindex && !chainman.ActiveChainstate().LoadGenesisBlock()) {\n-        result.Update({util::Error{_(\"Error initializing block database\")}, ChainstateLoadError::FAILURE});\n+        result.Set({util::Error{_(\"Error initializing block database\")}, ChainstateLoadError::FAILURE});\n         return result;\n     }\n\n@@ -136,7 +136,7 @@ static FlushResult<InterruptResult, ChainstateLoadError> CompleteChainstateIniti\n         // Refuse to load unsupported database format.\n         // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate\n         if (chainstate->CoinsDB().NeedsUpgrade()) {\n-            result.Update({util::Error{_(\"Unsupported chainstate database format found. \"\n+            result.Set({util::Error{_(\"Unsupported chainstate database format found. \"\n                                          \"Please restart with -reindex-chainstate. This will \"\n                                          \"rebuild the chainstate database.\")},\n                                        ChainstateLoadError::FAILURE_INCOMPATIBLE_DB});\n@@ -145,7 +145,7 @@ static FlushResult<InterruptResult, ChainstateLoadError> CompleteChainstateIniti\n\n         // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate\n         if (!chainstate->ReplayBlocks()) {\n-            result.Update({util::Error{_(\"Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.\")}, ChainstateLoadError::FAILURE});\n+            result.Set({util::Error{_(\"Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.\")}, ChainstateLoadError::FAILURE});\n             return result;\n         }\n\n@@ -156,7 +156,7 @@ static FlushResult<InterruptResult, ChainstateLoadError> CompleteChainstateIniti\n         if (!is_coinsview_empty(chainstate)) {\n             // LoadChainTip initializes the chain based on CoinsTip()'s best block\n             if (!chainstate->LoadChainTip()) {\n-                result.Update({util::Error{_(\"Error initializing block database\")}, ChainstateLoadError::FAILURE});\n+                result.Set({util::Error{_(\"Error initializing block database\")}, ChainstateLoadError::FAILURE});\n                 return result;\n             }\n             assert(chainstate->m_chain.Tip() != nullptr);\n@@ -167,7 +167,7 @@ static FlushResult<InterruptResult, ChainstateLoadError> CompleteChainstateIniti\n         auto chainstates{chainman.GetAll()};\n         if (std::any_of(chainstates.begin(), chainstates.end(),\n                         [](const Chainstate* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {\n-            result.Update({util::Error{strprintf(_(\"Witness data for blocks after height %d requires validation. Please restart with -reindex.\"),\n+            result.Set({util::Error{strprintf(_(\"Witness data for blocks after height %d requires validation. Please restart with -reindex.\"),\n                                                  chainman.GetConsensus().SegwitHeight)}, ChainstateLoadError::FAILURE});\n             return result;\n         };\n\n```\n\nIt's kind of a similar situation to having a `std::vector<>&`out-parameter that we use here and there in the codebase. When that happens, first you need to check if the vector is supposed to be empty or not. Then, you need to check if it actually _is_ empty. Sometimes we call `.clear()` in the beginning of the function, sometimes we don't. It's just confusing and time consuming and error prone (see e.g. https://github.com/bitcoin/bitcoin/pull/26289). With differentiated `Update()` and `Set()` functions we allow the developer to signal intent, which makes it easier to understand the code and to identify potential bugs (manually or through run-time/fuzzing checks).\n\nI've ranted about this already a bit too long, so please do let me know if you (dis)agree but I'll stop commenting further until I've (re)-reviewed the rest of this PR and I maybe get new insights."
  },
  {
   "t": "2024-05-01T17:39:44Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "db91dbb5a9a0413d6ee22ed6e32d1221d5b6d996"
  },
  {
   "t": "2024-05-01T17:46:45Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "db91dbb5a9a0413d6ee22ed6e32d1221d5b6d996",
   "text": "Rebased 0c8a1bb1445e8b88bb0ad9d440830ef215e9e8f8 -> db91dbb5a9a0413d6ee22ed6e32d1221d5b6d996 ([`pr/bresult2.56`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.56) -> [`pr/bresult2.57`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.57), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.56-rebase..pr/bresult2.57)) after #29906 was merged"
  },
  {
   "t": "2024-05-01T19:26:40Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-2080843513\n\nThanks @stickies-v. I think since `Update()` is not required immediately I might move the first and third commits of this PR to another PR without `Update()`. The only downside will be some churn in the `CompleteChainstateInitialization` function, since I believe at some point it will need to be changed again to use the `Update()` pattern or a similar pattern, when other functions it calls are changed to return `util::Result`.\n\nOn your latest feedback, I think I understand the scenario you are concerned about. It seems like you are worried about future uses of `util::Result` where sometimes completely resetting a result object is useful, and other times updating pieces of the result object is useful. And you want developers to clearly indicate their intent in both cases by calling `Set()` in the former case and `Update()` in the latter case. If developers were required to express their intent this way, it could avoid bugs when existing fields of a result object are unintentionally cleared by a `Set()` call, or unintentionaly left with stale values after an `Update()` call.\n\nI think I might have agreed with that before writing #25722 and #29700. But after writing these PRs, I don't think a `Set` method would be useful in practice. The most straightforward way to write functions that return `util::Result` and also pass along error messages from other functions returning `util::Result` is to use `result.Update()`. The most straightforward way to write functions that just return `util::Result` without forwarding messages from other functions is just to construct separate result objects and not mutate existing objects. I didn't encounter scenarios where code would be clearer or safer if it reset an existing object instead just declaring a new object, or just updating the relevant fields in an existing object.\n\nBasically, I think the `result.Update()` pattern is a safe, simple pattern to follow that was general enough to handle the cases I encountered in #25722 and #29700 without the need the need for set, reset, or assignment. If that statement is not convincing, I understand, and think we could move forward with a smaller PR that does not include `Update()`. You might also be interested to look at a random commit from #25722 and #29700 and see if there's another way you think some of that code should be written. A lot of the code in #25722 especially was not using `result.Update()` pattern initially and was just using separate result objects for everything."
  },
  {
   "t": "2024-06-17T22:57:25Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "b08548336eda489ad5be9e25542d2b73e7606204"
  },
  {
   "t": "2024-06-27T10:47:36Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/util/result.cpp",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": null,
   "text": "Style nit: `{` on new line."
  },
  {
   "t": "2024-06-27T11:11:17Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": null,
   "text": "Nit: Call this DstContructed like in the template declaration?"
  },
  {
   "t": "2024-07-04T17:23:32Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "79a970d4f12458a175317c453e251db7846c3561: I am not really sure, what the point of `Update` here is. A simple `return Interrupted{};` compiles as well. I fail to see why it would be wrong, because the default constructed monostate should not be returned either way.\n\n(Same for all code below)\n\nMy recommendation would be to keep the code as simple as possible and not add complicated features or complication that isn't required.\n\n<!--\n\ncommit fdcb7d752273d83fedfcc9829a9180d72ab87faa\nAuthor: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>\nDate:   Thu Jul 4 20:19:13 2024 +0200\n\n    refactor: Add util::Result failure values\n\ndiff --git a/src/util/result.h b/src/util/result.h\nindex 122a7638fa..50a242f5ce 100644\n--- a/src/util/result.h\n+++ b/src/util/result.h\n@@ -12,8 +12,9 @@\n\n namespace util {\n\n+template <class FailData = bilingual_str>\n struct Error {\n-    bilingual_str message;\n+    FailData message;\n };\n\n //! The util::Result class provides a standard way for functions to return\n@@ -31,13 +32,13 @@ struct Error {\n //! `std::optional<T>` can be updated to return `util::Result<T>` and return\n //! error strings usually just replacing `return std::nullopt;` with `return\n //! util::Error{error_string};`.\n-template <class M>\n+template <class M, class ErrorType = Error<>>\n class Result\n {\n private:\n     using T = std::conditional_t<std::is_same_v<M, void>, std::monostate, M>;\n\n-    std::variant<bilingual_str, T> m_variant;\n+    std::variant<ErrorType, T> m_variant;\n\n     //! Disallow copy constructor, require Result to be moved for efficiency.\n     Result(const Result&) = delete;\n@@ -55,7 +56,7 @@ private:\n public:\n     Result() : m_variant{std::in_place_index_t<1>{}, std::monostate{}} {}  // constructor for void\n     Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {}\n-    Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error.message)} {}\n+    Result(ErrorType error) : m_variant{std::in_place_index_t<0>{}, std::move(error)} {}\n     Result(Result&&) = default;\n     ~Result() = default;\n\n@@ -83,8 +84,10 @@ public:\n         return has_value() ? std::move(value()) : std::forward<U>(default_value);\n     }\n     explicit operator bool() const noexcept { return has_value(); }\n+    const auto& GetFailure() const LIFETIMEBOUND { assert(!has_value()); return std::get<0>(m_variant); }\n     const T* operator->() const LIFETIMEBOUND { return &value(); }\n     const T& operator*() const LIFETIMEBOUND { return value(); }\n+    auto& GetFailure() LIFETIMEBOUND { assert(!has_value()); return std::get<0>(m_variant); }\n     T* operator->() LIFETIMEBOUND { return &value(); }\n     T& operator*() LIFETIMEBOUND { return value(); }\n };\n@@ -92,7 +95,7 @@ public:\n template <typename T>\n bilingual_str ErrorString(const Result<T>& result)\n {\n-    return result ? bilingual_str{} : std::get<0>(result.m_variant);\n+    return result ? bilingual_str{} : std::get<0>(result.m_variant).message;\n }\n } // namespace util"
  },
  {
   "t": "2024-07-05T10:32:53Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1665942681,
   "text": "I wrote a simple patch to make the existing `Result` more flexible (allow inner error types other than `bilingual_str`), for places that want to use something like `std::expected` in code today by using `Result`.\n\nI understand that the `ErrorString` helper won't be working as-is anymore. But that seems fine, because a standalone function can be provided to turn `B` into a string.\n\nI also understand that the approach does not allow for multiple failures, errors, and warnings.\n\nNot sure how to proceed here. Should I submit my patch as alternative pull request (it can be reverted here, if merged sooner)? Or should I backport `std::expected` into a separate header file? Or should I just wait until this pull is merged or C++23 happens, whichever happens earlier?\n\nFor reference, my patch is:\n\n```diff\ncommit fac1bdf332ccb241dbebf7ee421bb885381242ab\nAuthor: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>\nDate:   Fri Jul 5 09:54:12 2024 +0200\n\n    refactor: Add util::Result failure values\n\n    This allows to use an inner error type different than bilingual_str. For\n    example, an enum class.\n\n    The ErrorString helper will not compile in this case, and a GetFailure()\n    method is added to retrieve the error value.\n\ndiff --git a/src/util/result.h b/src/util/result.h\nindex 122a7638fa..038ed6336e 100644\n--- a/src/util/result.h\n+++ b/src/util/result.h\n@@ -12,8 +12,9 @@\n\n namespace util {\n\n+template <class Inner = bilingual_str>\n struct Error {\n-    bilingual_str message;\n+    Inner inner;\n };\n\n //! The util::Result class provides a standard way for functions to return\n@@ -31,13 +32,14 @@ struct Error {\n //! `std::optional<T>` can be updated to return `util::Result<T>` and return\n //! error strings usually just replacing `return std::nullopt;` with `return\n //! util::Error{error_string};`.\n-template <class M>\n+template <class M, class F = bilingual_str>\n class Result\n {\n private:\n     using T = std::conditional_t<std::is_same_v<M, void>, std::monostate, M>;\n+    using Error = Error<F>;\n\n-    std::variant<bilingual_str, T> m_variant;\n+    std::variant<Error, T> m_variant;\n\n     //! Disallow copy constructor, require Result to be moved for efficiency.\n     Result(const Result&) = delete;\n@@ -55,7 +57,7 @@ private:\n public:\n     Result() : m_variant{std::in_place_index_t<1>{}, std::monostate{}} {}  // constructor for void\n     Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {}\n-    Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error.message)} {}\n+    Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error)} {}\n     Result(Result&&) = default;\n     ~Result() = default;\n\n@@ -83,8 +85,10 @@ public:\n         return has_value() ? std::move(value()) : std::forward<U>(default_value);\n     }\n     explicit operator bool() const noexcept { return has_value(); }\n+    const auto& GetFailure() const LIFETIMEBOUND { assert(!has_value()); return std::get<0>(m_variant).inner; }\n     const T* operator->() const LIFETIMEBOUND { return &value(); }\n     const T& operator*() const LIFETIMEBOUND { return value(); }\n+    auto& GetFailure() LIFETIMEBOUND { assert(!has_value()); return std::get<0>(m_variant).inner; }\n     T* operator->() LIFETIMEBOUND { return &value(); }\n     T& operator*() LIFETIMEBOUND { return value(); }\n };\n@@ -92,7 +96,7 @@ public:\n template <typename T>\n bilingual_str ErrorString(const Result<T>& result)\n {\n-    return result ? bilingual_str{} : std::get<0>(result.m_variant);\n+    return result ? bilingual_str{} : result.GetFailure();\n }\n } // namespace util"
  },
  {
   "t": "2024-07-08T13:29:13Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1665942681,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1666644819\n\n[quoted text omitted]\nI think it could be a good idea to introduce a `util::Expected` class if you see places in our code that need to return structured failure information but do not need to return error messages along with the failure data. If we have a `util::Expected` class it should make it easier to transition code from `util::Expected` to `std::expected` (maybe even with a scripted-diff) than if that code were written `util::Result`.\n\nI do see benefits of `util::Result` and `std::expected` as being pretty different. I think `util::Result` class provides a good way to return complete error information for GUI, RPC, and libbitcoinkernel users when code is doing a big operation like loading a wallet, connecting a block, or creating a transaction, that can fail in complicated ways. It provides a way for wallet code in #25722 and kernel code in #29700 to return error information in a standard format in a single return value without ad-hoc `bilingual_string& error` `std::vector<bilingual_str>& warnings` `bool& fatal_error` `bool& is_interrupted` in/out arguments. I think `Result` class works best when you have a chain of `Result` functions calling other `Result` functions, because the class provides ways to safely merge information for types that can be merged, while triggering compile errors if there are attempts to combine incompatible results.\n\nBy contrast, `std::expected` is basically syntax sugar over `std::variant`, which is great, but I think doesn't help as much with problems in our codebase of returning error messages with enough context to users and making sure fatal errors and `SignalInterrupt` statuses are bubbled up to libbitcoinkernel callers.\n\nI'd very much encourage adding a `util::Expected` class which is a simple wrapper over `std::variant` like your patch, if you see potential uses for this. But if you think adding a separate `util::Expected` class would be overkill, and instead would prefer to build this functionality into `util::Result` that would also be fine with me. I just think it might make it harder to disentangle the different use-cases for `util::Result` and `std::expected` later when we update to c++23, if we are using one class instead of two."
  },
  {
   "t": "2024-07-08T14:22:54Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 1665942681,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r1665942681\n\n[quoted text omitted]\nI don't see a big difference in complexity here, but I'll make the suggested change since two people asked for it. Stickies suggested the same change in https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-2079388456 and posted a diff.\n\nFor background, a good reason to use the `result.Update()` pattern is when you have a function performing multiple operations, and you want to return warnings and errors from all operations, not just the last one.\n\nWhen I wrote more code using the `Result` class in #25722 and #29700, I found that whenever you have functions returning `Result` and calling other functions returning `Result`, a good way to write them was to declare a single `Result` variable at the top, and accumulate error and warning messages in it, and return it after updating it with a final success or failure value. Other patterns could work too, but this pattern was easy to follow, and worked in all cases including more complicated ones with loops, and nested if statements, and #ifdef code. In #25722 and #29700, for simpler `Result` functions that don't call other `Result` functions, I did use simpler pattern of just returning success values or `util::Error` directly, as you suggest.\n\nIn `CompleteChainstateInitialization` right now, either pattern works fine, because it does not currently call any other functions returning `Result`. I just thought `result.Update` pattern was appropriate because it is a pretty long function, and later in #29700 `LoadBlockIndex` and `MaybeRebalanceCaches` will be updated to return `Result` values, so using `result.Update` now could avoid code churn later."
  },
  {
   "t": "2024-07-09T22:35:06Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "4eb36d1c41704f947f22d3b52f7799be23e4261c"
  },
  {
   "t": "2024-07-09T22:39:03Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Rebased db91dbb5a9a0413d6ee22ed6e32d1221d5b6d996 -> b08548336eda489ad5be9e25542d2b73e7606204 ([`pr/bresult2.57`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.57) -> [`pr/bresult2.58`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.58), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.57-rebase..pr/bresult2.58)) due to conflicts with #30255 and #30132\nRebased b08548336eda489ad5be9e25542d2b73e7606204 -> 4eb36d1c41704f947f22d3b52f7799be23e4261c ([`pr/bresult2.58`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.58) -> [`pr/bresult2.59`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.59), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.58-rebase..pr/bresult2.59)) to fix conflict with #30344. Also took suggestions to simplify usage in CompleteChainstateInitialization.\nUpdated 4eb36d1c41704f947f22d3b52f7799be23e4261c -> 15b673d122532d44fea2e6d026172ac90929da14 ([`pr/bresult2.59`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.59) -> [`pr/bresult2.60`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.60), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.59..pr/bresult2.60)) adding wallet clang-tidy fix\nRebased 15b673d122532d44fea2e6d026172ac90929da14 -> 7e2b35711e11aa404eb0bd86776beb52916d354d ([`pr/bresult2.60`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.60) -> [`pr/bresult2.61`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.61), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.60-rebase..pr/bresult2.61)) due to various conflicts"
  },
  {
   "t": "2024-07-19T14:36:09Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "15b673d122532d44fea2e6d026172ac90929da14"
  },
  {
   "t": "2024-12-06T11:36:33Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Rebased 7e2b35711e11aa404eb0bd86776beb52916d354d -> 58c33f0f3a93cbe8b8e7e04fdc5ab09734db49b0 ([`pr/bresult2.61`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.61) -> [`pr/bresult2.62`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.62), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.61-rebase..pr/bresult2.62)) due to conflict with #30377\nRebased 58c33f0f3a93cbe8b8e7e04fdc5ab09734db49b0 -> 5e14665e04d96bbc59eec27d95b7beea33f81c74 ([`pr/bresult2.62`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.62) -> [`pr/bresult2.63`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.63), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.62-rebase..pr/bresult2.63)) due to conflict with #31072\nRebased 5e14665e04d96bbc59eec27d95b7beea33f81c74 -> 15adb64db80fe001b95b1fb4f309e52d11be413e ([`pr/bresult2.63`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.63) -> [`pr/bresult2.64`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.64), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.63-rebase..pr/bresult2.64)) due to conflicts with #31483 and #30965\nUpdated 15adb64db80fe001b95b1fb4f309e52d11be413e -> 69b14c8122d69ae25b42a46e70f80aad1f783f0e ([`pr/bresult2.64`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.64) -> [`pr/bresult2.65`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.65), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.64..pr/bresult2.65)) to fix clang-tidy errors https://github.com/bitcoin/bitcoin/runs/38587781248\n\nRebased 69b14c8122d69ae25b42a46e70f80aad1f783f0e -> 8b892d41fdeb5756fd83f6050f27a170338d260a ([`pr/bresult2.65`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.65) -> [`pr/bresult2.66`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.66), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.65-rebase..pr/bresult2.66)) due to conflict with #32987"
  },
  {
   "t": "2025-10-23T09:38:00Z",
   "kind": "review_comment",
   "who": "laanwj",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": null,
   "text": "nit: Does this change to the wallet belong in this commit?"
  },
  {
   "t": "2025-10-23T09:44:17Z",
   "kind": "review_comment",
   "who": "laanwj",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": null,
   "text": "i wonder if it makes sense to allow update only in one direction: from Success to Failure. No idea if there's a use case for going the other way around, but it might indicate a potential bug (overwriting a failure) in some cases."
  },
  {
   "t": "2025-10-23T09:46:20Z",
   "kind": "review",
   "who": "laanwj",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "text": "Concept and code review ACK 8b892d41fdeb5756fd83f6050f27a170338d260a"
  },
  {
   "t": "2025-10-27T20:26:24Z",
   "kind": "comment",
   "who": "achow101",
   "assoc": "MEMBER",
   "text": "ACK 8b892d41fdeb5756fd83f6050f27a170338d260a"
  },
  {
   "t": "2025-10-28T14:05:11Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": 2454538331,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r2454538331\n\nThis is an interesting idea because you are right that basically everywhere the `Update()` method is used here and in follow-up PRs (#25722 and #29700), result state rarely goes from failure->success.\n\nThere is one place it happens in this PR though: when a failed LoadChainstate operation is [retried](https://github.com/ryanofsky/bitcoin/blob/8b892d41fdeb5756fd83f6050f27a170338d260a/src/init.cpp#L1753-L1758).\n\nWe could provide a different Update() method to distinguish cases like these but my bigger hesitation in changing this would be wondering how exactly the result class should respond if a disallowed failure->success update is attempted. The Update method could trigger an assertion on transition from failure to success, or just discard the success value when a failure state is set, but either of these behaviors could be harmful if unexpected. It seems like just updating the state with the information provided is the least surprising thing to do."
  },
  {
   "t": "2025-10-28T14:29:43Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.cpp",
   "commit": "8b892d41fdeb5756fd83f6050f27a170338d260a",
   "in_reply_to": 2454523296,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r2454523296\n\n[quoted text omitted]\nNice catch. Dropped this change. I assume this change was necessary at some point but it no longer seems to be. (For reference this change was in commit f142cc48c7e67a2414f30487e2b9c58e868e2b23)"
  },
  {
   "t": "2025-10-28T16:15:23Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "90b6a005d20ee6375beea1e685c35f265f6829c1",
   "text": "Thanks for the reviews\n\nUpdated 8b892d41fdeb5756fd83f6050f27a170338d260a -> 90b6a005d20ee6375beea1e685c35f265f6829c1 ([`pr/bresult2.66`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.66) -> [`pr/bresult2.67`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.67), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.66..pr/bresult2.67)) fixing typos and reverting unneeded wallet change"
  },
  {
   "t": "2025-10-28T17:10:18Z",
   "kind": "comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "text": "Looks like the new valgrind fuzz task is failing due to a false positive warning, which needs to be disabled like in the other GCC tasks:\n\n```\n$ git grep maybe-uninitialized ./ci\nci/test/00_setup_env_arm.sh:export BITCOIN_CONFIG=\"-DREDUCE_EXPORTS=ON -DCMAKE_CXX_FLAGS='-Wno-psabi -Wno-error=maybe-uninitialized'\"\nci/test/00_setup_env_win64.sh:-DCMAKE_CXX_FLAGS='-Wno-error=maybe-uninitialized'\""
  },
  {
   "t": "2025-10-28T18:24:07Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Added 1 commits 90b6a005d20ee6375beea1e685c35f265f6829c1 -> 90b81a71e49c1984120e35e060e3414fa0bb7205 ([`pr/bresult2.67`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.67) -> [`pr/bresult2.68`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.68), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.67...pr/bresult2.68)) to try to fix maybe-uninitialized errors in https://github.com/bitcoin/bitcoin/actions/runs/18881332233/job/53885646274?pr=25665\n\nRebased 90b81a71e49c1984120e35e060e3414fa0bb7205 -> f0aff63b5ad51566e626d5b24eee08eb81df54a1 ([`pr/bresult2.68`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.68) -> [`pr/bresult2.69`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.69), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.68-rebase..pr/bresult2.69)) due to conflict with #30595\n\nRebased bbcabe3206430895747679c90bde28273db6f62f -> 2db8bd994a75a105a9e249085a71d2b18fdb64b0 ([`pr/bresult2.71`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.71) -> [`pr/bresult2.72`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.72), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.71-rebase..pr/bresult2.72)) due to conflict with #30214\n\nUpdated 2db8bd994a75a105a9e249085a71d2b18fdb64b0 -> a3c37e68a7bc312f4f6287ba2bd4e83c80de4c11 ([`pr/bresult2.72`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.72) -> [`pr/bresult2.73`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.73), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.72..pr/bresult2.73)) to fix IWYU errors https://github.com/bitcoin/bitcoin/actions/runs/20769214790/job/59641680094?pr=25665\n\nRebased a3c37e68a7bc312f4f6287ba2bd4e83c80de4c11 -> 9383c398031986bda9bd2c7e4c9314795f82595e ([`pr/bresult2.73`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.73) -> [`pr/bresult2.74`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.74), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.73-rebase..pr/bresult2.74)) to avoid conflicts in followup PR #29700\n\nUpdated 9383c398031986bda9bd2c7e4c9314795f82595e -> ba5f435034bfaab78725b7f51dc1e9d6775b96f6 ([`pr/bresult2.74`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.74) -> [`pr/bresult2.75`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.75), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.74..pr/bresult2.75)) to fix IWYU error https://github.com/bitcoin/bitcoin/actions/runs/22559085195/job/65341883099?pr=25665\n\nRebased ba5f435034bfaab78725b7f51dc1e9d6775b96f6 -> bced7df90245ddad2c0646d6bb02c0442d17a797 ([`pr/bresult2.75`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.75) -> [`pr/bresult2.76`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.76), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.75-rebase..pr/bresult2.76)) due to conflict with #34589\n\nUpdated bced7df90245ddad2c0646d6bb02c0442d17a797 -> 5ef13873a9eb8b021596db617e91b9a3e2e81657 ([`pr/bresult2.76`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.76) -> [`pr/bresult2.77`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.77), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.76..pr/bresult2.77))\n\nRebased 5ef13873a9eb8b021596db617e91b9a3e2e81657 -> 417f05e7f590ca1259b2f3088db1fc1fe9d74cfa ([`pr/bresult2.77`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.77) -> [`pr/bresult2.78`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.78), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.77-rebase..pr/bresult2.78)) due to conflict with #34544\n\nAdded 1 commits 417f05e7f590ca1259b2f3088db1fc1fe9d74cfa -> e7f719937c290d5ec851a3bb4d45e6e90fdf3560 ([`pr/bresult2.78`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.78) -> [`pr/bresult2.79`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.79), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.78...pr/bresult2.79)) to fix spurious -Werror=maybe-uninitialized CI error https://github.com/bitcoin/bitcoin/actions/runs/25426711469/job/74581986567?pr=25665\n\nRebased e7f719937c290d5ec851a3bb4d45e6e90fdf3560 -> 9191f3607745557dcecae72c16356a96c35b0b43 ([`pr/bresult2.79`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.79) -> [`pr/bresult2.80`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.80), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.79-rebase..pr/bresult2.80)) due to conflict with #35182 (libevent replacement)\n\nRebased 9191f3607745557dcecae72c16356a96c35b0b43 -> fbd968bc9b35395902e665fcc30791af24f8f6af ([`pr/bresult2.80`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.80) -> [`pr/bresult2.81`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.81), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.80-rebase..pr/bresult2.81)) due to conflict with #35673\n\nRebased fbd968bc9b35395902e665fcc30791af24f8f6af -> 95c744333eb0d5fd8fc2dd7a76569a6c52930e8c ([`pr/bresult2.81`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.81) -> [`pr/bresult2.82`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.82), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.81-rebase..pr/bresult2.82)) due to conflicts with #30595 and #35205\n\nRebased 95c744333eb0d5fd8fc2dd7a76569a6c52930e8c -> 389ab06bb04dee0f056ac27760840bb09e440efb ([`pr/bresult2.82`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.82) -> [`pr/bresult2.83`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.83), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.82-rebase..pr/bresult2.83)) due to conflict with #35182"
  },
  {
   "t": "2025-12-01T09:03:44Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "This has been repeatedly close to merging, and I am a bit puzzled it didn't make it over the line a few times already (though I have myself to blame for that too by not being consistent on the review). At this point I wonder though if using `std::expected` instead would have more success. Afaict our minimal compiler versions are close to supporting c++23 and `std::expected` in particular."
  },
  {
   "t": "2025-12-01T17:24:15Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nNote that goals of std::expected and util::Result are different. The goal of util::Result is to let code provide descriptive error messages to users when it fails (this is why it uses translated strings). The goal of std::expected is to return error information to callers so they can distinguish between different types of failures and handle them in different ways. The Result class is better at error reporting, while the expected class is currently better at error handling. This PR just improves the Result class so it has some of the expected class's features and can be used more widely in places that require fine-grained error handling as well (#25722, #29700). I'd expect both classes to be useful: Result class for higher level code, std::expected for low-level code."
  },
  {
   "t": "2025-12-02T20:47:05Z",
   "kind": "review",
   "who": "sedited",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "text": "Re-ACK f0aff63b5ad51566e626d5b24eee08eb81df54a1"
  },
  {
   "t": "2025-12-02T20:50:05Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "Re https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-3597867646\n\n[quoted text omitted]\nI think I'd be fine with that, but would appreciate to just have a consistent way to propagate our errors. I was more suggesting it, because it seems like this PR is not compelling for everybody. But maybe this can get over the line now :)"
  },
  {
   "t": "2025-12-05T13:54:00Z",
   "kind": "comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "text": "At this point I would prefer `util::Expected` be merged first (#34006).\n\nI think `util::Result` is conflating 2 related but orthogonal needs:\n\n* Returning a successful value or error(s).\n* Returning multiple structured errors/warnings, not just one.\n\nMaybe it would be clearer to use something like `util::Expected<V, util::ErrorReport>` directly in \"user code\". With...\n```C++\nclass ErrorReport\n{\n    std::unique_ptr<detail::Messages> m_data;\n    ...\n```\n...to fulfill the wish to keep memory usage low for the happy path.\n(Is there some case where we want to return a successful value *together with* a warning?)\n\n---\n\nAn alternative would be to implement `util::Result` as a subclass of `util::Expected` as an intermediate step.\n\n Compiling example based upon fa1eee4f46fd089d6e19b124addee7c7679585f4 from #34006.\n\n```diff\ndiff --git a/src/util/expected.h b/src/util/expected.h\nindex 38baef4d21..bf8fa2f25c 100644\n--- a/src/util/expected.h\n+++ b/src/util/expected.h\n@@ -7,6 +7,7 @@\n\n #include <attributes.h>\n\n+#include <cassert>\n #include <variant>\n\n namespace util {\ndiff --git a/src/util/result.h b/src/util/result.h\nindex 39c224f61b..fe00bf3b41 100644\n--- a/src/util/result.h\n+++ b/src/util/result.h\n@@ -5,11 +5,9 @@\n #ifndef BITCOIN_UTIL_RESULT_H\n #define BITCOIN_UTIL_RESULT_H\n\n-#include <attributes.h>\n+#include <util/expected.h>\n #include <util/translation.h>\n\n-#include <variant>\n-\n namespace util {\n\n struct Error {\n@@ -31,14 +29,10 @@ struct Error {\n //! `std::optional<T>` can be updated to return `util::Result<T>` and return\n //! error strings usually just replacing `return std::nullopt;` with `return\n //! util::Error{error_string};`.\n-template <class M>\n-class Result\n+template <class V, typename E = bilingual_str>\n+class Result : public Expected<V, E>\n {\n private:\n-    using T = std::conditional_t<std::is_same_v<M, void>, std::monostate, M>;\n-\n-    std::variant<bilingual_str, T> m_variant;\n-\n     //! Disallow copy constructor, require Result to be moved for efficiency.\n     Result(const Result&) = delete;\n\n@@ -49,50 +43,31 @@ private:\n     Result& operator=(const Result&) = delete;\n     Result& operator=(Result&&) = delete;\n\n-    template <typename FT>\n-    friend bilingual_str ErrorString(const Result<FT>& result);\n+    template <typename T>\n+    friend bilingual_str ErrorString(const Result<T, bilingual_str>& result);\n\n public:\n-    Result() : m_variant{std::in_place_index_t<1>{}, std::monostate{}} {}  // constructor for void\n-    Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {}\n-    Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error.message)} {}\n+    using Expected<V, E>::Expected;\n+    constexpr Result(Error error) requires(std::is_same_v<E, bilingual_str>) : Expected<V, E>{Unexpected<E>{std::move(error.message)}} {}\n     Result(Result&&) = default;\n     ~Result() = default;\n\n-    //! std::optional methods, so functions returning optional<T> can change to\n-    //! return Result<T> with minimal changes to existing code, and vice versa.\n-    bool has_value() const noexcept { return m_variant.index() == 1; }\n-    const T& value() const LIFETIMEBOUND\n-    {\n-        assert(has_value());\n-        return std::get<1>(m_variant);\n-    }\n-    T& value() LIFETIMEBOUND\n-    {\n-        assert(has_value());\n-        return std::get<1>(m_variant);\n-    }\n     template <class U>\n-    T value_or(U&& default_value) const&\n+    V value_or(U&& default_value) const&\n     {\n-        return has_value() ? value() : std::forward<U>(default_value);\n+        return this->has_value() ? this->value() : std::forward<U>(default_value);\n     }\n     template <class U>\n-    T value_or(U&& default_value) &&\n+    V value_or(U&& default_value) &&\n     {\n-        return has_value() ? std::move(value()) : std::forward<U>(default_value);\n+        return this->has_value() ? std::move(this->value()) : std::forward<U>(default_value);\n     }\n-    explicit operator bool() const noexcept { return has_value(); }\n-    const T* operator->() const LIFETIMEBOUND { return &value(); }\n-    const T& operator*() const LIFETIMEBOUND { return value(); }\n-    T* operator->() LIFETIMEBOUND { return &value(); }\n-    T& operator*() LIFETIMEBOUND { return value(); }\n };\n\n template <typename T>\n-bilingual_str ErrorString(const Result<T>& result)\n+bilingual_str ErrorString(const Result<T, bilingual_str>& result)\n {\n-    return result ? bilingual_str{} : std::get<0>(result.m_variant);\n+    return result ? bilingual_str{} : result.error();\n }\n } // namespace util\n\n ```\n\nThen from that point, more advanced `util::Result` changes could be made, like switching the default error type from `bilingual_str` to `std::unique_ptr<util::Messages>`:\n```C++\ntemplate <class V, typename E = std::unique_ptr<Messages>>\nclass Result : public Expected<V, E>\n```\nor if preferred:\n```C++\ntemplate <class V>\nclass Result : public Expected<V, std::unique_ptr<Messages>>\n```"
  },
  {
   "t": "2025-12-05T15:31:55Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-3617021123\n\nThanks for taking a look at this.\n\n[quoted text omitted]\nThe result class is handling both of these things (since c++ works most conveniently with a single return value), but I don't see a sense in which it is conflating them. The implementation handles them independently accepting `FailureType` and `MessagesType` as separate template parameters which are both customizable:\n\nhttps://github.com/bitcoin/bitcoin/blob/f0aff63b5ad51566e626d5b24eee08eb81df54a1/src/util/result.h#L67-L68\n\nYou suggestion to use a `util::Expected<V, util::ErrorReport>` type could clearly work as well, but if I think if you look at current uses of the `Result` class in existing code, or at intended uses in https://github.com/bitcoin/bitcoin/pull/25722 and https://github.com/bitcoin/bitcoin/pull/29700, you can see how it would make calls more awkward and verbose.\n\nYour suggestions to make the `Result` class inherit from the `expected` class, or use it internally, or use value types instead of `unique_ptr`, also probably could be implemented, but it's not clear to me what they would be accomplishing. They seem like relatively small implementation changes that would not affect the `Result` API  or relate to the main goals of this PR which are to: (1) give the existing `Result` class feature-parity and compatibility with `expected` and (2) give it the ability to merge results together, which is useful for high level functions (loading a wallet, connecting a block) that perform many operations internally and can return a cumulative status instead of a single one-shot value.\n\nI think if an `expected` class gives you all the error-handlng functionality you need, it's great to use, especially in lower-level utility code. But in higher level wallet and validation code more types of failures are possible and the `Result` class can be a better fit."
  },
  {
   "t": "2025-12-05T20:51:49Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": null,
   "text": "in e78cfb399e5e59805557992c32d34080bfca6eee \"refactor: Add util::Result failure values\":\n\nIsn't it closer to:\n```suggestion\n//!     tuple<optional<SuccessType>, unique_ptr<tuple<FailureType, MessagesType>>>\n```"
  },
  {
   "t": "2025-12-05T21:19:23Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": null,
   "text": "remark: Took a few minutes to realize that `has_value()` doesn't exist because of the `void` template specialization of `SuccessHolder` which doesn't have that. Makes sense."
  },
  {
   "t": "2025-12-05T21:36:23Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": null,
   "text": "Would anything be gained from making the template parameter an r-value? (Earlier commits do explicit `std::move()`s, justifying the function's name, but that justification appears to have dissipated).\n```suggestion\n    static void Move(DstResult& dst, SrcResult&& src)\n```"
  },
  {
   "t": "2025-12-06T12:55:13Z",
   "kind": "comment",
   "who": "arejula27",
   "assoc": "NONE",
   "text": "Concept ACK [f0aff63b5ad51566e626d5b24eee08eb81df54a1]\nThis PR was started in 2022, before the C++23 standard introduced `std::expected`. I agree with @hodlinator  that this PR attempts to solve two different issues:\n1. The error-handling workflow\n2. The ability to merge results, which is useful for high-level functions (e.g., loading a wallet, connecting a block) that perform many internal operations and may want to return a cumulative status instead of a single one-shot value\n\nI agree that these are interesting problems to address. However, I believe the first one is already solved by `utils::expected` (and i suggest merging first the #34006 pr and then this one with the required modifications to adapt to it) and will be solved by `std::expected` in the future.\n\nThis PR has been open for three years, and it is clear that a lot of work and constant updates have gone into it. Still, I feel that merging another `utils::expected` like mechanism would be redundant regarding error-handling workflow. That said, I think a small refactor could help to merge both: removing the `Result` class while keeping components like `FailDataHolder`, which could then be used inside `utils::expected`.\n\nOne of the most appealing aspects of the current `utils::Result` is the `ErrorString` helper, as shown in the example:\n```c++\nvoid TryAddNumbers(int a, int b)\n    {\n        if (auto result = AddNumbers(a, b)) {\n            LogPrintf(\"%i + %i = %i\\n\", a, b, *result);\n        } else {\n            LogPrintf(\"Error: %s\\n\", util::ErrorString(result).translated);\n        }\n    }\n```\n\nThis feels smooth and does not add verbosity. However, I would also like to consider an approach like this:\n```c++\ntemplate <typename T, typename E>\nrequires requires(const E& e) { e.messages; }   // has .messages\nbilingual_str ErrorString(const utils::expected<T,E>& result)\n{\n    if (result.has_value())\n        return bilingual_str{};\n\n    const Messages& m = result.error().messages;\n    return detail::JoinMessages(m);\n}\n```\nIf you agree, this direction could be interesting, I can continue exploring the idea and evaluating how viable it is. I doubt the snippet I provided would compile as-is, it is only meant to illustrate the proposal.\n\nAnother good option (as mentioned earlier in the discussion) would be to base the `Result` type on `expected`.\n```c++\ntemplate <class V>\nclass Result : public Expected<V, std::unique_ptr<Messages>>\n```\nThis would isolate all error-handling mechanics in the `expected` class, while keeping reporting, updating, and merging logic inside `Result`.\n\nFinally, I would like to mention that [clearer documentation](https://github.com/bitcoin/bitcoin/pull/34006#discussion_r2593725731) would be valuable. It would be helpful to specify when this class should be used, as the author mentioned several use cases beyond simply reporting errors to the user."
  },
  {
   "t": "2025-12-06T16:24:09Z",
   "kind": "review_comment",
   "who": "arejula27",
   "assoc": "NONE",
   "path": "src/util/result.cpp",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": null,
   "text": "I removed this include and it continue compiling, are we sure this is required? I executed the following commands:\n```bash\n\u279c  bitcoin (25665) % git log -1 --format=%H                                                                                                           17:21\nf0aff63b5ad51566e626d5b24eee08eb81df54a1\n\u279c  bitcoin (25665) % git diff src/util/result.cpp                                                                                                     17:21\ndiff --git a/src/util/result.cpp b/src/util/result.cpp\nindex ea79375aa3..423618e85d 100644\n--- a/src/util/result.cpp\n+++ b/src/util/result.cpp\n@@ -4,7 +4,6 @@\n\n #include <util/result.h>\n\n-#include <algorithm>\n #include <initializer_list>\n #include <iterator>\n #include <util/translation.h>\n\u279c  bitcoin (25665) % rm -rf build                                                                                                                     17:22\n\u279c  bitcoin (25665) % cmake -B build > /dev/null 2>&1                                                                                                  17:22\n\u279c  bitcoin (25665) % cmake --build build -j \"$(($(nproc)/2))\" > /dev/null 2>&1                                                                        17:22\n\u279c  bitcoin (25665) % ./build/bin/test_bitcoin                                                                                                         17:22\nRunning 686 test cases...\n\n*** No errors detected\n\n```"
  },
  {
   "t": "2025-12-06T16:50:54Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/util/result.cpp",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": 2595092169,
   "text": "We usually treat missing or extra includes as nits. There is an iwyu run as part of the tidy CI job. See the logs here: https://github.com/bitcoin/bitcoin/actions/runs/19279986116/job/55128814542?pr=25665#step:9:13821 ."
  },
  {
   "t": "2025-12-06T17:06:23Z",
   "kind": "review_comment",
   "who": "arejula27",
   "assoc": "NONE",
   "path": "src/util/result.cpp",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": 2595092169,
   "text": "Does this mean that I should not review includes? I am starting to contribute, sorry if this is not relevant"
  },
  {
   "t": "2025-12-06T17:19:47Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/util/result.cpp",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": 2595092169,
   "text": "If it is important to you, it is enough to link the respective lines in the iwyu report."
  },
  {
   "t": "2025-12-06T17:26:43Z",
   "kind": "review_comment",
   "who": "arejula27",
   "assoc": "NONE",
   "path": "src/util/result.cpp",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": 2595092169,
   "text": "Thx\ud83e\udee1, I guess this conversation can be marked as resolved then"
  },
  {
   "t": "2025-12-08T15:36:54Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.cpp",
   "commit": "5ef13873a9eb8b021596db617e91b9a3e2e81657",
   "in_reply_to": null,
   "text": "nit Q in 3c535e299efbf445ccd33c633ed455399d9785cd \"wallet: fix clang-tidy warning performance-no-automatic-move\":\nI got the impression our expectation is that all commits should pass CI. So I would expect this change to come before or in the same commit that would cause CI failure. Is that only valid for the HEAD commit when it comes to commits that resolve clang-tidy and similar checks?"
  },
  {
   "t": "2025-12-10T22:16:43Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": null,
   "text": "I'm guessing the reason for the existence of a separate `SuccessHolder` type is in order to specialize away a minimal subset of functionality in `SuccessHolder<void, ...>`. If that's part of the reason, it could be admitted in the comment block for the main `SuccessHolder` template?"
  },
  {
   "t": "2025-12-10T23:06:11Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": null,
   "text": "An example from my larger experimentation showed that `Expected` can be used to implement a variant of the chainstate refactor from this PR (0ad3a45633433377b44c9ae89b52703e0c750fdd), see self-contained commit https://github.com/hodlinator/bitcoin/commit/b40a36cbbab59440d84dba6d1cc16bce17d4869c."
  },
  {
   "t": "2025-12-10T23:12:28Z",
   "kind": "review",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-3617394520\n\nExcuse me, I somehow glossed over the fact that you had 3 template parameters in this PR, not 2. :facepalm: I missed that you allowed for a `FailureType` apart from `MessageType`, the former defaulting to `void` but messages being default-on. I see a greater justification for the distinct `Result` type. However, it seems the either/or aspect remains, if I'm not mistaken.\n\nInspired by your reply, I nerd-sniped myself into experimenting with a branch based on #25722 to check my assumptions. I'm able to replace `Result` with raw `Expected` in most cases, but wallet code forces me to use:\n```C++\ntemplate <typename T, typename FailureType = void>\nusing ResultLog = Expected<T, ErrorLog<FailureType>>;\n```\nThe benefit I see to using `Expected` even as part of \"ResultLog\" is that `expected` is a known pattern in C++, so it would slot into people's understanding. From there it comes down providing sufficient ergonomics of mutating/merging when using `ErrorLog`."
  },
  {
   "t": "2025-12-12T14:45:18Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": 2593959586,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r2593959586\n\n[quoted text omitted]\nThe current comment here says \"Logically, a result object is equivalent to `tuple<variant<SuccessType, ErrorType>, MessagesType>`\".\n\nThis is just trying to get across the idea that a `Result` holds a success value or a failure value, plus some messages.\n\nIMO, adding unique_ptr to this description would make it more confusing (and the specific suggestion would also not be accurate since failure and message values can be set independently). Use of unique_ptr is an implementation detail not exposed to callers. The heap allocation is relevant since it could have performance implications, so it's mentioned in the comment. But it's not important for understanding what information is stored in the class or how the class can be used."
  },
  {
   "t": "2025-12-12T14:52:21Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": 2594047330,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r2594047330\n\n[quoted text omitted]\nThere isn't a great way of forcing this to be an rvalue, since just replacing `&` && would make it a universal reference and make using the  deduced `SrcResult` type more awkward. I also don't think it would be too helpful in any case, since this is not a public function and there are only 2 internal callers. Using a plain reference here is the simplest approach, I believe."
  },
  {
   "t": "2025-12-12T15:02:13Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.cpp",
   "commit": "5ef13873a9eb8b021596db617e91b9a3e2e81657",
   "in_reply_to": 2599090229,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r2599090229\n\n[quoted text omitted]\nI don't think there's a rule about this, but yes I wouldn't choose a commit only fixing a clang-tidy warning (that seems very brittle anyway) to be the first change here, since it seems easier to understand as a followup. Could reorder commits though if you or anyone else feels this is important."
  },
  {
   "t": "2025-12-12T15:04:10Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "f0aff63b5ad51566e626d5b24eee08eb81df54a1",
   "in_reply_to": 2608405722,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r2608405722\n\n[quoted text omitted]\nYes exactly. Added a comment mentioning the void type to make this clearer."
  },
  {
   "t": "2025-12-12T15:10:59Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "074cb32216824cc05433ec44cd3d41e0cc5a14cd",
   "text": "Thanks for the reviews! The feedback's been very helpful and led to a few updates here.\n\nRebased f0aff63b5ad51566e626d5b24eee08eb81df54a1 -> 074cb32216824cc05433ec44cd3d41e0cc5a14cd ([`pr/bresult2.69`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.69) -> [`pr/bresult2.70`](https://github.com/ryanofsky/bitcoin/commits/pr/bresult2.70), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/bresult2.69-rebase..pr/bresult2.70)) due to conflict with #34006. Also:\n- Renamed methods and types to be consistent with the `std::expected` class.\n- Updated documentation to have more examples and focus on features not in the `std::expected` class.\n- Tried to respond to hodlinators concerns by moving message types and functions to a new `util/messages.h` file, to allow wider use and make it clear the result and message types are independent.\n\n---\n\nre: @arejula27 https://github.com/bitcoin/bitcoin/pull/25665#issuecomment-3620230189\n\n[quoted text omitted]\nIIUC the suggestion there is to change implementation of `ErrorString` so it could work with `std::expected` and not be tied to `util::Result`. If so that does seem like a potentially useful change and maybe a simplifying one. TBH I don't know of code that would directly benefit from combining `ErrorString` with `std::expected`  because I think validation and wallet code are better off using `util::Result`, which I've tried to show in s #25722 and #29700. But I don't see harm in generalizing the implementation.\n\n---\n\nre: hodlinator  https://github.com/bitcoin/bitcoin/pull/25665#pullrequestreview-2343976961\n\n[quoted text omitted]\nThanks for looking into this. These experiments seem useful and likely to generate some good ideas. I will say I'm not really clear on what things you'd like to provide which the Result class isn't providing in this PR. I do think the current implementation should \"slot into\" someone's understanding of `std::expected` extremely well since it has the same interface, and just adds extra features for merging result instances and returning error messages."
  },
  {
   "t": "2025-12-12T19:35:46Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/test/result_tests.cpp",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": null,
   "text": "nit in ab94499c2a9841a655f92c0f90ff520102bec953 commit message:\n- Smaller type size section could mention that given values are for 64-bit platforms, since we still ship ARM32 releases."
  },
  {
   "t": "2025-12-13T01:07:33Z",
   "kind": "comment",
   "who": "arejula27",
   "assoc": "NONE",
   "text": "Re @ryanofsky\n[quoted text omitted]\n\nIf you don't see any benefits keep your implementation, a generalisation can be implemented later if required \ud83d\ude04"
  },
  {
   "t": "2025-12-15T14:02:17Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 2608521278,
   "text": "I maintain that the current example in this PR of applying `util::Result` to `LoadChainstate` & `VerifyLoadedChainstate` is not well motivated as they don't use warnings or multiple errors, and are thus a better fit for `util::Expected` as in my linked commit.\n\nIt would be better to use a different example in this PR unless I'm still missing something."
  },
  {
   "t": "2025-12-15T14:11:25Z",
   "kind": "review",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "074cb32216824cc05433ec44cd3d41e0cc5a14cd",
   "text": "Thanks for the updates!\n\nAnnoyed at myself for not investigating my assumed either/or-ness of your proposed `util::Result` sooner. Somehow I'd interpreted `FailDataHolder`s:\n```C++\nexplicit operator bool() const { return !m_fail_data || !m_fail_data->failure; }\n```\nas plainly:\n```C++\nexplicit operator bool() const { return !m_fail_data; }\n```\nThe former makes it a clearer departure from `util::Expected` - warnings can be added and merged into parent results while still returning successful values."
  },
  {
   "t": "2025-12-17T13:36:33Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/util/result.h",
   "commit": "bbcabe3206430895747679c90bde28273db6f62f",
   "in_reply_to": null,
   "text": "nit: Maybe this could be made more distinct from warnings by changing the name?\n\n```suggestion\n        std::optional<std::conditional_t<std::is_same_v<ErrorType, void>, Monostate, ErrorType>> error{};\n```\n\nWould hopefully decrease misunderstandings like I had myself in https://github.com/bitcoin/bitcoin/pull/25665#pullrequestreview-3573338179, since in that case it would be:\n\n```C++\nexplicit operator bool() const { return !m_fail_data || !m_fail_data->error; }\n```"
  },
  {
   "t": "2026-02-10T08:36:42Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 2608521278,
   "text": "I think it could use a struct instead of a raw std::pair, but otherwise, if std::expected or util::Expected work out of the box here, it seems easier to just use them?"
  },
  {
   "t": "2026-02-10T13:27:50Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 2608521278,
   "text": "[quoted text omitted]\n\nThey don't. Hodlinator is suggesting replacing:\n\n- `Result<InterruptResult, ChainstateLoadError>`\n\nwith:\n\n-  `Expected<InterruptResult, pair<ChainstateLoadError, bilingual_str>>`.\n\nSo using `pair` + `Expected` together to replicate functionality of `Result`.\n\nThis does work fine (it's just slightly more verbose) in cases like this example where you have one function or a set of functions that each produce their own error messages and need to return those messages to callers. But it falls apart when the functions call other functions that also produce error messages and those errors need to be forwarded or merged (#25722, #29700).\n\nThe point of `Result` is to be a superset of `Expected` and drop-in replacement that provides:\n\n- An implicit `messages` field so you do not need specify `bilingual_str` everywhere and can avoid `pair<X, bilingual_str>`, `make_pair` boilerplate.\n- Merging operators and methods (`>>`, `update`) so when `Result` functions call other `Result` functions, complete error messages can be returned with information about low level failures and higher level context.\n- Merging hooks so `Result` functions calling other `Result` functions can bubble up other information as well, such as fatal/nonfatal error status and flush status in [#29700](https://github.com/bitcoin/bitcoin/pull/29700).\n\n`Expected` is a good way to return simple status information from low-level C++ functions. `Result` is an extension of `Expected` intended to be used for high level functions which can fail in complicated ways and should be able to return detailed descriptive messages. (It also supports returning warnings which are used heavily in wallet code, though not currently in the kernel.)"
  },
  {
   "t": "2026-02-10T13:40:17Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 2608521278,
   "text": "Returning both error enum value and error string is a bit unusual. It seems one could reduce to the more conventional `Expected<InterruptResult, ChainstateLoadError>` by slightly increasing the number of `ChainstateLoadError`-enum members and having a separate mapping from error enum value -> error string.\n\nnop\n\n~There's only one `strprintf` that would lead to actually loosing information~ I realized this doesn't rely on local information, so could also be moved:\nhttps://github.com/bitcoin/bitcoin/blob/64294c89094d5ab10d87236729cc267fde0a24ca/src/node/chainstate.cpp#L132-L133"
  },
  {
   "t": "2026-02-10T14:01:24Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 2608521278,
   "text": "[quoted text omitted]\n\nRight, that is why `Result` second parameter defaults to `void`. The point is that generally `Result` should be a better choice than `Expected` when you do want to return error messages.\n\n[quoted text omitted]\nDisagree that enums are a good way to return error messages from high level code. This results in programs telling you things like \"permissions error\" without telling you which resource couldn't be accessed or \"syntax error\" without telling you where the problem occurred. If you want to return helpful error messages, you need to a way to construct them in them places where context is available, and a way to bubble them up to callers, and this is what the `Result` class provides. Or we could just go with `bool` and \"Oops, something went wrong!\" :wink:"
  },
  {
   "t": "2026-02-10T14:29:30Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 2608521278,
   "text": "[quoted text omitted]\n\nDon't start me on `GenericError` being used everywhere. :)\n\n[quoted text omitted]\nTo some extent `util::Result` and `util::Expected` both compete with Rust's `std::Result` which is empowered by Rust `enum`s being able to contain error strings. I guess defining the untranslated error string at the place in the code that triggers the error should make for the best messages.\n\n[quoted text omitted]\nAn inner `Expected<InterruptResult, pair<ChainstateLoadError, bilingual_str>>` could be transformed into an outer `Expected<FooResult, pair<FooError, bilingual_str>>` in that the outer error message could include some part of the inner error string. In Rust one could even preserve two levels of error enum values, that is not supported by this PR's `util::Result` nor `util::Expected`.\n\nWhat I mean to say at the beginning of the thread is that there probably are other use-cases (definitely in #25722 and probably in #29700) which better motivate your modifications to `util::Result` in this PR."
  },
  {
   "t": "2026-02-10T16:11:35Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.h",
   "commit": "389ab06bb04dee0f056ac27760840bb09e440efb",
   "in_reply_to": 2608521278,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/25665#discussion_r2788299698\n\nThanks analogies with rust are interesting and I think the approach described is probably pretty good for error handling, but not well suited for error reporting, at least in high level application code. For manageable error handling you want to return coarse, rigidly structured types, and for good error reporting you want to be return more detailed less structured information. So the two goals are in tension and you will create problems (vague or incomplete error reports or overly complicated error handling) if you mix up the purposes of the returned information.\n\n[quoted text omitted]\nYes, your initial comment here led me to add some toy examples in the Result class documentation. I just don't see other ways to act on the feedback. The `Result` class has features for handling error messages and error status values, and the `LoadChainstate` example shows both of those features. It also has features for merging results that are useful when you have a library full of functions returning error messages. These are shown in #25722 and #29700 (which makes sense as separate PR's because they affect many more functions)."
  },
  {
   "t": "2026-04-01T06:43:10Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "ci/test/00_setup_env_native_fuzz_with_valgrind.sh",
   "commit": "bced7df90245ddad2c0646d6bb02c0442d17a797",
   "in_reply_to": null,
   "text": "there is no GCC anymore here, so this commit can be dropped"
  },
  {
   "t": "2026-05-08T14:05:49Z",
   "kind": "comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "text": "I think this went through many revisions in the last couple of years, and some comments do not apply anymore here. Also, with more than 300 comments, they don't load anymore on GH easily. So I think this should be turned into draft for now, and possibly closed and opened as a new pull, if this is still relevant."
  },
  {
   "t": "2026-05-11T07:53:34Z",
   "kind": "comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "text": "Concept ACK\nThis is useful not only for cleaning the wallet code, but also for new interface methods with complex results https://github.com/bitcoin/bitcoin/pull/34861#discussion_r3172753745\n\n[quoted text omitted]\nI agree, would like to review this in a fresh PR. There's too much noise here."
  },
  {
   "t": "2026-05-29T06:49:07Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "I've ACKed this pull request a few times, but I agree with the preceding comments here: This is clearly not getting review at the moment, so should be closed and re-attempted again in a fresh pull request."
  }
 ],
 "labels_log": [
  {
   "t": "2022-07-22T07:54:07Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2022-07-22T11:10:35Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2022-07-27T17:39:43Z",
   "action": "labeled",
   "label": "Refactoring",
   "who": "DrahtBot"
  },
  {
   "t": "2022-08-05T13:55:33Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2022-08-05T20:13:16Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2022-09-16T10:15:51Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2022-09-20T18:07:16Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2022-10-13T16:07:19Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2022-10-14T21:19:53Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-01-03T18:09:19Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-01-06T20:35:34Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-01-27T17:27:12Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-02-10T22:41:27Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-02-22T20:57:37Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-03-01T17:45:01Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-03-08T00:33:18Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-03-16T20:49:18Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-03-23T16:56:48Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-04-04T21:23:58Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-04-24T01:07:40Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2023-05-02T22:53:21Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2023-05-26T13:32:44Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-07-21T18:13:02Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-07-21T18:44:40Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2023-07-21T21:31:13Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2023-08-01T21:40:48Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2023-08-02T00:09:59Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2023-08-03T22:22:04Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2023-08-04T16:50:49Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2023-08-29T19:39:04Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2023-09-05T17:24:29Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "achow101"
  },
  {
   "t": "2023-09-05T18:00:08Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2023-09-07T04:22:42Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2023-10-05T15:01:04Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2023-10-18T20:59:49Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2023-12-12T16:37:29Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-01-24T18:50:08Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-02-13T18:23:09Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2024-02-21T21:58:57Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2024-02-23T12:09:15Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2024-02-28T13:08:46Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2024-03-26T20:30:53Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2024-03-27T04:26:13Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2024-04-25T00:21:25Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2024-04-26T08:30:22Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2024-04-26T16:22:33Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2024-04-30T18:38:13Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-05-01T19:48:03Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-05-01T20:41:44Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2024-05-20T11:58:41Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-06-17T23:31:40Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-07-02T11:20:01Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2024-07-10T02:42:40Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2022-07-27T16:45:33Z",
   "kind": "renamed",
   "who": "ryanofsky",
   "from": "BResult improvements, allow returning separate value on failure",
   "to": "refactor: Add util::Result class and use it in LoadChainstate"
  },
  {
   "t": "2022-07-27T19:30:07Z",
   "kind": "ready_for_review",
   "who": "ryanofsky"
  },
  {
   "t": "2022-08-05T18:45:12Z",
   "kind": "renamed",
   "who": "ryanofsky",
   "from": "refactor: Add util::Result class and use it in LoadChainstate",
   "to": "refactor: Add util::Result failure values, multiple error and warning messages"
  },
  {
   "t": "2024-03-22T22:02:23Z",
   "kind": "convert_to_draft",
   "who": "ryanofsky"
  },
  {
   "t": "2024-03-27T18:03:19Z",
   "kind": "ready_for_review",
   "who": "ryanofsky"
  },
  {
   "t": "2024-04-18T19:12:21Z",
   "kind": "convert_to_draft",
   "who": "ryanofsky"
  },
  {
   "t": "2024-05-01T17:41:21Z",
   "kind": "ready_for_review",
   "who": "ryanofsky"
  }
 ],
 "text_chars": 176981,
 "text_tokens_estimate": 44245,
 "changed_paths": [
  "ci/test/00_setup_env_native_previous_releases.sh",
  "src/init.cpp",
  "src/kernel/CMakeLists.txt",
  "src/kernel/bitcoinkernel.cpp",
  "src/node/chainstate.cpp",
  "src/node/chainstate.h",
  "src/test/result_tests.cpp",
  "src/test/util/setup_common.cpp",
  "src/util/CMakeLists.txt",
  "src/util/messages.cpp",
  "src/util/messages.h",
  "src/util/result.h",
  "src/wallet/wallet.cpp"
 ],
 "files": [
  {
   "path": "ci/test/00_setup_env_native_previous_releases.sh",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/init.cpp",
   "add": 21,
   "del": 20
  },
  {
   "path": "src/kernel/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/kernel/bitcoinkernel.cpp",
   "add": 7,
   "del": 7
  },
  {
   "path": "src/node/chainstate.cpp",
   "add": 56,
   "del": 39
  },
  {
   "path": "src/node/chainstate.h",
   "add": 6,
   "del": 22
  },
  {
   "path": "src/test/result_tests.cpp",
   "add": 195,
   "del": 11
  },
  {
   "path": "src/test/util/setup_common.cpp",
   "add": 4,
   "del": 4
  },
  {
   "path": "src/util/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/util/messages.cpp",
   "add": 30,
   "del": 0
  },
  {
   "path": "src/util/messages.h",
   "add": 53,
   "del": 0
  },
  {
   "path": "src/util/result.h",
   "add": 355,
   "del": 63
  },
  {
   "path": "src/wallet/wallet.cpp",
   "add": 2,
   "del": 2
  }
 ],
 "test_lines": 216,
 "git": {
  "head": "389ab06bb04dee0f056ac27760840bb09e440efb",
  "head_matches_backup": true,
  "base": "4ec6ff022a4b33fab46afa5656a983cda8ba3099",
  "commits": [
   {
    "sha": "f1e827bc20",
    "subject": "refactor: Add util::Result failure values",
    "files": 3,
    "add": 335,
    "del": 65
   },
   {
    "sha": "2a59241faf",
    "subject": "wallet: fix clang-tidy warning performance-no-automatic-move",
    "files": 1,
    "add": 1,
    "del": 1
   },
   {
    "sha": "335a6af84e",
    "subject": "refactor: Add util::Result::Update() method",
    "files": 2,
    "add": 51,
    "del": 7
   },
   {
    "sha": "f3d9b8993a",
    "subject": "refactor: Use util::Result class in LoadChainstate and VerifyLoadedChainstate",
    "files": 5,
    "add": 94,
    "del": 92
   },
   {
    "sha": "b7640ff7db",
    "subject": "refactor: Add util::Result multiple error and warning messages",
    "files": 6,
    "add": 271,
    "del": 30
   },
   {
    "sha": "fdeb223231",
    "subject": "test: add static test for util::Result memory usage",
    "files": 2,
    "add": 7,
    "del": 1
   },
   {
    "sha": "389ab06bb0",
    "subject": "ci: Avoid -Wno-error=maybe-uninitialized false positives",
    "files": 1,
    "add": 1,
    "del": 1
   }
  ],
  "patch_truncated": true
 },
 "input_hash": "851a1784acd570da",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}