{
 "number": 35788,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/35788",
 "title": "bitcoin-util: Add evalscript subcommand",
 "author": "ajtowns",
 "author_association": "MEMBER",
 "created_at": "2026-07-24T01:56:45Z",
 "updated_at": "2026-09-16T19:41:31Z",
 "age_days": 55,
 "draft": false,
 "labels": [],
 "milestone": null,
 "base": "master",
 "head_sha": "a64f2ac5b11ac95a43d11c2846e461de0b6eb48a",
 "head_ref": "202607-evalscript",
 "head_repo": "ajtowns/bitcoin",
 "head_history": [
  {
   "t": "2026-07-24T02:07:25Z",
   "sha": "a64f2ac5b11ac95a43d11c2846e461de0b6eb48a"
  }
 ],
 "additions": 560,
 "deletions": 17,
 "changed_files": 13,
 "commit_count": 4,
 "size_bucket": "L",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "ack": [
     {
      "login": "jeanpablojp",
      "url": "https://github.com/bitcoin/bitcoin/pull/35788#issuecomment-5346218321"
     }
    ]
   },
   "conflicts": [
    {
     "number": 29247,
     "title": "CAT in Tapscript (BIP-347)",
     "author": "arminsabouri"
    }
   ]
  }
 },
 "acks_parsed": {},
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 0,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "jeanpablojp"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-07-24T02:07:25Z",
  "last_reviewer_activity": "2026-08-19T18:16:16Z",
  "last_reviewer": "jeanpablojp",
  "author_silent_days": 55,
  "waiting_on_author_days": 28,
  "days_since_update": 0
 },
 "refs": {
  "mentioned": [],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [],
  "conflicts": [
   29247
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [],
 "body": "Adds an `evalscript` subcommand for using bitcoin's consensus logic to evaluate script fragments. Intended for debugging and development.\n\nExamples:\n\n```\n# check a script fragment's behaviour\n$ bitcoin-util evalscript '1 2 ADD'\n{\n  \"script\": {\n    \"asm\": \"1 2 OP_ADD\",\n    \"hex\": \"515293\",\n    \"type\": \"nonstandard\"\n  },\n  \"sigversion\": \"witness_v0\",\n  \"script_flags\": [\n    \"CHECKLOCKTIMEVERIFY\",\n    \"CHECKSEQUENCEVERIFY\",\n    \"DERSIG\",\n    \"NULLDUMMY\",\n    \"P2SH\",\n    \"TAPROOT\",\n    \"WITNESS\"\n  ],\n  \"dummy_sig_checker\": true,\n  \"stack_after\": [\n    \"03\"\n  ],\n  \"sigop_cost\": 0,\n  \"success\": true\n}\n\n# validate a real signature\n$ bitcoin-util -sigversion=base \\\n    -spentoutput=00f2052a0100000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac \\\n    -tx=0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000 \\\n    evalscript '0x410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3 CHECKSIG' \\\n    '304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901'\n{\n  \"script\": {\n    \"asm\": \"0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3 OP_CHECKSIG\",\n    \"hex\": \"410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac\",\n    \"type\": \"pubkey\"\n  },\n  \"sigversion\": \"base\",\n  \"script_flags\": [\n    \"CHECKLOCKTIMEVERIFY\",\n    \"CHECKSEQUENCEVERIFY\",\n    \"DERSIG\",\n    \"NULLDUMMY\",\n    \"P2SH\",\n    \"TAPROOT\",\n    \"WITNESS\"\n  ],\n  \"dummy_sig_checker\": false,\n  \"stack_after\": [\n    \"01\"\n  ],\n  \"sigop_cost\": 4,\n  \"success\": true\n}\n```",
 "commits": [
  {
   "sha": "f3ad9ba72cf3280f62104b024aa65e57fca33c6d",
   "date": "2026-07-23T06:34:39Z",
   "message": "script: expose CastToBool function"
  },
  {
   "sha": "9d1482911df69b978edcbd47f176a0c2cef6976e",
   "date": "2026-07-23T10:15:57Z",
   "message": "[consensus] script/interpreter: Expose OP_SUCCESS logic\n\nReview with `git diff --color-moved=zebra --color-moved-ws=allow-indentation-change`"
  },
  {
   "sha": "f0556b061d67ad783a9b322ac60cea537f559390",
   "date": "2026-07-24T02:07:14Z",
   "message": "bitcoin-util: Introduce evalscript subcommand"
  },
  {
   "sha": "a64f2ac5b11ac95a43d11c2846e461de0b6eb48a",
   "date": "2026-07-24T02:07:14Z",
   "message": "tests: Add functional test for bitcoin-util evalscript"
  }
 ],
 "timeline": [
  {
   "t": "2026-07-24T02:02:13Z",
   "kind": "comment",
   "who": "ajtowns",
   "assoc": "MEMBER",
   "text": "Previously included in bitcoin-inquisition (https://github.com/bitcoin-inquisition/bitcoin/pull/58, also https://github.com/bitcoin-inquisition/bitcoin/pull/64 and https://github.com/bitcoin-inquisition/bitcoin/pull/79).\n\nMakes minimal changes to consensus logic, but still has to duplicate a bunch of code to get equivalent behaviour, might be worthwhile simplifying that API in followups, and potentially exposing as a kernel API of some sort?"
  },
  {
   "t": "2026-07-24T02:07:25Z",
   "kind": "force_push",
   "who": "ajtowns",
   "commit": "a64f2ac5b11ac95a43d11c2846e461de0b6eb48a"
  },
  {
   "t": "2026-08-19T18:16:16Z",
   "kind": "comment",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "text": "tACK a64f2ac5b11ac95a43d11c2846e461de0b6eb48a\n\nRan tool_utils, the script unit tests and feature_taproot on the head, and both examples from the description reproduce here.\n\nThe PR description mentions `-tx`, but I noticed no case in bitcoin-util-test.json uses `-tx`, so that path goes uncovered. To confirm, I disabled the `-input` range check and the suite still passes. Would it be worth adding a case like that?"
  }
 ],
 "labels_log": [
  {
   "t": "2026-07-24T02:07:52Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-24T03:09:55Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 3520,
 "text_tokens_estimate": 880,
 "changed_paths": [
  "src/bitcoin-util.cpp",
  "src/script/interpreter.cpp",
  "src/script/interpreter.h",
  "src/test/fuzz/script_interpreter.cpp",
  "test/functional/data/util/bitcoin-util-test.json",
  "test/functional/data/util/evalscript-add.json",
  "test/functional/data/util/evalscript-base-noflags.json",
  "test/functional/data/util/evalscript-customflags.json",
  "test/functional/data/util/evalscript-empty.json",
  "test/functional/data/util/evalscript-op1.json",
  "test/functional/data/util/evalscript-opsuccess-discouraged.json",
  "test/functional/data/util/evalscript-opsuccess.json",
  "test/functional/data/util/evalscript-tapscript.json"
 ],
 "files": [
  {
   "path": "src/bitcoin-util.cpp",
   "add": 290,
   "del": 0
  },
  {
   "path": "src/script/interpreter.cpp",
   "add": 24,
   "del": 15
  },
  {
   "path": "src/script/interpreter.h",
   "add": 11,
   "del": 0
  },
  {
   "path": "src/test/fuzz/script_interpreter.cpp",
   "add": 0,
   "del": 2
  },
  {
   "path": "test/functional/data/util/bitcoin-util-test.json",
   "add": 66,
   "del": 0
  },
  {
   "path": "test/functional/data/util/evalscript-add.json",
   "add": 23,
   "del": 0
  },
  {
   "path": "test/functional/data/util/evalscript-base-noflags.json",
   "add": 17,
   "del": 0
  },
  {
   "path": "test/functional/data/util/evalscript-customflags.json",
   "add": 18,
   "del": 0
  },
  {
   "path": "test/functional/data/util/evalscript-empty.json",
   "add": 23,
   "del": 0
  },
  {
   "path": "test/functional/data/util/evalscript-op1.json",
   "add": 23,
   "del": 0
  },
  {
   "path": "test/functional/data/util/evalscript-opsuccess-discouraged.json",
   "add": 18,
   "del": 0
  },
  {
   "path": "test/functional/data/util/evalscript-opsuccess.json",
   "add": 23,
   "del": 0
  },
  {
   "path": "test/functional/data/util/evalscript-tapscript.json",
   "add": 24,
   "del": 0
  }
 ],
 "test_lines": 237,
 "git": {
  "head": "a64f2ac5b11ac95a43d11c2846e461de0b6eb48a",
  "head_matches_backup": true,
  "base": "7b6f9ba7bad13b0c4169259000f7802854cdda0d",
  "commits": [
   {
    "sha": "f3ad9ba72c",
    "subject": "script: expose CastToBool function",
    "files": 2,
    "add": 2,
    "del": 2
   },
   {
    "sha": "9d1482911d",
    "subject": "[consensus] script/interpreter: Expose OP_SUCCESS logic",
    "files": 2,
    "add": 33,
    "del": 15
   },
   {
    "sha": "f0556b061d",
    "subject": "bitcoin-util: Introduce evalscript subcommand",
    "files": 1,
    "add": 290,
    "del": 0
   },
   {
    "sha": "a64f2ac5b1",
    "subject": "tests: Add functional test for bitcoin-util evalscript",
    "files": 9,
    "add": 235,
    "del": 0
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "14eafeb8eac29e3e",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}