Segwit Ephemeral Anchors

Ephemeral Anchors are the concept where we can have a key-less output type that is allowed to have dusty values, provided they are atomically spent in the mempool.

Implementation and BIP text here for more background: policy: Ephemeral anchors by instagibbs · Pull Request #26403 · bitcoin/bitcoin · GitHub

One large drawback of this approach is that it relies on Bitcoin’s legacy script. This means that the transaction spending the anchor is txid-malleable by miners. This is due to legacy script’s lack of CLEANSTACK consensus rules. This means composition with other protocols like splicing can be problematic, where the pre-signed transaction chains can be broken unless a new signature type like ANYPREVOUT or similar is used.

At first blush, something like wsh(OP_TRUE) neatly solves this, at the expense of 33 more output vbytes, and a witness script of “OP_TRUE” being revealed. This seems pretty costly, and theoretically could also already be used in mainnet, both for output creation and redemption.

Instead, why not just utilize bip141’s softfork for witness programs, and use an otherwise undefined witness program? For example, replace the script “OP_TRUE” with “OP_TRUE 0xffff” which triggers the scriptSig rule in bip141:

The scriptSig must be exactly empty or validation fails.

But is otherwise undefined, allowing an empty witness to spend. This is 3 additional vbytes over the original proposal total, and is implemented here:

https://github.com/instagibbs/bitcoin/commits/ephemeral-anchors-segwit

Note that these (non-dust)outputs are already standard to create, but not to spend, which is the additional relay relaxation in the commit.

The branch will actually get smaller since I’m not messing with OP_TRUE outputs anymore which tests in master love to use.

3 Likes

If you made the two digit code be 0x4e73 instead of 0xffff that would give it the bech32m address bc1pfeessrawgf (ie “bc1p”, “fees”, checksum).

You can choose any three letters in the bech32 charset followed by either q or s, followed by the 6 char checksum. (0xffff is bc1plllsqd8ech; 0x0100 (1) gives bc1pqyqqgs7ult; 0x0001 (256) gives bc1pqqqs4em24r and 0x0000 gives bc1pqqqqqcnjqs)

EDIT: testnet/signet has 4e73 look like tb1pfees9rn5nz or with regtest bcrt1pfeesnyr2tx. bitcoin-cli decodescript 51024e73 if you want to try other combinations for something fun.

6 Likes

I mostly did ff’s because I realized I couldn’t do 0’s…

bc10feespdsrh8 (0fees) bc1z9gfqhanchr (anchr) bc1zfeesuqhy82 (zfees)

I’m glad we’re discussing the real questions left.

good point we’ll probably want it obvious in with any checksum due to network/address differences.

1 Like

Sticking with witness version 1 (taproot-adjacent) and bc1p seems like it would be wise, at least.

I’m considering supporting both OP_TRUE and OP_TRUE 0x4e73 at this point. It’s a tiny difference, and users can opt into non-segwit versions if they simply don’t care about the child transactions’ txid stability.

1 Like

I don’t understand what you’re doing here. The BIP you link seems to only talk about plain OP_TRUE, right? So the malleable version? What part of the BIP141 are you using to do this?

I don’t understand “otherwise undefined witness program”. You mean v1 programs that are not 32 bytes and redefine those? But then why would you need OP_TRUE? Can’t you simply standardize a v1 program that is 1-byte in size and make it standard if thar 1 byte has a fixed value? Which is anyone can spend anyway, so it’s the same as OP_TRUE?

That’s the malleable version yes.

Because that’s not a witness program, meaning it’s allowed to have non-empty scriptSig data, making it malleable.

Heh? Can you re-read my original message? And explain what you are proposing/describing? What I said was to standardize a v1 (taproot-version) witness program of a single byte. So like scriptPubkey of OP_1 OP_PUSHBYTES_1 0x42. I think for consensus any non-32-byte v1 program is anyone-can-spend, no?

couple of confusions:

  1. bip141 requires two byte push to 40.
  2. OP_TRUE==OP_1

I’ll cleanup my branch to refer to OP_1 since it’s more clear what we’re going for.

1 Like

Did you mean: bip141 requires a push of between 2 and 40 bytes?

What was wrong with a 1 byte push again?

Seems like a good question for https://bitcoin.stackexchange.com/ – I think segwit was originally a single push, where the first byte was the version, and the rest was the program; with that push being between 2 and 41 bytes; now the version and program are separate pushes, but rather than having the program be 1-40, it’s 2-40…

EDIT: How could a 2 byte witness program make sense? - Bitcoin Stack Exchange suggests it’s to avoid ambiguity on how to push one-byte (OP_1 vs 0101 etc)

2 Likes

I don’t have any concrete cases which could benefit from such short witness programs.

Glad to find a counter-example

1 Like

update here, I’ve broken off this specific feature into the new output type only, separate from what I’m now calling “ephemeral dust”, calling it Pay To Anchor(P2A): policy: Add PayToAnchor(P2A), `OP_TRUE <0x4e73>` as a standard output script for spending by instagibbs · Pull Request #30352 · bitcoin/bitcoin · GitHub

concept (n)ACKs/review would be welcome

1 Like