Bitcoin Forum

Bitcoin => Development & Technical Discussion => Topic started by: domob on January 22, 2018, 08:01:52 PM



Title: Understanding P2SH
Post by: domob on January 22, 2018, 08:01:52 PM
I'm trying to fully understand how P2SH (BIP16) works, and I thought I did.  For fun and to check my understanding, I disabled BIP16 in Bitcoin Core (setting BIP16Height in chainparams to a high value) and tried to "sign" a transaction spending a P2SH output by just providing the redeem script.  According to my understanding, this should be enough pre-BIP16, since it will make the "OP_HASH160 <hash> OP_EQUAL" script of the P2SH output succeed, right?  But that seems to be not the case.

In regtest mode, I created the following P2SH address:

Code:
$ addmultisigaddress 1 '["03c278d06b977e67b8ea45ef24e3c96a9258c47bc4cce3d0b497b690d672497b6e", "0221ac9dc97fe12a98374344d08b458a9c2c1df9afb29dd6089b94a3b4dc9ad570"]'
2MwCrk6S9UEeFujacKe7m4uDCzu25F3VAeM

$ validateaddress 2MwCrk6S9UEeFujacKe7m4uDCzu25F3VAeM
{
  "isvalid": true,
  "address": "2MwCrk6S9UEeFujacKe7m4uDCzu25F3VAeM",
  "scriptPubKey": "a9142b6defe41aa3aa47795b702c893c73e716d485ab87",
  "ismine": false,
  "iswatchonly": false,
  "isscript": true,
  "script": "multisig",
  "hex": "512103c278d06b977e67b8ea45ef24e3c96a9258c47bc4cce3d0b497b690d672497b6e210221ac9dc97fe12a98374344d08b458a9c2c1df9afb29dd6089b94a3b4dc9ad57052ae",
  "addresses": [
    "mg41i3DBptiWbQ9PQ59ykdbc8T85gEqWdK",
    "muC6tdGQrYXSqghPZziyvZwu1KSwL49ioy"
  ],
  "sigsrequired": 1,
  "account": ""
}

And funded it:

Code:
$ sendtoaddress 2MwCrk6S9UEeFujacKe7m4uDCzu25F3VAeM 10
14e8f61534b9a0b6110655dc153d41cc90f64b8104b820e1f4534fd14a732df0

$ generate 1

$ gettxout 14e8f61534b9a0b6110655dc153d41cc90f64b8104b820e1f4534fd14a732df0 0
{
  "bestblock": "40d573ebb78bdab760d6659b8ad9d91c46633144d25084eaf3de1f7411040305",
  "confirmations": 1,
  "value": 10.00000000,
  "scriptPubKey": {
    "asm": "OP_HASH160 2b6defe41aa3aa47795b702c893c73e716d485ab OP_EQUAL",
    "hex": "a9142b6defe41aa3aa47795b702c893c73e716d485ab87",
    "reqSigs": 1,
    "type": "scripthash",
    "addresses": [
      "2MwCrk6S9UEeFujacKe7m4uDCzu25F3VAeM"
    ]
  },
  "coinbase": false
}

Then, I tried to spend it by providing just the serialised redeem script as scriptSig, but this fails:

