It's quite imperative for you as a Smart Contract Developer to always be within the pre-defined Smart Contract Bytecode size limit.
Wait, What is Bytecode? 🤔
In very simpler terms,
Humans understand Solidity,
EVM understands Bytecode.
Bytecode is the low-level language that our solidity smart contracts (a high-level programming language) get translated to.
It technically represents a long sequence of machine codes or opcodes which are pieces of instructions that defines how a particular smart contract is supposed to behave.
Most importantly, these instructions are easily understandable by the EVM and thus allow them to interpret and execute smart contracts accurately.
Alright, What's Bytecode Size Limit? 🤔
Every blockchain has a limit on the maximum size of Smart Contract bytecode that can be deployed.
In the world of Ethereum, after the implementation of EIP170, the maximum bytecode size is 24.576 kilobytes.
Why do we even have a limit? 😫
This limit was introduced in Ethereum with EIP-170 to prevent excessive resource usage and potential network congestion caused by deploying and executing excessively large smart contracts on the blockchain.
The limit was set at 24.576 kilobytes (KB) in order to maintain network performance and prevent spamming attacks that could bloat the blockchain.
By setting a reasonable limit on the size of the contract bytecode, Ethereum nodes can process transactions and execute smart contracts more efficiently, as they have to store and maintain a copy of the entire blockchain on their local machines. Furthermore, the limit discourages the deployment of overly complex and inefficient contracts, which could negatively impact the network as a whole.
In short, this was mainly to prevent any DOS attacks on the network.
Here is a portion of what an article on ethereum.org says about this:
This limit was introduced to prevent denial-of-service (DOS) attacks. Any call to a contract is relatively cheap gas-wise.
However, the impact of a contract call for Ethereum nodes increases disproportionately depending on the called contract code's size (reading the code from disk, pre-processing the code, adding data to the Merkle proof). Whenever you have such a situation where the attacker requires few resources to cause a lot of work for others, you get the potential for DOS attacks.
What does this mean for you as a Solidity Developer?
- You don't just need to manage gas optimizations but also your contract's bytecode size optimization.
- If you keep adding functions to your smart contract, at some point you will hit the size threshold and you will not be able to deploy that contract on-chain. Trust me, it's not possible.
if you ever try to deploy an extremely bulky contract of contract size more than 24.576 kilobytes, this is what you might get 👇
Therefore it's crucial to learn optimization techniques so that smart contracts can stay within the 24.576 KB size limit without breaking intended functionality.
Well, this is easier said than done since we might need large contracts for our intended use-cases
However, with sufficient knowledge of optimizing contract bytecode size, we can write smart contracts to fit our needs without surpassing the bytecode threshold.
In this short article series, we will mainly learn two things:
- Solidity development tricks that can help us optimize contract bytecode size.
- Then, decipher and dive deep to understand why some of these tricks help us optimize contract bytecode size
It's gonna be FUN, as always. 😀
Let’s explore some of these bytecode size optimization tricks to keep in mind while writing solidity code:
- Minimize code redundancy: Avoid writing repetitive code and reuse existing code as much as possible. This can significantly reduce the size of the Smart Contract bytecode.
- Start using Libraries: Using a library in a smart contract can help reduce the size of the bytecode because it allows you to reuse code that has already been deployed to the blockchain.
- Follow ERC-2535, Diamonds, Multi-Facet Proxy: This smart contract system, introduced by @mudgen, is a complete game changer. It effectively allows you to create modular smart contract systems that can be extended after deployment, and thus helps significantly in optimizing contract size.
- Use smaller data types: Use smaller data types such as uint8, uint16, and uint32 instead of uint256 whenever possible.
- Shorter error messages should be preferred: Long error messages in require statements can inflate the bytecode size. Consider using shorter and more concise error messages.
- Use of Custom errors: If you are using solidity versions of 0.8.4 or more, you prefer replacing error messages with custom errors. These can significantly help in contract size reduction as they are ABI-encoded as selectors. Read more about it HERE
- Wipe out unnecessary functions and variables: Remove any functions or variables that are not required for the Smart Contract to function properly.
- Optimize code logic: Optimize the code logic to reduce the number of instructions required to execute the Smart Contract.
- Replacing modifiers with Private Function: Excessive use of modifiers in solidity smart contracts can actually increase contract size. However, replacing modifiers with private functions can actually help reduce contract size.
Curios about why this happens? Read more about it here 👇
Tools for Checking Smart Contract Size
Now that you know, the bytecode size limit is a thing, you will definitely need tools that can help track this limit during smart contract development.
Luckily, we do have various tools to monitor their smart contract bytecode size during development, like:
hardhat-contract-sizer- Provides details and warnings about contract sizes in a hardhat project
truffle-contract-size- displays the contract size of all or a selection of your smart contracts in kilobytes.
solc: Provides a built-in bytecode size checker
There you have it devs.
Try using these tricks and never be worried about hitting the threshold for smart contract bytecode size.
Drop your suggestions, in case you have more tricks 😉.
Next Parts of the series 👇
- Part 2 - Replace modifiers with private functions and reduce your contract's size
- Part 3 - Custom Errors in solidity are more useful than you think
- Part 4 - Using libraries to optimize contract size