Algebra Puzzle - Legacy P2SH
|
To follow along this tutorial
|
Let’s create a simple math puzzle with a legacy P2SH transaction.
Creating and Funding the P2SH
const bitcoin = require('bitcoinjs-lib')
const { alice } = require('./wallets.json')
const network = bitcoin.networks.regtest
const redeemScript = bitcoin.script.compile([
bitcoin.opcodes.OP_ADD,
bitcoin.opcodes.OP_5,
bitcoin.opcodes.OP_EQUAL])
console.log('Redeem script:')
console.log(redeemScript.toString('hex'))
decodescript 935587
The p2sh method will generate an object that contains the P2SH address.
const p2sh = bitcoin.payments.p2sh({redeem: {output: redeemScript, network}, network})
console.log('P2SH address:')
console.log(p2sh.address)
sendtoaddress 2N7WfHK1ftrTdhWej8rnFNR7guhvhfGWwFR 1
| We can note that anyone can create this script and generate the corresponding address, it will always result in the same address. |
gettransaction TX_ID
| Find the output index (or vout) under . |
Preparing the spending transaction
Let’s now prepare the spending transaction by setting input and output.
Alice_1 wants to send the funds to her P2WPKH address.
const psbt = new bitcoin.Psbt({network})
.addInput({
hash: 'TX_ID',
index: TX_VOUT,
nonWitnessUtxo: Buffer.from('TX_HEX', 'hex'),
redeemScript: Buffer.from(redeemScript, 'hex')
}) (1)
.addOutput({
address: alice[1].p2wpkh,
value: 999e5,
}) (2)
| 1 | Input referencing the outpoint of our P2SH funding transaction, the previous tx, and the redeem script |
| 2 | Output, leaving 100 000 satoshis as mining fees |
Creating the unlocking script
Now we can finalize the transaction with the unlocking script, providing a solution to the math problem.
We provide 02 and 03 as an answer satisfying the redeem script.
const getFinalScripts = (inputIndex, input, script) => {
// Step 1: Check to make sure the meaningful locking script matches what you expect.
const decompiled = bitcoin.script.decompile(script)
if (!decompiled || decompiled[0] !== bitcoin.opcodes.OP_ADD) {
throw new Error(`Can not finalize input #${inputIndex}`)
}
// Step 2: Create final scripts
const payment = bitcoin.payments.p2sh({
redeem: {
output: script,
input: bitcoin.script.compile([bitcoin.opcodes.OP_2, bitcoin.opcodes.OP_3]), (1)
},
})
return {
finalScriptSig: payment.input
}
}
psbt.finalizeInput(0, getFinalScripts)
| 1 | The condition that unlocks the redeem script |
We don’t need to sign this transaction since the redeem script doesn’t ask for a signature.
console.log('Transaction hexadecimal:')
console.log(psbt.extractTransaction().toHex())
decoderawtransaction TX_HEX
Broadcasting the transaction
sendrawtransaction TX_HEX
getrawtransaction TX_ID true
Observations
We can decrypt the unlocking script in Bitcoin Core CLI with decodescript. You will notice that it is the concatenation of the corresponding hex value of the specified opcodes, OP_2, OP_3 and the redeem script OP_ADD OP_5 OP_EQUAL.
decodescript 5253935587
| Be aware that the hex script is serialized and includes a <03> before the redeem script. In order to decode the script properly we need to remove this pushbyte. |