Code:
$ decoderawtransaction 0100000001f02d734ad14f53f4e120b804814bf690cc413d15dc550611b6a0b93415f6e814000000004847512103c278d06b977e67b8ea45ef24e3c96a9258c47bc4cce3d0b497b690d672497b6e210221ac9dc97fe12a98374344d08b458a9c2c1df9afb29dd6089b94a3b4dc9ad57052aeffffffff0100e1f505000000001976a914cf112b41997697caa3eee9e308ad9b2b917b4e4c88ac00000000
{
  "txid": "1971750cd655c7f93627354c380595e3e3434b69c3b6e788eecfb9c685eba703",
  "hash": "1971750cd655c7f93627354c380595e3e3434b69c3b6e788eecfb9c685eba703",
  "version": 1,
  "size": 157,
  "vsize": 157,
  "locktime": 0,
  "vin": [
    {
      "txid": "14e8f61534b9a0b6110655dc153d41cc90f64b8104b820e1f4534fd14a732df0",
      "vout": 0,
      "scriptSig": {
        "asm": "512103c278d06b977e67b8ea45ef24e3c96a9258c47bc4cce3d0b497b690d672497b6e210221ac9dc97fe12a98374344d08b458a9c2c1df9afb29dd6089b94a3b4dc9ad57052ae",
        "hex": "47512103c278d06b977e67b8ea45ef24e3c96a9258c47bc4cce3d0b497b690d672497b6e210221ac9dc97fe12a98374344d08b458a9c2c1df9afb29dd6089b94a3b4dc9ad57052ae"
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 1.00000000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 cf112b41997697caa3eee9e308ad9b2b917b4e4c OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a914cf112b41997697caa3eee9e308ad9b2b917b4e4c88ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mzPpjgciTo6DMGpE3Lkb4ZLBSn8A239aDZ"
        ]
      }
    }
  ]
}

$ sendrawtransaction 0100000001f02d734ad14f53f4e120b804814bf690cc413d15dc550611b6a0b93415f6e814000000004847512103c278d06b977e67b8ea45ef24e3c96a9258c47bc4cce3d0b497b690d672497b6e210221ac9dc97fe12a98374344d08b458a9c2c1df9afb29dd6089b94a3b4dc9ad57052aeffffffff0100e1f505000000001976a914cf112b41997697caa3eee9e308ad9b2b917b4e4c88ac00000000 true
error code: -26
error message:
16: mandatory-script-verify-flag-failed (Operation not valid with the current stack size)

As you can see, the scriptSig of the raw transaction I try to send matches the hex of the P2SH address.  (A very similar script is sent for a correctly signed spending of the P2SH output, except prepended by the actual signatures as mandated by BIP16.)  From my understanding of how P2SH works, this should be a valid script pre-fork.  Can someone please explain to me what I'm missing here?


Title: Re: Understanding P2SH
Post by: achow101 on January 23, 2018, 12:48:42 AM
You will need to change this line: https://github.com/bitcoin/bitcoin/blob/master/src/script/standard.h#L54 and remove "SCRIPT_VERIFY_P2SH" (just change that to be 0).

The way that P2SH is enforced is that, at this point, all new blocks and transactions must pass the P2SH checks. Changing the chainparams parameter for bip16Hash will only effect the verification of old blocks.


Title: Re: Understanding P2SH
Post by: pebwindkraft on January 23, 2018, 12:50:58 AM
I am not 100% sure... wasn't there this OP_CHECKMULTISIG off-by-one error, and you had to put a hex "0" before the signature?
See the explanation in Andreas' book "Mastering Bitcoin" (2nd edition) in chapter 7, page 150 ... (book is online available)


Title: Re: Understanding P2SH
Post by: achow101 on January 23, 2018, 12:51:49 AM
I am not 100% sure... wasn't there this OP_CHECKMULTISIG off-by-one error, and you had to put a hex "0" before the signature?
See the explanation in Andreas' book "Mastering Bitcoin" (2nd edition) in chapter 7, page 150 ... (book is online available)
The point of this is to not validate the redeemScript. Thus that is not a concern.


Title: Re: Understanding P2SH
Post by: domob on January 23, 2018, 05:12:00 PM
You will need to change this line: https://github.com/bitcoin/bitcoin/blob/master/src/script/standard.h#L54 and remove "SCRIPT_VERIFY_P2SH" (just change that to be 0).

The way that P2SH is enforced is that, at this point, all new blocks and transactions must pass the P2SH checks. Changing the chainparams parameter for bip16Hash will only effect the verification of old blocks.

Indeed, that was it.  I was not aware of a second flag that turns on P2SH validation besides the chain parameters, thanks for pointing this out!

Resetting this made everything work as expected.