Add PayToAnchor(P2A), OP 1 <0x4e73> as standard output script for spending (tx fees and policy)

https://github.com/bitcoin/bitcoin/pull/30352

Host: glozow  -  PR author: instagibbs

The PR branch HEAD was 67c3537f75bcf085bb98e3830649e93da124cb06 at the time of this review club meeting.

Notes

  • Lightning Network (LN) commitment transactions may use anchor outputs to allow channel participants to fee-bump the presigned transactions through Child Pays For Parent (CPFP) at broadcast time. The current design (see BOLT 3) has a few limitations described in this blog post.

    • The most relevant point here is the fact that the anchors currently specify a p2wsh script including two spending paths: using the party’s funding key, or anyone 16 blocks after the transaction confirms. Spending this anchor output requires paying fees for a relatively large amount of data. We call these anchors keyed because of the presence of a key in the locking script.

    • Assuming there are no reasons to use keyed anchor outputs (there are, but that is out of scope for this review club), a keyless anchor may reduce complexity (including for a watchtower) and make fee-bumping more space and fee-efficient.

  • Ephemeral Anchors enable a new pattern for adding fees to presigned transactions, with a few key improvements:

    • The anchor output can have any nValue, including amounts below the dust threshold such as 0, as long as it is spent immediately, i.e. relayed in a package with a fee-bumping child. Implementing this policy requires ensuring that the anchor is always spent after subsequent mempool updates, so it is only implemented for TRUC transactions which are restricted to a very simple topology. This portion of the proposal was split into its own “ephemeral dust” PR, #30239.

    • The anchor output is “keyless” or “anyone-can-spend”, reducing the amount of data (and thus fees) needed in the CPFP transaction, and making it easier for watchtowers to help broadcast presigned transactions. This part of the proposal, #30352, is independent of the “ephemeral dust” concept, and the implementation is simple regardless of transaction topology.

  • While scriptPubKeys can be fairly freeform, Bitcoin Core enumerates several TxoutTypes. These correspond to output types that you may be familiar with like SCRIPTHASH (P2SH), WITNESS_V0_KEYHASH (P2WPKH), WITNESS_V0_SCRIPTHASH (P2WSH), and NULL_DATA (OP_RETURN or datacarrier).

    • Solver pattern-matches scriptPubKeys to classify their output type; anything that does not fall into the known categories is TxoutType::NONSTANDARD.

    • By default, a transaction must pass standardness checks to be accepted to mempool. IsStandardTx() inspects the TxoutTypes of each of the transaction’s inputs and outputs, among other checks.

    • Notice the difference in rules applied to inputs and outputs. A particular output type may be nonstandard to create but standard to spend, and vice versa.

  • This PR does two things: it defines OP_1 <0x4e74> as a new output type, and relaxes policy rules to make it standard to spend this output type, as long as the witness is empty.

Questions

  1. Did you review the PR? Concept ACK, approach ACK, tested ACK, or NACK? What was your review approach?

  2. Before TxoutType::ANCHOR is defined in this PR, what TxoutType would a scriptPubKey OP_1 <0x4e73> be classified as? (Hint: what would Solver return?)

  3. Based on the answer to the previous question, would it be standard to create this output type? What about to spend it? (Hint: how do IsStandard and AreInputsStandard treat this type?)

  4. Before this PR, with default settings, which output types can be created in a standard transaction? Is that the same as the script types that can be spent in a standard transaction?

  5. Define anchor output, without mentioning Lightning Network transactions (try to be more general).

  6. The PR description claims that creation of the defined P2A output type is already standard prior to the PR. Is this true, and how did you verify this?

  7. Why does the size of the output script of an anchor output matter?

  8. What other ways can you think of to implement an ‘anyone-can-spend’ anchor?

  9. Continuing on the previous question, what would be the problem with using P2SH(OP_TRUE)?

  10. What is the difference between OP_TRUE and OP_1? (Hint: where are they defined in the code?)

  11. How many virtual bytes are needed to create and spend a P2A output?

  12. The 3rd commit adds if (prevScript.IsPayToAnchor()) return false to IsWitnessStandard. What does this do, and why is it needed?

  13. How is witness program defined in BIP141? Where is it implemented in the code? (Hint: look for IsWitnessProgram)

  14. VerifyWitnessProgram is modified to allow version 1, <0x4e73>, if is_p2sh is false. Why is !is_p2sh needed?

