tohka

tohka

Hack for fun!
twitter
github

How can I conserve fuel?

1. Using Short-Circuiting to Optimize Solidity Operations#

Short-circuiting is a Solidity contract development pattern that uses logical OR/AND to prioritize operations with different gas costs. It places low gas cost operations first and high gas cost operations later, so if the low cost operation is feasible, it can skip (short-circuit) the high cost Ethereum virtual machine operations.

// f(x) is a low gas cost operation
// g(y) is a high gas cost operation

// Sort operations with different gas costs as follows
f(x) || g(y)
f(x) && g(y)

2. Explicitly Declare the Visibility of Solidity Contract Functions#

In Solidity contract development, explicitly declaring the visibility of functions not only improves the security of smart contracts but also optimizes the gas cost of contract execution. For example, by explicitly marking a function as external, the storage location of function parameters can be set to calldata, which saves the Ethereum gas cost required for each function execution.

External visibility consumes less gas than public.

3. Use Appropriate Data Types#

In Solidity, some data types have higher gas costs than others. It is necessary to understand the gas utilization of available data types in order to choose the most efficient one based on your needs. Here are some rules regarding gas consumption of Solidity data types:

  • Avoid using string type whenever uint type can be used.
  • Storing uint256 has lower gas cost than storing uint8. Why? Click here to find out.
  • When bytes type can be used, avoid using byte[] type in Solidity contracts.
  • If the length of bytes has a predictable upper limit, consider using fixed-length Solidity types such as bytes1 to bytes32.
  • bytes32 has lower gas cost compared to string type.

4. Avoid Dead Code in Solidity Smart Contracts#

Dead code refers to Solidity code that will never be executed, such as code with conditions that can never be satisfied. For example, the following Solidity code block with two contradictory conditional statements consumes Ethereum gas resources but serves no purpose:

function deadCode(uint x) public pure {
if(x < 1 {
if(x > 2) {
return x;
    }
 }
}

5. Avoid Unnecessary Conditional Statements#

Some conditional assertions can be known without executing Solidity code, so such conditional statements can be simplified. For example, in the following Solidity contract code with nested conditional statements, the inner condition is wasting valuable Ethereum gas resources:

function opaquePredicate(uint x) public pure {
 if(x < 1) {
    if(x < 0 ) {// uint cannot be less than 0
    return x;
    }
 }
}

6. Avoid High Gas Cost Operations in Loops#

Due to the high cost of SLOAD and SSTORE opcodes, managing storage variables has much higher gas cost compared to memory variables. Therefore, avoid operating on storage variables in loops. For example, in the following Solidity code, num is a storage variable, and performing unknown iterations of operations can result in unexpected Ethereum gas consumption:

uint num = 0;

function expensiveLoop(uint x) public {
for(uint i = 0; i < x; i++) {
    num += 1;
  }
}

The solution to the above Ethereum contract code problem is to create a temporary Solidity variable to replace the global variable in the loop, and then assign the value of the temporary variable back to the global state variable after the loop ends:

uint num = 0;

function lessExpensiveLoop(uint x) public {
uint temp = num;
for(uint i = 0; i < x; i++) {
    temp += 1;
  }
  num = temp;
}

7. Avoid Loops with Constant Outcomes#

If the result of a loop calculation can be predicted without compiling and executing Solidity code, then the loop should be avoided as it can significantly save gas. For example, the following Ethereum contract code can directly set the value of the num variable:

function constantOutcome() public pure returns(uint) {
uint num = 0;
for(uint i = 0; i < 100; i++) {
    num += 1;
  }
return num;
}

8. Avoid Redundant Computations in Loops#

If an expression in a loop produces the same result in each iteration, it can be calculated outside the loop to save additional gas costs. This is even more important if the expression uses a storage variable. For example, in the following smart contract code, the value of the expression a*b does not need to be recalculated in each iteration:

uint a = 4;
uint b = 5;
function repeatedComputations(uint x) public returns(uint) {
uint sum = 0;
for(uint i = 0; i <= x; i++) {
    sum = sum + a * b;
  }
}

9. Remove Comparison Operations in Loops#

If a comparison operation is executed in each iteration of a loop, but the result of each comparison is the same, it should be removed from the loop.

function unilateralOutcome(uint x) public returns(uint) {
uint sum = 0;
for(uint i = 0; i <= 100; i++) {
if(x > 1) {
      sum += 1;
    }
  }
return sum;
}

10. Choose a Function Name for Common Functions to Minimize Hash Value#

Adding an image from the paper#

image

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.