When we develop smart contracts, we have available different types of storage:
- Volatile stack access: Stack
- Volatile memory access: Memory
- Non-volatile: storage
Furthermore, we also have available the context information:
- Code associated to the contracts
- Access to the data field of the transactions
How to operate with the different storage types
All Ethereum Virtual Machine operations (EVM opcodes), except the operations STOP, JUMPDEST and INVALID, use the stack both to read or to write on it. However, we are gonna see the operations that read or write data without performing any computation:
The stack depth ranges from 0 to a maximum of 1024
- POP: Gets the value on the top of the stack (level 0)
- PUSH1...PUSH32 (PUSHX): Inserts X bytes on top of the stack
- DUP1…DUP16 (DUPX): Duplicates the value at X on top of the stack
- SWAP1…SWAP16 (SWAPX): Swaps values on X and the top of the stack
The operations that access to this memory, either to read or to write, are:
- CALLDATACOPY: Reads the data field of a transaction and load it in memory
- CODECOPY: Reads the code associated to the current contract and load it in memory
- EXTCODECOPY: Reads the code associated to an external contract and load it in memory
- MLOAD: Reads, from the memory, a value
- MSTORE: Stores in memory a word/32bytes value
- MSTORE8: Stores in memory a 8bytes value
Unlike stack and memory, the data stored on this memory are persistent on the contract address for future accesses. The operations to manipulate this memory are:
It’s worth to mention that “S” and “M” means storage and memory, respectively.
All previous operations have a cost expressed in GAS units. When an user sends a transactions he/she set an ETH price per GAS unit. The miners have configured a minimum GAS price so a higher minimum GAS will let more margin but discarding a bigger number of transaction. It generates a market where ETH is traded per GAS. The less the code consumes in terms of GAS, more efficient will be in terms of resources needed to execute the code. The following table shows the costs, in GAS, of the different operations depending of the size of the data:
The most expensive one is the non-volatile storage. Operate with the memory is similar to operate with the stack in term of GAS when the size is about the KB but it increases exponentially with the size. This relation is shown in the following picture:
If we set a GAS price in ETH based on https://ethgasstation.info:
We can make an estimation, in terms of ETH, of the cost per storage type:
Above table values are prices in ETH. The miners will include transactions with a higher price so when an user pays more per GAS, more fast his/her transaction will be included in a block.
Last, we can set a $/ETH rate, for example, 1356.30$:
Store data permanently on Ethereum is extremely expensive. It has no sense to use Ethereum to store data. It should store only the required data to work properly and delegate the storage to other solutions: Swarm, Filecoin, IPFS, etc. A good idea is to store a Merkle Tree root hash as a tamper proof of data store on an external service.
Also, an unexpected and fast increase of ETH prices can increase the cost of the operations in terms of FIAT money to high levels. Miners have to adjust their min ETH price per GAS, if it happens, to readjust the costs.
It’s important to analyse smart contracts in terms of GAS consumption to control the operational costs.