Script Templates
Allows 3 agent (covenant, owner, and spender) trustless interaction
Introduction
A script template is a generalisation of the P2SH (pay-to-script-hash) format, that allows for the implementation of covenants. It uses a three party system whereas the traditional system in Bitcoin uses only two parties. The three parties in script templates are:
* The holder
The spender
The contract/covenant author (often the group creator)
Script templates use a template system that factors all data in a traditional script out into arguments that are furnished by the holder and spender.
For example, a traditional pay-to-pubkey-hash script looks like this:
DUP HASH160 PUSH pubkeyhash EQUALVERIFY CHECKSIG
Since the pubkeyhash changes for each address, a slightly different script is created for each address. A script template factors this variable data out of the script creating a template for pay-to-pubkey-hash. This template will be the exact same bytes for everyone because all of the variable data is put on to the stack as arguments before the script is executed and not contained in the script itself.
Script templates confer several advantages: * easy script identification * parameter extraction is unnecessary * The hash of the script template does not change when parameters change * 3 participant interaction
Note that the arguments may themselves be scripts, executed via the EXEC opcode.
Definitions
"Constraint Args" - A term used to encompass all constraining arguments to the template script. It includes both the Hidden Args and the Visible Args.
"Group ID" - A data string of 32 bytes or more that identifies the group token held in an output.
"Group Amount" - The amount of group tokens held in an output.
"Hash160" - Hash160 is a shorthand for a sha256+ripemd160 hash. The input data is first hashed using sha256 and the output is used as the input for ripemd160. The end result is a 20 byte hash.
"Hash256" - Hash256 is a shorthand for a double sha256 hash. The input data is first hashed using sha256 and the output is used as the input for a second iteration of sha256. The end result is a 32 byte hash.
"Hidden Args" - Hidden constraining arguments to the template script. They are optional and when present are provided by the holder of a UTXO to constrain future spending in a manner enforced by both the template and the future holders. Hidden Args are found in the Unlocking Script.
"Hidden Args Hash" - The Hash160 or Hash256 of the Hidden Args, or a 0x00 byte indicating no Hidden Args are present in the Unlocking Script.
"Locking Script" - The summation of all constraints on an output. The Locking Script contains up to five field in the following order: Group ID, Group Amount, Template Hash, Hidden Args Hash, and Visible Args. There may be more than one Visible Arg but they all belong to the field of Visible Args. The Locking Script is found in the "scriptPubKey" field in an output.
"ScriptPubKey" - ScriptPubKey is another common name for the Locking Script. See definition of Locking Script for more information.
"Satisfier Args" - Arguments that are needed to satisfy the constraints enforced by the Locking Script. They are optional. When present they are included in the Unlocking Script and are provided by the spender.
"Scriptlet" - A scriptlet is a small script provided as a PUSH of the serialized script. It can be executed by the EXEC opcode or JUMPed into.
"ScriptSig" - ScriptSig is another common name for the Unlocking Script. See definition of Unlocking Script for more information.
"Template Hash" - The Hash160 or Hash256 hash of the Template Script if the Template Script is not a well-known template. If it is a well-known template, the Template Hash is the ID of the well-known template instead.
"Template Script" - The Template Script is the list of instructions describes how to to spend the output. It does not contain any variable data or arguments. It is defined by the contract/covenant author. It may be conserved from input to output so implements covenants. The Template Script is found in the Unlocking Script unless the Locking Script has a well-known template ID in its Template Hash field.
"Unlocking Script" - The Unlocking Script is the data required to spend an output. This script found in the "scriptSig" field in a transaction input. It contains the following data fields in the following order:
-
Template Script
- If the template script is not well-known, the template script is added to the scriptSig as a single script data "push". If the template is well-known do not push anything.
-
Hidden Args (optional)
- If present, the Hidden Args are first serialised into a single push only script which is then added to the scriptSig as a single script data "push". If there aren't any Hidden Args do not push anything.
-
Satisfier Args (optional)
- If present, each Satisfier Arg is added to the scriptSig in an individual script data push. If there aren't any satisfier args do not push anything.
During script execution the Template Script is not pushed onto the script machine stack allowing it to exceed stack limits. When creating the stacks for script execution the Hidden Args are parsed from the single script data push in the Unlocking Script back into individual args and are pushed on to the stack individually allowing them to collectively exceed stack limits but not individually. Individually the Hidden Args can not exceed stack limits.
"Visible Args" - Visible constraining arguments to the template script. Optional additional data put on to the end of the Locking Script. Each visible arg is pushed individually.
Script Template Structure Within a Transaction
Outputs/ Creating UTXOs
To indicate a script template output, a transaction output's type is set to TEMPLATE(1).
Inputs / Spending UTXOs
A script template output is spent with a "push-only" script located in the scriptSig field of a transaction input.
Script Constraint Visibility
To minimize space in the UTXO, and manage data visibility, a creator can choose to add constraining arguments to their script in two places: Hidden Args and Visible Args. The arguments added to the Hidden Args are not visible from the UTXO, only a hash commitment to them (Hidden Args Hash) is present. the arguments added to the Visible Args are individually pushed directly to the Locking Script and are visible directly in the UTXO.
The Hidden Args are revealed in the unlocking script prior to script template evaluation. The revealed Hidden Args are pushed onto the alt stack followed by the Visible Args. All args are pushed in order and once pushed onto the alt stack it is impossible to distinguish which args are were revealed Hidden Args and which were Visible args. The inability to determine the origin of the args on the alt stack allows the output creator to choose between Hidden Args, Visible Args, or a mix of both for the same template. As long as the order is maintained the template will be satisfied.
Hash Functions
Hashes can either be Hash160 or Hash256 hash functions (creator's choice). The choice is clear based on the size of the pushed item. Hash160 is recommended unless the creation of the preimage is multi-party and potentially susceptible to Wagner's Birthday Attack.
Well-known script templates
Certain well-known script templates are specified with hard-coded numbers. From time to time new well-known script templates may be added via a hard fork.
Script Template Execution Model
Script templates use a three stage processing model; deconstructing the Locking Script, deconstructing the Unlocking Script, and executing the Template Script.
-
Deconstruct the Locking Script
The Locking Script has five fields. It needs to be parsed into its parts for Unlocking Script evaluation. The Template Hash and Hidden Args Hash are needed to verify the Script Template and Hidden Args in the Unlocking Script respectively. The Visible args (if present) should be set aside to be added to the Alt Stack later.
-
Group ID
If this field is 0 then this output does not contain any group tokens and a value for Group Amount is not included in the Locking Script. -
Group Amount
The Group Amount is only present if Group ID is not 0. -
Template Hash
The Template Hash is either a 20 byte Hash160, 32 byte Hash256, or a single well known script template identifier. -
Hidden Args Hash
The Hidden Args Hash is either a 20 byte Hash160, 32 byte Hash256, or a 0x00 byte indicating no Hidden Args. -
Visible args Anything after the Hidden Args Hash are Visible Args. The inclusion of Visible Args is optional. When present there maybe be more than one Visible Arg.
-
-
Deconstruct the Unlocking Script
The Unlocking Script has 3 parts.
-
Template Script
The first part of the Unlocking Script is the Template Script. If the Template Hash in the Locking Script was well known script identifier byte rather than a full hash, the Script Template is not included in the Unlocking Script. If a full hash was included for the Template Hash in the Locking Script, hash the Template Script and verify it matches the Template Hash. If these hashes do not match the Unlocking Script is invalid. If they match set the Template Script aside to execute later. -
Hidden Args
If the Locking Script has a 0x00 byte for the Constrain Hash then skip this step. Otherwise, the Hidden Args needs to be verified. It is possible for there to be multiple Hidden Args but they are included in the Unlocking Script via a single script data push. Hash the entirety of the pushed Hidden Args data and verify that the hash matches the Hidden Args Hash in the Locking Script. If the hash matches, parse the Hidden Args data and push each argument on to the Alt Stack independently. -
Satisfier Args
Anything else in the Unlocking Script are the Satisfier Args. This field is optional and there may be no Satisfier Args included in the Unlocking Script. Push each of the Satisfier Args on to the Main Stack independently.
-
-
The Visible Args (if any) that were set aside when the Locking Script was parsed should now be pushed on to the Alt Stack in the same order they appeared in the Locking Script.
-
Execute the Template Script The final step is to execute the template script. If this successfully runs and ends with an empty stack the signature is valid.
Scriptlets
Scriptlets are fundamentally valuable feature in script templates. They allow the holder to add their own programmatic constraints to the locking script as a whole. Without scriptlets, the holder can only contribute data constraints not arbitrary programs.
Within a Locking Script, the holder can push arbitrary binary data as either the hidden args or the visible args. If this data is a script, it can be executed by the Template Script, at the appropriate moment, using the EXEC opcode.
Example
Many script template authors want to have spending capability independent of the holder, to further constrain the holder's spending capabilities, or both. Traditionally these scripts might look something like this:
IF
authorSpendConstraints()
ELSE
authorConstraintsOnHolderSpend()
<pick holderSig from the satisfier args>
<pick holderPubkey from the locking script args>
CHECKSIGVERIFY
ENDIF
The last 3 lines of the ELSE clause allow the holder to constrain spending to their public key.
However, this script structure places severe limitations on the holder. They MUST use a simple public/private key lock. What about multisig or complex scripts?
Scriptlets solve this problem using the following structure:
IF
authorSpendConstraints()
ELSE
authorConstraintsOnHolderSpend()
<pick the rest of the satisfier args>
<pick holderScriptlet from locking script args>
EXEC
ENDIF
With this structure, we allow the holder to specify a script for their locking constraints rather than requiring a public key for CHECKSIGVERIFY.