The many ways of testing Smart Contracts in Ethereum

In an earlier blog post, Alexey has written about the development lifecycle of an Ethereum contract.
The Truffle Framework allows one to compile, test, deploy, and manage Solidity smart contracts.
In this follow-up, I would like to elaborate about the Ethereum networks that can be used for this, because it turns out, there are many of them!
Also, we’ll take a look at what other things we can do when we pick an alternative network.

But before that, let’s talk about why we would want to do this in the first place.
For starters, the main Ethereum network requires us to stake actual money when deploying and interacting with a contract.
That is, before we can start experimenting with a contract, we need to send Ether to our wallet via a public exchange in order to pay the regular gas fees.
For experiments, this is surely overkill.

This is why test networks exist.
They largely use the same algorithms and protocols as the Ethereum main net, but the common understanding is that their currency – i.e. test Ether – has no value.
Consequently, we don’t have to spend money to deploy our contracts.

There’s a variety of different test networks.
Let’s take a look at the most common ones:

Ropsten

Ropsten is essentially a parallel universe to the Ethereum main net.
It is supported by both major clients (Geth and Parity) and uses virtually the same settings as the main network.
However, the difficulty to mine blocks is orders of magnitude lower in Ropsten: it should be possible to mine a few Ether on commodity hardware in a short time.

Rinkeby

Rinkeby is a test network where only a small group of nodes can mine blocks.
This approach is called Proof-of-Authority (PoA), as opposed to Proof-of-Work (PoW):
In PoW networks (like the Ethereum mainnet), any participant with enough compute power can process transactions by including them in a block and solving the hash puzzle.
In Rinkeby, only a few authoritative nodes are allowed to do that.
This means that those nodes completely control the transactions; on the other hand, this approach requires less energy.
As of writing, Rinkeby comprises seven such nodes.

Kovan

Kovan, as Rinkeby, is also a PoA network.
It differs from Rinkeby by the consensus algorithm and the supported client: Rinkeby is only supported by Geth, whereas Kovan is only supported by Parity.
Additionally, Parity has added support for other experimental features, which means that conditions may differ significantly from the main net.
In particular, Kovan is able to execute smart contracts written in WebAssembly (more about that below).

Görli

Görli is a relatively young network that was launched in early 2019.
Like Rinkeby and Kovan, it uses PoA, but supports Geth, Parity, and a few other clients.

Ropsten and Rinkeby are named after metro stations in Stockholm, Kovan in Singapore and Görli in Berlin.

Naturally, the test networks are much smaller than the main net, where most of the action happens.
Whereas the main net has a total of over 560 million of transactions, Ropsten and Rinkeby only clock in at 119 and 42 million, respectively.
Kovan is the smallest “large” network with at a mere 25 million transactions.
Görli, being brand new, has yet to accumulate a million transactions.

On top of that, users of test networks have to expect that entire networks may disappear or be rebooted.
For example, some two years ago, Ropsten was subject of a spam attack which saw the network flooded with large transactions.[1][2]
By nature, PoA networks such as Rinkeby and Kovan are not susceptible to such problems.
This is why the Ropsten operators write:

Since the Ethereum mainnet still operates based on PoW consensus, a PoW testnet best reproduces the current production environment, i.e. system and network conditions on the live Ethereum mainnet.
Thus, Ropsten is useful for experiments to investigate certain issues that we observe today on the mainnet, such as the relation between uncle rates and gas prices.
And for Dapp developers, Ropsten is useful for realistic tests of back-end performance (i.e. mainnet transactions and block times) and front-end user experience.

In case you do not want to expend energy into mining blocks (Ropsten) or are not part of the clique that is allowed to mine blocks (Rinkeby and Kovan), how can you obtain test Ether?
Luckily, all three networks provide faucets: accounts that can “drip” Ether on request.
The concrete mechanisms differ, but in principle you’ll have to provide some website with your wallet address and they’ll send you some Ether.
In Ropsten, this can be done via a website.

Rinkeby and Kovan both require some form of authentication, in order to prevent exhausting the network’s capacity.
This usually works by filing a request through a Twitter or GitHub account.

But this obviously raises the question about privacy.
Aren’t cryptocurrencies supposed to be anonymous?
Obtaining funds via a social media identity appears to be going against that spirit.

Most test network are built by mere mortals: they use the exact same software (Parity or Geth) that is also used for peers in the main network.
On top of that, some of them use well-documented configuration.
Nobody’s stopping you from running your own instance of such a network.
This is different from forking: in a fork, the entire existing transaction history would be carried over, which is usually irrelevant for local testing purposes.
Instead, we want to start with a clean slate.

One option to do this is to look at the Görli configuration, copy the Parity files and modify it to one’s own liking.
Parity allows the specification of pre-existing balances on particular accounts; consequently one could assign a sufficiently large amount of Ether to an admin account to which one has the private key.

But assuming you’re impatient, isn’t there a way that requires less work?
Interestingly enough, Microsoft Azure offers a template that comes with a step-by-step assistant:

Azure Ethereum assistant

This allows to configure e.g. the number of participating nodes and block frequency.
The template creates a bunch of resources, including a load balancer and some virtual machines.
Clients like Metamask can be configured to use this network and then use it like any other.
Metamask communicates via an RPC protocol with the Ethereum nodes.
Azure will show the necessary (public) URL that can be then used to set up Metamask for our own private network.
It is then possible to deploy and interact with contracts in Metamask:

Metamask account overview

A pecularity is that the Azure setup does not mine currency, so all transactions have to be done using a gas fee of zero.
This shouldn’t be a problem for most up-to-date wallet software.

Equipped with these tools, it should be simple to write smart contracts using familiar tools like Truffle or Remix IDE, deploy them to the private test network and observe the propagation of transactions.
An additional advantage of running a private network is that experiments stay private: no need to broadcast your draft code to the entire world!

Depending on the test net you chose, there are some experimental Ethereum features available.
In my opinion the most exciting one is the possibility to use WebAssembly as a runtime for smart contracts.

WebAssembly(wasm) is an open assembly standard that was initially intended for the web.
Today, it can run alongside JavaScript in browsers and on the backend and languages like C++ and Rust can be compiled to it.
Already in 2016, some people started working on a draft of a next-generation Ethereum Virtual Machine using wasm instead of EVM bytecode.

A consequence of this is that smart contracts can be implemented in Rust, compiled to wasm and run on top of Parity nodes.
Bear in mind that this is highly experimental: I don’t recommend this for handling any tokens of value.
Azure has support for wasm already enabled, but it is also possible to configure this on any other Parity node.
As an example, consider a Rust implementation of an ERC 20 token (trimmed down from the original sources):

In Rust, the implementation of a contract is always separated from its interface.
Just like in Solidity, we can declare a constructor, some functions and events.
In the implementation, we can refer to the sender and arguments and write into storage.
Unfortunately, the entire Ethereum API provided by Parity is rather low-level: storage needs to be addressed by memory addresses.
Syntactic sugar like state variables and struct types that are offered by Solidity can’t be used in Rust (yet).