Everyone Should Learn Ethereum

We pride ourselves on being polyglots at 8th Light, and I learn something new from every new language and paradigm I try. If you’re a Javascript or Python programmer, learning Haskell, Rust, or Clojure will give you a new perspective on programming, introduce you to new ideas and patterns, and challenge you to think differently about your code. If you’re used to writing web applications, exploring a different domain like embedded systems or game programming will always teach you a few new tricks.

Over the past few years, I’ve been working with blockchains, web3 technologies, and smart contracts, and I’ve discovered a paradigm as weird, interesting, and challenging as anything I’ve tried before.

My own experience has mostly been with Ethereum, the most popular public programmable blockchain. Ethereum combines concepts and ideas from distributed systems and cryptography to create a system unlike any other: a distributed, singleton “world computer.” It’s a programming environment that is public, permissionless, immutable, costly, and adversarial. It will challenge you to do your very best, and make you think in new and creative ways. Whether or not you think web3 is here to stay, smart contract programming is a fascinating paradigm to explore, and I think it has made me a better programmer.

What Is Ethereum?

You may know of Ethereum as a cryptocurrency, but that’s really just one aspect of the technology. Storing and sending the digital asset called Ether is one important function of the Ethereum network, but it can do much more, including running general purpose programs called “smart contracts.” In fact, Ethereum combines a number of ideas and technologies related to distributed systems, cryptography, and computation together.

In addition to being a cryptocurrency, Ethereum is …

A peer-to-peer network

The Ethereum network consists of thousands of individual, interconnected nodes running all over the world. Each of these nodes shares data about the state of the network with all the others over a peer-to-peer gossip protocol. In this way, Ethereum is kind of like BitTorrent.

A cryptographic protocol

Actors broadcasting messages on the network are identified by public keys. The messages they send can be authenticated and verified using public key cryptography. In this way, Ethereum is kind of like SSH.

A distributed key-value store

Every account on the network can read and write from its own key-value data store. Every node on the network has its own copy of this data, for all accounts. That means it’s highly available, replicated, and robust to censorship and disruption. In this way, Ethereum is kind of like Cassandra.

A state machine

Transactions that change data in the key-value store are subject to a set of rules that describe valid state transitions, and nodes in the network use a consensus algorithm to agree on a consistent state. In this way, Ethereum is kind of like Raft.

A blockchain

Oh yeah, it’s a blockchain. A blockchain synchronizes and stores the system’s state changes. With each new block, the network transitions to a new state. The full history of states and transitions is available and verifiable. In this way, Ethereum is kind of like Bitcoin.

A payment network

End users pay for storage and computation on the network using a digital asset, which can also be used to store and send value. In this way, Ethereum is kind of like AWS and Visa at the same time.

A general purpose world computer

State transitions from block to block are processed by the Ethereum Virtual Machine, a stack-based VM. High-level smart contract programming languages like Vyper and Solidity compile to EVM bytecode executed by nodes on the network. In this way, Ethereum is like nothing else: it is a decentralized, general purpose, singleton virtual computer. (And anyone can program it!)

How to Program the World Computer

Here’s a really simple counter program written in Solidity, the most popular Ethereum smart contract language. (This excerpt is from Solidity By Example).

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract Counter {
    uint public count;

    // Function to get the current count
    function get() public view returns (uint) {
        return count;
    }

    // Function to increment count by 1
    function inc() public {
        count += 1;
    }

    // Function to decrement count by 1
    function dec() public {
        // This function will fail if count = 0
        count -= 1;
    }
}

High-level programs like this one compile to bytecode and run on the EVM. Perhaps the syntax looks familiar. (If you squint, it’s not too different from Javascript.) But what’s really interesting and challenging about writing smart contracts is the surrounding environment.

Writing programs for this shared "world computer" means working in a paradigm with a few unusual properties. In particular, the EVM execution environment is public, permissionless, immutable, costly, deterministic, and adversarial. Let's look at each of these properties in turn.

Public

Smart contract code is deployed in public, replicated across thousands of nodes on the Ethereum network. Anyone can see the deployed bytecode of any contract, decompile it, and interact with it. Any legitimate project will open-source and verify their code if they expect anyone to trust it or interact with it. If you like poking around with “view source” on the frontend, you’ll love this property: it’s like “view source” for smart contract code.

Permissionless

In addition to reading code and data, anyone on the network can call the public API of any contract at any time. Combined with the public property of code and data, it’s as if your API is always open to the world, your application logs are out in the open, and your database read replica is public. Web services kind of work this way: usually anyone can (and will) find your API endpoints and call them with unexpected arguments. But smart contracts on public blockchains take this property to the extreme.

Immutable

Once a contract is deployed, it can’t be changed. There are patterns for designing upgradeable systems and migrating from one contract to another, but ultimately the underlying code is immutable. Your bugs will be deployed forever and you have to get your design right the first time. Hope you wrote some unit tests!

Costly

Every state-changing interaction on the network has an associated cost in money, measured in an abstract unit called “gas.” Deploying code costs gas. Calling functions costs gas. Every computation and storage operation has an associated cost. This sometimes feels like being a kid at Chuck-E-Cheese: you have to keep putting quarters into the machine in order to press the fun buttons.

There is actually a good reason for gas: it’s a defense against programs that could otherwise loop forever, and payment for the computation and storage you consume. And in some ways, it’s hard to value. Is it a ripoff or a great deal that the contract I deployed for $400 will continue to work and store data until the Ethereum network disappears?

Deterministic

The EVM is a deterministic state machine. Since every node on the network must be able to validate any computation, every computation is deterministic. On one hand, this means common tasks like generating a random number, reading a file from the filesystem, or making an HTTP request are impossible on the EVM. On the other hand, it means we can simulate the outcome of any operation starting at some known state.

Adversarial

Finally, all of the previous properties combined with the fact that smart contracts are used to store and send value mean that even the smallest vulnerabilities will be found and exploited. What might be a minor bug in any other program might become the cause of a massive loss in a smart contract.

The public, adversarial nature of blockchains means testing and code quality are extremely important. It’s critical to test extensively, simulate the unexpected, and think adversarially. And the deterministic property of blockchain computation means it’s possible to test in ways that are difficult in other environments, like forking the state of the world and precisely simulating some result. I’ve always been interested in tools like property based testing, but I’ve found that smart contracts demand every testing tool in the kit: unit tests, fuzz tests, static analysis, formal verification, simulation testing, and more.

Immutability means thinking carefully about separation of concerns, modularity, and abstraction from the very start. An immutable suite of smart contracts is a true test of whether the system you’ve designed really is “open for extension but closed for modification.” It’s still possible to build iteratively and evolve immutable smart contract systems, but it demands careful thinking about design at every step.

Finally, costliness is a forcing function for simple design. Good contracts must be small, simple, opinionated, and elegant, but they rarely start that way. Optimizing gas usage requires iterating on a design until there is nothing left to take away.

If writing code for a system that has all these properties doesn’t sound like fun to you, I totally get it. It’s an extremely challenging environment. But I’ve found that it motivates me to do my best work and put everything I’ve learned about testing, simplicity, and design into practice. Constraints enable creativity, and this particular set of constraints demands excellence. I’ve learned a lot from working with Ethereum, and I think you can, too.

If you’re interested in learning more about Ethereum and Solidity, check out Tic Tac Token, or some of the Web3 work we’ve done at 8th Light.

Connor Mendenhall, Software Craftsman

Connor Mendenhall practices test, hammock, and blog-driven development.

Interested in 8th Light's services? Let's talk.

Contact Us