© Harris Brakmić 2019
H. BrakmićBitcoin and Lightning Network on Raspberry Pihttps://doi.org/10.1007/978-1-4842-5522-3_7

7. Bitcoin Script

Harris Brakmić1 
(1)
Troisdorf, Germany
 

In this chapter we will learn about the core element of Bitcoin, the language called Script. Script is an embedded programming language that runs inside every Bitcoin node and is responsible for processing transactions. Unlike most other programming languages, it wasn’t designed upfront with formalized grammar and syntax. Instead of using a proper notation technique like Backus-Naur1 to describe its syntax, Script was hard-coded in the very first version of Bitcoin.

Script, the Programming Language

Whenever we talk about sending or receiving funds in Bitcoin’s network, what we really do is execute a series of commands that constitute Bitcoin scripts. Spoken from a very abstract level, we could say that all Bitcoin “sees” are scripts only. There are neither addresses nor bitcoins in Bitcoin’s network. Everything that happens (or fails) in Bitcoin is based on some script execution. To learn “Script”, which is its colloquial name, means to go much deeper into Bitcoin’s code and touching things which are not even familiar to most programmers. Script is very different, both for technical and nontechnical audiences.

However, there is no reason to stay away from it, as Bitcoin could never exist without it. And the first step is to understand its base structures. The first among them is the Stack, a data structure used heavily in computer science.
../images/486570_1_En_7_Chapter/486570_1_En_7_Fig1_HTML.jpg
Figure 7-1

Graphical representation computer’s memory organized as stack structure

A stack is a collection of “things” of any kind that are linearly ordered, where operations can only be done beginning with the top element. This constraint is also called LIFO (last in, first out), because any allowed operations have to begin with the top element. Bitcoin Script uses such a structure to manage and execute commands that come with transactions. As we have already seen in previous chapters, every Bitcoin transaction combines two script parts, a locking and an unlocking script , which then get executed as a single one. If the execution returns a TRUE value, a transaction will be accepted as valid.

Otherwise, the transaction will be rejected by the network. The reason for this seemingly complex behavior lies in the fact that without it no entity participating in the Bitcoin network could ever claim any ownership of bitcoins. There is no option to encode ownership of any funds in Bitcoin’s blockchain as there is no way to define a “bank account” or any other kind of account in it. And because we don’t have them at our disposal, there is no way for us to build relations like “X owns Y bitcoins”. The only thing a party could own is a proof that gives a right to access certain elements, or funds, from the currently available UTXO set. To “own” bitcoins actually means to be in possession of a piece of code that solves the puzzle previously defined by the creator of the UTXO in question. This is mostly done by providing signatures created by using private keys. That’s why wallets aren’t “wallets” at all, but more like keychains as they never hold any bitcoins, but only private keys. Unlike physical ownership of metal coins or paper money, where we have direct access to them, the decentralized ownership relies on signatures as we always have to reference some previous transaction, before spending any bitcoins from them. To have a right to spend funds in real world, we only have to have physical access to them. The same right in decentralized world must be proven by providing a signature that unlocks funds from an unspent transaction that got created in the past.

Simply spoken, when you buy something in the real world, you don’t have to track the past transactions of the coins in your purse. And nobody would ever ask you for such information. You just use coins to buy stuff with them. Not so in Bitcoin. There you must always have a reference to some previous UTXO and a valid proof of the right to change ownership of those funds.

