Smart Contracts 101: The Ethereum Virtual Machine (EVM)

Smart Contracts 101: The Ethereum Virtual Machine (EVM)

Before we get started

This post is the second part in a series of posts introducing the basic concepts of smart contracts from the ground up. The previous post can be found here: Smart Contracts 101: An introduction to smart contracts on Ethereum


The Ethereum Virtual Machine (EVM)

When a smart contract gets invoked its code gets executed in an environment called the Ethereum Virtual Machine (EVM). The EVM can be imagined as a virtual processor which operates on 256-bit words. Compared to modern hardware processors the instruction set offered by the EVM is rather limited. However it is powerful enough to achieve Turing completeness . That has implications of its own which we will explore further down in this post.

Instructions and bytecode

The code of a smart contract is called EVM bytecode. The bytecode itself consist of instructions, also known as opcodes. An instruction tells the virtual processor what to do. For example executing the ADD instruction will result in the top two numbers on the stack to be added together. For a complete reference of all opcodes visit ethervm.io

Open source

Once a contract is deployed to the blockchain its bytecode is saved eternally and thus publicly visible to everyone. It is also immutable and cannot, even by its creator, be changed once it has been deployed.

Example. Visit the contract page for the Dai token on Etherscan and scroll down to Contract Creation Code. What you are seeing there is the contract’s bytecode in hexadecimal representation. You can click Switch To Opcodes View to view the bytecode in human readable form.


Properties of a smart contract

A smart contracts state is defined by multiple different properties:

  • An address which is deduced by the creator’s address and account nonce. There is also the CREATE2 instruction for which the calculation of the resulting address is different. See Using Ethereum’s CREATE2 on Hackernoon .
  • A balance in ether. Contracts are able to send and receive ether.
  • Bytecode which gets executed from the first instruction when the contract gets invoked.
  • Persistent storage which is kept across executions of the contract. Storage can be understood as the contract’s hard drive.

Additionally, there are more address spaces and properties available during execution:

  • Memory which can be imagined as RAM .
  • A stack similar to the stack in a normal process. See The Stack .
  • Global variables like the current timestamp or the current block number.
  • Calldata which is additional data that can be supplied to the contract’s execution, like parameters.

The EVM provides instructions to interact with everything listed above.

On a side note: The address spaces offered by the EVM are strictly seperated from each other. A side effect of this seperation is that it prevents some classical software exploitation patterns, like overwriting the return pointer and redirecting code execution to the stack. However this does not mean that smart contracts are immune to exploitation! We will cover contract security later in this series.


Turing completeness and execution cost

Turing completeness is a complex topic and requires knowledge of further theoretical concepts to understand. The formal definition goes something like this:

A computational system that can compute every Turing-computable function is called Turing-complete (or Turing-powerful). Alternatively, such a system is one that can simulate a universal Turing machine. Source

Luckily we don’t need to understand the full formal definition. A generally accepted simplification which is sufficient for our usecase is:

Turing complete means that your mechanism can run any algorithm you could think of, no matter how complex, deep, recursive, complicated, long […] it is, and no matter how much storage or time would be needed to evaluate it. Source

The problem

A proven fact about Turing complete machines (machine in this case being our EVM) is that there cannot be a program which when given any program with any input can always reliably determine whether or not execution will come to an end or continue forever. This problem is known as the Halting Problem.

With the EVM being Turing complete what stops a malicious actor from deploying a smart contract which will run into an infinite loop, causing Ethereum nodes worldwide to eat up more and more resources from their host machines until being killed by the OS and going offline— effectively causing a global DOS attack on the Ethereum network from the inside?

And even if we ignore infinite loops, there is still the possibility to put a lot of load onto the node operators processors by executing complex instructions (like the SHA3 instruction which calculates the SHA3 hash of an input), causing nodes to consume an increased amount of resources and power. How can we make sure that node operators get compensated for the resources they supply without restricting the capabilities of the EVM?

The solution

Every instruction the EVM offers has a cost attached to its execution — the gas cost. Gas is a virtual unit used to measure contract execution complexity and resource usage which cannot be bought or sold anywhere.

While a contract runs the node keeps track of the gas it consumes. If the next instruction would cause the amount of consumed gas to exceed the gas limit — a value supplied by the initiator of the transaction which caused the contract execution — it will abort the run and mark the entire transaction as failed.

The initiator of the transaction also supplies another value called gas price which is the amount of ether the initiator is willing to pay per unit of consumed gas. This value is often measured in Gwei with 1 Gwei = 10^(-9) ether = 0.000000001 ether.

Finally the fee for a transaction can be calculated as amount of consumed units of gas * gas price. This fee is paid from the account which initiated the transaction to the miner which mines the block which includes the transaction.


Summary

In this part we covered the basic inner workings of the EVM which will serve us as foundation for the next parts to come. In the next part we will explore the different kinds of nodes in the Ethereum network and which role they play.

I am happy to receive feedback and suggestions for content you would like to see covered by the following posts. Feel free to reach out to me!