Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Runestone tags to be placed in witness data #4219

Open
joshdoman opened this issue Feb 11, 2025 · 2 comments
Open

Allow Runestone tags to be placed in witness data #4219

joshdoman opened this issue Feb 11, 2025 · 2 comments

Comments

@joshdoman
Copy link

I've been thinking about basic improvements that can be made to the Runestone scripting language, which I expect will become more important over time as the number of even tags expands and it becomes more common for large Runestones to be made.

First and foremost, I think ord should consider adding an even tag, which indicates that additional tags are in a taproot or P2WSH witness envelope.

There are two problems with requiring a Runestone to be placed in an OP_RETURN as it stands today:

  1. If the Runestone exceeds approximately 133 bytes, it becomes more cost effective to inscribe some data in a witness envelope to benefit from the witness discount (like the details of an etching).
  2. If the Runestone exceeds 80 bytes, the transaction can't pass Bitcoin Core mempool standardness rules. It could still be submitted to a private mempool, but this can be expensive, making 80 bytes effectively the limit. ord already has a number of runestone_size test cases that exceed 80 bytes if a new tag is added, and one test already exceeds the limit.

Bitcoin Core recently introduced support for ephemeral anchors and package relay, which would make it quite easy for users to submit a package of commit and reveal transactions, where the Runestone is in the witness of the latter.

Potential Cost Savings

For maximum efficiency, I'd recommend the data be allowed to be put in a taproot witness envelope or a P2WSH envelope, with a pointer to the tx envelope number. The latter would cut out the 33 byte control block in the witness, which is unnecessary if you only need a single script path. You could even remove the signature if you don't require an OP_RETURN and don't mind others placing tags there. If something like OP_CTV eventually gets implemented, you could specify that there's no OP_RETURN or that the OP_RETURN contains nothing.