To achieve such a goal, one basically must execute a small program that defines certain constraints and expects the claiming party to provide data that’ll become integral part in the next Script execution. A script written in Bitcoin Script is a program that defines rules for releasing funds, which must be followed by the claimant. In most cases, such a script defines the amounts of bitcoins to be spent. This mostly includes change-transactions too, as well as the expected signatures that must be provided by the claimant. However, unlike most other programming languages, Bitcoin Script is not Turing-complete,2 which means that it’s incapable of executing loops, jumps, and complex control constructs. This was deliberately chosen and for a good reason: a Turing-complete programming language has no guarantee that it’ll ever stop. For example, it is trivial to write a never-ending for-loop in a Turing-complete language, which basically means that the executing machine could never again be used for anything else. A simple example to show the power, and the potential for misuse, of Turing-completeness can be done directly in a browser. Open your browser’s console, usually with F12, and type in this code.
for(;;) {
console.log("I will never end - " + new Date().toTimeString());
}
After having started it with ENTER, the output will look rather boring and pretty harmless (Figure 7-2).
../images/486570_1_En_7_Chapter/486570_1_En_7_Fig2_HTML.jpg
Figure 7-2

Browser Console output

But only for some time, because soon your browser would start complaining about a web page that’s consuming too many resources (Figure 7-3). The culprit here is of course the script we just started.
../images/486570_1_En_7_Chapter/486570_1_En_7_Fig3_HTML.jpg
Figure 7-3

Browser warning

Now imagine Bitcoin’s network with nodes executing a script with similar logic. This would effectively cripple the network by exhausting all of its resources, regardless how powerful the participants are. That’s also the reason why Turing-complete languages like Solidity, one of the scripting languages of Ethereum, which itself runs on top of EVM, the Ethereum Virtual Machine, have the costly “gas consumption” that has to be paid during execution of their programs. Every time a command gets executed, a certain amount of money must be paid or the script execution would stop. This is a strategy to stop malicious actors from exhausting their resources by exploiting the power of Turing-completeness.

Script Notation

We can define Bitcoin scripts as Stack-based programs written in Reverse Polish Notation that are guaranteed to stop at some point in time. Every Bitcoin transaction contains a script which must return a Boolean TRUE to be accepted as valid. To get to this value, one must solve all the puzzles given in the locking script and provide all the data needed via unlocking scripts. And just like any other programming language, Script too has its own set of commands, or as we call them “Op-Codes”, which is short for Operation Codes. Every operation that Script can execute has a certain number assigned to it so that Bitcoin nodes can easily and quickly parse them when reading serialized scripts from the blockchain.

Due to the fact that Bitcoin Script is written in Reverse Polish Notation, the writing and execution of these OP-Codes looks very differently from most of the other programming languages. As we have already seen in the small example before, languages like JavaScript mostly write their statements or object names first (like for or console) and then, if needed, any number of parameters in parentheses. The logic there can be described as command followed by parameters . However, this is not the only way to represent an operation.

We all know the mathematical representation like 2 + 2, where the operator stands between two operands. The Reverse Polish Notation changes the usual mathematical representation by moving the operator behind the operands so that 2 + 2 becomes 2 2 +. At the first sight, the reader would maybe reject this way of writing, but RPN is actually more powerful and better suited for complex operations than the way we learned in school. This has to do with the way it treats operands and operators. When we write 2 2 +, we actually mean put 2 and 2 into the stack and the next operator you read will take as many operands as it needs to complete its operation successfully. In this case the + operator needs two operands, so that it would take both 2s and push back a 4 into the stack. Now imagine a more complex operation like (2 + 3) ∗ (4 - 2) + 10. As we already see, we first need to use parentheses to make sure that (2 + 3) and (4 - 2) will be executed separately from other operations. This isn’t needed in RPN as there we would simply write 2 3 + 4 2 - ∗ 10 +

If we combine this notation with our concept of the stack data structure, we can say that we do nothing else but putting operands into the stack first followed by operators that take out as much operands as they need to complete their respective operations. The operators we show here actually never go into the stack but instead execute operations by manipulating elements in the stack. We show them here only to demonstrate the order of operations being executed.
../images/486570_1_En_7_Chapter/486570_1_En_7_Fig4_HTML.jpg
Figure 7-4

Calculation with a stack

In Figure 7-4 we start with the two innermost operations and forward their results to operators in higher layers until we have reached the topmost operation that also concludes the script execution.

