An sCrypt Developer’s Guide to Optimization
sCrypt programming is different from traditional programming done in Javascript or Python, as the compiled code size directly determines their running cost when the transaction encapsulating it is submitted to the Bitcoin network. It is thus imperative that the resulting Script is as small as possible to save transaction fees¹. We list some tips for developers to manually optimize their sCrypt contracts’ Script outputs.
1. Batch same function calls
All function calls are implemented by inlining. The function body is copied to where it is called. If there are multiple callers of the same function, code size can be saved by merging them. In the following example, two Tx.checkPreimage() calls are consolidated into one.
2. Code in raw Script
Inline assembly allows native Bitcoin Script to be directly embedded in sCrypt code, for more fine-grained control. If you know customized Script that is shorter than what sCrypt yields, you can use it instead.
3. Use implicit/default constructors
A constructor often just uses its arguments to initialize each property. Use default constructor if this is the case to save code size.
4. Avoid variable reassignments
Bitcoin Virtual Machine (BVM) operates purely on stack. Unlike many other VMs, it does not have other types of memory like register or RAM, in which writing to a variable location takes O(1). BVM takes O(n) to write to a variable, where n is the depth of the variable down the stack².
A special case is static properties of a contract. They are stored at the bottom of the stack internally, making them especially expensive to update. If they really have to be changed, see if they can be made into non-static properties.
5. Use loop induction variables
An induction variable is cheaper than a regular variable incremented in every loop.
6. Use optimized version of OP_PUSH_TX
See optimal and OP_CODESEPARATOR version of OP_PUSH_TX.
7. Use Merklized Abstract Syntax Tree
See this article.
[1] Currently, transaction fee is simply proportional to script/transaction size, which will evolve to take script complexity into consideration. Thus optimization objective is expected to evolve in the future as well.
[2] Reading a variable is always O(1).