Skip to content

BIP440: Varops Budget for Script Runtime Constraint, BIP441: Restoration of disabled Script (tapleaf 0xc2)#2118

Open
rustyrussell wants to merge 3 commits intobitcoin:masterfrom
rustyrussell:varops-bips
Open

BIP440: Varops Budget for Script Runtime Constraint, BIP441: Restoration of disabled Script (tapleaf 0xc2)#2118
rustyrussell wants to merge 3 commits intobitcoin:masterfrom
rustyrussell:varops-bips

Conversation

@rustyrussell
Copy link
Copy Markdown
Contributor

The full revision history is available in a separate branch (https://github.com/rustyrussell/bips/tree/guilt/varops): this is a clean one to submit for merge.

@jmoik
Copy link
Copy Markdown

jmoik commented Mar 9, 2026

to fix the CI we should add Toom = "Toom" to the [default.extend-words] section in .typos.toml.

Copy link
Copy Markdown
Member

@murchandamus murchandamus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only made it to the Multiply and Divide Opcodes in this first read. I suspect that I’m missing something about how you are describing the opcodes. Please see my comments for details.

@murchandamus murchandamus added the PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author label Mar 14, 2026
@rustyrussell rustyrussell force-pushed the varops-bips branch 3 times, most recently from c4572fe to 7d29c19 Compare March 23, 2026 04:21
@rustyrussell
Copy link
Copy Markdown
Contributor Author

@murchandamus thankyou for your detailed review. Here's the comment on the fixup commit which I hope addresses it:

Great feedback from Murch:
1. Lots of markdown instead of mediawiki formatting fixed.
2. Input count max fixed (explanatory only, but still a good fix).
3. Justification for detailed by-byte nature of descriptions added to global Rationale.
4. Note on truncation moved earlier, and expanded.
5. OP_OR/OP_XOR clarified to make it clear that A is altered "in-place".
6. Clarification on early termination (and thus cost) of OR and XOR.
7. nee is spelled "née" (Julian suggested replacing it, but let's try to keep some culture alive!).
8. Murch is now thanked in the thanks section.

In particular, Murch's confusion was enlightening.  I had not appreciated that
the reduction in script capability (removing all bitops and limiting operand
size) made endian of stack objects very much an *implementation detail*, thus
these descriptions are battling with people's head-canon of how Bitcoin's Stack
Is Just Numbers.

Mere words can only do so much to address this issue, but I've tried, and at
least I'm now aware of this.

Copy link
Copy Markdown
Member

@murchandamus murchandamus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the additional explanation and additions to the abstract helped.

My first impression from the document titles was that "Restoration of disabled script functionality (Tapscript v2)" would be focused on explaining the functionality of the restored opcodes (and perhaps only maybe mention costs), whereas "Varops Budget For Script Runtime Constraint" would expound on the budget and how the costs were found. It seemed to me that you were splitting the content for users of script from the content for the implementers.

In hindsight, I should have first read "Varops Budget For Script Runtime Constraint", I think "Restoration of disabled script functionality (Tapscript v2)" would have made more sense to me after that. Either way, the title "Restoration of disabled script functionality (Tapscript v2)" does not set the expectation that the main focus of the document would be to provide Rationale for the costs of the restored opcodes.

@rustyrussell
Copy link
Copy Markdown
Contributor Author

Thanks, the additional explanation and additions to the abstract helped.

My first impression from the document titles was that "Restoration of disabled script functionality (Tapscript v2)" would be focused on explaining the functionality of the restored opcodes (and perhaps only maybe mention costs), whereas "Varops Budget For Script Runtime Constraint" would expound on the budget and how the costs were found. It seemed to me that you were splitting the content for users of script from the content for the implementers.

Yes, the split is kind of awkward :(

In hindsight, I should have first read "Varops Budget For Script Runtime Constraint", I think "Restoration of disabled script functionality (Tapscript v2)" would have made more sense to me after that. Either way, the title "Restoration of disabled script functionality (Tapscript v2)" does not set the expectation that the main focus of the document would be to provide Rationale for the costs of the restored opcodes.

If we were to put restoration first, that BIP would become trivial. But, also, kinda useless? The varops budget BIP would then have to re-describe the restored opcodes in precise detail, in order to derive their costs.

I guess there are three parts:

  1. The concepts of varops, such as it limits and factors for different kinds of work opcodes can do.
  2. The restoration of script: removing length limits, making numbers unsigned, restoring old opcodes (presumably with a mention that this is deeply unsafe without the new varops).
  3. The reference-style listing and derivation of varops costs for every opcode.

Happy to do this. If so, would number 3 be a separate BIP, or a giant appendix? I think I'm too close to it to see it through fresh eyes, so I'll take your advice here? Help!

@murchandamus
Copy link
Copy Markdown
Member

I think my confusion was mostly caused by reading the documents in the order they appear in this PR instead of the intended order. When they’re assigned numbers, putting them in the order of recommended reading should mostly resolve that. The "Restoration" BIP should then also have a Requires header along the lines of “Requires: Varops BIP" in the Preamble to clarify.

After that, the split into three documents does not seem necessary.

Perhaps some tweaks to the tables would be able to address both parts of the audience. (This is a spontaneous suggestion, please feel free to reject or amend as makes sense to you.)

I’m thinking the following might help:

  • Required Stack Elements is a bit of a waste of space. Replace it with a column "Inputs", "Operands", or "Input Stack". This could communicate the count of operands and save you the "Pop x off the stack" lines in the Definition.
  • I would refer to the number as the opcode, so maybe rename "Opcode" to "Operation" or "Word" and "value" to "Opcode".
  • Add a column "Description" that gives a very short summary of what the opcode does. Between the Operands column and Description, the functionality should be clear enough to the Script users that read the BIP.
  • Then perhaps move the Varops Cost and Varops Reason to the end, to illustrate that they follow from the Definition.
image

That would make the columns:

| Operation | Opcode | Inputs | Description | Definition | Varops Cost | Varops Reason |

@rustyrussell rustyrussell force-pushed the varops-bips branch 2 times, most recently from 0c7e36a to 1093247 Compare March 24, 2026 04:14
Copy link
Copy Markdown
Member

@murchandamus murchandamus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, except for one more MediaWiki quirk and a potential issue in OP_RIGHT.

Copy link
Copy Markdown
Member

@murchandamus murchandamus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noticed a few more minor things when scanning the changes from the last version I reviewed.

@rustyrussell
Copy link
Copy Markdown
Contributor Author

Note: I noticed that we used the marker ARITH on some costs. This is not present in the varops BIP: I'm consulting with @jmoik now to see if this is a simple omission, or requires deeper change :(

@murchandamus
Copy link
Copy Markdown
Member

My apologies, @rustyrussell. I was intending to experiment on my own branch whether there is an easy way to prevent line breaks in the Input Stack column, but I pushed the commit to your branch instead of my repository. I’ve reverted the change.

Copy link
Copy Markdown
Member

@murchandamus murchandamus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the line breaking. Got a couple more format nits for you. Please feel free to ignore.

Also, let’s refer to the Grand Script Restoration BIPs as BIP 440 and BIP 441. I assume you’ll want to make it BIP440: Varops, and BIP441: Restoration, but please feel free to do it the other way around, if I misunderstood.

Could you please rename the files, set the BIP number and Assigned date in the Preamble headers, and add table entries to the table in the README.mediawiki?

@murchandamus murchandamus changed the title Varops: Two BIPs for Script Restoration: varops calculations and tapleaf version (0xc2). BIP440,441—Varops: Two BIPs for Script Restoration: varops calculations and tapleaf version (0xc2). Mar 25, 2026
@rustyrussell
Copy link
Copy Markdown
Contributor Author

OK, I shall also rebase to squash the bazillion fixes, if that's OK? I will leave the final change (which actually was a change in how OP_MUL costs are calculated) as a separate commit though.

@rustyrussell
Copy link
Copy Markdown
Contributor Author

I smooshed all the fixes, here's the diff from the last commit I pushed which you reviewed:

$ git diff 4256c69b5ade17e36e0cb30c07a33cf47125188a
diff --git a/bip-unknown-script-restoration.mediawiki b/bip-unknown-script-restoration.mediawiki
index 9e01eae6..56691843 100644
--- a/bip-unknown-script-restoration.mediawiki
+++ b/bip-unknown-script-restoration.mediawiki
@@ -624,7 +624,8 @@ Work in progress:
 
 ==Changelog==
 
-- 0.1.0: 2025-09-27: first public posting
+* 0.2.0: 2025-02-21: change costs to match those in varops budget
+* 0.1.0: 2025-09-27: first public posting
 
 ==Thanks==
 
diff --git a/bip-unknown-varops-budget.mediawiki b/bip-unknown-varops-budget.mediawiki
index c74c05be..bfc927b3 100644
--- a/bip-unknown-varops-budget.mediawiki
+++ b/bip-unknown-varops-budget.mediawiki
@@ -111,6 +111,7 @@ Each class then has the following costs.
 # OP_ROLL costs an additional 48 units (24 bytes per std::vector * 2 units per byte) per stack entry moved (i.e. the value of its operand).
 # Fast operations cost 2 units per byte output.
 # Copying operations cost 3 units per byte output.
+# Arithmetic operations (which don't pipeline as well due to the overflow between words) cost 6 units per byte output.
 # Other operations cost 4 units per byte output.
 
 ===Variable Opcode Budget===
@@ -127,6 +128,8 @@ We use the following annotations to indicate the derivation for each opcode:
 : Copying bytes: cost = 3 per byte copied.
 ;LENGTHCONV
 : Converting an operand to a length value, including verifying that trailing bytes are zero: cost = 2 per byte examined.
+;ARITH
+: Arithmetic operations which have carry operations: cost = 6 per byte examined.
 ;SIGCHECK
 : Checking a signature is a flat cost: cost = 500,000.
 ;HASH
@@ -328,8 +331,8 @@ Work in progress:
 
 ==Changelog==
 
-- 0.2.0: 2026-02-21: increase in cost for hashing and copying based on benchmark results.
-- 0.1.0: 2025-09-27: first public posting
+* 0.2.0: 2026-02-21: increase in cost for hashing and copying based on benchmark results.
+* 0.1.0: 2025-09-27: first public posting
 
 ==Thanks==
 

Sorry, I missed the nbsp; change. But it's horrible, because it makes the text unreadable. Let me experiment with putting a nbsp in the title as a workaround.

@rustyrussell rustyrussell force-pushed the varops-bips branch 2 times, most recently from 4a87852 to 9341e57 Compare March 27, 2026 04:11
@murchandamus murchandamus changed the title BIP440,441—Varops: Two BIPs for Script Restoration: varops calculations and tapleaf version (0xc2). BIP440: Varops Budget for Script Runtime Constraint, BIP441: Restoration of disabled Script (tapleaf 0xc2) Mar 27, 2026
Copy link
Copy Markdown
Member

@murchandamus murchandamus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the summary. Squash was a good call, changes look good, except that the Assigned date should be 2026-03-25 (see inline comment).

Sorry, I missed the nbsp; change. But it's horrible, because it makes the text unreadable. Let me experiment with putting a nbsp in the title as a workaround.

Wondering whether we crossed a wire here. I had tried using the non-breakable space HTML code in the commit that I accidentally pushed to your branch, but in <nowiki> it was written out which looked terrible (as you seem to have discovered as well).
Using the non-breakable space UTF-8 character (U+00A0) looked fine in the render and code (unless you have your editor set up to show it?), so that was what I recommended.

Otherwise looks good. Thanks for the quick turn-around, pleasure to work with you. :)

|-
|OP_CAT
|126
|<nowiki>[A B]</nowiki>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we crossed a wire here. I had tried and discarded the idea of using an HTML code (&nbsp;) in the <nowiki> but that looked terrible. I had then recommended on using a UTF-8 non-breakable space character instead (U+00a0). Like so (space in suggestion is actually a non-breakable space):

Suggested change
|<nowiki>[A B]</nowiki>
|<nowiki>[A B]</nowiki>

Preventing a linebreak in the title seems like a good idea, but it seems to be a bit unreliable:

Image

…eaf version (0xc2).

Special thanks to Murch for teaching me mediawiki, and so much great
formatting and clarity advice.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ndary.

Julian points out that the implementation does this, which improves accuracy
for the case of small B (since the term is multiplied: for normal OP_ADD etc
we don't bother, since the difference is very bounded).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
@rustyrussell
Copy link
Copy Markdown
Contributor Author

OK, fixed to use literal NO-BREAK SPACE not &nbsp, which is much better. And fixed dates. Squashed into three neat commits. Here's the overall diff since last review:

diff --git a/bip-0440.mediawiki b/bip-0440.mediawiki
index a8d58895..409b5a0f 100644
--- a/bip-0440.mediawiki
+++ b/bip-0440.mediawiki
@@ -6,7 +6,7 @@
            Julian Moik <julianmoik@gmail.com>
   Status: Draft
   Type: Specification
-  Assigned: 2026-03-27
+  Assigned: 2026-03-25
   License: BSD-3-Clause
   Discussion: https://groups.google.com/g/bitcoindev/c/GisTcPb8Jco/m/8znWcWwKAQAJ
               https://delvingbitcoin.org/t/benchmarking-bitcoin-script-evaluation-for-the-varops-budget-great-script-restoration/2094
diff --git a/bip-0441.mediawiki b/bip-0441.mediawiki
index 6caf21b5..f658bcef 100644
--- a/bip-0441.mediawiki
+++ b/bip-0441.mediawiki
@@ -6,7 +6,7 @@
            Julian Moik <julianmoik@gmail.com>
   Status: Draft
   Type: Specification
-  Assigned: 2026-03-27
+  Assigned: 2026-03-25
   License: BSD-3-Clause
   Discussion: https://groups.google.com/g/bitcoindev/c/GisTcPb8Jco/m/8znWcWwKAQAJ
   Version: 0.2.1
@@ -181,7 +181,7 @@ Fifteen opcodes that were removed in v0.3.1 are re-enabled in 0xC2 Tapscript.
 
 If there are fewer than the required number of stack elements, these opcodes
 fail validation.  These are popped off the stack in right-to-left order,
-i.e. <nowiki>[A B]</nowiki> means pop B off the stack, then pop A off the
+i.e. <nowiki>[A B]</nowiki> means pop B off the stack, then pop A off the
 stack.
 
 See [[bip-0440.mediawiki|BIP440]] for the meaning of the
@@ -192,7 +192,7 @@ annotations in the varops cost field.
 {|
 ! Mnemonic
 ! Opcode
-! Input&nbsp;Stack
+! Input Stack
 ! Description
 ! Definition
 ! Varops Cost
@@ -200,7 +200,7 @@ annotations in the varops cost field.
 |-
 |OP_CAT
 |126
-|<nowiki>[A B]</nowiki>
+|<nowiki>[A B]</nowiki>
 |Append B to A
 |
 # Pop operands off the stack.
@@ -211,7 +211,7 @@ annotations in the varops cost field.
 |-
 |OP_SUBSTR
 |127
-|<nowiki>[A BEGIN LEN]</nowiki>
+|<nowiki>[A BEGIN LEN]</nowiki>
 |Extract bytes BEGIN through BEGIN+LEN of A
 |
 # Pop operands off the stack.
@@ -223,7 +223,7 @@ annotations in the varops cost field.
 |-
 |OP_LEFT
 |128
-|<nowiki>[A OFFSET]</nowiki>
+|<nowiki>[A OFFSET]</nowiki>
 |Extract the left OFFSET bytes of A
 |
 # Pop operands off the stack.
@@ -234,7 +234,7 @@ annotations in the varops cost field.
 |-
 |OP_RIGHT
 |129
-|<nowiki>[A OFFSET]</nowiki>
+|<nowiki>[A OFFSET]</nowiki>
 |Extract the right bytes of A, from OFFSET onwards
 |
 # Pop operands off the stack.
@@ -259,7 +259,7 @@ OP_RIGHT must copy the bytes, which depends on the OFFSET value.
 {|
 ! Mnemonic
 ! Opcode
-! Input&nbsp;Stack
+! Input Stack
 ! Description
 ! Definition
 ! Varops Cost
@@ -278,7 +278,7 @@ OP_RIGHT must copy the bytes, which depends on the OFFSET value.
 |-
 |OP_AND
 |132
-|<nowiki>[A B]</nowiki>
+|<nowiki>[A B]</nowiki>
 |Binary AND of A and B
 |
 # Pop operands off the stack.
@@ -290,7 +290,7 @@ OP_RIGHT must copy the bytes, which depends on the OFFSET value.
 |-
 |OP_OR
 |133
-|<nowiki>[A B]</nowiki>
+|<nowiki>[A B]</nowiki>
 |Binary OR of A and B
 |
 # Pop operands off the stack.
@@ -302,7 +302,7 @@ OP_RIGHT must copy the bytes, which depends on the OFFSET value.
 |-
 |OP_XOR
 |134
-|<nowiki>[A B]</nowiki>
+|<nowiki>[A B]</nowiki>
 |Binary exclusive-OR of A and B
 |
 # Pop operands off the stack.
@@ -331,7 +331,7 @@ OP_DOWNSHIFT (née OP_RSHIFT).
 {|
 ! Mnemonic
 ! Opcode
-! Input&nbsp;Stack
+! Input Stack
 ! Description
 ! Definition
 ! Varops Cost
@@ -339,7 +339,7 @@ OP_DOWNSHIFT (née OP_RSHIFT).
 |-
 |OP_UPSHIFT
 |152
-|<nowiki>[A BITS]</nowiki>
+|<nowiki>[A BITS]</nowiki>
 |Move bits of A right by BITS (numerically increase)
 |
 # Pop operands off the stack.
@@ -352,7 +352,7 @@ OP_DOWNSHIFT (née OP_RSHIFT).
 |-
 |OP_DOWNSHIFT
 |153
-|<nowiki>[A BITS]</nowiki>
+|<nowiki>[A BITS]</nowiki>
 |Move bits of A left by BITS (numerically decrease)
 |
 # Pop operands off the stack.
@@ -385,7 +385,7 @@ routine as OP_DOWNSHIFT.
 {|
 ! Mnemonic
 ! Opcode
-! Input&nbsp;Stack
+! Input Stack
 ! Description
 ! Definition
 ! Varops Cost
@@ -418,7 +418,7 @@ routine as OP_DOWNSHIFT.
 |-
 |OP_MUL
 |149
-|<nowiki>[A B]</nowiki>
+|<nowiki>[A B]</nowiki>
 |Multiply A by B
 |
 # Pop operands off the stack.
@@ -432,7 +432,7 @@ routine as OP_DOWNSHIFT.
 |-
 |OP_DIV
 |150
-|<nowiki>[A B]</nowiki>
+|<nowiki>[A B]</nowiki>
 |Divide A by (non-zero) B
 |
 # Pop operands off the stack.
@@ -446,7 +446,7 @@ routine as OP_DOWNSHIFT.
 |-
 |OP_MOD
 |151
-|<nowiki>[A B]</nowiki>
+|<nowiki>[A B]</nowiki>
 |Replace A with remainder when A divided by (non-zero) B
 |
 # Pop operands off the stack.
@@ -476,7 +476,7 @@ The opcodes OP_ADD, OP_SUB, OP_1ADD and OP_1SUB are redefined in 0xC2 Tapscript
 {|
 ! Mnemonic
 ! Opcode
-! Input&nbsp;Stack
+! Input Stack
 ! Description
 ! Definition
 ! Varops Cost
@@ -484,7 +484,7 @@ The opcodes OP_ADD, OP_SUB, OP_1ADD and OP_1SUB are redefined in 0xC2 Tapscript
 |-
 |OP_ADD
 |147
-|<nowiki>[A B]</nowiki>
+|<nowiki>[A B]</nowiki>
 |Add A and B
 |
 # Pop operands off the stack.
@@ -509,7 +509,7 @@ The opcodes OP_ADD, OP_SUB, OP_1ADD and OP_1SUB are redefined in 0xC2 Tapscript
 |-
 |OP_SUB
 |148
-|<nowiki>[A B]</nowiki>
+|<nowiki>[A B]</nowiki>
 |Subtract B from A where B is <= A
 |
 # Pop operands off the stack.

@murchandamus murchandamus removed the PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author label Mar 29, 2026
Copy link
Copy Markdown
Member

@murchandamus murchandamus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I’m gonna leave it open for a few more days to see if more review substantiates. I’ll be afk for a week, will then revisit.

What’s the next step from your perspective? Is there still have planned work, are you waiting for any expected reviewers, or is it ready for publication from your side?

@rustyrussell
Copy link
Copy Markdown
Contributor Author

LGTM. I’m gonna leave it open for a few more days to see if more review substantiates. I’ll be afk for a week, will then revisit.

That seems wise: we're not suddenly in a hurry!

What’s the next step from your perspective? Is there still have planned work, are you waiting for any expected reviewers, or is it ready for publication from your side?

I am not expecting more reviewers, but of course I'm hoping that once it's merged we can get some more eyes on it. More feedback is always welcome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants