Ethereum Smart Contracts: Tips for Handling Data in Solidity - dummies

Ethereum Smart Contracts: Tips for Handling Data in Solidity

By Michael Solomon

Solidity is the most popular language for writing Ethereum smart contracts. Solidity was proposed by Gavin Wood in August 2014. Although it isn’t the only language you can use to write smart contracts, it is the most popular language for writing smart contracts that run in the Ethereum. It enjoys solid support from the Ethereum community and was developed by the Ethereum project’s Solidity team.

Solidity was designed to be similar to JavaScript and was influenced by a few other popular programming languages as well, including C++ and Python. The goal of Solidity is to provide a language that is familiar to web application developers but targeted at smart contract development. Solidity isn’t intended not as a general-purpose language but to support blockchain specific operations with code that runs in the EVM.

Before your code can run in the EVM, you have to compile it. That’s why one of the components you installed when building your development environment was a Solidity compiler. You first write your Solidity source code in an editor. Then you compile it into bytecode, which are the instructions that run in the EVM. After you deploy your smart contract bytecode, it runs on all Ethereum nodes.

Because smart contracts run on all nodes, Solidity must enforce determinism, that is, the results must be the same for all nodes running your smart contract code with the same input. If you look at the Solidity documentation, you won’t find a random() function. That omission is specifically to support Solidity’s determinism. Your code gets run first by the node that mines a new block, but then all nodes verify the block and run the code to ensure that they don’t get a different result.

In many ways, Solidity is similar to other programming languages. The biggest differences are in how the programs are run and how Solidity deals with data. Note that Solidity deals with data only in the EVM or the blockchain.

Solidity doesn’t interact with the outside world much, but it is possible. Solidity supports the concept of an oracle, which is a trusted source of information from the outside world.

Calling an oracle is easy. One problem is being able to trust the oracle. Another problem is dealing with oracle data that may return different data each time it’s called. Before using any oracles, you must ensure that the data source is trustworthy and consistent. It is common for oracles to return data and some proof of authenticity.

The concept of trust with respect to oracles is just an extension of blockchain trust. Remember that blockchain technology provides a trusted ledger of data in an environment of trustless network nodes. Because trust is such a foundational property of blockchain, it isn’t surprising that trusting an oracle is an important concern.

Solidity is particular about where you can store data. You generally define two types of variables in Solidity: state variables and local variables. You define state variables in the contract section, and those variables are available anywhere in the smart contract. These variables store the state of your smart contract by saving the values in a block on the blockchain. You define local variables inside functions. Local variables don’t save their values between function calls. Those values aren’t stored on the blockchain and go away when the function ends.

Solidity defines three places for storing data:

  • Stack: Where Solidity stores local simple variable values defined in functions.
  • Memory: An area of memory on each EVM that Solidity uses to store temporary values. Values stored here are erased between function calls.
  • Storage: Where state variables defined in a smart contract reside. These state variables reside in the smart contract data section on the blockchain.

Variable storage location is one of the more confusing aspects of Solidity. The Solidity language doesn’t have a stack keyword but does have memory and storage keywords. Solidity uses its own defaults, depending on where you define variables and how you use them, but you can override some of these defaults and also use the keywords to modify how Solidity treats variables.

Here are a few rules that help keep things straight when learning about storing data in Solidity:

  • State variables are storage by default (values are stored in the blockchain).
  • Local variables in functions are memory by default (values are stored temporarily in memory).
  • Structs are storage by default (values are stored in the blockchain).

Solidity can handle different types of data and provides different types of variables to handle each type. When you define variables, you have to specify the datatype of the variable. The datatype tells Solidity how much space to allocate for the value you will store in the variable and how to treat the data. The following table lists the data types that Solidity supports.

Solidity Data Types
Data type Comments Example When to use
uint 32-byte (256 bit) unsigned integer. You can also define smaller uints as uint8, unit16, … up to uint256 (which is the same as uint). uint x = 10;

uint16 x = 44;

To store positive integers. Using smaller uints (such as uint8) saves storage space and processing cost.
int 32-byte (256 bit) signed integer. You can also define smaller ints as int8, int16, … up to int256 (which is the same as int). int x = -10;

