Bitcoin Forum

Bitcoin => Development & Technical Discussion => Topic started by: NotATether on August 26, 2020, 05:20:08 PM



Title: What's stopping OP_CHECKMULTISIG extra pop bug from being fixed?
Post by: NotATether on August 26, 2020, 05:20:08 PM
OP_CHECKMULTISIG opcode has a bug where N, the public keys, M and the signatures are popped from the stack, it pops an extra unnecessary item off the stack. This forces all multisig transactions to have a dummy value at the beginning of the unlocking script like OP_0 or something. Since it's only one byte, the space saved by fixing this is negligible and not much of a big deal but this is a long standing bug. The only explanation I found is that it's consensus-critical code (https://bitcoin.stackexchange.com/a/40673). So what will happen to the consensus if this is fixed?


Title: Re: What's stopping OP_CHECKMULTISIG extra pop bug from being fixed?
Post by: achow101 on August 26, 2020, 05:37:29 PM
Changing this is a hard fork, so everyone needs to upgrade their node to one which doesn't have this bug. This is difficult to do and not very worthwhile.


Title: Re: What's stopping OP_CHECKMULTISIG extra pop bug from being fixed?
Post by: pooya87 on August 27, 2020, 03:39:15 AM
a dummy value at the beginning of the unlocking script like OP_0 or something.

there is a partial fix for this in BIP-147 (https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki) that was deployed with SegWit soft-fork that forces this dummy value to be OP_0 whereas before it could be anything and waste more bytes.


Title: Re: What's stopping OP_CHECKMULTISIG extra pop bug from being fixed?
Post by: BrewMaster on August 27, 2020, 01:24:17 PM
Changing this is a hard fork, so everyone needs to upgrade their node to one which doesn't have this bug. This is difficult to do and not very worthwhile.

On a side note, what would happen to old P2SH/P2WSH addres which uses OP_0 at the beginning of multisig script if hard fork which fixed the bug happened?
Would it become invalid or the client explicitly check when the input is created just like other fork?

any standard multisig redeem-script that is created by any wallet only contains the public keys and the m and n values. the OP_0 is always part of the signature that will be included after the signatures were produced and the transaction is ready to be included in a block and it is placed all the way at the beginning of the scriptsig like this:
Code:
OP_0 <m*signatures> <redeemscript>
after such a hard fork the above simply becomes the following spending the same P2SH or P2WSH output:
Code:
<m*signatures> <redeemscript>

it is highly unlikely that an un-revealed redeem script has both the signature and the OP_0 inside in which case such redeem script can be spent by anyone as soon as it is revealed. and it will become unspendable after such hard fork.


Title: Re: What's stopping OP_CHECKMULTISIG extra pop bug from being fixed?
Post by: NotATether on August 27, 2020, 02:33:18 PM
it is highly unlikely that an un-revealed redeem script has both the signature and the OP_0 inside in which case such redeem script can be spent by anyone as soon as it is revealed. and it will become unspendable after such hard fork.

So it looks like that after a hard fork, the nodes which haven't updated and still send redeem scripts with OP_0 will be rejected by updated nodes. I wonder if theoretically there is a way to signal that such scripts come from older node versions and still be processed equivalently? Normally, and not in OP_CHECKMULTISIG special case, does an OP_0 at the beginning make the script evaluate to true?


Title: Re: What's stopping OP_CHECKMULTISIG extra pop bug from being fixed?
Post by: BrewMaster on August 27, 2020, 03:21:01 PM
So it looks like that after a hard fork, the nodes which haven't updated and still send redeem scripts with OP_0 will be rejected by updated nodes.
yes but also the old nodes will reject any similar thing without the OP_0 coming from the new nodes. that is why it is called hard fork and needs the entire network to upgrade.

Quote
I wonder if theoretically there is a way to signal that such scripts come from older node versions and still be processed equivalently?
the problem is transaction ID. the new node could technically add the OP_0 (it is malleable) and send it to the old node so that it doesn't fail while evaluating that tx but it will also change the txid and when someone spends that transaction with the different txid the old node won't be able to verify that new tx and fails there.

Quote
Normally, and not in OP_CHECKMULTISIG special case, does an OP_0 at the beginning make the script evaluate to true?
normally if after there is one last OP_0 left it has to push an empty array to the stack so the top stack item is converted (CastToBool) to false hence the evaluation fails.

in case of OP_CHECKMULTISIG, it pops that extra item and throws it away then pushes the result of signature verification to the stack.
this is also why P2WSH scripts don't fail since they expect a clean stack after evaluation, that dummy item is already popped and thrown away.


Title: Re: What's stopping OP_CHECKMULTISIG extra pop bug from being fixed?
Post by: gmaxwell on August 27, 2020, 11:21:41 PM
I think it is probably wrong to describe it as a bug.  I think it was intended to indicate which signatures were present to fix the otherwise terrible performance of checkmultisig.

Regardless, there is no real point to fixing it:  Any 'fix' would require that all software using checkmultisig get an incompatible change (as part of a highly disruptive hard fork).  Because the extra value is now always zero (and was pretty much always, or was actually always zero before)  you can compress it out  completely over the wire or on disk if you really care-- so the only effect it has is its weight in transactions and the one or so extra cpu cycle going into a hash.

Instead a new operation can be introduced that just doesn't have that behaviour-- and that would be compatible, software that wants the new behaviour would just upgrade when it wants it,  no flag day, no disruption.

BIP342 replaces checkmultisig entirely with something that is more computationally efficient and more flexible (and more space/weight efficient too, once you count that the signatures are 9 bytes shorter and the pubkeys are 1 bytes shorter).