The first two numbers 2 and 3 would be popped by + and its result, 5, pushed back into the stack. Then the next round of computation will be done, this time 4 and 2, and their result too would be pushed back. Then those two operands (5 and 2) would be multiplied, because ∗ is the next operator that will be executed. Ultimately, their result 10 would be added to the other 10, which would return the final result, 20. As we can see, the RPN is not only ideal for stack-based languages, but it’s also much more suitable for complex operations as it doesn’t need any “supporting” infrastructure like parentheses.

Had this been a Bitcoin Script, the result would be TRUE, because our result is nonzero. In fact, it is allowed to create any kind of script and define any type of unlocking logic as long as we use the allowed OP-Codes and follow certain rules regarding script creation. Of course, a script that doesn’t have any unlocking puzzles included is practically allowing anyone to pilfer the funds. Our following scripts would therefore look a bit more sophisticated than the last example from Figure 7-4.

The complete language of Script comprises of about 100 OP-Codes, but only a handful of them are responsible for the majority of transactions in the current blockchain. Over the next few pages, we will talk about some of them, create a few scripts, and also let them run in controlled environments.

OP-Codes

The OP-Codes3 comprise of several types grouped as
  • Cryptographic functions

  • Stack functions

  • Flow control

  • Bitwise operation

  • Pseudo-words

  • Arithmetic commands

Regardless of type, every OP-Code is prefixed with OP, like OP_ADD, OP_DUP, etc. There are many older OP-Codes that can’t be used, because they’ve been declared disabled, mostly because of security concerns. For example, several of string-operations have been marked as disabled (OP_CAT, OP_SUBSTR etc.). The adjective “disabled” in this case is actually a misnomer, because there is no valid way to re-enable them ever again, so it’d be better to call them “deleted”.

Most of the allowed Op-Codes can be used in own scripts with the exception of pseudo-words that can never be part of any valid script. Pseudo words are OP_PUBKEY, OP_PUBKEYHASH, and OP_INVALIDOPCODE. These can only be used internally for transaction matching.

The standard transaction script, which we already learned about in previous chapters, comprises of two parts, the locking script, also called scriptPubKey, and the unlocking script, called scriptSig:
scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
scriptSig: <sig> <pubKey>

The scriptPubKey is being defined by the current owner of funds we want to get access to. The owner defines what’s needed to unlock them, and we provide the solution by delivering our own script, scriptSig, that comprises of a signature and a public key that’s related to the private key we just used to create the signature. This way we can prove that we indeed control the private key whose signature was expected in the locking script. The rest of the operation is already known to us. First, the unlocking script will be appended to scriptPubKey, and then the OP-Codes from scriptPubKey will be executed one by one, each time doing something with the signature and public key we provided, like duplicating the public key, hashing the public key, comparing data, and checking the signature. Here we can see the difference between those two scripts. The previous owner defined the execution logic while we have to provide data that will hopefully keep this logic running and ultimately deliver the needed TRUE value. We have no option to change the logic that comes with scriptPubKey. All we can do is to provide data and wait for the script to complete successfully.

But before we start our practical examples with different Op-Codes, let’s look into some of the available commands and groups they belong to. The first group of Op-Codes are used for pushing data into the stack. These are commands like
  • OP_0

  • OP_1

  • OP_2 through OP_16

  • OP_FALSE

  • OP_TRUE

  • OP_PUSHDATA1

  • OP_PUSHDATA2

  • OP_PUSHDATA4

They serve to push data into the stack and can range from empty arrays like OP_0 to numbers like OP_16. An OP_6, for example, pushes number 6 into the stack, while OP_FALSE pushes a zero, which counts as Boolean FALSE in Bitcoin Script.

The second group of commands serves the purpose of controlling the Script execution (Table 7-1). These commands partially resemble the usual if-else constructs found in many other programming languages. However, the way they execute is different than “normal” if-else control structures.
Table 7-1

