Understanding The Web

Ethereum Bootcamp: Solidity

Posted

In week 5 of Alchemy University’s Ethereum Bootcamp, the material dives deeper into Solidity. Building on smart contract basics, more advanced topics are explored.  Students learn about mappings, events, and the reference types arrays and structs.  Understanding the details of these data types are essential in reading and creating smart contracts.

Mappings

Hash Tables

Understanding mappings in Solidity is easier to process with a knowledge of hash tables.  A hash table is a type of data structure that implements an associative array.  Data is stored as a collection of key-value pairs.  A key represents some data to be stored.  The key is fed into an algorithm which produces a hash value.  The hash value dictates the index where the data associated with the key will be stored.  Hash tables are extremely efficient for looking up data.  The same key always returns the same value. 

Mappings

In solidity, hash tables are known as mappings.  A key is associated to a corresponding value.  Mappings are declared like other variables types in Solidity:

The mapping keywords indicates a mapping is to be created. In the example above, _KeyType is the key and the arrow => points to its value, _ValueType. These key value pairs are stored inside the mapping named mappingName.

Useful for Address Association

Mappings are useful for address association. Mappings make it easy to associate an Ethereum address with a value.  In the example below, a mapping is created to keep track of how many sodas a specific address has purchased:

Using the address as a key, a function can be used to extract the associated value:

The function above takes an address as a parameter. The function returns a uint which is a value associated with the address used as the function parameter. Using the sodasPurchased mapping created earlier, the address input is used with brackets to retrieve its associated value.

Mappings can have many use cases. Any type of data that needs a key-value pair form of tracking would be ideal to use with mappings:

Nested Mapping

Mappings can keep track of multiple associations through nesting

In the example above, an address is mapped to an association between a uint key and bool value.  This example would be a way to track whether an address voted on a proposal. 

Mappings are very useful and important to understand.  Understanding mappings gives developers an efficient way to track data.  Creating associations can be a powerful tool when using Ethereum addresses. 

Events

Introduction to Events

Events are a way to log information about a smart contract onto the blockchain.  Events are an abstraction on top of the EVM’s low-level logging functionality through log opcodes.  The low-level logs are stored in the transaction receipt.  Logs are written by smart contracts when they emit events, but logs cannot be read by smart contracts.  Logs serve the purpose of storing data on chain in a searchable and gas efficient way.

Defining Events

Events are defined in a smart contract using the event keyword.

In the snippet above, an event is named Transfer.  The event has three topics: from, to, and value.  When the Transfer event is emitted, the from, to, and value data will all be included in the event.  Code that is listening for the event will be able to filter topics that have the indexed keyword.

Emitting Events

After an event is defined, the next step is to emit the event.

Listening to Events

Smart contracts can write events, but they cannot read them.  In order to do so, a library like ethers.js can be used.  Ethers.js allows the use of a provider class which can connect to the smart contract. 

Finding Events in Logs

While using ethers.js abstracts away low level code, the eth_getLogs method interacts directly with Ethereum’s JSON-RPC endpoint.  Using this lower-level method, a loop would be needed in order to parse through all the information retrieved to narrow down the address in question.  This highlights one of the benefits of using a library like ethers.js as there is no need for a loop. 

Events and logs are stored on the blockchain in transaction receipts, but they are not required for blockchain consensus.  Because events are stored in transaction receipts, they are verified by the blockchain even though events are not a requirement for consensus.  Events are the ideal way to emit occurrences on the blockchain to the outside world.

Reference Types: Arrays and Structs

Solidity Reference types

Primitive data types in Solidity include uint/int, boolean, address, enum, and bytes. Primitive types are also referred to as value types, and they store data directly in a variable. Solidity also has reference based data types which include arrays, strings, structs, and mappings. A reference type does not store values directly in a variable.  Reference types hold a pointer to the address of the data’s location.  The important concept to understand is that primitive types hold value directly while reference types point to a data location that holds the value.

Arrays

In computer science, an array is a data structure consisting of a collection of elements that are each identified by at least one array index or key.  Arrays in Solidity behave like arrays in other programming languages. Solidity has both fixed and dynamic sized arrays.

Dynamic and Fixed Arrays

Dynamic arrays do not have a fixed size when they are defined.  Elements can be added and the size of the dynamic array will change.  Fixed arrays have a predetermined size.  The amount of elements in a fixed array cannot exceed the size of the array.

Storage arrays

Storage arrays are typically declared as a state variable and they can be either fixed or dynamic in size. Both fixed and dynamic arrays have access to the .length method which returns how many values an array holds per index.  Dynamic storage arrays also have typical array methods such as .push() and .pop().push() adds an element to the last position while .pop() removes the last element from an array.

Structs

Structs are a feature of Solidity that allow developers to define their own data type.  Structs are most often used to represent a grouping of common data.  Structs are declared similar to object declarations in JavaScript.

Arrays and Struct Use Case

The concept of a struct and the usage of arrays can be exemplified through a Library smart contract.  To keep track of books, a Book struct can be used to define a book by title, author, and id.

The struct keeps track of a single book. Single books would then be placed into a books array.

In order to add a book, a function can be used that would take arguments to satisfy the parameters of the Book struct.

In the snippet above, the add function takes two arguments.  Both arguments are strings.  When reference types are used as parameters for a function, they must be qualified by a data location declaration.  Inside the function, the push method is used to push the book into the books array.  The Book struct is initialized with three arguments as it is pushed into the books array.

Structs are an extremely useful data type that developers should familiarize themselves with.  As they are a custom data type, structs provide developers with flexibility when storing data.  They are best utilized when grouping related data together. Structs can be declared outside of a contract and imported in another contract.

Conclusion

After completing week 5 of Alchemy University’s Ethereum Bootcamp, students are equipped with advanced Solidity knowledge.  Building on the fundamental topics explored in earlier weeks, students learn more complex Solidity data types.  In Solidity, mappings function as hash tables which are ideal for creating key-value pairs. Events allow developers to monitor the changes that occur on the blockchain.  Arrays offer a way to store data while structs provide a custom data type ideal for grouping related data. The concepts covered provide developers with a strong foundation to understand and create smart contracts.