Bitcoin Script is a simple, stack-based programming language that enables the processing of transactions on the Bitcoin blockchain. To understand more about Bitcoin Script, we’ll first look at its characteristics and a basic example of how this programming language works. Then, we’ll overview some of the most common operation codes (Opcodes) for Script as well as the advantages and disadvantages of Turing Completeness. Finally, we’ll highlight four additional blockchain programming languages in use today.
What Is Bitcoin Script?
Script is a Forth-like, stack-based, reverse-polish, Turing incomplete programming language. This might sound like a complicated description on the surface, but these concepts are actually relatively easy to understand. We’ll discuss these points in greater detail shortly.
Before we dive any deeper, it’s important to note that Bitcoin software (also known as Bitcoin Core) is not actually written in Bitcoin Script. Script itself is implemented using the programming language the Bitcoin software is written in. The original implementation of the Bitcoin software was written in C++. Since then, additional implementations have been written in Python, Java, and Go. Thus, for the version of the Bitcoin software written in Go, the Bitcoin Script inside it is also implemented using Go. The same applies for the other implementations, as well.
Bitcoin Script is a simple programming language used to interact with the Bitcoin software. In particular, Script gives the Bitcoin software instructions on how coins in a UTXO can be spent. Of course, most users never need to learn Bitcoin Script. Wallets and other Bitcoin applications complete all the processing behind the scenes automatically.
Script was implemented by Satoshi Nakaomoto in the release of Bitcoin Core version 0.1. However, it had several bugs. Some users have commented that the initial code for Bitcoin Script seemed like an afterthought and was impractical for real world transactions, but improvements were introduced with later versions of Bitcoin Core.
Now, let’s cover some of the finer details about Bitcoin Script.
Bitcoin Script uses a data structure that can be thought of as a linear structure represented by a physical stack or pile. Items at the top of the stack can be added (pushed) or removed (popped) in a “Last In, First Out (LIFO)” queue. Imagine stacking three books: Book A (top), Book B (middle), and Book C (bottom). With Bitcoin Script, Book A would need to be the first taken out of the stack (popped), followed by Book B and Book C, to put anything at the bottom of the stack (pushed). The same concept is applied virtually to operations in a sequence with Script.
Script resembles Forth, a programming language that first appeared in 1970. Forth is used in the Open Firmware Bootloader, space applications (including the Philae spacecraft), and a variety of other embedded systems involving interactions with hardware.
Reverse-Polish Notation (RPN)
Also known as postfix notation, RPN is a method of placing the operation function at the end of a sentence. For example, adding 5 and 6 in Script must be written as “5 6 +” rather than “5 + 6.”
Turing incomplete means that Script does not allow infinite loops. This has both advantages and disadvantages. One advantage of using a Turing incomplete language is the inability to run malformed scripts, regardless if they are intentional malicious attacks or unintentional programming errors. Essentially, Script is able to prevent the halting problem. Other blockchains developed since Bitcoin have mainly chosen to be Turing Complete, or at least have a high degree of Turing completeness. Although this potentially brings the halting problem into play, it also provides better support for the complex logic required for developing smart contracts.
How Does Bitcoin Script Work?
From a very high level, Bitcoin Script can be thought of as a list of instructions recorded with each transaction that describes how the recipient of the funds can gain access to them. Most Bitcoin transactions only require simple scripts, but more complex scripts can be implemented. To understand how Script works, let’s breakdown the steps required for a basic Pay To PubKey Hash (P2PKH) transaction.
Basic P2PKH Transaction Example
Let’s suppose that Alice wants to send 1 Bitcoin (BTC) to Bob. This transaction is simple with any Bitcoin wallet application, but there is actually a lot of Bitcoin Script code behind the scenes that makes the transfer possible. Each Bitcoin transaction involves at least one locking script and one unlocking script to determine who can spend funds sent to a specific Bitcoin address.
In a P2PKH transaction, Alice does not know Bob’s public key. She only knows Bob’s address, which is a Base58Check encoded cryptographic hash of Bob’s public key. Alice can create the transaction by decoding Bob’s address to his “pubkey hash.”
When Alice sends 1 BTC to Bob, a locking script called scriptPubKey is placed on the funds. At that point, the only person who can spend this 1 BTC is the person that supplies the input (i.e., the public key) that produces the pubkey hash to which Alice sent the funds, along with a digital signature from the corresponding Bitcoin private key. In other words, 1 BTC now belongs to Bob, but only if Bob can prove that he is the owner of the BTC address that he provided to Alice.
Bob checks his wallet balance and finds that the Bitcoin network has recognized the 1 BTC sent from Alice. Although Bob now technically "owns" these funds, he can't spend them yet. He needs to verify his true ownership of this 1 BTC to the network before he can send them to someone else.
Let's suppose that Bob wants to send that same 1 BTC to Chris. Before this can happen, Bob first needs to submit an input (UTXO) that meets two requirements. First, the funds Bob is trying to spend must reference the transaction in which he received the funds from Alice by its transaction identifier (TXID). Second, the funds Bob wants to spend must reference the same index number (also called a vector out or vout) as the funds that Alice sent to him in the first place.
Finally, Bob creates an unlocking script called scriptSig that enables him to spend the funds. As long as Bob provides the scriptSig which matches the conditions set by scriptPubKey, he is able to send 1 BTC to Chris. If Chris wants to send funds to someone else, the cycle of using locking and unlocking scripts continues.
Bitcoin Script And The Command Line
The above example is a simplified explanation for how Bitcoin Script works to support transactions on the Bitcoin network. If you examine a standard locking script for scriptPubKey on a Pay To PubKey Hash (P2PKH) transaction, you will find something a bit more complex like:
OP_DUP OP_HASH160 <371c20fb2e9899338ce5e99908e64fd30b789313> OP_EQUALVERIFY OP_CHECKSIG
The long string in the middle is an example of a hashed public key, though it’s sometimes replaced with <pubKeyHash>. Several tutorials are available if you want to learn more about running Bitcoin Script on a command-line interface.
Overview Of Common Opcodes in Bitcoin Script
Above, we looked at an example of how a commonly-used script looks. You might have noticed that “OP_” is used a lot. This prefix is used to identify operation codes, more commonly referred to as Opcodes. Simply put, opcodes are commands that tell nodes in the Bitcoin network how to deal with any specific transaction request. Let’s look at a few of the most common ones.
OP_ADD: Pops two items off the stack, adds them together, and pushes the result back onto the stack.
OP_EQUAL: Pops two items from the stack and compares them to check if they are equal. if they are equal, then it pushes the result TRUE back onto the stack.
OP_RETURN: Can be used to store up to 80 bytes of arbitrary data on the Bitcoin blockchain and also to mark a transaction output as invalid. OP_RETURN transaction outputs are provably unspendable, making this opcode an efficient way to burn BTC. It also makes Komodo's delayed Proof of Work (dPoW) security mechanism possible.
OP_CHECKSIG: Verifies that the signature for a transaction input is valid.
OP_CHECKMULTISIG: Commonly used in Pay To Script Hash (P2SH) transactions. OP_CHECKMULTISIG looks at 3 public keys and 2 signatures in the stack and compares them one-by-one. Funds become spendable only when the order of the signatures matches the order in which the public keys were provided.
A full list of opcodes can be found on Bitcoin Wiki.
Turing Complete Programming With Komodo
As you can see with the numerous programming languages used above, support for blockchain programming has advanced significantly since the initial launch of Bitcoin Core in 2009. Even Script has had numerous improvements. One example relevant to Komodo is OP_CHECKCRYPTOCONDITION, usually written as OP_CCC for brevity.
Although not originally implemented on the Bitcoin network, this opcode adds major enhancements to the technology. First developed by the Komodo Dev Team, OP_CCC is based on a proposed standard introduced by the Interledger team called "CryptoConditions." This opcode can now be used to add the logical conditions necessary for running smart contracts.
Komodo Custom Contracts are UXTO-based smart contracts that can be written in any compiled programming language that can create a linkable library capable of calling and being called by C/C++ functions.
Because Komodo Custom Contracts run in the daemon, developers can avoid the limitations and hassles of having to run code in a virtual machine, as is the case with many gas-based smart contract platforms. Because they are UTXO-based, making it practically impossible to use a module to flood the main chain's coin supply with illegitimate coins. This is a security challenge which is common among numerous balance-based smart contracts. Additionally, Komodo provides an open API that can be used to write blockchain-based applications and software in any programming language.
Begin your blockchain journey with Komodo today.