Back

Spending from a P2SH address in Dash

In my last post, we created the P2SH address

8nrtzFk4y1t9sL15GzbwFK9DYuiEpTtAzA

from this trivial script

OP_2 OP_EQUAL

Now we are going to fund that address and create a transaction that can spend those funds.

You can send funds to that address like you would any other address

$ ./dash-cli -regtest sendtoaddress 8nrtzFk4y1t9sL15GzbwFK9DYuiEpTtAzA 10

4f81887665855eef119b2a7ae6ef73c3ffca7adb507213f0f724067b919ccffe

We are going to be spending the output from that transaction, so we will need its details:

$ ./dash-cli getrawtransaction 4f81887665855eef119b2a7ae6ef73c3ffca7adb507213f0f724067b919ccffe 1


{
  "txid": "4f81887665855eef119b2a7ae6ef73c3ffca7adb507213f0f724067b919ccffe",

   -- snip --

  "vout": [
    {
      "value": 10.00000000,
      "valueSat": 1000000000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_HASH160 5c9081ddd7c74d71e183b104abcc3f74be54c9c7 OP_EQUAL",
        "hex": "a9145c9081ddd7c74d71e183b104abcc3f74be54c9c787",
        "reqSigs": 1,
        "type": "scripthash",
        "addresses": [
          "8nrtzFk4y1t9sL15GzbwFK9DYuiEpTtAzA"
        ]
      }
    },

In order to spend the funds for this address, we first need to construct an unlocking script, often called a scriptSig because in most cases it is providing a signature.

But in the case of P2SH, the unlocking script first pushes the parameters onto the stack that will satisfy the locking script and then pushes the hex of the locking script itself. It took me quite a while to figure out this detail, this page helped me a lot.

We can create a script that does that with the following code:

var script = dashcore.Script.fromString('OP_2 OP_EQUAL');

var scriptLength = script.toBuffer().length;

var unlockingScript = dashcore.Script.fromString(

  'OP_2 ' + scriptLength + ' 0x' + script.toHex() 

);

Which will create the script

OP_2 2 0x5287

Where OP_2 is the argument that will satisfy our script and 0x5287 is our script which is 2 bytes long and therefore pushed onto the stack with the op-code “2”.

We can now create an input from that transaction output using this unlocking script.

var output = {
    address: '8nrtzFk4y1t9sL15GzbwFK9DYuiEpTtAzA',
    prevTxId: '4f81887665855eef119b2a7ae6ef73c3ffca7adb507213f0f724067b919ccffe',
    outputIndex: 0,
    script: unlockingScript,
    satoshis: 1000000000
  };

  var input = dashcore.Transaction.Input(output);

And finally we can construct a transaction that spends that input to a new address. First lets create that address.

$ ./dash-cli -regtest getnewaddress

yiAsS8X9xBx8oGm7vgwca9ve5nLh3rMH3e

And now we can create the transaction.

var transaction = new dashcore.Transaction()
        .uncheckedAddInput(input)
        .to('yiAsS8X9xBx8oGm7vgwca9ve5nLh3rMH3e', 999999000);

console.log(transaction);

Running all this will get us the raw transaction.

$ node p2sh_tx.js 

<Transaction: 0100000001fecf9c917b0624f7f0137250db7acaffc373efe67a2a9b11ef5e85657688814f000000000452025287ffffffff0118c69a3b000000001976a914efb38bcb860f3704cadab10947be89b7b24de70a88ac00000000>

We can now send that transaction to the network and see that it is accepted.

$ ./dash-cli -regtest sendrawtransaction 0100000001fecf9c917b0624f7f0137250db7acaffc373efe67a2a9b11ef5e85657688814f000000000452025287ffffffff0118c69a3b000000001976a914efb38bcb860f3704cadab10947be89b7b24de70a88ac00000000
 
ea8f2e00011be9e68a2633ef4eb0f94ec247f55b9a96a631583d40e5de2d4d6f

Now, to validate that the locking script works, let’s see what would happen if we tried to spend it with a script that did not satisfy the locking condition.

Let’s generate a new transaction using this script instead, which tries to us 3 as an unlocking parameter instead of 2.

var unlockingScript = dashcore.Script.fromString(
    'OP_3 ' + scriptLength + ' 0x' + script.toHex() 
);

I also had to send more funds to the script address and use that transaction information. Here is what happens when I try to send this transaction to the network.

$ ./dash-cli -regtest sendrawtransaction 01000000010f98c159075eb049de6cda98c3d3ad942b2b984971d3ca4506b895e267b85b38000000000453025287ffffffff0118c69a3b000000001976a914efb38bcb860f3704cadab10947be89b7b24de70a88ac00000000 

error code: -26
error message:
16: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)

Which is exactly as expected since an unlocking script passes by leaving true on the stack.

Leave a Reply

Your email address will not be published. Required fields are marked *