Transaction validation and scripts



One of the fundamentals in understanding the transfer of satoshis from one address to another on the bitcoin network is the concept of scripts. All satoshis that exist on the network have been "locked away" by means of different lock scripts that define the conditions which have to be met to unlock them. In the majority of cases the lock script contains an address (the hash of a publik key) to which the specific amount of satoshis is assigned. To "unlock" the satohis that are assigned to an address it is necessary to present a script that fulfills the conditions of the lock script. It has to complement the lock script in such a way that the combined script validates to true. In case of an address the unlock script has to include the public key and a valid signature.

Figuratively speaking the lock script defines the unique lock of a specific vault where satoshis are stowed away and the unlock script provides a key that is supposed to unlock this vault. The most important part of transaction validation is thus to check if all the keys provided in the inputs of a transaction really unlock the vaults defined in the outputs of previous transactions they try to open. And it has to be checked as well if the satoshis in the vault haven't been spent already.



The bitcoin reference implementation includes its own programming language that allows to define the conditions for locking satoshis and to express the necessary knowledge to unlock them. These comparatively short programs that are part of the transaction are called scripts.

A script is constructed by combining data objects, i.e. byte arrays that contain information (e.g., an address), with so called OpCodes, i.e. single byte encoded functions that manipulate this data. To allow a script to temporarily persist data during transaction validation a stack-like data structure is provided. This memory data structure conforms to the last-in-first-out principle, i.e. the last item pushed onto the stack is the first that gets popped off the stack. The OpCodes enable the script to push data on and pop data off the stack and to execute operations like comparing values or verifying signatures.

Lock script


The lock script is part of every transaction output. It defines the conditions that have to be fulfilled to unlock the satoshis that have been locked by the script. It is important to understand that assigning satoshis to a bitcoin address being very common is only one possible type of lock script. More complex scripts can be build that define a number of public keys for which a quorum of signatures has to be presented (m-of-n multi-signature). It is also possible to define other mathematical equations that have to be solved as is the case with several bounty addresses set up to find hash collisions for different hashing algorithms.

Unlock script


The unlock script is part of every transaction input. It provides specific knowledge encoded in data to fulfill the conditions defined in the lock script. In case of satoshis assigned to an address the knowledge needed to construct the unlock script consists in the private key corresponding to the public key. The posession of the private key allows to create a signature that is specific to the public key and constitutes the unlock script together with the public key.

Transaction validation


To validate if the input of a transaction is allowed to spend the output of a previous transaction these two scripts have to be validated as a whole. To do this the unlock script and the lock script are concatenated and the combined script is executed. The script is valid if no error occurs during execution and if after execution the stack is left in a valid state, i.e. a non-zero value is on top of the stack at the end of execution. If the stack is empty or the value on top of the stack is zero the validation fails.

The validation of a transaction unlocking p2pkh-scripts necessitates validating the signature(s) of every single input. The validation of a signature requires the public key, the signature itself (r-/s-value) and the hash of the data that is signed (signature hash). To prevent the modification of the transaction the data that is hashed is the transaction itself. Since the final transaction does contain all signature(s) its data can not be used for signing without modification. To obtain the modified transaction data the unlock script of the input that will be signed is replaced by the referenced lock script of the previous transaction and all other unlock scripts are removed. For this reason the hash of the transaction data that is signed is different for every input in the case of multiple inputs. To this modified data a hash type (4 bytes) is appended. The hash type is usually 1 (SIGHASH_ALL).