Meeting Log

  117:00 <glozow> #startmeeting
  217:00 <glozow> hi
  317:00 <monlovesmango> hey
  417:00 <instagibbs> hi (lurking only)
  517:00 <vostrnad> hi
  617:00 <codingp110> hi
  717:00 <glozow> Welcome to PR Review Club! Feel free to say hi
  817:00 <stickies-v> hi
  917:01 <glozow> Today's PR is P2A: https://bitcoincore.reviews/30352
 1017:01 <glozow> Did everybody get a chance to review the PR or read through the notes?
 1117:01 <monlovesmango> yes
 1217:01 <stickies-v> yup
 1317:02 <glozow> Awesome. For those who reviewed, what was your review approach?
 1417:02 <emc99> hi
 1517:03 <monlovesmango> mostly just reviewed the code (as much as I could) and read through pr and some of other linked documentation
 1617:03 <glozow> monlovesmango: cool!
 1717:03 <glozow> Let's dive into the questions
 1817:03 <glozow> Before `TxoutType::ANCHOR` is defined in this PR, what TxoutType would a scriptPubKey OP_1 <0x4e73> be classified as?
 1917:04 <monlovesmango> TxoutType::WITNESS_UNKONWN I think
 2017:04 <stickies-v> yup that's my understanding too
 2117:04 <glozow> monlovesmango: yep!
 2217:05 <stickies-v> it's witness version 1 but not 32 bytes in size
 2317:05 <glozow> didn't need to give the hint, but here's the code: https://github.com/bitcoin/bitcoin/blob/24f86783c87e836c98404bcc20a07742736d6b56/src/script/solver.cpp#L172-L176
 2417:05 <glozow> And would it be standard to create this output type (`WITNESS_UNKNOWN`)?
 2517:05 <monlovesmango> yes
 2617:06 <vostrnad> it's even been done already ;)
 2717:06 <instagibbs> *looks suspiciously at vostrnad*
 2817:06 <monlovesmango> XD
 2917:06 <glozow> indeed, do anyone have a block explorer link to that tx? I couldn't find it
 3017:06 <glozow> does*
 3117:07 <vostrnad> all 3 existing P2A UTXOs here: https://mempool.space/address/bc1pfeessrawgf
 3217:07 <glozow> Ok, what about to spend it? Would that have been standard? (before this PR)
 3317:07 <instagibbs> b10c0000004da5a9d1d9b4ae32e09f0b3e62d21a5cce5428d4ad714fb444eb5d
 3417:07 <monlovesmango> no
 3517:07 <glozow> monlovesmango: bonus points if you have a link to code :P
 3617:08 <glozow> (correct)
 3717:08 <monlovesmango> https://github.com/bitcoin/bitcoin/blob/master/src/policy/policy.cpp#L188
 3817:08 <monlovesmango> ?
 3917:09 <instagibbs> that's one spot, there's another too(read hte comment)
 4017:10 <vostrnad> https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L1950
 4117:12 <glozow> vostrnad: nice
 4217:12 <glozow> Before this PR, with default settings, which output types can be created in a standard transaction?
 4317:12 <monlovesmango> haha i was not going to find that anytime soon...
 4417:13 <monlovesmango> PUBKEY, PUBKEYHASH, SCRIPTHASH, MULTISIG, NULL_DATA, WITNESS_V0_KEYHASH, WITNESS_V0_SCRIPTHASH, WITNESS_V1_TAPROOT, WITNESS_UNKNOWN
 4517:14 <vostrnad> correct
 4617:14 <glozow> monlovesmango: awesome yeah, more details at https://github.com/bitcoin/bitcoin/blob/e8eab747192bd330e67bff1222bb851bc515b134/src/policy/policy.cpp#L53-L74
 4717:14 <glozow> And as we've established, that's not the same as what can be spent in a standard tx
 4817:15 <glozow> Define anchor output, without mentioning Lightning Network transactions (ie try to be more general).
 4917:16 <monlovesmango> an extra output created on presigned transactions which allows fees to be added via CPFP at the time of broadcasting.
 5017:16 <glozow> monlovesmango: great definition 👍
 5117:17 <glozow> Not on the list, but can someone tell us the difference between a keyed and a keyless anchor? And why that matters?
 5217:17 <stickies-v> a keyless anchor doesn't contain a pubkey in its scriptpubkey, significantly reducing its on-chain footprint (and cost)
 5317:18 <glozow> stickies-v: yes, and anybody can spend it
 5417:18 <monlovesmango> I think keyless means that anyone can create a child for it (ie you don't need a specific key), which reduces the scriptPubkey size
 5517:19 <glozow> monlovesmango: yes anybody can spend it. it doesn't inherently make the onchain data smaller but it is true in this case
 5617:19 <glozow> for example you could have a p2wsh where one of several spending paths is something anybody can spend, which is larger
 5717:20 <glozow> Did anybody, while reviewing, try to verify that a P2A tx can be created but not spend in policy (before the PR)?
 5817:20 <glozow> Beyond code review I mean
 5917:20 <monlovesmango> was just about to ask about what case this wouldn't be true! thanks!
 6017:20 <monlovesmango> no
 6117:22 <vostrnad> instagibbs was, using Twitter as a broadcasting channel, doesn't seem to have worked
 6217:22 <glozow> current LN commitment transactions are a more concrete example https://github.com/lightning/bolts/blob/master/03-transactions.md#to_local_anchor-and-to_remote_anchor-output-option_anchors (there is a key, but since it is revealed, anybody can reconstruct the script)
 6317:22 <glozow> vostrnad: ah cool i didn't see that
 6417:22 <instagibbs> vostrnad ;(
 6517:23 <glozow> I was just suggesting you compile master, and then run the tests 😅
 6617:23 <glozow> Why does the size of the output script of an anchor output matter?
 6717:24 <vostrnad> the smaller the betterer?
 6817:24 <monlovesmango> the larger the anchor output size, the more fees you need to prioritize it to be relayed
 6917:25 <glozow> yeah pretty much
 7017:25 <instagibbs> smaller script also means min satoshi value to relay is smaller too
 7117:26 <glozow> also more efficient fee bumping = incentives to fee bump this way...
 7217:27 <glozow> What other ways can you think of to implement an ‘anyone-can-spend’ anchor?
 7317:27 <vostrnad> instagibbs: sure but policy can be changed any time, perhaps there could be a dust policy carve out for P2A as it's unusually cheap to spend
 7417:28 <monlovesmango> P2SH of OP_TRUE..?
 7517:28 <glozow> I suppose you could just implement GetDustThreshold for P2A for the same effect, no?
 7617:28 <glozow> monlovesmango: great! And why is that not as good as P2A?
 7717:28 <monlovesmango> bc it introduces transaction malleability
 7817:29 <monlovesmango> (which makes chained presigned transactions unreliable)
 7917:30 <glozow> monlovesmango: how would you malleate the tx?
 8017:31 <monlovesmango> i guess i am fuzzy on whether its a problem if there is only a single presigned tx. however if there were multiple presigned txs strung together, the miner could insert a OP_NOP in the scriptSig which would change the tx id
 8117:31 <monlovesmango> which would break the chain
 8217:32 <monlovesmango> (all taken from instagibbs pr comment https://github.com/bitcoin/bitcoin/pull/30352#issuecomment-2228528366)
 8317:33 <instagibbs> fwiw p2sh requires push-only scriptsig, so I don't think the NOP thing works for p2sh, but cleanstack is the other thing
 8417:33 <glozow> it's also larger, no?
 8517:33 <instagibbs> yeh. p2sh(OP_DEPTH OP_NOT) might be txid stable?
 8617:33 <instagibbs> (but ugh)
 8717:34 <glozow> wait what does OP_DEPTH do?
 8817:34 <monlovesmango> if there were only usecases for a single presigned tx, would there be any issue with P2SH?
 8917:34 <monlovesmango> (apart from maybe size..?)
 9017:34 <glozow> oh size of stack
 9117:35 <sipa> p2sh(OP_DEPTH OP_1 OP_EQUALVERIFY OP_1) maybe?
 9217:35 <sipa> eh
 9317:35 <sipa> p2sh(OP_DEPTH OP_0 OP_EQUALVERIFY OP_1) maybe?
 9417:35 <sipa> oh, OP_NOT, i misread it as OP_NOP; indeed!
 9517:35 <vostrnad> instagibbs: interesting, it never occurred to me you could make a non-malleable P2SH output like that
 9617:35 <instagibbs> so you could probably get smaller than P2WSH(OP_TRUE) and still be txid stable
 9717:36 <monlovesmango> what does push-only scriptsig mean? that you can only use OP codes that push onto the stack?
 9817:36 <sipa> monlovesmango: indeed, this is a BIP16 consensus rule
 9917:36 <instagibbs> vostrnad h/t jeremy, he proposed the bare version
10017:36 <vostrnad> monlovesmango: scriptSig is actually a script that in legacy script can have non-push opcodes as well
10117:37 <sipa> which likely was one day intended to support delegation, before the scriptSig/scriptPubkey execution split in 2010
10217:37 <monlovesmango> got it thank you for all the background!!
10317:37 <vostrnad> instagibbs: bare version is malleable though because no push-only
10417:37 <instagibbs> vostrnad exactly 👍
10517:38 <glozow> What is the difference between OP_TRUE and OP_1? (Hint: where are they defined in the code?)
10617:39 <monlovesmango> but just to verify my understanding, its the spending tx that becomes malleable when using the bare version right?
10717:39 <instagibbs> monlovesmango yes a miner can insert OP_NOP
10817:40 <monlovesmango> awesome thanks
10917:41 <abubakarsadiq> glozow: I think they are the same?
11017:41 <vostrnad> "they're the same picture"
11117:41 <glozow> abubakarsadiq: yes :D
11217:41 <abubakarsadiq> `OP_TRUE=OP_1`
11317:41 <glozow> What is the difference between OP_TRUE and OP_1? (Hint: where are they defined in the code?)
11417:41 <glozow> oops wrong paste
11517:41 <glozow> https://github.com/bitcoin/bitcoin/blob/da083d4bbdb37737f5080fada97bd15f5a8bfb2d/src/script/script.h#L82-L83
11617:42 <monlovesmango> haha tricky q
11717:42 <Murch[m]> What’s OP_TRUE? Isn’t that just OP_1?
11817:42 <glozow> it's a Q to get people out of lurking, it worked :P
11917:42 <monlovesmango> heheheh
12017:42 <glozow> How many virtual bytes are needed to create and spend a P2A output?
12117:43 <glozow> that Q was designed to lure Murch here, but I see he's already appeared
12217:43 <sipa> Murch[m]: I see your message as "What’s QOP_TRUE? Isn’t that just QOP_1?", what are those Qs?
12317:43 — Murch[m] goes back into hiding
12417:43 <glozow> backticks?
12517:44 — Murch[m] uploaded an image: (7KiB) < https://matrix.bitcoin.ninja/_matrix/media/v3/download/matrix.org/OwgTaVVPBpxeysmEgKuIuRET/image.png >
12617:44 <Murch[m]> Are you on IRC or Matrix?
12717:44 <Murch[m]> But sorry, we are derailing
12817:45 <Murch[m]> A keyless Anchor is 11 bytes, and the input would be 41 bytes?
12917:45 <Murch[m]> s/bytes/vbytes/
13017:46 <vostrnad> Murch[m]: I count 40.25 vbytes to spend, did you round down?
13117:46 <vostrnad> *up
13217:46 <Murch[m]> The input script length is a whole vbyte, right?
13317:46 <Murch[m]> 32+4+4+1
13417:47 <vostrnad> sorry, 41.25 vbytes (1 WU for the witness stack length)
13517:47 <Murch[m]> Also it might only be 10 bytes for the output? Amount (8 B), output script length (1  B), OP_1 (1 B)
13617:47 <Murch[m]> vostrnad: Sure, if you have other inputs with witnesses
13717:48 <vostrnad> you better do!
13817:48 <instagibbs> segwit.... but !HasWitness(), spooky
13917:49 <vostrnad> I get 12 bytes for a P2A output, 8 bytes for amount and 4 bytes for output script
14017:49 <vostrnad> wrong again, 13 (forgot output script length)
14117:49 <instagibbs> :)
14217:49 <vostrnad> these things are hard
14317:49 <Murch[m]> Yeah
14417:49 <Murch[m]> What do you have for the output script in detail?
14517:50 <glozow> 51 02 4e 73 is 4 bytes yes?
14617:50 <glozow> oh and 1
14717:50 <Murch[m]> Oh, it’s witness output, not a bare output
14817:50 <vostrnad> bare output would be malleable
14917:50 <glozow> instagibbs: too spooky
15017:51 <glozow> ok so we've landed on 13 + 41?
15117:51 <sipa> woah, segwit output but !HasWitness() on the input is legal?
15217:51 <sipa> i guess it's only the other way around that non-segwit output with HasWitness() is illegal?
15317:51 <glozow> 9 more minutes, 3 more questions
15417:51 <glozow> The 3rd commit adds `if (prevScript.IsPayToAnchor()) return false` to IsWitnessStandard. What does this do, and why is it needed?
15517:55 <monlovesmango> does it allow the option to opt out of anchor txs?
15617:55 <abubakarsadiq> It prevent adding a witness for a keyless anchor input, since it's no witness is needed to validate the utxo
15717:55 <glozow> maybe the code link will help https://github.com/bitcoin-core-review-club/bitcoin/commit/ccad5a5728c8916f8cec09e838839775a6026293#diff-ea6d307faa4ec9dfa5abcf6858bc19603079f2b8e110e1d62da4df98f4bdb9c0R228-R232
15817:56 <glozow> abubakarsadiq: correct, no witness stuffing allowed
15917:56 <glozow> anybody have a link to the test case for this? (you can find it by commenting out this line to see what fails)
16017:56 <instagibbs> an adversary could take an honest spend, add stuff to witness, propagate it at a lower feerate, and honest user would have to pay incremental fees to replace it...
16117:57 <instagibbs> (and the adversary could just keep doing it)
16217:57 <abubakarsadiq> the tx is just not standard, but still valid right?
16317:58 <glozow> ye, `IsWitnessStandard`
16417:58 <vostrnad> abubakarsadiq: yes, but miners have no reason to inflate your tx if it doesn't malleate it
16517:59 <glozow> test: https://github.com/bitcoin/bitcoin/blob/da083d4bbdb37737f5080fada97bd15f5a8bfb2d/test/functional/mempool_accept.py#L399-L414
16618:00 <glozow> that's time
16718:00 <glozow> #endmeeting