int32 x = 45;

To store integers with negative and positive values. Using smaller ints (such as int8) saves storage space and processing cost.
byte A single byte. You can also define arrays of 1–32 bytes using the type bytes2, byte3, … up to bytes32. byte singleChar = ‘t’;

bytes16 msgHello = ‘Hello, world!’;

To store any number (up to 32) bytes. The bytes datatype makes it easy to access and manipulate array contents.
string 32-byte array of characters. This datatype is most often used to store strings of UTF-8 characters. string myString = “Hello, world!”; To store character strings. Solidity strings are difficult to manipulate directly. In most cases, using bytes is more convenient.
bool Boolean, or logical, values (yes/no or true/false). bool isOK = true; To store yes/no, true/false values.
address 20 byte Ethereum address. address myAddress; To store an Ethereum address.
mapping A dictionary that relates key to a value. Mappings provide an easy method to lookup a value that corresponds to a key. mapping (address => uint) balances; To lookup data for a specific key, such as finding the balance of an account.
enum Enumerated list of options. enum surveyResult { StronglyDisagree, Disagree, Neutral, Agree, StronglyAgree }; To store meaningful values from a limited set of choices.

As your smart contracts become more complex, you’ll probably need to represent more complex types of data. For example, you might want to define a physical address type that contains several pieces of information, including street address, city, state, and postal code.

You also might need to store tables or lists of data. Solidity allows you to create your own data structures with the struct complex data type. You can also define arrays that store groups of similar data items. Solidity arrays can be groups of simple data types or groups of structs.

Here is a smart contract that demonstrates some of Solidity’s simple data types. In this example, you’re using only state variables, which means you’re writing to the blockchain. Defining all of your variable as state variables is not a good idea unless you want to store data forever. Data stored to the blockchain requires expensive operations and shouldn’t be used unless you need to store your data persistently. For now, you’ll use state variables.

Open VS Code for the myProject project:

To open VS Code in the myProject project, open a Windows Command prompt or PowerShell (my favorite) and use the cd command to navigate to your project directory (myProject.) From here, just enter the following command and press Enter:

code .

Then type the following code or download the Ethereum project files from Dummies.

pragma solidity 0.4.24;
/*
* @title Solidity data types
* @author Michael Solomon
* @notice A simply smart contract to demonstrate simple data types available in Solidity
*
*/
contract DataTypes {
uint x = 9;
int i = -68;
uint8 j = 17;
bool isEthereumCool = true;
address owner = msg.sender; //Ethereum address of the message sender
bytes32 bMsg = "hello";
string sMsg = "hello";
function getStateVariables() public view returns (uint, int, uint8, bool, address, bytes32, string) {
return (x, i, j, isEthereumCool, owner, bMsg, sMsg);
}
}<

Before you can deploy and test your new smart contract, you need to add it to the migration JavaScript script. In VS Code, open the 2_contracts_migrations.js file in the Migrations directory. Then add the two lines with comments so your file looks this:

var HelloWorld = artifacts.require("HelloWorld");
var DataTypes = artifacts.require("DataTypes");// Add this line
module.exports = function(deployer) {
deployer.deploy(HelloWorld);
deployer.deploy(DataTypes);// Add this line
};

Don’t forget to save your file after adding the new text!

Here are the steps you can use to deploy and test your new smart contract:

  1. Make sure you have Ganache running.
  2. In VS Code, click or tap the Terminal tab, type the following, and then press Enter:truffle deploy --reset
  3. Type truffle console and press Enter.
  4. At the Truffle console prompt, type the following and press Enter:DataTypes.deployed().then(function(instance) {return instance.getStateVariables() });

The following image shows the values that your new smart contract returns. Truffle displays the return values in an interesting way. Numbers are returned as BigNumber objects. You can call functions in a BigNumber library to convert them, but for now just read the values directly.

For the numeric returned values, the first value, s: is the sign of the number, and the third value, c: is the unsigned value the function returned. Also note that the address and bytes32 values are in hexadecimal format.

Ethereum smart contract
Smart contract return values.