Solidity uses three different options when it comes to storing data:
- Storage – This is where contract variables are stored and new storage values can only be created on contract creation. It is a key-value store where the keys and values are both 32 bytes.
- Memory – This is where values are stored short term and will be cleaned up when leaving an external function or once a function is finished.
- Stack – A limited amount of small variables are stored on a Stack.
We will be focusing on the storage and memory key words and how those impact where values are stored.
Example Storage Contract
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; /** * @title ScoreStorage * @dev This contract will demo using storage */ contract ScoreStorage { // Stored as storage int[] public scores; /// Puts two numbers in the scores array function insertAndUpdateScores() public { scores.push(27); scores.push(42); // newCounts will still be referencing counts int[] storage newScores = scores; newScores[0] = 0; } }
In this example contract we are using the storage keyword to create a new variable called newScores.
Using the storage
keyword in the function will create a reference to the contract’s variable – scores. Since it is a reference to the scores variable, any changes in newScores will appear in scores.
If we were to look at the values in scores after calling this function we would see [0, 42].
Example Memory Contract
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; /** * @title ScoreMemory * @dev This contract will demo using memory */ contract ScoreMemory { // This is still stored as storage int[] public scores; /// Puts two numbers in the scores array function insertAndUpdateScores() public { scores.push(27); scores.push(42); // newCounts will be a copy of the values from scores int[] memory newScores = scores; newScores[0] = 0; } }
In this example contract we are using the memory keyword to create a new variable called newScores.
Using the memory
keyword in the function will copy the values from scores and create a new array. Since it is a new copy of the scores variable, any changes in newScores will not appear in scores.
If we were to look at the values in scores after calling this function now, we would see [27, 42] because we changed a copy of scores.
Considerations
When having to decide between storage or memory there are a couple things you want to consider:
- How long does this value need to stay around?
- Am I dealing with a large array? If so, what are the gas/performance impacts of copying that?
- Are you only reading the values from the contract storage?
- Can the value be calculated?
Code – https://github.com/derekarends/solidity-vulnerabilities/tree/main/storage-vs-memory