When writing smart contracts, it’s usually relatively easy to set up your first one, but the deeper you dig, the more complex it might get. We thought about sharing our knowledge and experience around working with smart contracts on Algorand, so if you’re a developer, you can work more efficiently and if you’re a founder, you can better understand the specifics of blockchain development, especially on Algorand.
This is the second part of the Smart Contracts on Algorand Best Practices series that covers the concepts mentioned in Part 1 in a greater detail. If you haven’t read it first, we strongly recommend you start there.
In this article, we focus especially on how to optimize the smart contract code, so your application can run faster.
The article has been written based on an interview with our experienced blockchain developer, Łukasz Ptak.
How to make Algorand smart contracts run faster?
Algorand’s smart contract system has two key limitations that the developers should have in mind – contract size and execution cost (opcode budget). We wrote about these characteristics in the first part, but let’s go back to the key concepts that can make your code run faster.
- Avoiding using byte math when unnecessary
- Paying attention to opcode cost of specific operations
- Performing expensive calculations off-chain
- When there’s no good way for optimization, increasing the opcode quota is still a viable option.
Avoid using byte math
Using byte math is very convenient–under some circumstances. First, it allows you to use wider integers and larger numbers, but it comes with a cost. Those operations are an order of magnitude more expensive than the integers counterparts.
Avoid using byte math any time that you have a problem that can be solved using standard uint64. In some cases, the ratio function can be calculated using 128 bit math, which TEAL has some limited support for.
Move complex calculations off-chain
The operation budget is very limited in Algorand Smart Contracts (ASC1) to prevent the network from being overloaded and slowing down. Because of that, you can only perform some limited operations on layer 1.
The default opcode cost limit is set to 700. That means you can only perform 700 algorithmic operations, and for some calculations that is simply not enough. It is not possible to follow the standard approach for certain problems inside the smart contract.
For example, finding a path in the graph might be just too expensive to even bother trying. However, with Algorand’s smart contracts the path finding task can be done outside the smart contract, just in the backend. The smart contract can work with an off-chain calculated result and then continue designed, less costly operations. This way, you can reduce the cost of running a smart contract, even going further to using smart contracts just to validate the end results of more expensive calculations.In programming, there are multiple problems that can be solved elsewhere and then validated cheaply. You can adapt this concept to your applications.
Manage opcode costs like a pro
Sometimes when you want to solve a specific problem, you may find a function or a method or an approach that seems to solve your problem perfectly. But this straightforward solution might come with unexpected costs.
Those costs vary significantly. A simple operation like adding two numbers together would have a cost of 1. Of course, loading those numbers would have its own cost, but just the simple addition costs 1 unit. When you add two bytes together, then the cost is 10. But when you want to calculate a hash of anything, then the cost soars into hundreds.
With the cap of 700 operations, you can see that calculating hashes is very limiting. So you may not do a lot of these operations, unless of course you expand your budget and simply pay more for each transaction.
You need to find a balance between using expensive operations and finding ways to cut costs. That's why you have to pay attention to the opcode cost to foresee how much your algorithm will make an operation. The good thing is that you can make quite detailed estimates.
With the costs varying a lot between operations, you may choose to use a cheaper hashing function. If you are validating some hashes on-chain, this cheaper hash function is quite useful–it performs the same task at a lower cost.
In some cases, when it cannot be avoided, then you have to use those operation budget. The opcode cost of every operation can be found on Algorand’s developer portal.
Remember that if you’re using PyTEAL–which translates Python to TEAL–there is some abstraction and it’s not obvious what is happening underneath. The implication is that most PyTEAL operations have equal cost to TEAL operations, a pure 1:1 ration, but in some cases it might be slightly different. PyTEAL might sometimes consume more operation budget compared to TEAL.
Use PyTEAL, debug in TEAL
TEAL is a very specific programming language. It's an assembly language that is used by Algorand Virtual Machine and has been created solely for this purpose. Algorand founders wanted to have an assembly language that would be much simpler than the ones already available. Based on that idea, the key was to make it easy to read and understand.
Looking at TEAL code on chain, it’s rather easy to determine what is happening, and even go through it manually to determine what is the expected result. How is that? The opcode names are meaningful and simple, and the code is executed line by line on a stack machine (with a certain line count limit).
While TEAL is a language that many developers would have to learn from scratch (although knowledge of any other assembly language is helpful), Python is one of the most used languages out there–and you can use it to manage AVM through PyTEAL.
PyTEAL is an abstraction of the TEAL language inside Python. It provides some mechanisms to make development simpler, faster and safer. The way the program is constructed is different, however, and the code compiled to TEAL from PyTEAL will usually be longer than if written only in TEAL. As it was mentioned earlier, in some cases this approach might use more operations budget, too.
Again–in TEAL we had a list of commands that were being executed and in PyTEAL, on the other hand, we are building an Abstract Syntax Tree (AST). This is very different from the usual way that software is being developed.
The Abstract Syntax Tree is usually constructed automatically by a compiler, but PyTEAL requires building it manually. ASTs are usually an intermediate form of expressing the code.
How does that work? You build the AST directly in a smart contract code in Python, and then it’s compiled to TEAL function. The AST is reduced to text, which becomes the TEAL program.
It’s important to know both Python and TEAL to be good at programming on Algorand but even if you get a grasp of TEAL, it’s still more beneficial to use PyTEAL. The room for error is smaller there which makes the end code less buggy.
Still, if TEAL fails for any reason, or you’d like to know an exact value in the code, you have to debug the program in TEAL. You can determine which line in TEAL corresponds to which line in PyTEAL and then fix it in PyTEAL, but even though it sounds more complex, it is actually the way to program smart contracts on Algorand faster and with fewer errors.
Need to audit your smart contract code?
At Ulam Labs, we’re focused on adding to the crypto world. We’re building projects end-to-end, as well as audit smart contracts for their optimization and security. If you’d like us to audit your code, consult development, or build the whole project using our extensive knowledge – don’t hesitate to contact us!