Op-Codes for Script Execution Control

Op-Code (Word)

Op-Code (Number)

Purpose

OP_NOP

97

Do nothing

OP_IF

99

Execute statements if the topmost element in the stack is not False (it also removes the element)

OP_NOTIF

100

Execute statements if the topmost element in the stack is False (it also removes the element)

OP_ELSE

103

Execute statements if preceding IF, ELSE, or NOTIF wasn’t executed; otherwise ignore these statements

OP_ENDIF

104

Mark the end of an IF/ELSE block. All such blocks must end with an ENDIF; otherwise they’ll be rejected as invalid

OP_VERIFY

105

Check if topmost element is True. If not, mark this transaction as invalid; otherwise do nothing. Removes the element

OP_RETURN

106

Mark transaction as invalid. This command always succeeds and is the default way of removing funds from the UTXO set. With this command one can “burn” coins

The third group of Op-Codes deals with management of the stack itself (Table 7-2). These commands can, for example, duplicate elements (OP_DUP), move them throughout the stack (OP_SWAP, OP_PICK, OP_ROLL), and similar operations. We will describe a few of them, but in general one will not very often deal with them. The most prominent of those commands is surely OP_DUP which we have already seen a few times, because it’s the first command in many scriptPubKey locking scripts:
 OP_DUP OP_HASH160 <pubKeyHash>
Table 7-2

Stack Management

Op-Code (Word)

Op-Code (Number)

Purpose

OP_DUP

118

Duplicate topmost item

OP_IFDUP

115

Duplicate topmost item if not zero

OP_DROP

117

Remove topmost item

OP_PICK

121

Copy n-th item to top of the stack

OP_ROLL

122

Move n-th item to top of the stack

OP_SWAP

124

Swap two topmost items in the stack

OP_TUCK

125

Copy the topmost item before the second-to-top item

The fourth group of commands are mostly declared as disabled and therefore can’t be used anymore. They have been designed for working with string values, like concatenating or splitting them. The only available command as of now is OP_SIZE that calculates the string-length of the topmost stack and pushes this value to the stack. Other commands from this group are OP_CAT, OP_SUBSTR, OP_LEFT, and OP_RIGHT.

Another, also mostly disabled, group of commands deals with bitwise logic. It comprises of Op-Codes like
  • OP_AND

  • OP_OR

  • OP_XOR

  • OP_INVERT

  • OP_EQUAL

  • OP_EQUALVERIFY

Only the two last commands are available, and we have already used them in previous scripts. The difference between OP_EQUAL and OP_EQUALVERIFY is that OP_EQUAL only pushes a Boolean result into the stack, while OP_EQUALVERIFY internally runs an OP_VERIFY command that checks the returned value as well. If the result is TRUE, it will continue with script execution; otherwise it’d stop.

The next group of commands deals with arithmetic and is the largest of the groups. Most of its Op-Codes can be directly mapped to usual mathematical syntaxes found in other programming languages. For example:
  • OP_MUL

  • OP_SUB

  • OP_ADD

  • OP_DIV

  • OP_NOT

  • OP_MOD

and so on.

However, several of them are disabled and therefore can’t be used in any scripts. It is also important to keep in mind that numerical inputs for these Op-Codes are constrained to 32-bit integers, whose return values also can overflow, which puts a great amount of responsibility on the programmer.

The last and the most important group of Op-Codes are cryptographic operations (Table 7-3). We have seen several of them, like OP_SHA256, OP_HASH160, OP_CHECKSIG, and others. These Op-Codes are the bread and butter of Bitcoin Script. Without them, no single locking script could ever be created, and there would be no way to produce any proofs of ownership.
Table 7-3

Cryptographic Operations

Op-Code (Word)

Op-Code (Number)

Purpose

OP_RIPEMD60

166

Get RIPEMD160 hash

OP_SHA1

167

Get SHA-1 hash

OP_SHA256

168

Get SHA-256 hash

