Skip to content
This repository has been archived by the owner on Jan 29, 2025. It is now read-only.

Added the Optimized Code - Sample 1 #25

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

gowtham-ponnana
Copy link

@gowtham-ponnana gowtham-ponnana commented Nov 25, 2024

Old Code vs Optimized Code (with 100 optimizer runs)
image

Changes Implemented:

  1. Modified Structs

    • What: Packed data types efficiently within structs.
    • Why: Writing/reading to storage incurs higher gas costs as data length increases. Optimizing struct alignment minimizes these costs.

  2. Added Custom Errors

    • What: Replaced all require statements with if conditions and used custom errors for reverting.
    • Why:
    • Custom errors reduce bytecode size.
    • Saves gas by avoiding the overhead of require’s default error messages.

  3. Changed Zero Values to Non-Zero Values

    • What: Initialized storage variables with bytes32(bytes1(0x01)) instead of 0.
    • Why:
    • Changing storage from zero to non-zero requires 20,000 gas for storage write + 2100 gas for cold storage access.
    • Pre-initializing with non-zero reduces this cost significantly: updating a non-zero value only requires 5000 gas.

Old Method:

hashlock = bytes32(0);
// Writing 0 to a zero slot.
// Changing hashlock later incurs 22,100 gas for storage updates.

New Method:

hashlock = bytes32(bytes1(0x01));
// Writes a non-zero value during initialization, incurring little gas.
// Updates to hashlock cost only 5000 gas as it's non-zero to non-zero.

  1. Changed Default DataType for timestamp

    • What: Reduced timestamp data type from uint256 to uint48.
    • Why:
    • A uint48 can store timestamps for millions of years (block increments every ~12 seconds).
    • Smaller data types pack better in storage, reducing gas usage.

  2. Changed Parameters from memory to calldata

    • What: Used calldata for external function parameters instead of memory.
    • Why:
    • calldata avoids copying data into memory, which is expensive.
    • Saves gas for functions that don’t modify the input parameters.

  3. Replaced Arrays with Mappings

    • What: Replaced arrays with mappings where applicable.
    • Why:
    • Reading an index from an array incurs additional gas due to boundary checks (e.g., 2102 gas for index >= length).
    • Mappings eliminate boundary checks, reducing gas.
    • Important: Ensure code prevents reading unallocated indices.

Old Method (Array):

uint[] public values;

function getValue(uint index) external view returns (uint) {
return values[index]; // Implicit boundary check incurs gas.
}

New Method (Mapping):

mapping(uint => uint) public values;

function getValue(uint index) external view returns (uint) {
return values[index]; // No boundary checks, direct storage access.
}

Explanation of Optimizations:

Why These Changes?

1.	Struct Optimization: Better packing of struct fields reduces the number of storage slots used, saving gas during reads/writes.
2.	Custom Errors: Eliminates redundant error messages, reducing contract size and deployment costs.
3.	Non-Zero Initialization: Saves gas on state changes by avoiding expensive zero-to-non-zero storage operations.
4.	Reduced Data Type Size: Smaller data types like uint48 lead to better packing and lower storage costs.
5.	Calldata Parameters: Avoids unnecessary memory allocations for read-only parameters.
6.	Mapping Over Arrays: Eliminates gas costs for boundary checks while providing similar functionality.

These changes demonstrate a significant reduction in gas consumption while maintaining functionality and security.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant