पाठ 7 / 25

Storage, Memory, Calldata and Transient Storage

Choose data locations correctly and understand their costs.

Where data lives

Reference types need a data location. storage is persistent contract state on chain; reading and especially writing it is the most expensive operation (a new non-zero slot costs about 20,000 gas). memory is temporary, exists for the duration of a call and is cleared afterwards. calldata is the read-only input data of an external call, the cheapest location for array and string parameters you do not modify. Assignments behave differently by location: Item storage item = items[i]; creates a reference, so changes write to storage, while Item memory item = items[i]; makes a copy, so changes are lost unless written back, a classic bug. The stack holds value-type local variables (limited to 16 reachable slots, which is the origin of "stack too deep" errors). Storage is organised in 32-byte slots, and adjacent small variables are packed into one slot. Transient storage (EIP-1153, active since the Cancun upgrade in 2024) is cleared at the end of each transaction and is cheap; recent Solidity versions support the transient keyword for value types, useful for reentrancy locks.

Data locations

Storage persists across transactions; memory and calldata exist only during a call.

Three containers side by side: a heavy safe labelled with a chain icon, a whiteboard that gets wiped, and a sealed read-only envelope.
Figure 3.1 — Storage, memory and calldata.

Storage references versus memory copies

A common bug and its fix.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract Inventory {
    struct Item {
        string sku;
        uint128 stock;
        uint128 priceWei;
    }

    Item[] public items;

    function add(string calldata sku, uint128 stock, uint128 priceWei) external {
        items.push(Item(sku, stock, priceWei));   // calldata string copied into storage
    }

    // BUG: modifies a memory copy; storage is unchanged
    function restockBroken(uint256 index, uint128 amount) external {
        Item memory item = items[index];
        item.stock += amount;
    }

    // FIX: a storage reference writes through to contract state
    function restock(uint256 index, uint128 amount) external {
        Item storage item = items[index];
        item.stock += amount;
    }

    // calldata avoids copying a large array we only read
    function totalStock(uint256[] calldata indexes) external view returns (uint256 total) {
        for (uint256 i = 0; i < indexes.length; i++) {
            total += items[indexes[i]].stock;
        }
    }
}
// stock and priceWei (uint128 each) pack into a single 32-byte storage slot

Read storage once

Each storage read costs gas. In loops or repeated checks, copy a storage value into a local variable once (uint256 bal = balances[user];), work with it, and write the result back once.

त्वरित जाँच: What does `Item memory item = items[i]; item.stock += 1;` do to contract storage?

  • Nothing: it changes a temporary memory copy
  • Increments the stored stock
  • Deletes the item
  • Reverts the transaction
Answer

Nothing: it changes a temporary memory copy — Memory variables are copies; use a storage reference to modify state.