OP_HASH160

169

Get a double-hash: first with SHA-256 then with RIPEMD160

OP_HASH256

170

Get a double-hash by using two times SHA-256

OP_CODESEPARATOR

171

Only match signatures to the data after the most recently executed OP_CODESEPARATOR

OP_CHECKSIG

172

Get a hash for all of the transaction inputs, outputs, and script, then compare it with the given signature

OP_CHECKSIGVERIFY

173

Same as OP_CHECKSIG, only with additional OP_VERIFY executed afterward

OP_CHECKMULTISIG

174

Compare given signatures against available public keys. It continues comparing until it has either found enough number of matches (n-of-m) or it stops if there are no more public keys left for comparison

OP_CHECKMULTISIGVERIFY

175

Same as OP_CHECKMUTISIG but with additional OP_VERIFY

Additionally, there are several Op-Codes that don’t belong to any of the previous groups as they’re either reserved code-words or pseudo-words, that can never be used in scripts directly (Table 7-4).
Table 7-4

Reserved Words

Op-Code (Word)

Op-Code (Number)

Purpose (Representation)

OP_PUBKEYHASH

253

Public key hash with OP_HASH160

OP_PUBKEY

254

Public key compatible with OP_CHECKSIG

OP_INVALIDOPCODE

255

Any unassigned Op-Code

Reserved words are following Op-Codes: OP_RESERVED, OP_VER, OP_VERIF, OP_VERNOTIF, OP_RESERVED1, OP_RESERVED2, OP_NOP1, and OP_NOP4 through OP_NOP10.

Testing Bitcoin Script with JavaScript

As there is no better way to learn anything than by doing practical examples, we will now build a small JavaScript/NodeJS environment for executing several of the previously mentioned Op-Codes. Being originally designed in C++ and running in an abstract machine, which only deals with raw bytes, learning Bitcoin Script inside Bitcoin’s decentralized network itself is a rather hard task that demands deep knowledge about all of its intricacies, history, and also a good amount of C++ knowledge. To avoid such obstacles without losing practicality, which is always needed in Bitcoin, we will resort to a more welcoming and also easier to use environment based on NodeJS and JavaScript. However, we will still be using raw Script and it’s Op-Codes as they are, so we will still be using Script.

Our setup is based on the same NodeJS environment we used previously during our experiments with ZeroMQ messaging. This time we just add another npm package by issuing this command:
npm install -S bitcoin-script

It will add bitcoin-script package to our package.json configuration. You can of course create a completely new package with npm init and then add bitcoin-script, or you can download the prepared environment that comes with this book, then install the packages with npm install, and run it with npm start in the console.

The package bitcoin-script allows us to write Bitcoin Script Op-Codes and execute them in the NodeJS environment. This of course makes the learning easier as we don’t have to run our scripts inside a real wallet or node. This way it we can concentrate on the language itself without exposing us to everything around it, like networks, blockchain handling, and other nodes. Additionally, bitcoin-script package allows execution of previously mentioned “disabled” commands so that we can extend our experiments to parts of Bitcoin Script that aren’t available in the “real environment” anymore. As a warm-up we will now write a very simple script that checks the current topmost value in the stack for Boolean “truthiness”.
let evaluate = require('bitcoin-script').evaluate;
let parse = require('bitcoin-script').parse;
let myScript = "OP_TRUE OP_VERIFY";
console.log('Script result is: ' + evaluate(myScript));
In the above example, we used the Op-Code OP_TRUE to push a 1 into the stack. As we already know, OP_VERIFY pops the topmost value from the stack, and it marks the transaction as invalid if the value is not True. To execute this script, one can either type node ./app.js from within the directory where the script is located, or if running a NodeJS project with a package.json, execute the default start script with npm start. The result would be:
Script result is: true
There is another function available in bitcoin-script called “parse” that returns the parsed structure of the code.
let evaluate = require('bitcoin-script').evaluate;
let parse = require('bitcoin-script').parse;
let myScript = "OP_TRUE OP_VERIFY"
console.log('Script result is: ' + evaluate(myScript));
console.log('Parsed script is: ' + JSON.stringify(parse(myScript), null, 3));
This is how the output now would look like
Parsed script is: {
   "value": true,
   "code": "stack.OP_TRUE(); return stack.OP_VERIFY();"
}
We can now emulate the handling of locking and unlocking scripts by providing signatures and public key addresses. For this we can use any available data form “real world”. Here is an example with OP_CHECKSIG, where we use another function from bitcoin-script called “unlock”.
var unlock = require('bitcoin-script').unlock;
var scriptSig = '8459928119273117345498277881459870695761758288324491597610541854186847739718715161792675821745501378459187582098956166340492444286324429807893570567079694 0348726694288015a15558ed9bebcf398684cb95988bb9fa1c59366415871e9ecc';
var scriptPubKey = 'OP_CHECKSIG OP_VERIFY';
console.log(unlock(scriptSig, scriptPubKey));

