Building a custom script

As mentioned before, we can define our own scripts instead of using the standards. In the following example, we will define a non-standard bitcoin script based on a simple equation, X+13=15. Therefore, to spend our transaction, the recipient needs to come up with a ScriptSig presenting the correct solution, which is obviously 2, in order to solve the equation and spend the output.  

If we translate this equation into bitcoin scripts, we get the following: 

Bitcore enables us to create transactions with custom script. Hence, in the following example, we will create a non-standard transaction with the puzzle (ScriptPubkey) described previously.

Firstly, we need to select a UTXO from our bitcoin wallet to construct a new transaction. For that, make sure bitcoin Core is still running in Regtest mode and use the command bitcoin-cli listunspent to get an available UTXO with its details: txid, ScriptPubkey, and receiving address. Then create a new destination address with bitcoin-cli getnewaddress.

On the other hand, the private key can be unveiled using  bitcoin-cli dumpprivkey <utxo address>. Once you have all these ingredients, edit the following code accordingly (the full code is available at https://github.com/bellaj/Bitcoin_payment/tree/master/custom%20scripts):

var pkey = 'cPJCt9r5eu9GJz1MxGBGgmZYTymZqpvVCZ6bBdqQYQQ5PeW4h74d'; //UTXO's private key
var Taddress = 'n1PoDECeUwbXgktfkNkBcmVXtD2CYUco2c'; //Destination address
var lockingscript = bitcore.Script('OP_13 OP_ADD OP_15 OP_EQUAL'); //PubKeyScript
var g_utxos=[{"address":"n1PoDECeUwbXgktfkNkBcmVXtD2CYUco2c", "txid":"c6758cf22346d3d8b7b6042b7701a5f07d140732bf5b93e1fb92ed250e5b6d20","vout":0,"scriptPubKey":"210330b8e88054629399e6c90b37503f07fbc1f83aa72444dd2cfd9050c3d08d75fcac","amount":50.0}]; //UTXO details

var transaction = new bitcore.Transaction();
transaction = transaction.from(g_utxos);
transaction = transaction.to(Taddress, 4000000000); //Add a first output with the given amount of satoshis
transaction = transaction.fee(0.0001*100000000);
transaction = transaction.addOutput(new bitcore.Transaction.Output({script: lockingscript, satoshis: 1000000000,address:Taddress }));
transaction = transaction.sign(pkey); //Sign all inputs
console.log("Raw Transaction\n" + transaction);

The preceding code is self-explanatory: we construct a transaction using the Transaction() method, and then we define two outputs – one sending 40 BTC to a P2PKH address and the other sending 10 with a custom script.

Save this code in a file called custom_pubkeyscript.js and run it using node custom_pubkeyscript.js. As a result, a raw transaction will be constructed. If you decode the resulting transaction using bitcoin-cli decoderawtransaction <your tx>you'll be able to see our custom ScriptPubkey:

Then send the raw transaction to the local network using bitcoin-cli sendrawtransaction <your raw transaction> and you'll get back the transaction ID. To get it validated, we only have to mine a block using bitcoin-cli generate 1.

Now we have a non-standard output carrying 10 bitcoins waiting to be spent. To consume it, we need to construct a transaction with the correct ScriptSig op_2 as follows:

var unlockingScript = bitcore.Script().add('OP_2');
var transaction = new bitcore.Transaction();
transaction.addInput(new bitcore.Transaction.Input({prevTxId:'c6758cf22346d3d8b7b6042b7701a5f07d140732bf5b93e1fb92ed250e5b6d20', outputIndex: 1, script: unlockingScript }), unlockingScript, 10000);
transaction = transaction.to(Taddress, 90000000);
transaction = transaction.fee(0.0001*100000000);
console.log(transaction)

We define here an input pointing the previously created output with a custom ScriptSig. As you may notice, the output can be spent without providing a signature. As we did for the previous transaction, you can send the transaction and mine it.

When ScriptSig and ScriptPubkey are executed, the opcode .add('OP_2') pushes value 2 onto the stack, and then the operands (13 and 2 from ScriptSig) are added using .add('OP_ADD')and the result is compared using .add('OP_EQUAL') to 15; therefore the top of the stack will be true, which means the full script (unlocking + locking) is valid and the output is "unlocked" and can be spent. 

To observe the execution of a bitcoin script  on the stack. , there is an interesting open source IDE for bitcoin transactions called H ashmal, available at  https://github.com/mazaclub/hashmal.

If everything went correctly, you should be able to successfully spend the previous output with the custom ScriptPubkey. Just a minor warning: in public networks, non-standard transactions may not be validated by the network.

All set. We're done with non-standard transactions and bitcoin scripting. Now you have a basic understanding of bitcoin under your belt, you should be ready to tackle the rest of this chapter and build a real-world application.