Bitcoin Script

Bitcoin has been programmable since it's inception. When a transaction is verified this is done by running small programs embedded into the transactions. The Script platform is a very low-level stack based language. Programming in Script is like programming in assembly.

No Loops

Script has basic mathematical and logic operators, some special operators for verifying transaction signatures. Conditionals are supported, but there is no facility for loops.

The Halting problem

Adding loops to Script introduces a problem known as the halting problem . The execution of a script might never finish. For many programs it easy to determine if execution will halt or run into an infinite loop, but unfortunately no method that will work for every possible program is known.

A Workaround

A workaround is to introduce a run time limit. If the script doesn't finish within a predefined time limit, it's aborted and the execution is consider unsuccessful, in turn making the transaction containing the script invalid. In order to reach consensus, everyone need to use the exact same time limit. Defining the limit as the number of script operations executed is one way of achieving this.

Using Fee as Run Time Limit

The idea is quite simple. Some of the transaction fee is used to pay for script execution time. The creator of a transaction must specify the run time limit for each script, and include enough fee to cover the cost of all scripts in the transaction. The number of satoshis per instruction executed will be determined by supply and demand, similar to how the satoshis per byte fee level is determined.

Calculating the Run Time Limit

The creator of the transaction will have to inspect every loop in the script. Any loop that can't be determined to always finish within a reasonable number of iterations will have to be adjusted. Good tools will help the programmer with this job.

Example: A loop is counting the number of zeros in a byte string. The number is thus dependant on the length of the input string. In this particular case the byte string happens to be the result of a ripemd160 or sha256 operation, thus it's guaranteed to be at most 32 bytes long.

Ethereum?

Yes. This essentially how Ethererum works. But we can do better.

Bitcoin has always supported loops

Loop unrolling is a method sometimes used to optimise program execution speed. In bitcoin this technique is instead used to simply the complexity of the system. A loop is unrolled by duplicating the instructions inside the loop. It increases the script size, but this actually a good thing. We don't need the complicated run time limit logic any more. The run time limit of a script is dictated by it's size. More iterations ⇒ more bytes in the transaction ⇒ higher fee required.

Re-rolling the Loops

Using compression it's possible undo the size expansion caused by loop unrolling. A generic compression algorithm would probably work fine. An alternative could be to define the script before unrolling as the compressed form and define a deterministic unrolling algorithm as the decompression function.

Back to start?

What's the point of unrolling then re-rolling? Why not just make loops an integral part of script? The answer is greatly reduced complexity of the consensus rules. Script compression is not part of the consensus rules. The transaction id the hash of the uncompressed transaction data. Compression is thus just an optimisation. It's optional and everyone doesn't have to agree on the algorithm.

Op-code limit

Bitcoin has a limit of 201 op-codes (instructions) per script. This limit was added to protect against potential denial-of-service attacks (just like the block size limit). If looping had been supported by Script, this limit would have been defined as the maximum number of op-codes executed. Otherwise it would not serve as a denial-of-service protection.

The limit has to be raised, or preferably removed, in order to unleash the full potential of Script. Denial-of-service protection is taken care of by fee.

Credits