The result would be a Boolen value of TRUE, indicating that the signature corresponds to the given key.

As the whole purpose of Script in Bitcoin is to evaluate if a logic returns a True or False, everything we execute here will ultimately lead to a Boolean value. No matter how complex a script might be, the execution engine will in the end return one of these two possible values. This has to do with the nature of Script programs which are “predicates”. In mathematics the term predicate means a function that can take any data but will always lead to either True or False. The range of input values for these functions is indefinite, while the possible output values are constrained to those two Boolean values.

To get a more visual representation on what’s going on inside the scripting engine and also what its data structure looks like, there is a web site available for visual script execution (Figure 7-5):

https://siminchen.github.io/bitcoinIDE/build/editor.html

Here is the script from our JavaScript code in the web execution engine.
../images/486570_1_En_7_Chapter/486570_1_En_7_Fig5_HTML.jpg
Figure 7-5

Visual execution of Bitcoin Scripts

As already mentioned, bitcoin-script allows us to execute disabled Op-Codes. All we need is to do is provide an additional parameter to the parsing engine. Here is an example of a script that uses the “disabled” OP_MUL command.
let evaluate = require('bitcoin-script').evaluate;
let script = 'OP_2 OP_2 OP_MUL OP_4 OP_EQUAL OP_VERIFY';
let useDisabledOpCodes = true;
console.log(evaluate(script, useDisabledOpCodes));
In this example we push two “2” and multiply them. Then we compare the result with 4 that of course leads to a True. The step-by-step execution would be like this:
  • Push 2 into the stack.

  • Push 2 into the stack.

  • Take two values from the stack (the two “2”), and multiply them.

  • Push the result of the multiplication into the stack (here, 4).

  • Push 4 to the stack.

  • Take two values (the two “4”) from the stack, and compare them for equality.

  • Push back the result of comparison into the stack. (here, “true”)

  • Check the topmost element from the stack for “truthiness”.

The final result will be True, and therefore our script execution marked as successful.

Flow Control

If you have ever written code before, you will be able to understand the meaning of this short JavaScript code:
if (2 < 3) {
   console.log("Yes, this is true.");
} else {
  console.log("Nope, will never get executed!");
}
Just paste this code into your browser’s console (press F12 to open it) and start it with ENTER. You should get a result like this:
../images/486570_1_En_7_Chapter/486570_1_En_7_Fig6_HTML.jpg
Figure 7-6

Flow control example in JavaScript

What we have done here (Figure 7-6) is a typical if-then-else branching logic, which lets the machine execute certain parts of the program depending on “truthiness” of some value. In our case we wrote the condition “2 < 3” and let the machine check in the if-statement, if it’s true or not. Depending on the outcome, only one of the two possible paths could ever be executed. So far, so easy.

