Skip to main content

Storing Data

Ultimately, the power of the blockchain is that anyone can store their data on it via the storage in a smart contract. In this step by step guide, you'll learn how to access and use the storage data location.


Objectives

By the end of this lesson you should be able to:

  • Use the constructor to initialize a variable
  • Access the data in a public variable with the automatically generated getter
  • Order variable declarations to use storage efficiently

Simple Storage Contract

Create a contract called SimpleStorage.

Add a Storage Variable

In Solidity, variables declared at the class level are automatically storage variables. Create a variable to store the age of a person and another to store the number of cars that they own. Give age an initial value of your choosing, but don't make an assignment for cars;

Reveal code
contract SimpleStorage {
uint8 age = 41;
uint8 cars;
}

Because the age of a person, or the number of cars they own, is unlikely to be greater than 255, we can use a uint8 for each of these. For types that are smaller than 32 bytes, multiple variables of the same type will be packed in the same storage slot. For this to work, the variables must be declared together.

// These variables take advantage of packing
uint8 first;
uint8 second;
uint third;

// These variables DO NOT take advantage of packing and should be reordered
uint8 fourth;
uint fifth;
uint8 sixth;

Initializing a Value with the Constructor

You may add a constructor function to your contract. Similar to other languages, this function is called exactly once, when the contract is deployed. The constructor may have parameters, but it does not require them.

You can use the constructor to perform various setup tasks. For example, the constructor for the ERC-721 token that is the underlying mechanism for most NFTs uses the constructor to set up the name and symbol for the token.

Create a constructor function and use it to assign the value of your choosing to cars.

Reveal code
constructor() {
cars = 1;
}

Accessing State Variables

Deploy your contract in Remix. It should work fine, but you'll have one problem: there isn't a way to see if the variables have the expected values!

You could solve this by writing functions that return the values in your state variables, but you don't need to. The Solidity compiler automatically creates getters for all public variables.

Add the public keyword to both variables. Unlike most languages, public goes after the type declaration. Your contract should now be similar to:

Reveal code
contract SimpleStorage {
uint8 public age = 41;
uint8 public cars;
constructor() {
cars = 1;
}
}

Redeploy your contract and test to confirm.


Setting a State Variable with a Function

Good news! Our user bought a second car! The only problem is that we don't have a way to update the number of cars stored.

Add a Function to Update cars

Before writing the function, let's think about design considerations for this feature. At any point in time, a user could:

  • Buy or otherwise acquire a new car
  • Get several new cars all at once (Woohoo!)
  • Sell or give away one or more cars (😞)

Given this wide variety of conditions, a good approach would be to handle calculating the correct number of cars on the front end, and passing the updated value to the back end.

To meet this need, we can write a public function that takes a uint8 for _numberOfCars and then simply assigns that value to the state variable cars. Because this function modifies state, it does not need pure or view. It isn't either of those.

Reveal code
function updateNumberOfCars(uint8 _numberOfCars) public {
cars = _numberOfCars;
}

Deploy and test to make sure it works as expected.

danger

While packing variables can save on gas costs, it can also increase them. The EVM operates on 32 bytes at a time, so it will take additional steps to reduce the size of the element for storage.

Furthermore, the savings in writing to storage only apply when writing multiple values in the same slot at the same time.

Review the Warning in the layout section of the docs for more details!

Add a Function to Update age

It would also be good to be able update the age value. This problem has slightly different considerations. Sadly, age will never go down. It should also probably only go up by one year for each update. The ++ operator works in Solidity, so we can use that to create a function that simple increments age when called.

Reveal code
function increaseAge() public {
age++;
}

But what if a user calls this function by mistake? Good point!

On your own, add a function called adminSetAge that can set the age to a specified value.

Refactor the Constructor to Accept Arguments

We've got one problem remaining with this contract. What if your user has a different age or number of cars than what you've hardcoded into the contract?

As mentioned above, the constructor can take arguments and use them during deployment. Let's refactor the contract to set the two state variables in the constructor based on provided values.

Reveal code
contract SimpleStorage {
uint8 public age;
uint8 public cars;
constructor(uint8 _age, uint8 _cars) {
age = _age;
cars = _cars;
}
}

Redeploy your contract. Note that now you have added parameters to the constructor, you'll have to provide them during deployment.

Deployment

Once completed, your contract should be similar to:

Reveal code
contract SimpleStorage {
uint8 public age;
uint8 public cars;
constructor(uint8 _age, uint8 _cars) {
age = _age;
cars = _cars;
}

function updateNumberOfCars(uint8 _numberOfCars) public {
cars = _numberOfCars;
}

function increaseAge() public {
age++;
}

function adminSetAge(uint8 _age) public {
age = _age;
}
}


Conclusion

In this lesson, you've explored how to persistently store values on the blockchain. You've also practiced updating them from functions. Finally, you've learned how to use the constructor to perform setup functionality during deployment, with and without parameters.


We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking . For more information see our Cookie Policy.