Based on Gaschecker there are three types of optimizations we can perform on loops. Three catergories identified below with the identified from the same work:
- Moving updates to storage variables in a loop to outside of the loop.
- Moved declarations of static variables which are not modified in the loop to outside of the loop.
- Move computations that involve storage access to outside the loop if the computation yields the constant result all through the execution of the loop.
Below we define the step-by-step approach for loop optimization:
- Read complete solidity code from a file.
- For each function with a for loop, create a solidity file with contract C and a function foo(). The for loop must be placed in function foo().
- For each solidity file that was created, call bmc-synthesizer to create loop summary in DSL.
- For each loop summary created, use the updated templates for the operations in loop summary and create new solidity files with the optimized for loop code.
- Merge all solidity files into one to create a new gas optimized solidity contract with all the new functions in place.
- Final step is to confirm using bisimulations to prove the equivalence of the generated solidity code with the original one using solci-verify.
- Download (link) and install Racket (v7 or later) if you do not already have it installed on your system.
- Make sure that the Racket binaries are available on your
PATH
.
- Make sure that the Racket binaries are available on your
- Download (link) and install Rosette.
- Compile the bounded model checker (in Rosette) into executable:
cd ./src/rosette
raco exe ./bmc-rosette.rkt
- Then run the loop optimizer synthesizer:
python ./src/loop-optimizer.py <path to the solidity file>
If successful a contract with gas optimized code will be generated in "./src/contractfiles/" folder.