However, the IF-ELSE-ENDIF constructs in Bitcoin Script are a bit different. Or rather, very different. Let’s try to understand them by analyzing this script:
IF
      AlicePubKey CHECKSIG
ELSE
      BobPubKey CHECKSIG
ENDIF

At the first sight, we recognize the usual keywords and different execution branches. The script itself seems to be a simple 1-of-2 multisig, where either of the parties can spend. However, as the IF statement has no visible conditions, the question is, how can any logic from this script be executed? Where does the condition come from?

The answer to this has to do with the stack data structure Script uses to operate. We already know that data can be pushed in or popped from the stack. Also, that operators can take one or more elements from the stack, do something with them, and push the results back. If this code is a locking script, then the missing conditions are part of the unlocking script, which the spending party must provide. What we see here is only one-half of the whole code. Now, let’s imagine that we have the other half and want to execute the script as a whole. Where does the condition go? After the IF keyword, maybe? Like this:
IF condition
      AlicePubKey CHECKSIG
Sadly, this wouldn’t work, because IF, like any other operator, must pop data from the stack first. There is no way that we could make IF, or any other operator, work on data that’s coming after it. Therefore, the condition will always stay in front of IF, like this:
Condition IF
      AlicePubKey CHECKSIG
ELSE
      BobPubKey CHECKSIG
ENDIF

But how are we supposed to execute IF if there is no condition for it? The answer, again, lies in the way how IF. It always pops data from the stack first and depending on the result (TRUE or FALSE) executes the one or another code branch. This means that in our example, IF would pop one value from the stack and, if it qualifies as true (a non-zero value), execute the first branch. Otherwise, the script would continue with the branch under ELSE.

However, only having provided a condition alone isn’t enough as the two branches contain CHECKSIG that would need two operands to execute properly: signature and public key. The public keys are given, but signatures are missing. Where do they come from? From the unlocking script of course. To execute either branch, the unlocking script must provide two elements: a value and a signature. And depending on the value, one of the two branches will be executed. In practice, this would mean that when Bob wants to spend funds locked by the script, he would have to provide FALSE + BobSignature, while Alice would need to push TRUE + AliceSignature into the stack. The condition in Script functions like a switch for the spending party to activate the “correct” code part. We also call the IF-ELSE-ENDIF constructs “guard clauses”, because they isolate different code parts from each other.

In Figure 7-7 we see our locking script ordered horizontally, while the unlocking script that contains TRUE and AliceSignature is in the stack. The next Op-Code to be executed is IF, which pops the TRUE value from the stack.
../images/486570_1_En_7_Chapter/486570_1_En_7_Fig7_HTML.jpg
Figure 7-7

Script execution with IF-ELSE

The IF operator would now let the first branch execute. In the next step (Figure 7-8), AlicePubKey will be pushed into the stack, because it’s not an operator. After it, CHECKSIG will be read, which pops two parameters from the stack: AlicePubKey and AliceSignature.
../images/486570_1_En_7_Chapter/486570_1_En_7_Fig8_HTML.jpg
Figure 7-8

CHECKSIG pops two elements from the stack

And because CHECKSIG is the last command from the current branch (Figure 7-9), the other code after ELSE won’t be read. CHECKSIG would check the signature of Alice and push a TRUE back, signaling that the transaction is valid.
../images/486570_1_En_7_Chapter/486570_1_En_7_Fig9_HTML.jpg
Figure 7-9

CHECKSIG is the last command to be executed

Summary

In this chapter we have learned about the very heart of Bitcoin, it’s scripting language. Anything we do in Bitcoin is basically a script, or part of it. Every single transaction is based on some script that gets validated by every participating node. We have learned about its many commands and what their purposes are. We have also learned how to read Bitcoin Scripts and what constitutes them. We have learned how owners of funds create small locking scripts with puzzles that can only get unlocked by those who provide correct data like signatures and corresponding public keys. We have also learned how to test Op-Codes, the commands of Script, inside a controlled environment based on NodeJS.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.162.247