By my calculation, in a purely taproot package of transactions with 2 signatures, the Runestone would need to be ~177 bytes for this to make sense. To move a Runestone to a witness, you need 3 additional pieces of data:

  1. An even Witness tag that indicates that Runestone tags are in a witness envelope (the tag followed by the envelope index, ~2vb)
  2. A witness envelope (3 vb)
  3. The equivalent of a transaction spending to a taproot output and spending from a taproot output using a script path with a single signature (128 vb).
    3a. For reference, a script path spend with a single signature has 68 bytes of additional witness data, or 17 vb, vs a taproot key path spend (1 byte for script length, 34 bytes for the script, and 33 bytes for the control block.
    3b. Meanwhile, a 1-input-1-output taproot key path spend is 111 vb.

Adding them up, you have 133 vb of additional data. This would imply that the Runestone itself would need to be ~177 bytes of data before it becomes cost effective to move it to the witness (133 + 177 / 4 = 177). If you want, you could save 7vb by using a P2WSH commitment output, which would get rid of the control block, but add 1 vb for the ECDSA signature. This would imply you'd add 126 vb of additional data and need 168 bytes of tag-related data before it makes sense to put it in a witness envelope.

The real cost savings come when you remove the need for a signature. With a P2WSH commitment output, you would need nothing but the witness envelope, getting rid of the signature and the script altogether. This would save 105 bytes of witness data, or 26.25 vb, reducing the amount of additional data to 100 vb, which would require 133 bytes of tag-related data to breakeven.

This would be ideal for use cases where you don't need a Runestone in the OP_RETURN of the reveal transaction, and you don't care if there is one. This could include messages authorizing an asset to be released from a vault, or the details of an etching, which was made in the commitment transaction.

Use Cases for Large Runestones

This could provide meaningful cost savings, especially in etchings with many tags, or with tags that reference large values. If fee rates rise significantly, cost efficient tagging could mitigate the impact on use cases that require frequent etchings, like an event organizer creating multiple classes of tickets for multiple recurring events, and use cases where there may be a lower willingness to etch, like a commemorative airdrop to attendees of an event, which may or may not be transferable.

In particular, I think this could be particularly useful for #4218 by making it more cost effective for rune holders to vote on governance proposals. Users could sign messages offchain, proving they own a UTXO through a virtual deterministic self-spend no-fee transaction that includes the message they want to sign. Only the signatures and unlocking scripts authorizing the virtual transaction and the message itself would need to be placed in the envelope.

Signatures could then be aggregated and broadcast all at once in a transaction. There could even be a tip to the broadcaster, in the form of a rune, or in the case of a vault sending out an asset, it could be paid for by the recipient. With a way to sign arbitrary messages proving ownership of any UTXO, the possibilities become endless.

A more near-term compelling argument, though, is to ensure users can get transactions relayed and included in blocks, even if the runestone exceeds 80 bytes. If core devs saw that users were doing this, there would be a stronger case for changing relay policies and lifting the OP_RETURN limit.

Concluding Thoughts

Even if this isn't a pressing issue now, it could become one, especially if ord starts adding new tags, which make it hard for certain transactions to get relayed. Many new types of features can then be safely added to ord, like transfiguration / vaulting, unvaulting, changes to vault governance, freezing, dynamic minting, etc.

@casey How would you feel about adding this to the roadmap? It doesn't need to be added imminently, and perhaps it shouldn't be until users complain, but it might be good to start thinking about. At a protocol level, I don't think it would be too difficult to do.

The biggest challenge I see is implementing this safely. If marketplaces and wallets don't upgrade their version of ord, users might buy a rune in one wallet or marketplace that isn't supported elsewhere. To mitigate this, ord might require runes to opt in by adding the Witness tag in the etching. Additionally, ord could apply this retroactively to all runes etched with a turbo flag, allowing the feature to be used for runes immediately while encouraging new runes to be made explicitly compatible, even if some wallets don’t yet support it.

@casey
Copy link
Collaborator

casey commented Feb 12, 2025

Here's my thinking:

  • Regarding the 80 byte OP_RETURN standardness limit, I actually do not think that this is something we should work around. Many miners already accept nonstandard transactions, and Peter Todd's Libre Relay fork of Bitcoin Core can be used to submit oversize OP_RETURNs without needing to send them to a specific miner. It is in the rational self-interest of miners to accept transactions with oversize OP_RETURNS, and I think eventually, Bitcoin Core will lift the standardness limit, so we just shouldn't worry about it.

  • The space savings is nice, but it comes at the cost of a high degree of protocol complexity. Additionally, there is little demand for this at the moment. I myself made one transaction with a really large runestone which had to be submitted directly to a miner, and I think that there are a few others, but they are rare.

  • If we put data anywhere, this should ideally go in the taproot signature annex. The signature annex is covered by signatures, so doesn't require a commit/reveal, and receives the witness discount. Attempts to standardize a format for unstructured data in the annex have kind of stalled out. (See Store inscriptions in taproot signature annex #2405.) But in this case I think we should just wait. If you wanted to champion carving out a standardness exception for unstructured annex data, I think that would be a worthy cause, and would allow this to come closer to being actionable.

So I think I would change this issue to "allow edicts to be placed in the taproot signature annex", since edicts are what winds up being large. A runestone would have a new flag (there is a flags field which is an even tag, and if there are unrecognized flags, it is treated as an unknown even field) which indicates that edicts are present in the signature annex. It then looks for a signature annex with edicts and processes the transaction accordingly.

And I think a prerequisite for that would to be worth doing would be the ability to construct a transaction with a signature annex with unstructured data, which can be broadcast and mined without needing to collude with a miner. I think if Libre Relay supported it, that would be good enough.

@joshdoman
Copy link
Author

And I think a prerequisite for that would to be worth doing would be the ability to construct a transaction with a signature annex with unstructured data, which can be broadcast and mined without needing to collude with a miner. I think if Libre Relay supported it, that would be good enough.

I think the proposal to put data in the taproot annex is a fantastic one. I had no idea such a thing even existed, until you mentioned it.

What will it take for Core Devs to preemptively soft-fork in functionality for arbitrary data to be safely placed in the annex? I really like the TLV proposal you suggested in #4229 , but it seems to me that there is little incentive on Core's part, or on the part of regular users, to build this functionality. Might it make sense for ord devs to create a BIP or implement your proposal? Anyone can be a Core dev, technically, if they can create a PR.

That being said, many people, rightfully or not, hate the idea of 1s and 0s existing onchain which they do not consider meaningful, and which they do not value. Never mind the fact that data in the taproot annex could meaningfully reduce congestion, and thereby reduce fees. People still tend to despise non-bitcoin data existing onchain.

This suggests to me that nothing short of a "hack," where some developer goes ahead and builds a metaprotocol that uses the annex, or that could use the annex, is the only way to force the issue. I don't like the idea of force, so that developer will never be me, but I would hope that this would not be necessary. I just struggle to see a path right now, given how contentious soft forks can be, where this happens without such a "hack."

I think this was part of my motivation for #4229 . If a unified protocol gets built, where data can live, for instance, in an OP_RETURN OR within a taproot annex, the protocol could go live, and the problem would be made front-and-center, even if users aren't actively submitting transactions with data in the annex. The fact that they could might be enough to place the issue front and center for discussion, with minimal risk to Bitcoin or the protocol if the annex is later divided up in an incompatible way. Because the OP_RETURN remains a fallback.

Anyway, I digress.

Thank you for the feedback. As you say, the question of putting Runestone data in the witness can be addressed later, when users start to complain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants